Typography

Two font families — Inter for UI and Literata for reading content — paired with Open Props size, weight, line-height, and letter-spacing scales.

Font families

Inter — body / UI text (default font-family on <body>).

Literata — long-form reading content (.font-reading). Italic variant supported.

Show code body { font-family: var(--font-neo-grotesque); } /* Inter, then Helvetica-metric faces */ .font-reading { font-family: Literata, Georgia, serif; }

Where the families come from

Both typefaces are files in this tree, under /vendor/fonts/ — six .woff2 faces next to the @font-face rules that name them, in /vendor/fonts/fonts.css. Nothing fetches them from a font service, and no page may load a typeface from another origin: a third family means adding its .woff2 files and its @font-face blocks beside those, never a <link> to a CDN.

Fonts must be local so the offline snapshot can include them. Externally hosted fonts can require network requests at startup and fall back to another font when offline. A cross-origin font URL also sends the reader's IP address to a third party before any consent prompt appears, adds a connection before the font can display, and makes browser tests depend on internet access.

Six faces: two subsets — latin and latin-ext — across three family/style pairs. Each face is the variable font, so one file carries a weight range rather than a single weight:

Font weights above the supplied range use the maximum available weight. For example, Inter at --font-weight-7 renders at 600, while bold Literata italic renders at 400. Inter has no italic file, so browsers synthesize its slant; Literata has a true italic face. Glyphs outside the Latin and Latin Extended subsets use the next suitable font in the stack. To support another subset, add its font file and @font-face declaration.

Every face declares font-display: swap, so text paints in the fallback immediately and re-paints when the face arrives. The fallback fonts reduce layout changes during this swap: the body font stack ends with fonts whose metrics resemble Helvetica, rather than the sans-serif generic, and .font-reading falls back to Georgia. A generic family can resolve to different fonts on different machines, changing the text width when the preferred font is unavailable.

Size scale — --font-size-*

Static: --font-size-00 .. --font-size-8. Fluid: --font-size-fluid-0..3 (scale with viewport via clamp()).

Size 0 — small / caption (--font-size-0)

Size 1 — button / compact (--font-size-1)

Size 2 — body copy / section heading (--font-size-2)

Size 3 — subheading (--font-size-3)

Size 5 — section heading (--font-size-5)

Fluid 2 — scales with viewport (--font-size-fluid-2)

Nothing declares a font-size on <body> or <html>, so text starts at the 1 rem root default — the same value as --font-size-1, which is also what buttons and inputs take. Reach for --font-size-2 for larger body copy or section headings. Guideline: fluid sizes for headlines, static sizes for body text.

Show code h1 { font-size: var(--font-size-fluid-3); font-weight: var(--font-weight-7); line-height: var(--font-lineheight-1); } body { /* no font-size — text starts at the 1rem root default, which is --font-size-1 */ line-height: var(--font-lineheight-3); }

Weight — --font-weight-*

Range: --font-weight-1 (thin) .. --font-weight-9 (black).

Weight 3 (300 — light) · Weight 4 (400 — regular) · Weight 5 (500 — medium) · Weight 6 (600 — semibold) · Weight 7 (700 — bold)

Line height & letter spacing

Show code h3.eyebrow { font-size: var(--font-size-0); font-weight: var(--font-weight-5); text-transform: uppercase; letter-spacing: var(--font-letterspacing-3); }

Project extras

/index.css adds --font-size-xs (0.6875 rem, between --font-size-00 and --font-size-0) for pills and micro-snippets.

See also