Skip to main content
Semantic colors define color by purpose, not by value. They live in 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:
  1. Same step, same job. Light and dark use the same scale position for the same role — optical relationships survive the mode switch.
  2. 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.
  3. Persistent states get tokens, transient states get ink. Selection is a token (stateSelected); a press is an alpha ink composited over whatever it touches.
  4. 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.