Design Tokens
All visual values are defined in src/brand/tokens.ts. This is the single source of truth. Never hardcode brand values in components — import them from tokens.
import { colors, typography } from '@/brand/tokens'Colours
Core Palette
Usage Rules
- Midnight is the dominant colour. It's used for all primary text and headers.
- Teal is the action colour. Every clickable element that invites action should be teal.
- Amber is used sparingly — for warnings, alerts, or a single warm accent. Never for CTAs.
- Canvas (
#fafaf9) is the default page background. Not pure white — warm white. - White (
#ffffff) is for cards and containers that sit on the canvas. - Aim for a ratio of roughly 70% midnight/slate, 20% teal, 10% everything else.
Semantic Mappings
For common UI patterns, use the semantic layer rather than raw colours:
import { semantic } from '@/brand/tokens'
// In components:
// color: semantic.text.primary → midnight
// background: semantic.bg.page → canvas
// borderColor: semantic.border.default → stone
// background: semantic.button.primary.bg → tealThis makes future palette changes a one-line edit in tokens.ts.
Typography
Typeface
Inter for everything. One family, multiple weights. Consistency over variety.
JetBrains Mono for data: response counts, statistics, code snippets, metadata.
Scale
| Variant | Size | Weight | Tracking | Line Height | Use For |
|---|---|---|---|---|---|
display | 48px | Light (300) | -0.02em | 1.1 | Hero headlines |
h1 | 36px | Semibold (600) | -0.02em | 1.2 | Page titles |
h2 | 24px | Semibold (600) | -0.01em | 1.3 | Section headings |
h3 | 18px | Medium (500) | 0 | 1.4 | Subsections, card titles |
body | 16px | Regular (400) | 0 | 1.6 | Prose, descriptions |
small | 14px | Regular (400) | 0 | 1.5 | Captions, metadata |
label | 12px | Medium (500) | 0.05em | 1.0 | Labels, tags (uppercase) |
Rules
- Weight does the work — Light for display, Semibold for headings, Regular for body.
- Never use Bold (700) in body text. Reserve for UI labels only.
- Tight tracking on headings, relaxed line height on body copy.
- Monospace for data. If it's a number the user is measuring, it's mono.
Spacing
All spacing follows a 4px base grid. Use Tailwind's spacing utilities where possible (p-4, gap-6, mt-8).
| Token | Value | Pixels | Common Use |
|---|---|---|---|
1 | 0.25rem | 4px | Tight gaps between related elements |
2 | 0.5rem | 8px | Inner padding on compact elements |
3 | 0.75rem | 12px | Between label and input |
4 | 1rem | 16px | Standard inner padding, mobile page padding |
6 | 1.5rem | 24px | Card padding, section gaps |
8 | 2rem | 32px | Desktop page padding, between cards |
12 | 3rem | 48px | Between major sections |
16 | 4rem | 64px | Page-level vertical rhythm |
Border Radius
| Token | Value | Use For |
|---|---|---|
sm | 6px | Tags, badges, small buttons |
md | 8px | Inputs, standard buttons |
lg | 12px | Cards, containers |
xl | 16px | Large cards, sections |
full | 9999px | Avatars, status dots, pills |
The general rule: the larger the surface, the larger the radius. But never exceed xl on rectangular elements — it starts looking playful rather than premium.