The system layer beneath the brand. Three tiers — primitives, semantic, component — that translate brand expression into reusable, role-based values.
Engineers and design tools consume tokens/tokens.css — a single CSS variables file. Three tiers organize the values:
Raw brand values: hex codes, spacing pixels, font sizes. The truth source. Never reference directly in components.
Role-based: surface.canvas, ink.default, border.focus. This is the API.
Per-component overrides: btn.radius, input.padding. Optional layer.
/* In a component, always reference semantic tokens */ .button { background: var(--btn-primary-bg); color: var(--btn-primary-ink); padding: var(--btn-padding-y) var(--btn-padding-x); border-radius: var(--btn-radius); transition: background var(--motion-state); } .button:focus-visible { outline: var(--state-focus-ring-width) solid var(--state-focus-ring); outline-offset: var(--state-focus-ring-offset); }
Backgrounds and container fills. Use surface.* wherever a component needs a fill. The page itself sits on surface.canvas; cards on surface.default.
| Preview | Token | Value | Role |
|---|---|---|---|
--surface-canvas | #FAF9F7 | Page background — warm off-white | |
--surface-default | #FFFFFF | Cards, panels, form fields | |
--surface-muted | #F2F1EB | Hover state on light surfaces | |
--surface-subtle | #E0E8EB | Callouts, info panels, element-notes | |
--surface-inverse | #1F1E1E | Dark sections, navigation chrome | |
--surface-inverse-soft | #1E4D5C | Dark-but-warmer dark sections | |
--surface-brand-primary | #061A49 | Hero, primary brand surface | |
--surface-brand-action | #2531A5 | CTA fills, action buttons | |
--surface-brand-accent | #CD9F36 | Emphasis, insight pulls | |
--surface-brand-cream | #F9F8F2 | Warm neutral surfaces |
Text colors. ink.default is full Grounded Black at 100%. ink.muted only for meta/captions — never body. ink.action is the link / interactive label color.
| Preview | Token | Value | Role |
|---|---|---|---|
--ink-default | #1F1E1E | Body, headings, default text | |
--ink-muted | #6B6B6B | Meta, captions, low emphasis (NOT body) | |
--ink-subtle | #9A9A9A | Placeholder, very-low emphasis | |
--ink-inverse | #F9F8F2 | Text on dark surfaces | |
--ink-brand | #1E4D5C | Eyebrows, secondary brand ink | |
--ink-accent | #061A49 | Primary brand text emphasis | |
--ink-action | #2531A5 | Links, action labels | |
--ink-warning | #B55312 | Friction, challenge, errors | |
--ink-emphasis | #CD9F36 | Insight pulls (use sparingly) |
| Preview | Token | Value | Role |
|---|---|---|---|
--border-subtle | #E4E2DE | Default rule line, card borders | |
--border-default | #CFCDC8 | Hover state on inputs | |
--border-strong | #1F1E1E | Secondary buttons, attribute-table head | |
--border-focus | #2531A5 | Focus ring, active inputs | |
--border-brand | #1E4D5C | Callout left accent |
Semantic mappings derived from the brand: Slate for affirmative/info, Ochre for warning/critical. Each set comes with a soft surface, a stronger border, and a high-contrast ink for body copy.
Use for affirmative confirmation, "do" guidance, and positive state messaging. Slate-derived.
Use for neutral context, callouts, and informational annotations. Identical visual language to the type-page element-note.
Use for caution, "don't" guidance, and friction states. Ochre-derived.
Use for blocking errors, destructive confirmations, and high-stakes warnings. Stronger ochre treatment.
4px base. Use semantic tokens (gap.tight, gap.default, gap.loose, gap.section) in components — primitives only when a specific pixel value is required.
--space-052px--space-14px--space-28px--space-312px--space-416px--space-520px--space-624px--space-832px--space-1040px--space-1248px--space-1456px--space-1664px--space-1872px--space-2080px--space-2496px| Token | Resolves to | Use for |
|---|---|---|
--gap-tight | 8px | Within a component (button label ↔ icon) |
--gap-default | 16px | Between fields in a form |
--gap-loose | 32px | Between content blocks |
--gap-section | 72px | Between major page sections |
The brand favors editorial precision over softness. Default to radius.none; use radius.sm for chrome (badges, tags, inputs); use radius.pill only for filter pills and toggles.
--border-11px · subtle--border-22px · strong--border-33px · accentComposite tokens — each maps to family + weight + size + line-height + tracking. See Type Scale and Brand Fonts for design rationale.
--type-display--type-h1--type-h2--type-h3--type-h4--type-body-lg--type-body--type-body-sm--type-pull-quote--type-eyebrow--type-ctaInconsolata is reserved. Use only for attributions and CTAs — never for eyebrows, labels, or general meta.
Four durations, three easings. Default to --motion-state for component state changes. Hover should feel imperceptible-but-confirmed; modal transitions should feel deliberate.
--motion-duration-quick
Hovers, micro state changes.
--motion-duration-standard
Default for most state transitions.
--motion-duration-deliberate
Modal entrance, expressive moments.
--motion-duration-slow
Page-level, hero choreography.
| Token | Curve | Role |
|---|---|---|
--motion-easing-standard | cubic-bezier(0.2, 0, 0, 1) | Default — for most transitions |
--motion-easing-entrance | cubic-bezier(0, 0, 0.2, 1) | Elements entering the screen |
--motion-easing-exit | cubic-bezier(0.4, 0, 1, 1) | Elements leaving the screen |
--motion-easing-emphasized | cubic-bezier(0.2, 0, 0, 1) | Drawing attention; key moments |
The brand is largely flat. Reserve elevation for system moments — focus indication, overlays, modals.
--elevation-none
--elevation-overlay
--elevation-modal
2px Intentional Blue, 2px offset. Always visible on keyboard focus — never outline:none without a replacement.
--container-narrow640px--container-prose720px--container-default960px--container-wide1200px| Token | Min width | Surface |
|---|---|---|
--breakpoint-sm | 640px | Large phone / small tablet |
--breakpoint-md | 900px | Tablet · most desktop content kicks in |
--breakpoint-lg | 1200px | Standard desktop |
--breakpoint-xl | 1440px | Large desktop / dashboard |
Non-negotiable rules baked into the system. Components inherit these — don't override.
| Rule | Why |
|---|---|
| Body text contrast ≥ 4.5:1 | WCAG AA for body. See Color → Accessible combinations. |
| Large text contrast ≥ 3:1 | WCAG AA for ≥18pt or ≥14pt bold. |
| Focus ring always visible | Keyboard users must always see what's focused. |
| Min touch target 44×44px | iOS HIG / WCAG 2.5.5 minimum. |
Motion respects prefers-reduced-motion | Components must collapse animation when set. |
| No color-only signaling | Always pair color with icon, label, or pattern. |
This token layer is the foundation. The remaining design system pieces hang off it:
| Layer | Status |
|---|---|
| Components — Button, Input, Card, Tag, Modal, Tooltip, Nav, Toast, Table | Pending |
| Iconography — Library, sizes, stroke discipline | Pending |
| Data viz palette — Categorical + sequential, colorblind-safe | Pending |
| Microcopy patterns — Errors, empty states, button labels | Pending |
| Motion library — Named animations beyond duration/easing tokens | Pending |