- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
PREDICT uses two typefaces and one size scale. Good type does most of the work in a health interface: it makes the result, the range, and what to do next easy to find.
Typefaces
Neue Montreal is the brand typeface, used for everything from headlines to buttons. Geist Mono is for codes, IDs, tokens, and numbers that need to line up.
Aa
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789 .,:;!?()&@%+−×÷=
- Biological age 45Light 300Large display text only.
- Biological age 45Regular 400Body text and descriptions.
- Biological age 45Medium 500Headings, labels, and buttons.
- Biological age 45Bold 700Rare emphasis, such as a key number.
Aa
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789 ·−+=%
- Sample ID
- PRD-20481
- Token
- --status-normal
- Z-score
- +2.71
- Unit
- mg·dL⁻¹
| Font | Class | Weights | Loaded in |
|---|---|---|---|
| Neue Montreal | font-sans (the default) | 300, 400, 500, 700 | apps/design/src/lib/fonts.ts, as --font-montreal |
| Geist Mono | font-mono | Variable | app/layout.tsx, from Google Fonts, as --font-mono |
- Neue Montreal is loaded in four weights only.
font-semibold(600) has no file, so it renders as Bold. Usefont-mediumorfont-boldso you get what you see in code. font-sansis set onhtml, so you rarely need to write it.
Type scale
Ten sizes, from 72px down to 14px. Type in the box to try your own text.
The tokens are defined in packages/ui/src/styles/typo.css and work like any Tailwind size: text-heading-32, md:text-heading-48.
| Token | Size | Rem | Default for |
|---|---|---|---|
text-heading-72 | 72px | 4.5rem | — |
text-heading-64 | 64px | 4rem | — |
text-heading-56 | 56px | 3.5rem | — |
text-heading-48 | 48px | 3rem | — |
text-heading-40 | 40px | 2.5rem | — |
text-heading-32 | 32px | 2rem | h1 |
text-heading-24 | 24px | 1.5rem | h2 |
text-heading-20 | 20px | 1.25rem | h3 |
text-heading-16 | 16px | 1rem | h4, p |
text-heading-14 | 14px | 0.875rem | small |
The tokens set the font size only. Line height is inherited (1.5 by default), which is too loose for large headings. Add leading-tight (1.25) or leading-none to headings of 32px and up.
For interface text below 14px, use Tailwind's sizes: text-xs (12px) for captions and labels, and text-sm (14px) for compact body text in cards and tables.
Semantic defaults
typo.css styles plain HTML elements, so content looks right without classes.
| Example | Element | Style |
|---|---|---|
Your October results | h1 | text-heading-32 |
Your October results | h2 | text-heading-24 |
Your October results | h3 | text-heading-20 font-medium |
Your October results | h4 | text-heading-16 |
Your October results | p | text-heading-16 text-muted-foreground |
| Your October results | small | text-heading-14 text-muted-foreground |
- Every
pis 16px and muted. Inside components, set the size and colour you need, such astext-sm text-foreground. Classes win over the defaults. - These defaults are in
@layer base, so any utility class overrides them. - In docs pages, the MDX components add spacing on top, such as a top margin on headings.
Hierarchy
A report header built from the scale. One clear title, a muted line of context, and the result as the largest thing in its section.
Report
Your October results
Collected 12 Oct 2026 · 40 biomarkers
Inflammation
hs-CRP is above the healthy range. A recent cold or hard training can raise it.
Healthy range 0.2–3.0 mg·L⁻¹
Text styles
The combinations used across PREDICT. Reuse them instead of inventing new ones.
| Role | Classes | Example |
|---|---|---|
| Hero title | text-4xl md:text-6xl font-medium tracking-tight | The home page headline |
| Page title | text-heading-32 leading-tight font-medium tracking-tight | "Your October results" |
| Section title | text-heading-20 font-medium | "Inflammation" |
| Card title | text-sm font-medium | "Bio clock" |
| Overline | text-xs font-medium tracking-[0.18em] uppercase text-muted-foreground | "DESIGN SYSTEM" |
| Body | text-sm or text-base, text-muted-foreground for descriptions | Card descriptions |
| Caption | text-xs text-muted-foreground | "Healthy range 0.2–3.0" |
| Result | font-mono tabular-nums with a large size | "3.5" |
| Code and tokens | font-mono text-xs | --primary |
Details
Weight
- Medium (500) for headings, labels, and buttons.
- Regular (400) for body text.
- Light (300) only for very large display text.
- Bold (700) for rare emphasis, such as one key number. Never for whole paragraphs.
Letter spacing
- Add
tracking-tightto headings of 24px and up. Large type looks loose at the default spacing. - Leave body text at the default.
- Uppercase overlines need extra space:
tracking-[0.18em].
Line length
Keep paragraphs to about 65 characters a line with max-w-2xl. Long lines are hard to follow, especially in dense medical text.
Numbers
Use tabular-nums wherever numbers sit in columns or update live, so digits line up and don't shift.
- LDL-C
- 185.5
- HDL-C
- 35.7
- TG
- 111.1
- LDL-C
- 185.5
- HDL-C
- 35.7
- TG
- 111.1
- Write units with a middle dot and superscript minus:
mg·dL⁻¹,mL·min⁻¹·1.73 m⁻². Put a space between the number and the unit. - Use an en dash for ranges, with no spaces:
0.2–3.0. - Use a real minus sign (−) for negative Z-scores in display text.
Case and punctuation
- Use sentence case for headings, buttons, and labels: "Book a test", not "Book A Test".
- Use uppercase only for short overlines.
- Avoid exclamation marks. Results can be worrying; keep the tone calm.
Implementation
| File | What it holds |
|---|---|
packages/ui/src/styles/typo.css | The text-heading-* scale and the semantic HTML defaults. |
packages/ui/src/styles/globals.css | Imports typo.css and maps font-sans to Neue Montreal. |
apps/design/src/lib/fonts.ts | Loads Neue Montreal from local files. |
apps/design/src/app/layout.tsx | Loads Geist Mono and adds both font variables to html. |
To add a size, add it to the @theme block in typo.css:
Then use it as text-heading-28. Each app that uses @workspace/ui must load Neue Montreal and set --font-montreal itself, as apps/design does.