The system

This site, documented from its own tokens

Not a picture of the design system – the system itself. Every swatch and sample below renders from the same custom properties the rest of the site consumes, and the values are read live from the page. Change a token, and this documentation changes with the product, because it is the product. Toggle the theme (top right) and watch the values swap.

Three layers, one direction

Primitives (raw scales like --gray-400) feed semantic aliases (roles like --border-default), which feed components. Components only ever consume roles – that's what a semantic colour token buys: the whole site flips light to dark by swapping primitive values under stable role names, and red can never quietly become decoration.

Colour primitives – the number encodes the state

The scale convention is adopted from Vercel's Geist system (primary-sourced): the step number tells you which interface state it's for, so "how much darker is hover?" is never a judgement call again.

Gray – cool neutral, carries the whole interface

  • --gray-100default background
  • --gray-200hover background
  • --gray-300active background
  • --gray-400default border
  • --gray-500hover border
  • --gray-600active border
  • --gray-650input borders – a demand-grown step (≥3:1, SC 1.4.11)
  • --gray-700high-contrast background
  • --gray-800hover high-contrast background
  • --gray-900secondary text & icons
  • --gray-1000primary text & icons

Indigo – the one accent (Linear lineage, chosen at checkpoint 2)

  • --indigo-100default background
  • --indigo-200hover background
  • --indigo-300active background
  • --indigo-400default border
  • --indigo-500hover border
  • --indigo-600active border
  • --indigo-700high-contrast background
  • --indigo-800hover high-contrast background
  • --indigo-900secondary text & icons
  • --indigo-1000primary text & icons

Status families – partial by design

Green, amber and red ship only the steps components actually use, and grow when one needs more. Coverage honesty is a design-system virtue: an unused token is a promise nobody is keeping.

Success

  • --green-100
  • --green-400
  • --green-700
  • --green-900

Warning

  • --amber-100
  • --amber-400
  • --amber-700
  • --amber-900

Danger

  • --red-100
  • --red-400
  • --red-700
  • --red-900

Semantic aliases – what components actually touch

  • --bg-pageThe page itself
  • --bg-raisedCards, panels, anything sitting on the page
  • --bg-activePressed and selected surfaces
  • --bg-inverseInverted surfaces (the skip-link pill)
  • --border-defaultHairlines – the site separates with borders, not shadows
  • --border-hoverBorders under the cursor
  • --border-activeBorders of engaged or emphasised edges
  • --border-inputText-input boundaries – the 3:1 non-text bar, honoured
  • --text-primaryWords that are the point
  • --text-secondaryWords that support
  • --text-inverseText on inverted surfaces
  • --accent-solidThe one accent: primary actions, the mark, the focus ring
  • --accent-solid-hoverThe accent under the cursor
  • --accent-bgAccent-tinted surfaces (callouts, featured cards)
  • --accent-bg-hoverAccent-tinted surfaces under the cursor
  • --accent-borderAccent-tinted borders (featured cards, the term underline)
  • --accent-textAccent-coloured text and links
  • --on-accentText sitting on the solid accent

Spacing – a 4px-base ladder

Nine rungs governing macro space – margins, gaps, panel padding: the distances that group things. Micro space (the optical padding inside a button, chip or badge) is tuned to the type it wraps instead, per the macro/micro distinction the grouping lesson teaches – a button's innards are a typography decision, not a layout one. The grouping lesson's page overlay lets you check the macro claim against this very site.

  • --space-1
  • --space-2
  • --space-3
  • --space-4
  • --space-5
  • --space-6
  • --space-7
  • --space-8
  • --space-9

Radius – Linear lineage

--radius-xs
--radius-s
--radius-m
--radius-l
--radius-full

Type – two families, three weights, one scale

Satoshi (variable, self-hosted) for everything you read, Geist Mono for code. Weights stop at 600 – the restraint rule from the type lesson, held by convention rather than by a token (an honest design-system reality: not every rule is mechanically enforced, and knowing which ones aren't is part of reading a system). The scale is hand-tuned near a Major Third (modular scale) rather than generated, because optical sizes beat arithmetic at the extremes.

  • --text-xsDesign is decisions
  • --text-smDesign is decisions
  • --text-baseDesign is decisions
  • --text-lgDesign is decisions
  • --text-xlDesign is decisions
  • --text-2xlDesign is decisions
  • --text-3xlDesign is decisions
  • --text-4xlDesign is decisions

Motion – feedback first, restraint always

Four durations, two curves – reveal exists only for narrative draws. Anything longer than 300ms had better be telling a story – and everything collapses to instant under prefers-reduced-motion, which is an accommodation, not a preference.

Elevation – three steps, hairlines still first

Borders group; shadows layer. Three steps: --shadow-1 for resting cards and controls, --shadow-2 for hover lift and emphasis,--shadow-3 for genuinely floating surfaces (the glossary popover, the release pills). Shadow values are literal rather than palette-derived on purpose: palette steps invert in dark mode, and an inverted shadow is a white glow. Floating surfaces add glass – translucency with backdrop blur – which is figure/ground doing work, and deliberately never sits under small text on busy backgrounds (Apple's 26.1/26.2 walk-backs are the cautionary tale, notes 09/13).

--shadow-1 · resting
--shadow-2 · lifted
--shadow-3 · floating
glass · floating layer

Component inventory – what's actually shipped

Live renders, not screenshots. The inventory grows as courses need components; nothing is documented before it exists.

Buttons
StatesLive, not simulated: hover, press and Tab the samples in this inventory – every state answers for real. Disabled and pressed are the two frozen here.
Chips & badgesBadgeAccentPassFail
Glossary termHover or focus a marked term like visual hierarchy – the popover is this system's one floating surface.
Focus ring– two layers: a page-colour gap, then the accent. The first sample holds the ring open so you can see the anatomy; the button shows it live on keyboard focus.

Larger assemblies shipped so far: demo frame, quiz, lesson chrome, case embed, specimen stage – all visible in course 1 and the library, all built from the parts above.

The rules that keep it a system

  1. No raw colours, radii or durations in components. Anything with a hue, curve or clock is a token reference, and macro spacing rides the ladder. Two documented exemptions: micro padding inside controls (under Spacing), anddepictions – the Linear case vignette bakes its palette deliberately, for the same reason shadows stay literal: a picture of another product must not obey our theme. When a component needs something new, the token is added first – that's how the shadow, reveal-duration and xs-radius tokens arrived.
  2. Components consume roles, not primitives. --gray-400 belongs to the palette; components reach for --border-default. Roles are the API; primitives are the implementation.
  3. One accent. Indigo does every "look here" job. Status colours mean status, never decoration – the colour lesson demonstrates exactly why.
  4. Coverage honesty. Scales ship the steps in use. Growth is demand-driven, documented by this page automatically – --gray-650 is the worked example: text inputs needed a boundary clearing the 3:1 non-text bar the colour lesson teaches, so the scale grew a step (closing the gap ADR #011 had put on the record).
  5. Utilities read the tokens too. Tailwind's theme is bridged from these custom properties (@theme inline in global.css), so even utility classes can't smuggle in off-system values.