A11y theme modes (color-blind, low-vision)

mandatory

Two additional theme modes alongside Verge light/dark — `color-blind` (deuteranopia-safe palette swap) and `low-vision` (text size +20%, font-weight ≥500, contrast floor AAA). User opt-in via Settings; persisted in `koder.a11y_mode`. Mirrors Duet (LocalTapiola) practice.

Status: v0.1.0 — Draft. Companion to Verge v0 (specs/themes/verge.kmd). v0 introduces the SELECTORS + token overrides; per-product implementation in koder_kit / koder_web_kit is sub-ticketed.

R1 — Two new modes

Mode Selector Default Purpose
color-blind [data-a11y-mode="color-blind"] OFF Deuteranopia/protanopia-safe palette: red→orange, green→blue (high-distinguishability pair)
low-vision [data-a11y-mode="low-vision"] OFF Larger text, heavier weight, AAA-floor contrast

Modes compose with light/dark ([data-theme="dark"][data-a11y-mode="color-blind"]).

R2 — Color-blind palette deltas

Verge v0 (Adwaita-based) currently exposes only bg / surface / surface-2 / text / text-muted / accent / accent-on / border / focus. Semantic status tokens (success / danger / warning) are NOT yet ratified in internal/kinds/verge.go. Until they are, color-blind mode v0 ships the selector only — the swap table below is the contract semantic tokens MUST honor when added.

Verge role (proposed) Default light color-blind light Default dark color-blind dark
--kdr-accent #1f3a93 (blue base) unchanged #6fa3ff unchanged
--kdr-success (TBR) #1a7f37 (green) #2563eb (blue) #46c476 #60a5fa (blue)
--kdr-danger (TBR) #cf222e (red) #ea7c34 (orange) #ff7b7b #f59e0b (amber)
--kdr-warning (TBR) #d29922 (amber) #a855f7 (violet) #f0c674 #c084fc (violet)

Rationale: deuteranopia-safe pairs use blue/orange axis where the typical red/green axis fails.

Follow-up ticket required in tools/design-gen to ratify --kdr-success / --kdr-danger / --kdr-warning tokens in Verge before the color-blind mode can carry semantic meaning.

R3 — Low-vision deltas

Token Default low-vision
--kdr-fs-base 16px 19px (+20%)
--kdr-line-height (TBR) 1.5 1.6
--kdr-font-weight-min (TBR) 400 500
--kdr-contrast-floor (TBR) 4.5 (WCAG AA) 7.0 (WCAG AAA)

Tokens marked (TBR) (to be ratified) are not yet in Verge v0; their introduction is gated on a follow-up Verge token-set expansion ticket. --kdr-fs-base already exists and IS swapped in v0 of this spec — text-scaling support ships immediately.

R4 — Implementation contract

  • base.css ships [data-a11y-mode="color-blind"] and

    [data-a11y-mode="low-vision"] selectors at the same cascade level as [data-theme="dark"]. Tokens cascade through; products that use var(--kds-color-...) get the swap for free.

  • Settings drawer ratchets the 4-segment control: default /

    color-blind / low-vision / both. Last option applies both selectors.

  • localStorage key koder.a11y_mode persists choice; anti-flash

    script sets the data-a11y-mode attr on <html> before first paint (same pattern as data-theme).

  • tools/design-gen/cmd/verge-contrast-audit extends to also audit

    pairs under both new modes; CI fails on regressions.

R5 — Live demo

/<locale>/themes/a11y-modes/ renders a sample card (heading + body + button + success + danger pills) in 4 modes side-by-side.

R6 — Nutrition-labels integration

Products that ship working color-blind / low-vision support SHOULD declare in their koder.toml:

[a11y_labels]
color-blind-mode = "supported"
high-contrast    = "supported"     # if also adding forced-colors
dynamic-type     = "supported"     # implied by low-vision

Per specs/accessibility/nutrition-labels.kmd.

Não-escopo

  • Auto-detect from OS (forced-colors media query is separate spec).
  • Per-locale typography overrides beyond size/weight (e.g., script-

    specific weight rebalancing for CJK).

  • Windows high-contrast bridge (separate spec).