Skip to content

Typography

"Sharp, clear, invisible. The best typography is the one you don't notice — you just read."

Font Choice: Inter

Inter is the typeface for the entire site — headings, body, UI, everything.

Why Inter?

  • Linear, Stripe, and Notion all use Inter — our three design references
  • Already loaded on the site (zero migration cost)
  • Excellent weight range: 400–800
  • Optimised for screens at all sizes (12px badges to 40px headlines)
  • Variable font support for precise weight control
  • Massive language support

Font Stack

--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;

What About Other Candidates?

Font Verdict Reason
Geist (Vercel) ❌ Rejected Slightly too tight at small sizes. Limited weight range.
Plus Jakarta Sans ❌ Rejected Too rounded/friendly — doesn't match the sharp, professional feel.
General Sans ❌ Rejected Good but adds a new dependency for marginal benefit over Inter.

Type Scale

Based on Linear's type system. Every text element on the site uses one of these sizes.

Token Size Weight Line Height Letter Spacing Usage
--text-display 2.5rem (40px) 600 1.2 -0.025em Hero headlines only
--text-h1 2rem (32px) 600 1.25 -0.02em Page titles
--text-h2 1.5rem (24px) 600 1.3 -0.01em Section headings
--text-h3 1.25rem (20px) 600 1.4 0 Sub-sections, card titles
--text-body 1rem (16px) 400 1.7 0 Reading text, descriptions
--text-sm 0.875rem (14px) 400 1.6 0 UI text, meta, compact areas
--text-caption 0.75rem (12px) 500 1.5 0.01em Badges, labels, timestamps

Rules

  1. No arbitrary font sizes. Every font-size must reference a token. No 0.82rem, no 0.92rem, no 1.1rem.
  2. Headings are always weight 600. Not 700, not 800. Clean and sharp, not heavy.
  3. Body text line-height is 1.7. This gives optimal reading comfort (Stripe uses 1.625, we round up for extra breathing room).
  4. Negative letter-spacing on headings only. Headlines look tighter and more premium with -0.02em. Body text stays at 0.
  5. No text-transform: uppercase except for --text-caption labels. ALL CAPS IS SHOUTING. Zen doesn't shout.

Reading Optimisation

For long-form content (blog posts, study guides):

.reading-content {
  font-size: var(--text-body);    /* 16px */
  line-height: 1.7;
  max-width: var(--max-reading);  /* 720px */
  color: var(--text-secondary);   /* Not primary — softer on the eyes */
}

.reading-content h1,
.reading-content h2,
.reading-content h3 {
  color: var(--text-primary);     /* Headings stand out */
  margin-top: 2em;
  margin-bottom: 0.5em;
}

Code Typography

code, pre {
  font-family: var(--font-mono);
  font-size: 0.875rem;  /* 14px */
  line-height: 1.6;
}

CSS Implementation

:root {
  /* Font families */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;

  /* Type scale */
  --text-display: 2.5rem;
  --text-h1: 2rem;
  --text-h2: 1.5rem;
  --text-h3: 1.25rem;
  --text-body: 1rem;
  --text-sm: 0.875rem;
  --text-caption: 0.75rem;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: 1.7;
  color: var(--text-secondary);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3 {
  font-weight: 600;
  color: var(--text-primary);
}
h1 { font-size: var(--text-h1); line-height: 1.25; letter-spacing: -0.02em; }
h2 { font-size: var(--text-h2); line-height: 1.3; letter-spacing: -0.01em; }
h3 { font-size: var(--text-h3); line-height: 1.4; }