Guidelines
The 13 guardrails
Zetta's build-time rulebook and migration audit checklist in one. Every rule references tokens, so it holds across Light, Dark and Accessibility. Detection patterns are starting points — colour judgement still needs an eye.
Allowed vs banned surfaces, per theme
The "canvas integrity" rule is about the main background and structural blocks — not a theme's own legitimate surface tints. In a migration, strip the dark-in-light / bleached-in-dark / derivative fills, never a theme's real tints.
Canvas and cards are white; light surface tints are correct (surface-sidebar #fafafa, surface-muted #bcbcbc, surface-secondary #f4f4f5, semantic *-bg, brand-bg #f0fcd4).
BannedDark / navy fills, colour floods on the canvas, derivative brand shades.
Slate surfaces (canvas #1d2125, surface-card #22272b, sidebar #161a1d, surface-muted #4c555d).
BannedBleached or white cards, flooded light panels.
Pure black, high-contrast: canvas #000000, all surfaces black. Brand, borders and semantics are white; semantic backgrounds are black. Meaning is carried by label + icon + border.
BannedAny colour fill used to convey state; shadows (all none).
The checklist
Brand never shifts hue
Primary interactive elements use brand (#b6d600). Hover and active are the opacity tokens brand-hover / brand-active (85% / 70% of brand) — never a different hue, no derivative or tinted lime, in any theme. Focus adds a ring; the fill stays brand.
Danger is the one variant that shifts colour
button-danger uses danger-solid → -hover → -active (darkens in Light, lightens in Dark). No other variant shifts colour on interaction — secondary, outline and ghost shift to surface tokens. Always reference the tokens.
Brand-text is text-only
brand-text (#0a0a31) appears only as text on brand fills. Never use it as a background or fill.
Canvas integrity
Use the active theme's canvas; never replace or flood it. No dark blocks in Light; no bleached or white blocks in the dark themes (Dark #1d2125, Accessibility #000000).
Border, not shadow, for structure — and shadows are tokens
Containers separate via a 1px border (border-strong for component edges like cards, inputs and tables; hairline for subtle dividers). Shadows are shadow-sm/md/lg tokens (theme-specific; none in Accessibility) reserved for overlays and elevated surfaces only — dialog, drawer, popover, dropdown, tooltip, command palette, toast. The modal scrim is overlay.
Two radii
Component containers use rounded.base = 8px; pills, avatars, switches and progress use rounded.full; full-bleed uses rounded.none. The only smaller radius is the checkbox → rounded.sm (4px).
Type roles and floor
Inter = structure (display, headings); Geist = operation (body, label, nav, caption); Geist Mono = code and OTP. There is a 12px floor (caption). Never mix Inter and Geist within one element.
Semantic = status only; fill ≠ text; charts are their own scale
Semantic colours communicate status, never interaction (button-danger excepted). Fill tokens (success) are for icons and decoration; text tokens (success-text) are contrast-safe foregrounds — never swap them. Data-viz uses the dedicated chart-1…5 orange ramp, not brand or semantic colours; gridlines use border-strong. In Accessibility the ramp is greyscale and requires non-colour separation (pattern, dash, label).
Active sidebar nav
The active sidebar nav item takes brand-bg (a lime tint) with a brand icon and bold weight.
Announcement card border
An announcement card carries border-announcement (high-contrast against the canvas) on the border only — the surface stays the card surface.
Focus = a 2px ring
Focus adds a 2px border-focus outline at 2px offset (button-danger uses danger). border-focus is lime in Light/Dark, white in Accessibility — reference the token. Every interactive component ships an explicit focus variant; apply it. Note: border-strong is a neutral grey structural border (it was lime in ≤v0.5) — only border-focus is lime.
Icons = Material Symbols Outlined
Material Symbols Outlined at weight 300; FILL 1 only for active toggles. Icon-only controls need an aria-label.
Accessible sizing
Interactive targets are ≥ 32×32px in Light/Dark (buttons, inputs, nav items, pagination, toggles, calendar days, carousel controls). The Accessibility theme raises the floor to 44×44px via padding and size overrides. Non-interactive display elements may be smaller (e.g. small avatars).
Where the spec is silent
Build from the foundation tokens plus these guardrails and state your assumptions for areas v0.10 does not yet specify: per-component motion mapping, data-viz chart structure (axes / tooltips / chart types), empty states, z-index / stacking, form-validation UX, theme-transition behaviour, and RTL / localization. Product-level concerns (lifecycle and domain colours, card-header/footer compositions) are deliberately out of core — they live in the product-token layer. See Known gaps for the full list.