Typography

Display serif for personality, humanist sans for readability, mono for code. The combination creates warmth without sacrificing legibility.

Font Stacks

TokenStackRole
--font-display'Fraunces', Georgia, serifHeadings h1–h3, display copy
--font-body'Instrument Sans', system-ui, sans-serifBody copy, paragraphs
--font-mono'JetBrains Mono', 'Courier New', monospaceCode, <pre> blocks

Fraunces is an optical-size variable serif — warm and considered rather than generic. Instrument Sans pairs naturally: geometric enough to feel clean, humanist enough to not feel cold. Together they create the “familiar but differentiated” quality the system aims for.

Fraunces Optical Size — Critical Rule

Fraunces is a variable font with an optical size axis (opsz). This axis must always be set explicitly — the font renders differently at different optical sizes and will look wrong without it.

Elementopsz valueWhy
h172Optimises letterform detail for large display sizes
h224Section heading weight — balanced stroke contrast
h320Subsection — slightly thicker strokes at smaller size
h1 {
  font-family: var(--font-display);
  font-weight: 800;
  font-variation-settings: 'opsz' 72;  /* mandatory */
}

h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: 'opsz' 24;  /* mandatory */
}

h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-variation-settings: 'opsz' 20;  /* mandatory */
}

Type Scale

A modular scale anchored at 16px base, stepping ~1.25× (major third).

rempxUse
0.75rem12pxCaptions, labels, badges
0.875rem14pxSmall body, UI secondary
1rem16pxDefault body
1.125rem18pxLarge body, intro copy
1.25rem20pxH3 base
1.5rem24pxH2 base
2.25rem36pxH1 base
4.5rem72pxDisplay / hero

Use clamp() for fluid heading sizes — no breakpoint jumps. The DocLayout already applies clamp() to all h1–h3 elements.

Heading Styles

ElementFontWeightSizeopszTracking
h1Fraunces800clamp(2.5rem, 5vw, 4rem)72-0.02em
h2Fraunces700clamp(1.5rem, 3vw, 2rem)24-0.02em
h3Fraunces600clamp(1.1rem, 2vw, 1.35rem)20-0.01em
h4Instrument Sans6001rem0
h5, h6Instrument Sans6000.875rem0.04em

Body & UI Styles

RoleFontWeightSizeLine height
BodyInstrument Sans40016px1.7
Body largeInstrument Sans40018px1.7
Body smallInstrument Sans40014px1.7
LabelInstrument Sans60012px
CaptionInstrument Sans40012px1.6
UI / buttonsInstrument Sans500–60013–14px1.6
CodeJetBrains Mono400–50013px1.6

Letter Spacing

ValueUse
-0.02emDisplay, h1, h2 — tightens large headings
0emDefault for body and most UI
0.04emH5/h6, small UI labels
0.12emUppercase caps, overline labels

Responsive Typography

BreakpointH1H2Body
Mobile < 640px28px22px16px
Tablet 640–1079pxclamp(28px, 5vw, 52px)clamp(22px, 4vw, 36px)16px
Desktop ≥ 1080px36px24px16px

Loading Fonts

Load via a <link> tag in <head> — not via @import url() inside CSS. The import approach delays rendering.

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..900;1,9..144,300..900&family=Instrument+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap"
/>

Usage Rules