Skip to content
Brand guide

Chapter 12

Accessibility

Target: WCAG 2.1 AA. Not because a regulation says so — because the audience is an owner-operator reading a phone in daylight at the end of a long day.

12.1 Contrast

Every ratio below is computed from tokens/tokens.json at build time and rendered live in the colour explorer.

Text on light surfaces

PairingRatioGrade
ink on paper16.14:1AAA
ink-body on paper13.14:1AAA
ink-muted on paper5.16:1AA
ink-muted on white5.61:1AA
ink-muted on mist4.87:1AA
accent #C4602A on white4.16:1✗ Fail
accent-ink #A34A1F on white5.90:1AA
accent-ink on paper5.43:1AA
accent-ink on accent-light4.73:1AA

Buttons

PairingRatioGrade
white on accent #C4602A4.16:1✗ Fail
white on accent-ink #A34A1F5.90:1AA
white on accent-hover #A84E225.56:1AA

Dark

PairingRatioGrade
on-ink on ink15.60:1AAA
accent-lift #E07A38 on ink5.86:1AA
accent #C4602A on ink4.23:1✗ Fail for body
dark.muted #98938C on ink5.76:1AA
#7A7570 on ink3.85:1✗ Fail for body

Status pairings

All six clear AA: success 5.43:1 · attention 4.98:1 · warning 6.25:1 · error 8.98:1 · info 7.88:1.

The two rules that follow

  1. #C4602A never carries letterforms on a light surface. Use #A34A1F.
  2. #C4602A never carries letterforms on a dark surface either. Use #E07A38.

12.2 Non-text contrast

WCAG 1.4.11 requires 3:1 for UI component boundaries and meaningful graphics.

PairingRatioVerdict
border-strong #D8D5D0 on white1.46:1Decorative only
border #E5E2DE on white1.29:1Decorative only
accent focus ring on paper3.82:1✅ Passes

Neither border colour identifies a control on its own. That is acceptable under the standard provided the control is identifiable another way — and in this system it always is:

  • Inputs have a persistent visible label and a 3.82:1 focus ring.
  • Buttons have a fill (primary, destructive) or a text colour clearing 4.5:1 (secondary, ghost).
  • Cards are containers, not controls.

Do not ship a control whose only affordance is a #D8D5D0 hairline. If you need a boundary to carry meaning by itself, darken it to at least #949089.


12.3 Focus

  • One ring everywhere: 2px solid #C4602A, outline-offset: 2px.
  • Global in tokens/since-brand.css on *:focus-visible.
  • Never outline: none without an equivalent replacement in the same rule.
  • The ring appears instantly — never transition a focus outline.
  • Focus moves into a dialog on open and returns to the trigger on close.
  • Tab order follows visual order.

12.4 Semantics

RequirementDetail
One h1 per pageThe PageHeader title. Never skip levels
Landmarks<main>, <nav aria-label>, <aside>, <header>
Buttons vs linksA link navigates; a button acts. <div onClick> is a bug
LabelsEvery input has a real <label for>
Tablesscope="col", and a visually hidden <caption>
ListsReal <ul>/<ol>. Stat tiles are <dl> with dt/dd
Iconsaria-hidden="true"; the label goes on the control
Dialogsrole="dialog", aria-modal="true", aria-label
Current pagearia-current="page" on the active nav row and last crumb
Live regionsrole="alert" on error and warning alerts only
Skip linkFirst focusable element on the page

12.5 Colour independence

WCAG 1.4.1 — colour is never the only signal.

  • Status chips carry a dot and a word.
  • Chart series are labelled directly, not only via a legend swatch.
  • Errors carry text, not just a red border.
  • Required fields are marked in text.
  • Links in prose are underlined, not colour-only.

Test: screenshot the page, desaturate it, and check every state is still readable.


12.6 Motion, targets, zoom

  • prefers-reduced-motion: reduce collapses every transition to 0.01ms. Ships in the token CSS.
  • Hit areas are 44×44px minimum, including padding.
  • The layout must survive 200% zoom and a 375px viewport without horizontal page scroll. Wide tables scroll inside their own box.
  • Text must reflow at 320px CSS width (WCAG 1.4.10).

12.7 Language and content

  • <html lang="en">; lang="fi" on Finnish passages.
  • Link text makes sense out of context — never "click here", never a bare URL.
  • alt describes the information, not the picture. Decorative images get alt="".
  • Sentence case is easier to read than Title Case for people with dyslexia — another reason for the rule in verbal identity.

12.8 Review checklist

Before shipping any surface:

  • Tab through it. Every control reachable, focus always visible, order sensible
  • Desaturate it. Every state still legible
  • Zoom to 200%. Nothing clipped, no horizontal page scroll
  • 375px viewport. Tables scroll in their box; modals fit
  • Every input has a visible label
  • Every icon-only button has aria-label
  • One h1; heading levels do not skip
  • Error messages say what to do
  • Text contrast ≥ 4.5:1; boundaries that carry meaning ≥ 3:1
  • Reduced motion honoured

This chapter as plain markdown: /docs/accessibility.md