Skip to Content
EngineeringDecisions (ADRs)ADR 0007 Theme tokens and geometry

ADR 0007: Theme tokens from the brand kit, monochrome product accents, 4/8 px geometry

Status
Accepted
Date
Deciders
Founder, product team

Context

The brand kit fixes seven colours (Midnight #121C38, Cobalt #2347F2, Ice #E8EEFF, Canvas #F7F9FD, Slate #515F77, Silver #D8E0ED, White), light and dark semantic tokens (tokens/brand-tokens.css: light action Cobalt with White label, dark action Ice with Midnight label, dark surface Midnight), four status pairs that are identical in both themes, radii 4 px (controls) and 8 px (cards), and motion 120/180/240 ms. tokens/accessibility.md measures Cobalt on Midnight at 2.61:1 (“Decorative only”) and forbids Cobalt as dark-theme text. The forge method expects one accent hue per product; the kit is deliberately monochrome and says status colours are the only functional colours. The forge defaults (radii 8/12 px, product hues) had to yield to the kit.

Decision

  • Semantic tokens map the kit one to one (PRODUCT-PLAN.md Part 2 B.2). Derived UI values that are not brand colours: #1B39C4 (hover step of Cobalt), #1C2848 and #26345C (rail hover/active, lifted Midnight), #0C1329 (dark rail, one step below Midnight). Status pairs are the kit’s and are not lifted in dark.
  • Product accents are tonal steps of the brand palette: evidence Cobalt #2347F2, plans #1B39C4, review Slate #515F77, progress Midnight #121C38, with light tints Ice, #DDE4FB, #E6EAF1, Silver and text tokens #1B39C4, #14289A, #3F4B60, #121C38. Dark accents are lifted so icons reach 3:1 on Midnight: #7D94FF, #A9B8FF, #A7B4CC, #D8E0ED; dark tints are 22 % mixes over Midnight stored as hex (#2A3664, #333E64, #333D59, #3E4760); dark text is Ice for all four. Product identity is carried primarily by the kit’s icons (source, modules, review, program) and labels.
  • Geometry and motion follow the kit: --shape-radius: 4px, --radius-panel: 8px, --radius-graphic: 0, --motion-fast/normal/slow 120/180/240 ms with cubic-bezier(0.2, 0, 0, 1), focus outline 2 px offset 3 px, reduced motion to 0.
  • Typography: IBM Plex Sans for display and headings (500/600, tracking -2 %/-1 %), Inter for body, labels and captions; tabular numerals on tables.

Measured on 2026-09-13 with web/scripts/check-contrast.mjs --verbose: check-contrast: ok (90 pairs across 2 themes; text >= 4.5:1, icons >= 3:1; lowest 5.57:1 for "status neutral on its background" in light). Selected pairs: Midnight on Canvas 15.95, White on Cobalt 6.45, Cobalt on Ice 5.56, Ice on Midnight 14.50, #1B39C4 on Canvas 8.20, Slate on Ice 5.57, dark #7D94FF on Midnight 6.05, dark #A7B4CC on Midnight 8.04. docs/scripts/check-tokens.mjs: check-tokens: ok (80 token values match).

Consequences

  • forge.config.json palette keys are the CSS custom properties; web/app/globals.css, docs/app/globals.css and deck/src/tokens.css are generated from it and are identical.
  • The deck’s CSS gate whitelist lacks 4px, so radii are always written as var(--shape-radius) / var(--radius-panel).
  • Products look alike in colour by design; screens rely on icon and label for identity, and accents never carry status meaning.

Alternatives considered

  • Four distinct hues derived from the brand family: stronger product identity, but introduces colours the kit does not define; rejected by the user.
  • Forge default geometry (8/12 px): contradicts the kit; rejected.
  • Dark card one step lighter than Midnight: the kit sets dark surface = Midnight; kept the kit’s value and separate cards with a Slate hairline.

Follow-ups

  • Record the measured ratios on the docs “Brand and theme” page (docs writer).