Accessibility
Vermilion and Moss are never the only signal. Every state has a glyph and a label, every control has a 44px hit area, every animation has a still version. The numbers below are computed from the token file when this page loads.
Token pairs, both modes
| Mode | Foreground | Background | Sample | Ratio | AA text | AA large / UI |
|---|
Two light-mode pairs fail: see the checklist at the foot of this page for the proposed token changes. AA text = 4.5:1. AA large text and UI components = 3:1. Vermilion 500 on cream is a mark and large-type colour; --milo-agent-ink (600) carries body text.
Map
- Tab / Shift TabMove through every interactive element in reading order. Rows are focusable as a unit; their actions follow.
- ↵Open the focused row, run the selected command, submit Quick Entry.
- SpaceToggle a disclosure, switch, or tab.
- ← →Move between tabs and recipe buttons.
- ↑ ↓Move within a list, menu or palette.
- EscDismiss the pill, Quick Entry, palette, popover or permission — always returns focus to the invoker.
- ⌘ KQuick Entry.
- ⌘ ⇧ DSwitch light / dark.
- ⌘ .Pause the current run.
Focus is visible
Two-pixel Vermilion ring, two-pixel offset, on every focusable element. Try it:
- Queued
Labelling
- GlyphsEvery ◉ ● ⌁ △ is
aria-hidden; the adjacent label is the accessible name. - Voice pill
role="status",aria-live="polite". The state word and transcript are announced as they change. - Run indicatorStandalone:
role="img"with "Running, step 3 of 5". In a row: decorative, the .state label speaks. - Progress
role="progressbar"with value, min, max and anaria-labelnaming the work. - DisclosureNative
<details>: expanded state comes for free. - Permission
role="dialog"/"alertdialog", labelled by the ask, focus trapped, Esc returns focus. - ImagesArt and nature carry the artist, title and institution in
alt; Milo interpretations say so.
Reduced motion and font scaling
Under prefers-reduced-motion the tokens collapse every duration to ≤120ms, ambient motion stops and the dither transition draws its final frame. Status: …
Font scaling: the whole system is in rem on a 4px baseline. Drag to preview 100–150%.
Preview
What matters now?
- Render Day 1 voice trackRunning
44px hit area
Visual size may be small. The hit area is not. Buttons extend their hit area 4px in every direction with a pseudo-element; rows, switches and nav items set min-height: 44px.
Dashed Vermilion = hit area (illustrative).
Remove the colour, keep the meaning
Milo is ◉ and a left rule. Offline is ⌁ and a boxed field. Position and glyph carry the ownership before Vermilion or Moss do.
Status
- Text contrast ≥ 4.5:1 for primary and secondary ink, both modes (table above)
- UI contrast ≥ 3:1 for hairline-strong, focus ring, error and both accents (marks and large type)
- Keyboard reachable: every control, row, tab, menu, dialog
- Visible focus on every focusable element
- Glyphs hidden from AT; labels present on every state
- Live regions on pill and toasts
- prefers-reduced-motion honoured in CSS and the engine
- Font scaling to 150% without overlap (rem, clamp, 4px baseline)
- Targets ≥ 44px
- Colour never the sole indicator (JEV colorstate gate)
--milo-agent-inkon cream measures 4.46:1 — 0.04 short of AA text. Proposed: darken Vermilion 600 to #C0361A (≈4.9:1). Logged in MILO_OPEN_QUESTIONS.--state-warning#D9A21B on cream is 2.0:1 — it is always paired with △ and a label, but as a colour it fails even the 3:1 UI bar. Proposed: #9A6E05 on light. Logged.- Automated axe scan results are recorded in evidence/accessibility.md; manual VoiceOver pass is an open item