Tokens
Every visual decision is a token defined once in src/styles/tokens.css and referenced everywhere else. Click any swatch to copy its var() reference. Hardcoded hex, rgb and pixel font-sizes are not allowed outside this file.
Color
oklch throughout, themed per html.dark / html.light. Ink for content, lines for structure, accent for actions, semantic hues for meaning.
Neutrals
Accent
Accent ramp — unsigned ranges only
Heatmaps, intensity, "more vs less". Pick a contiguous slice; 500 === --accent. Never use for signed values.
Semantic — signed values
Deltas, gains/losses, status. Charts with signed meaning use these exclusively — never the accent.
Chart categorical palette
Multi-series charts assign colors in order — series 0 gets --chart-1. Read them in JS with chartPalette() from lib/charts/palette.ts.
Typography
Perfect-fourth main scale anchored at 16px, with compact named tokens for chart and specimen labels. Fira Sans bold for headings, Inter for body, Fira Code (tabular) for machine content. Fontsource assets are bundled and served locally.
| Token | Size | Sample | Use |
|---|---|---|---|
| --text-5xs | 8.5px | Agent | Reduced-scale mockup labels only |
| --text-4xs | 9px | Agent | Chart axes and compact machine labels |
| --text-3xs | 9.5px | Agent | Compact navigation and chart captions |
| --text-2xs | 10px | Agent | Machine captions and specimen labels |
| --text-xxs | 10.5px | Agent | Compact metadata |
| --text-xs | 11px | Agent | Meta, eyebrows, tag content, table dense cells |
| --text-sm | 13px | Agent | UI labels, captions, button text, table cells |
| --text-base | 16px | Agent | Body prose |
| --text-md | 18px | Agent | H6, lede paragraphs |
| --text-lg | 21px | Agent | H5 |
| --text-xl | 24px | Agent | H4 |
| --text-2xl | 28px | Agent | H3, page titles, stat values |
| --text-3xl | 32px | Agent | H2 |
| --text-4xl | 42px | Agent | H1 (clamps 32→42px) |
| --text-5xl | 56px | Agent | Public display headings |
Fira Sans
All headings, bold. The brand voice — no exceptions.
Inter
Body, labels, buttons, table cells. Regular/medium.
Fira Code
Figures, code, IDs, dates, tool names. Always tabular.
Spacing
4px base. Use tokens, never raw pixels.
Radii
| Token | Value | Shape | Use |
|---|---|---|---|
| --radius-xs | 2px | chart marks and progress tracks | |
| --radius-accent | 3px | selected-edge accents | |
| --radius-sm | 4px | tags, pills, badges | |
| --radius-md | 6px | buttons, inputs, selects | |
| --radius-lg | 7px | cards, panels, modals | |
| --radius-xl | 10px | hero figures, mockup frames | |
| --radius-full | 999px | avatars, dots |
Elevation
Cards never have shadows — a 1px --line border is enough. Shadows are reserved for floating elements only.
Motion
Subtle, fast, functional. Transform and opacity only — never layout properties. All animations are disabled under prefers-reduced-motion.
| Token | Value | Use |
|---|---|---|
| --dur-instant | 80ms | hover tints, focus rings |
| --dur-fast | 140ms | button states, tooltips |
| --dur-base | 220ms | panel slides, modal entrance |
| --dur-slow | 360ms | drawers, stream panel |
| --dur-chart | 640ms | chart entrance animations |
| --ease-standard | cubic-bezier(.22,.61,.36,1) | default for all transitions |
| --ease-emphasized | cubic-bezier(.2,0,0,1) | entrances that must land firmly |
| --ease-spring | cubic-bezier(.34,1.4,.64,1) | playful micro-interactions only |
Rules of use
Signed values (deltas, gains/losses) use --positive / --negative / --warning exclusively. Never the accent.
Unsigned ranges (heatmaps, intensity) use a contiguous slice of the --accent-* ramp.
Multi-series charts assign --chart-1…8 in series order via chartPalette().
Buttons, links, focus rings use --accent; hover steps to --accent-deep.
Headings are Fira Sans bold. Body is Inter. Machine content is Fira Code tabular. No exceptions.
Cards get a 1px border, never a shadow. Shadows only on floating elements.
Every interactive element gets the same focus halo: var(--focus-ring).
No literal hex/rgb/oklch outside tokens.css. No pixel font-sizes or radii outside the scale, and no !important in canonical CSS.