Typography
Three families, self-hosted. Familjen Grotesk is for headings and the wordmark, Schibsted Grotesk for text and labels, and JetBrains Mono for data. Fonts load from this package, never from Google Fonts, which would send visitors' IP addresses to Google.
Roles
Seventeen roles, one per job. Set every piece of text with a role, either as a class (perron-typography-body) or as a composite custom property (font: var(--perron-typography-body) plus letter-spacing: var(--perron-typography-body-tracking)).
- Anything people compare down a column is a
datarole: times, countdowns, counts, delays, percentages. They use tabular figures, so columns line up. overlinesets its text in capitals: the class addstext-transform: uppercase, and with the custom property you add it yourself. Write the source text in sentence case.leadis for the paragraph under a page title, on the docs website and any long-form screen.bodystays at 14 px for sentences and inputs, so a page intro never borrows a heading role or a raw size.- On phones,
displayanddata-xlstep down tofont.size.800, andstattofont.size.600. These are the only places a component reaches for a size directly.
Hero headline. Steps down to font.size.800 on phones.
Dialog and page titles
Panel titles: a stop or a destination. The wordmark is heading-md set bold.
Card titles, such as a disruption
Page intros: the paragraph under a page title on long-form screens
Sentences in panels and dialogs, and the text typed into inputs
Supporting sentences: the line under a title, disruption details
Notes, second lines in rows, legend descriptions, map credits
Buttons, tabs, chips and names in lists
Legend items, field and stat labels, tooltips
Section headings and tags, set in capitals
The line name inside a line badge, such as M1 or 5C
Key figures. Steps down to font.size.600 on phones.
Kiosk clock. Steps down to font.size.800 on phones.
Top bar clock, departure countdowns
Times, delays, counts and percentages in lists and tables
Counts in chips and tabs, chart axes, the time under a countdown
Families and weights
| Token | Value |
|---|---|
font.family.displayDisplay: headings and the wordmark | Aa Øresund 08:14 Familjen Grotesk, Schibsted Grotesk, system-ui, sans-serif |
font.family.bodySentences, labels, controls and small headings: every role but the large headings and the figures | Aa Øresund 08:14 Schibsted Grotesk, system-ui, -apple-system, Segoe UI, Roboto, sans-serif |
font.family.dataData: times, countdowns, counts and data ages. Always tabular figures. | Aa Øresund 08:14 JetBrains Mono, ui-monospace, SF Mono, Menlo, Consolas, monospace |
font.weight.regularRunning text: lead, body and caption sentences | Aa 400 |
font.weight.mediumControls, list titles, data | Aa 500 |
font.weight.semiboldLabels, small headings, overlines and key figures | Aa 600 |
font.weight.boldDisplay titles, wordmark, line badges | Aa 700 |
Sizes
Sizes come from one scale, numbered like the spacing scale: the number divided by 100 is the size in 4 px units, so font.size.400 is 16 px. Roles use it.
| Token | Value |
|---|---|
font.size.275 | Aa 11 px |
font.size.300 | Aa 12 px |
font.size.325 | Aa 13 px |
font.size.350 | Aa 14 px |
font.size.400 | Aa 16 px |
font.size.500 | Aa 20 px |
font.size.600 | Aa 24 px |
font.size.700 | Aa 28 px |
font.size.800 | Aa 32 px |
font.size.1200 | Aa 48 px |
Line heights
Four line heights. Use none for single lines in a fixed box, tight for headings and figures, snug for labels and data, and normal for running text.
| Token | Value |
|---|---|
font.line-height.noneSingle lines in a fixed box: line badges, the kiosk clock | Two lines of body text 1 |
font.line-height.tightHeadings, key figures and clocks | Two lines of body text 1.15 |
font.line-height.snugLabels, small headings and data | Two lines of body text 1.3 |
font.line-height.normalRunning text that wraps: lead, body and caption sentences | Two lines of body text 1.5 |