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.

Spec — Accessibility theme modes

*tatus* 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/protanopiasafe palette: red→orange, green→blue (highdistinguishability 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 *he 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.

Followup ticket required in `tools/designgen to ratify -drsuccess / -kdrdanger / -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 followup Verge tokenset 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 sidebyside.

R6 — Nutrition-labels integration

Products that ship working colorblind / lowvision 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

  • Autodetect from OS (forcedcolors media query is separate spec).
  • Perlocale typography overrides beyond size/weight (e.g., script

    specific weight rebalancing for CJK).

  • Windows high-contrast bridge (separate spec).

Source: ../home/koder/dev/koder/meta/docs/stack/specs/themes/a11y-modes.kmd