--- name: choosing-typography description: Chooses and systematizes web typography — display/body typeface pairing matched to the brief, modular type scales with clamp(), line-height and line-length rules, and performant font loading with woff2 and font-display. Use when the user asks to pick or pair fonts, set up a type scale or heading sizes, fix readability or line length, load web fonts, or use variable fonts. Do not use for color, spacing, or theming token systems (theming-design-tokens) or for writing the copy itself. --- # Choosing Typography ## When to use / when NOT to use - **Use for:** typeface selection/pairing, type scales, line-height/measure, web-font loading, variable fonts. - **Do NOT use for:** color/spacing tokens (→ theming-design-tokens); page layout (→ designing-responsive-layouts); the words themselves — copy is not typography. ## Core rules 1. **Pair for the brief, not from the AI-default shelf.** Pick one display face with character matched to the subject and one quiet, workhorse body face; justify the choice in one sentence tied to the brief. - ✅ "Fintech dashboard → IBM Plex Sans (technical heritage) + Plex Mono for figures" - ❌ Playfair Display + Inter on cream, or any pairing you'd reach for on *every* project 2. **Two families maximum (display + body); get hierarchy from weight/size/case, not more fonts.** 3. **Modular scale, fluid at the top.** Body fixed at 1rem (16px minimum — never smaller); headings on a ratio (1.25 default; 1.333+ for editorial drama), made fluid with `clamp()`. - ✅ `h1 { font-size: clamp(2rem, 1.3rem + 3vw, 3.5rem); }` - ❌ `h1 { font-size: 56px; }` (desktop-only) or `font-size: 5vw` (unbounded, breaks zoom) 4. **Line-height by role:** body 1.5–1.7, headings 1.1–1.25, buttons/labels 1. Unitless values only. 5. **Measure 45–75 characters:** `max-width: 65ch` on prose containers. Long lines are the most common readability failure. 6. **Loading discipline:** self-hosted `woff2` only, `font-display: swap`, preload the one or two files used above the fold, and set `size-adjust`-matched fallbacks to keep CLS ≤ 0.1. 7. **Variable fonts when you need >2 weights of one family** — one file replaces four; animate weight sparingly and never on body text. 8. **Numbers in tables/dashboards get `font-variant-numeric: tabular-nums`** so columns align. ## Workflow 1. Read the brief; write one sentence naming the personality the type must carry. 2. Choose display + body per rules 1–2 (with licensing/availability check — Google Fonts, Fontshare, or the client's licensed faces). 3. Build the scale and roles (rules 3–5) as CSS custom properties. 4. Set up loading (rule 6): woff2 subset, preload, fallback stack with metric overrides. 5. Validate: body ≥16px; measure within 45–75ch at 360px and 1280px; headings don't wrap awkwardly at 360px; toggle network throttling — text visible immediately (swap) and no visible layout jump when the web font lands. ## Edge cases & failure modes - **Brand mandates a display-only face for body text:** refuse silently by scoping it to headings/pull-quotes; pick a compatible body face and note the substitution. - **Font file unavailable/offline build:** system stack fallback — `system-ui, -apple-system, "Segoe UI", Roboto, sans-serif` — and say so; never hotlink a foundry's CDN without license. - **Multilingual content:** confirm the chosen faces cover the required scripts/diacritics before committing; fall back per-script with `unicode-range`. - **User zoom/large-text settings:** everything in `rem` (rule 3) — px-based type breaks zoom accessibility. ## References Scale sheet, @font-face/preload boilerplate, metric-matched fallbacks, pairing shortlists by genre: see [references/patterns.md](references/patterns.md)