tokens/semantic_colors.dart as DesignSystemColors, a Flutter ThemeExtension with two static instances — DesignSystemColors.light and DesignSystemColors.dark — built from a single brightness factory so the modes cannot drift, installed by AppTheme, and read via context.colorTheme.
The grammar
Four rules govern every token below:- Same step, same job. Light and dark use the same scale position for the same role — optical relationships survive the mode switch.
- Containers set loudness; glyphs set legibility. Surfaces are planes content sits on; content tokens guarantee contrast against the whole surface band they’re legal on.
- Persistent states get tokens, transient states get ink. Selection is a token (
stateSelected); a press is an alpha ink composited over whatever it touches. - Disabled is a collapse. Container drops to step 5, content to step 8 — deliberately washy, WCAG-exempt.
Surfaces
Solids & accent
Content
Borders
States, inks, overlay
Brand surfaces
Mode-invariant spotlight planes, chosen per card:surfaceBrandLavender, surfaceBrandGreen, surfaceBrandOrange, surfaceBrandYellow, surfaceBrandDarkBeige, surfaceBrandLightBeige, surfaceBrandWhite, surfaceBrandBlack. Elements sitting on a mode-invariant surface must themselves be invariant — hence the pinned contentOnBrand* and solidOnBrand inks above.
Status
Error and warning each carry four roles from the cherry/amber stops:statusErrorContent (600 light / 400 dark — AA on the whole surface band), statusErrorSolid and statusErrorBorder (500 both modes — ≥3:1 non-text), statusErrorSurface (100 light / 800 dark — banner tints that pair with status content, never neutral content). Same shape for statusWarning*.
Destructive fills borrow the inverse pattern:
statusErrorContent as the fill with surfaceBg as its ink gives an AA pair in both modes (deep red + near-white in light; pale red + near-black in dark).Legacy names
The 1.0 names still compile as forwarding getters while call sites migrate —contrastStrong → contentPrimary, contrastMedium → contentSecondary, contrastWeak → contentPlaceholder, surfaceElevated → surfaceComponent, surfaceHigh → surfaceComponentStrong, disabledContainer → stateDisabledContainer, badgeRed → statusErrorSolid, badgePurple → accentSolid, errorColor → statusErrorContent, warningColor → statusWarningContent, and the surfaceOpacity01–05 tiers pin to the light alpha scale in both modes (1.0 scrims are always dark ink). New code uses the 2.0 names; the getters are removed once migration completes.