Type
Each theme names its face. neutral, the app’s and the console’s look, sets
every word in Inter: 500 at 14/20 for UI text, 600 for titles, and figures in
Inter with tabular digits. tempio, the site’s, the docs’ and the emails’,
sets Geist, the kit’s face, with Geist Mono for figures that are data. This
page opens on neutral; pick tempio above and every specimen redraws in
the other face.
Geist and Geist Mono load from @tempio/ui/fonts, Inter from
@tempio/ui/fonts/inter, each through a class on <html>. The app loads
Inter alone; the docs and the console load all three. next/font self-hosts
the files at build, so no font request leaves the page.
Geist is the brand face, from page 22 of Softriver’s guide. Geist Mono is not
in the kit. Both are set in type in packages/ui/tokens/brand.json. The
guide’s own hierarchy, 150px down to 20px, is set for print and 1920-wide
decks and is not the web scale.
The UI roles
What the parts read: buttons, menus, table cells, fields, the sidebar. Each
role is a text-ui-* utility carrying size, line-height, tracking and weight
together, and each theme sets its own numbers, printed beside each role.
neutral’s are measured off Attio; tempio’s draw what the parts drew
before the roles existed.
text-ui14/20 · 400 · 0Default UI text: nav rows, buttons, cells, menu items, fieldstext-ui-strong14/20 · 500 · 0Section headings, board column namestext-ui-prose14/22 · 400 · 0Rich text: a note and its liststext-ui-small12/16 · 400 · 0Meta: section and field labels, timestamps, tooltips, count badgestext-ui-input-lg16/24 · 400 · 0⌘K’s inputtext-ui-title16/22 · 500 · 0The workspace’s name, a tab’s page titletext-ui-record-title18/28 · 500 · 0A record’s name in its headertext-ui-h220/26 · 500 · -0.01emA note’s second heading, an empty state’s titletext-ui-h124/30 · 500 · -0.01emA note’s first headingtext-ui-display32/36 · 500 · -0.02emA note’s title in the editortext-ui-kbd12/16 · 500 · 0Kbd chips, 20px talltext-ui-kbd-sm12/16 · 500 · 0Small kbd chips inside a button, 16px talltext-ui-badge-sm12/16 · 500 · 0A tab’s count badge, 14px tallThe role scale
Named the way Geist names its styles: role, then pixel size. A row carries size,
line-height, tracking and weight together, so a block writes one class rather
than four. label-12 also gets its uppercase, from styles/base.css, because a
Tailwind text token cannot carry case.
The role scale is for blocks, templates and docs. Primitives keep shadcn’s
own text-sm and text-xs, and take the UI roles above under neutral
through neutral: classes. The two display sizes at the top are for the
marketing hero only: the app never sets one, and
apps/app/tests/no-display-type.test.ts fails on one in its pages or
components.
Each row carries size, line-height, tracking and weight together, and draws in the theme’s face: Inter under neutral, Geist under tempio. Headings take their face and Medium 500 weight from the base layer.
text-display-96Marketing hero onlytext-display-72Marketing hero onlytext-heading-56Hero H1, md and uptext-heading-48Hero H1 on mobile, page H1text-heading-40Section H2text-heading-32Section H2 on mobile, article H1text-heading-24H3, card titles on marketingtext-heading-20H4, dialog titlestext-heading-16Dense UI headingstext-copy-18Marketing lead paragraphtext-copy-16Marketing bodytext-copy-14App and docs bodytext-copy-13Dense app text, table cellstext-label-14Buttons, tabs, nav itemstext-label-13Badges, chipstext-label-12Eyebrows, kickers, table headers.font-dataROAS 3.21× · CPC $0.42 · spend $12,480.00 · 2026-08-23
Weights carry meaning
Headings are Medium 500 in every theme, as in the kit’s creatives, which set
headlines in Medium or Regular and never Bold. The weight is set once by the
h1–h6 rule in base.css from --font-weight-heading, and the face is the
theme’s. A component sizes a heading with a text-* utility and never
re-declares family or weight.
Under neutral, UI text is 500 and titles are 600, as Attio sets them.
Under tempio, marketing body runs light (300) at 16px and above, which reads
as air on a wide measure. Dense text at 13–14px stays at 400, because 300 at
that size loses the thin strokes on the digits. Eyebrows are 500, uppercase,
wide.
Figures
Every number that is data (money, ratios, counts, dates in a table) wears
.font-data, which reads --theme-font-data: Inter under neutral, Geist
Mono under tempio, with tabular figures and tracking pulled in slightly in
both, so a column of money aligns to the digit. Money renders from integer
minor units with its currency; a null ratio renders an em dash, never $0.00
or 0%.