2.1 Typography
One scale, everywhere. text-xs is the floor: a layout that needs smaller text needs fewer columns.
Faces
| Specimen | Token | Value |
|---|---|---|
| Handoff | font-sans | Inter — Default for all text |
| 0x4f2a…9c1b · 1,284,391 · 12.500000 | font-mono | DM Mono — Hashes, IDs, raw numeric values, code |
Figures
Numeric columns align because they are set in DM Mono; Inter has no tabular figures.
Size
| Specimen | Token | Value |
|---|---|---|
| The order shipped at 2:22pm | text-xl | 28px / 36px — Display — a short code read across two devices |
| The order shipped at 2:22pm | text-lg | 20px / 26px — Page headers |
| The order shipped at 2:22pm | text-md | 16px / 22px — Section headers |
| The order shipped at 2:22pm | text-base | 14px / 20px — Body default |
| The order shipped at 2:22pm | text-sm | 12px / 16px — Dense content |
| The order shipped at 2:22pm | text-xs | 11px / 15px — Component labels and secondary metadata |
Leading
The order shipped at 2:22pm and the invoice settled 12.50 USDC against a spend cap of 500.00. Three approvals were still open when the run finished, and the journal recorded every one of them.
The order shipped at 2:22pm and the invoice settled 12.50 USDC against a spend cap of 500.00. Three approvals were still open when the run finished, and the journal recorded every one of them.
The order shipped at 2:22pm and the invoice settled 12.50 USDC against a spend cap of 500.00. Three approvals were still open when the run finished, and the journal recorded every one of them.
The order shipped at 2:22pm and the invoice settled 12.50 USDC against a spend cap of 500.00. Three approvals were still open when the run finished, and the journal recorded every one of them.
The order shipped at 2:22pm and the invoice settled 12.50 USDC against a spend cap of 500.00. Three approvals were still open when the run finished, and the journal recorded every one of them.
The order shipped at 2:22pm and the invoice settled 12.50 USDC against a spend cap of 500.00. Three approvals were still open when the run finished, and the journal recorded every one of them.
Solid leading (§2.1B)
Line height equal to the size, for text centred inside a fixed-height control such as a button label.
Weight
| Specimen | Token | Value |
|---|---|---|
| The order shipped at 2:22pm | weight-normal | 400 — Body, table cells, values |
| The order shipped at 2:22pm | weight-medium | 500 — Table header labels, keys, active states |
| The order shipped at 2:22pm | weight-semibold | 600 — All headers |
Inline links (§2.1D rule 1)
A link is marked by its dotted underline, never by hue — this one is text-link, which equals text-primary on purpose.
2.2 Borders
Weight carries meaning, not decoration. A non-solid border carries its meaning in its line style, so it is always border-width-light.
| Specimen | Token | Value |
|---|---|---|
| border-width-heavy | 3px — Marks the start of a structure | |
| border-width-medium | 2px — Separates a table header from its rows | |
| border-width-light | 1px — Separates peers | |
| border-style-dotted | 1px dash 3px gap — Square dots — the dots are square, not round. Separators between table rows. Borders underneath section headers. | |
| border-style-dashed | 3px dash 3px gap — Borders for callouts and code blocks. |
A callout is marked by its dashed border, not by hue — there is no status-info token.
2.3 Color
Neutral from black to white; hue appears only in status. Showing the light values.
2.3A Surface
surface-raised matches surface-page — raised components separate by shadow, never by fill. surface-sticky exists for occlusion, not elevation.
2.3B Text
Contrast is measured against surface-page in the matching theme.
2.3C Border
2.3D Action
2.3E Status
The only chromatic tokens in the system. Hue is never the only carrier — every status pairs its color with an icon or a label.
2.3F Delta
One axis for any signed change — money, lines, bytes. Separate from status on purpose: money out is not an error.
2.3G Diff
Lighter than the delta backgrounds — they tint whole lines, not badges.
2.3H Focus and selection
2.3I Value
Not an alias of text-secondary — tuned against numeric columns.
2.4 Spacing
Base unit is 4px. space-2xs is the only half-step, and it exists for components rendered inside other components.
| Specimen | Token | Value |
|---|---|---|
| space-2xs | 2px — Chips. Small buttons. Icon to label at small size. | |
| space-xs | 4px — Table and list cell padding. Icon to label. | |
| space-sm | 8px — Gap between related controls. | |
| space-md | 12px — Button padding. Input padding. | |
| space-lg | 16px — Padding inside a component. Gap between components. | |
| space-xl | 24px — Gap between sections on a page. |
2.5 Radii · 2.6 Elevation
Sharp corners on records — tables, lists, code. Rounded on everything the interface invented — controls, containers, overlays.
| Specimen | Token | Value |
|---|---|---|
| rounded-xs | 2px — Marks smaller than a control: checkbox, skeleton block | |
| rounded-sm | 4px — Controls: buttons, inputs, chips | |
| rounded-md | 6px — Containers and overlays: cards, menus, dialogs, drawers | |
A data-bearing component. | shd-diffuse | 2px x-offset 2px y-offset 8px blur shadow-color |
| shd-overlay | 0 4px 14px shadow-color-strong — Anything that sits on top of the plane | |
| surface-scrim | black @ 40% — Raised only by a dialog |
2.7 Layout
Six columns with space-md gutters, at every breakpoint — density comes from what fills the columns.
Six columns, space-md gutters
Column count, and whether navigation is a column or a trigger, are the only two things a breakpoint changes.
Breakpoints
| Breakpoint | Width | Grid | Navigation |
|---|---|---|---|
| wide | ≥ 1024px | 6 columns | Column, visible |
| medium | 640–1023px | 6 columns | Collapsed to trigger |
| narrow | < 640px | 2 columns | Collapsed to trigger |
Row height: 24px, text only
| Conversation | Status | Amount |
|---|---|---|
| 0x1a2b…9f4c | Settled | 12.500000 |
| 0x77c1…0e28 | Blocked | 4.125000 |
The dimmed digits are value-padding — the eye stops at the last digit that carries information.
Row height: 30px, any cell holds a control or a chip
| Conversation | Tags | Amount |
|---|---|---|
| 0x1a2b…9f4c | payment | 12.500000 |
| 0x77c1…0e28 | memory write | 4.125000 |
The height is chosen once per table and applies to every row in it.
2.12 Size
Sizes are not spacing — never substitute one axis for the other.
| Specimen | Token | Value |
|---|---|---|
| size-row-text | 24px — Table and list row holding only text. | |
| size-row-control | 30px — Table and list row holding a control or chip. | |
| size-frame-cell | 16px — Avatar frame inline in a cell or chip. | |
| size-frame-header | 24px — Avatar frame in a header or the nav. | |
| size-box | 16px — Checkbox and radio box, default. | |
| size-box-small | 12px — Checkbox and radio box, small. |
2.8 Icons
Phosphor Icons, two weights: regular, and fill for selection. Icon size tracks the text it sits with, never the container.
| Specimen | Token | Value |
|---|---|---|
| Copy conversation ID | icon-default · regular | 16px — Alongside text-base and text-md |
| Copy conversation ID | icon-default · fill | Selected and active states only — an icon never fills on hover. |
| Settled | icon-small · regular | 12px — Alongside text-sm, inside table cells |
| Settled | icon-small · fill | The icon equivalent of surface-selected. |
The status vocabulary (§3.10)
Status renders as an outline icon plus its label — the icon carries the hue, the label carries the meaning.
| Specimen | Token | Value |
|---|---|---|
| Success | status-success-fg | Check circle — Success |
| Failure | status-error-fg | X circle — Failure |
| Warning | status-warning-fg | Warning circle — Warning |
| Blocked | status-error-fg | Circle with slash — Blocked |
| In progress | status-neutral-fg | Dashed circle — In progress |
| Paused | status-neutral-fg | Pause circle — Paused |
2.9 Motion
Motion is reserved for state the reader caused. Data never animates in; it appears. Under a reduced-motion preference these transitions are removed, not shortened.
| Specimen | Token | Value |
|---|---|---|
| duration-fast · ease-standard | 200ms — Hover, focus, selection | |
| duration-base · ease-standard | 180ms — Overlay entry and exit | |
| ease-standard | cubic-bezier(.2, 0, 0, 1) — Everything that moves |
2.10 Layering · 2.11 Focus
Two tiers: everything in the document flow shares one low band, and every overlay uses the browser's top layer, which stacks by the order things opened rather than by number.
| Tier | Token | Value | Use |
|---|---|---|---|
| In-flow | layer-base | 0 | Page content |
| In-flow | layer-raised | 1 | Elevated data components |
| In-flow | layer-sticky | 2 | Sticky table and page headers |
| Top | — | — | Dialog, menu, tooltip, toast |
A z-index above 2 anywhere in the system is a bug. Overlays carry no z-index at all.
The focus ring
Tab into the buttons — the ring is focus-ring-width in focus-ring, held off the control by focus-ring-gap. A click draws no ring: keyboard only.