ADR-0011 — Surfaces instead of themes
Status: Accepted (implemented 2026-10-10, DS-1). Supersedes ADR-0009.
Context
The brief alternates light and dark materials deliberately: paper sections, concrete panels, graphite and night rooms, signage plates in yellow and blue, botanical accents. That isn’t a theme a visitor toggles; it is composition. The brief’s palette also fails WCAG when used naively: gray on off-white is 3.86:1, transit blue on graphite 2.16:1, yellow on off-white 1.51:1.
Decision
- A surface is a material a section declares with
data-surface="…":paper(default),concrete,graphite,night,botanical,signal-yellow,signal-blue,signal-red. It paints its background and rebinds every semantic role (fg,fg-muted,rule,rule-strong,action,action-fill(-fg),focus,status-*,surface-alt) for its descendants. Components read roles only. - Roles are derived: a primitive moved in OKLCH lightness (hue and chroma kept)
until it reaches the target contrast against
surface-alt, the harder of the surface’s two tones. Any role can be hand-overridden per surface. scripts/check-contrast.tsasserts every promised pair on every surface in CI.- No
prefers-color-schemedark mode. The page composition decides tone.
Alternatives considered
- Light/dark themes: a dark-mode paper section would no longer be paper. The composition is the design.
- Hand-picked hex per role per surface (~70 values): brittle. A primitive change ripples nowhere, and nothing guarantees the pairs still pass.
Consequences
-
signal-red (added 2026-10-10): the brief’s red as a surface gave paper text only 4.54:1 and derived “muted” text lighter than primary. The surface uses the same hue/chroma darkened to 6:1 against paper (
#B21B1E). The checker now also asserts hierarchy:fg-mutedmust be quieter thanfgon every surface. -
The first run of the checker caught a real defect: muted text derived against the surface failed on its panel tone. This is why derivation targets
surface-alt. -
Derived values sometimes shift hue perception slightly (e.g. graphite’s link blue is
#5A9CEE). Overrides exist for when the eye disagrees with the math.