Typography
System SF Pro and Geist Mono on a nine-step ramp with one legibility cut; hierarchy comes from rank and weight 500, never bold.
Ramp
Nine steps, each a size, a line height and a tracking; the values are measured live, in px.
| Step | Sample | Size | Line | Tracking |
|---|---|---|---|---|
| Key caps, gutter numbers and captions | ||||
| Section labels, badges and code | ||||
| Rows, menus, pills and pickers | ||||
| Conversation, the composer and tool lines | ||||
| Markdown h3, a lead | ||||
| Markdown h2, settings titles | ||||
| Markdown h1, a section | ||||
| Page titles | ||||
| A public page's one statement |
Tracking tightens as the size grows, about 1% of the size from 24px up and 2% at 48, so large type sets as compact as the reading sizes. Display sizes use weight 460, between regular and medium.
13 is the UI default and 15/24 is for reading; display and hero are for page titles and empty states. Hierarchy comes from rank (text-1 to text-4) before size, and from weight 500, never bold.
Roles
--type-* shorthands name a role: weight, size, line height and family.
| Role | Sample | Size | Line | Weight |
|---|---|---|---|---|
| 2m ago | ||||
| Recent | ||||
| Rename project | ||||
| Fix the flaky settings test | ||||
| The release spring brings a pressed button back with a 2.8% overshoot: felt rather than seen, and never in the way of the next click. | ||||
| Settings | ||||
| Checkpoints | ||||
| Typography | ||||
| Projects | ||||
| Recent | ||||
| const turn = await agent.run(prompt); | ||||
| 473k tokens, synced 5m ago, v0.1.0 | ||||
| The harness is the lever. |
They set the font only, so set the paired tracking beside them. A group label (a sidebar's Projects) is sentence case at 13/500 in text-1; an eyebrow (12/16, sentence case, text-3) names sections only inside menus, palettes and pickers. A readout (mono 11/16) is for machine facts: counts, versions, refs, timings. It never labels anything: column heads and stat labels are sans. A hero opens a public page, once.
Weights
Four weights.
418 is where SF Pro reads crisp on both themes; 500 is every label, button, title and heading; 460 is for display sizes; 600 is only for strong text in prose and search hits.
Legibility cut
One OpenType feature, on everywhere: SF Pro's cv05, a capital I with serifs, so Il1 and ILineItem never collide in identifier-heavy prose. It lives in --font-features.
Geist Mono has no cv05, and neither do Segoe and the other fallbacks, so code needs no exclusion and other platforms keep their own I. There are no slashed zeros; numbers in readouts use tabular-nums, which the cut does not touch.
Links
Links are ink, told apart by a quiet underline rather than a colour. The accent is kept for lights.
The release spring is described in the motion notes. On hover the line brightens, like this. File paths such as src/routes/settings.tsx stay in the neutral ranks.
| Token | Use | Value |
|---|---|---|
| text-1: links are ink. | ||
| Ink at 30%: a quiet line under the ink. | ||
| text-1: on hover the line brightens to full ink; the text stays. | ||
| The underline's weight. | ||
| Clear of the descenders. |
A bare <a href> in running text (p, li, dd, blockquote, figcaption and table cells) gets this from base.css. Anything with a class is a component and styles itself with the same tokens; heading links and navigation stay plain.
Families
The system stack for text, so SF Pro on Apple platforms and the native UI face elsewhere, at no download.
| Token | Sample | Stack |
|---|---|---|
| The quick brown fox | -apple-system, SF Pro Text, Segoe UI, system-ui | |
| bun test --watch | Geist Mono, SF Mono, ui-monospace, Menlo, Consolas |
Conversation text (15/24) renders untracked; UI text (13/18) tightens by 0.08px. Code is Geist Mono at 12/19, a terminal's line; inline code inside prose is --font-size-code-inline: 0.867em, so 13px in 15px text. Geist Mono is the variable cut (100 to 900) under the SIL Open Font License, embedded in the kit's stylesheet.
The tracking follows Apple's table for SF Pro: a hair open at 11px, none at 12px, −0.08px at 13px, none again at the 15px reading size, and tighter from 17px up. Each --type-* role pairs with the tracking of its size, which is why the shorthand leaves letter spacing to you.
Geist Mono ships with the kit for code, paths and token names; numbers stay in SF Pro, tabular.