Typography
Two families and fifteen named roles cover every surface. Geist carries the interface and the draft, Geist Mono carries data, and the role name is the API: choose a role, never a raw size.
Families
Geist carries the product, marketing, and sustained reading. Geist Mono distinguishes counts, timestamps, and identifiers. Sora exists only inside the logo.
Use the exported logo assets. Never set headings, buttons, navigation, or campaign copy in Sora, and never use Geist below 400 or above 600.
Named scale
Every role fixes family, size, line height, weight, and tracking. The role name is the API: choose a role, never an arbitrary size.
display-xl, display-lg, and display scale with the viewport for marketing. Product and draft roles stay fixed so the editor never reflows between nearby widths.
Try a role
Test real copy against the scale before committing a composition.
In the draft workspace
The draft reads in prose; the margin works in body-sm, so questions never compete with the writing they refer to.
The city's decision did more than alter the square. It changed who could see their history represented in public. The debate therefore became a question about civic memory rather than a dispute over one statue.
What evidence shows how residents described that change at the time?
Rules
- Sentence case everywhere. Headings, buttons, tabs, labels, and table headers. Uppercase belongs only to the overline, at three words or fewer.
- Three weights. 400 for reading, 500 for labels, 600 for hierarchy. Thin text disappears on paper; bold turns every heading into a demand.
- Readable measure. Body copy stays at 45–75ch. Draft prose targets 55–72ch.
- Tracking is earned. Only headings at 20px and above tighten. Body copy never does.
- Never truncate the question. Margin questions, draft passages, errors, and button labels are always shown in full.
- Tabular figures for data. Counts, durations, and changing metrics use
tabular-numsin Geist Mono.
Loading
Use the locally bundled variable files and request only the allowed weights. Geist swaps in so writing stays usable; the logo font blocks so a substitute wordmark never flashes.
@font-face {
font-family: "Geist Inline";
src: url("../fonts/Geist-Variable.woff2") format("woff2");
font-style: normal;
font-weight: 400 600;
font-display: swap;
}
No faux bold, no synthetic italics. Email uses the system stack instead of loading web fonts.