# Bracen component contracts

**Version:** 1.0
**Status:** Canonical behaviour and visual roles. A component marked provisional still requires extraction into a shared implementation.

Every interactive control has a visible label, a minimum 44px target, keyboard access, a visible focus state and a disabled/loading state where relevant. State is not communicated by colour alone. Standard transitions are 160ms and must collapse under reduced motion.

## Actions and links

### Primary button

Use for the dominant next step within an action cluster. Blue background, white text, 3-4px radius, 44px minimum height and a darker blue hover/pressed state. Loading changes the label to a present-tense verb, sets `aria-busy` and prevents a duplicate submission.

### Secondary button

Use for a genuinely useful lower-commitment alternative. White or paper background, navy text and a zinc-400 boundary. It must not look equal to the primary action. Green and sand are never button colours.

### Text link

Body links are blue and underlined. Navigation or card-title links may omit the default underline where position makes the affordance obvious, but require a hover/focus cue. External-link meaning cannot depend on an icon alone.

Rules:

- One dominant action per cluster. A sticky/header action may coexist with a page action, but the page must not present two equal primary choices.
- No capsule CTA, gradient fill, bounce, icon-only primary action or button used merely as navigation decoration.
- The homepage hierarchy is `Find my next step` primary, `Get an online estimate` secondary.

Shared implementations: `.bracen-button-primary` and `.bracen-button-secondary`. Homepage modules implement the same roles locally pending consolidation.

## Navigation

The shared header contains the text-only Bracen wordmark, quiet market context, the minimum useful information architecture and one estimate action. Desktop dropdowns are functional popovers, so a restrained shadow is permitted. Active, hover and focus states need a non-colour cue as well as colour.

Mobile uses the same destinations and labels rather than inventing a second navigation model. Opening a menu updates `aria-expanded`; keyboard focus remains inside the visible flow and returns to the trigger on close. Footer groups routes by customer task and carries editorial/commercial disclosure where relevant.

Current implementation: `src/components/layout/Header.tsx`, `Footer.tsx`, plus the global and NZ homepage shells. Consolidating the bespoke homepage headers into shared primitives is implementation debt, not permission for a second identity.

## Forms and decision tools

**Visual primitive extraction is provisional; behaviour is locked.**

- Visible label above every field. Placeholder is never the label.
- White field, 3-4px radius, zinc-400 boundary and 44px minimum height.
- Help text follows the field; error text follows help and is connected with `aria-describedby` and `aria-invalid`.
- Error copy says what is wrong and how to recover; do not rely on a red border.
- A wizard presents one coherent question group per step, with blue progress and plain back/continue actions.
- Completion may use green. Evidence never uses green.

Restyling must preserve survey IDs, service variants, Google Places mode, validation, calculations, payloads, analytics, GHL tags, deduplication and form DOM contracts. A real `<form>` is for real lead capture only so third-party form detection does not misclassify utility controls.

## Evidence, alerts and status

Evidence is an inline, dated statement of what was checked, against which source, and when. Unknown states use plain language such as `Not checked` or `Not published`.

| Role | Surface | Text | Use |
|---|---|---|---|
| Evidence/information | Blue wash with blue rule | Navy | Method, provenance, checked fact |
| Positive | Pale neutral/green support | Green plus text | Completed task or confirmed positive state |
| Caution | Sand/pale sand | Navy or accessible amber | Limitation or decision note |
| Error | White/paper | Error red plus text | Failure and recovery action |

Badges state a fact with a date. A compact pill is allowed for status or market context only. Payment never implies approval or ranking. Do not expose private contact, owner/source fields, NZBN/LBP numbers or insolvency data. Association names remain neutral in public claims.

### Badges (off-site profile badges)

The design kit file `components/badges/ProfileBadge.jsx` is the visual authority for badges a
builder places on their own site; `src/lib/badge-kit.ts` renders it as static SVG. Claims are
`listed`, `featured` (cited by name in the linked guide) and `checked`; variants are `bar`
(default), `card` and `inline`, each light or dark. Status badges carry no date because the check
date and current status live on the linked Bracen page. `topRated` and award claims exist in the
kit as proposals and are not rendered until the ranking methodology is signed off. No text below
14px at 1x.

## Ranked comparison result

- Show selection criteria, evidence boundary, update date and commercial disclosure before the first result.
- Number one may receive one sand treatment when the documented method supports its position.
- Lower ranks remain quieter; no trophies, medals or score-gauge theatre.
- Paid placement is labelled, unnumbered and visually separate. It cannot receive the number-one treatment.
- Visible order and `ItemList` structured-data order match.
- A short cost/licensing/consent answer is useful when it links to the canonical deep guide; do not duplicate the full guide.

Current implementation: `src/components/content/LanePageTemplate.tsx` and `src/lib/lane-page-content.tsx`.

## Rows, cards and media

Prefer a ruled row for directory listings, guide indexes and related links. Use a flat bordered panel only where content forms one enclosed unit. Shadow is reserved for overlays/popovers or an exceptional raised object. A content block never combines border and shadow.

Cards are not banned, but repeated floating cards are the SaaS-template signal the system avoids. Builder rows stack image, identity, evidence and action in that order on mobile.

Media uses a 3-4px radius and a neutral backing. When there is no governed image, use an honest typographic/abstract placeholder rather than a misleading stock project.

Current global primitives: `.bracen-card`, `.bracen-page-shell`, `.bracen-page-hero` and route-specific ruled structures. A shared row/evidence primitive remains to be extracted.

## Tables

- Full width, left aligned, top aligned, ruled rows and tabular numerals for numeric columns.
- The caption or introducing sentence states what is compared and the relevant date/region.
- Units remain visible.
- Reflow to a definition list on mobile where possible; horizontal scrolling is acceptable only for a true comparison that cannot reflow.
- Headers may use a short uppercase micro style; body stays at least 14.5px.

## Accordions and disclosure

Use native `<details>`/`<summary>` for FAQs and secondary detail. Do not hide price, a material limitation or the primary decision behind an accordion. The summary is a full-width 44px target. Open state uses both a chevron and a weight/rule change. Structured-data answers remain in the DOM.

The pattern is locked; a dedicated shared class remains provisional.

## Empty, loading and error states

| State | Contract |
|---|---|
| Empty | State the fact, then offer the useful alternative route. No joke or decorative illustration. |
| Loading | Skeletons match final dimensions to prevent layout shift. Avoid a spinner where a skeleton communicates better. |
| Error | State what happened, what was not changed and the next safe action. One recovery action, optional secondary route. |

All states keep Bracen chrome and voice. Global `not-found` and `error` pages follow the same pattern.

## Interaction acceptance

For every component verify default, hover, focus-visible, active/pressed, disabled, loading, error and success states where applicable. Test keyboard order, 44px targets, contrast, 320/375px reflow and reduced motion. Automated checks support but do not replace visual and keyboard QA.

## Anti-patterns

- Large rounded cards, capsule CTAs, decorative gradients, glass, glows and dashboard widgets.
- Blue and green as co-primary actions.
- Feature-icon grids or oversized spot icons.
- Equal-weight CTA clusters.
- Decorative badges implying unsupported proof.
- Long unbroken article walls or alternating coloured sections with no semantic job.
