Typography

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

Font Families

Fraunces
--font-displayDisplay & headings (h1–h3)'Fraunces', Georgia, serif
Instrument Sans
--font-bodyBody copy, UI & navigation'Instrument Sans', system-ui, sans-serif
JetBrains Mono
--font-monoCode blocks & inline code'JetBrains Mono', 'Courier New', monospace

Critical — Fraunces optical size: Every Fraunces usage must setfont-variation-settings: 'opsz' <value>. Use 72 for display/h1, 24 for h2, 20 for h3. Omitting it gives incorrect letterform rendering at every size.

Type Scale

Display

.text-display · Fraunces 800 · clamp(3–4.5rem) · opsz 72 · lh 1.05

Heading 1

.text-h1 · Fraunces 800 · clamp(2.5–4rem) · opsz 72 · lh 1.1

Heading 2

.text-h2 · Fraunces 700 · clamp(1.5–2rem) · opsz 24 · lh 1.2

Heading 3

.text-h3 · Fraunces 600 · clamp(1.1–1.35rem) · opsz 20 · lh 1.3

Heading 4

.text-h4 · Instrument Sans 600 · 1rem · lh 1.4

Heading 5

.text-h5 · Instrument Sans 600 · 0.875rem · tracking 0.04em · lh 1.4

Body large — intro copy and lead paragraphs

.text-body-lg · Instrument Sans 400 · 1.125rem · lh 1.7

Body — default prose and paragraph text

.text-body · Instrument Sans 400 · 1rem · lh 1.7

Body small — secondary copy and supporting text

.text-body-sm · Instrument Sans 400 · 0.875rem · lh 1.7

Label

.text-label · Instrument Sans 600 · 0.75rem

Caption — timestamps, metadata, footnotes

.text-caption · Instrument Sans 400 · 0.75rem · lh 1.6

const result = compute(input);

.text-mono · JetBrains Mono 400 · 0.8125rem · lh 1.6

Utility Classes

Opt-in classes that encode the full type scale — including mandatory Frauncesfont-variation-settings — so consumers never need to look up opsz values or clamp ranges. Load alongside farn.css or farn-tokens.css:

<!-- npm -->
import 'farn-theme/typography';

<!-- CDN / manual -->
<link rel="stylesheet" href="farn-typography.css" />

Display & headings

Display

.text-display — Fraunces 800 · clamp(3rem, 7vw, 4.5rem) · opsz 72 · tracking -0.02em · lh 1.05

Heading 1

.text-h1 — Fraunces 800 · clamp(2.5rem, 5vw, 4rem) · opsz 72 · tracking -0.02em · lh 1.1

Heading 2

.text-h2 — Fraunces 700 · clamp(1.5rem, 3vw, 2rem) · opsz 24 · tracking -0.02em · lh 1.2

Heading 3

.text-h3 — Fraunces 600 · clamp(1.1rem, 2vw, 1.35rem) · opsz 20 · tracking -0.01em · lh 1.3

Heading 4

.text-h4 — Instrument Sans 600 · 1rem · lh 1.4

Heading 5

.text-h5 — Instrument Sans 600 · 0.875rem · tracking 0.04em · lh 1.4

Body & UI

Body large — intro copy and lead paragraphs

.text-body-lg — Instrument Sans 400 · 1.125rem · lh 1.7

Body — default prose and paragraph text

.text-body — Instrument Sans 400 · 1rem · lh 1.7

Body small — secondary copy and supporting text

.text-body-sm — Instrument Sans 400 · 0.875rem · lh 1.7

Label

.text-label — Instrument Sans 600 · 0.75rem

Caption — timestamps, metadata, footnotes

.text-caption — Instrument Sans 400 · 0.75rem · lh 1.6

Mono

text-mono · const result = compute(input);

.text-mono — JetBrains Mono 400 · 0.8125rem · lh 1.6

CSS reference
/* Display */
.text-display {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(3rem, 7vw, 4.5rem);
  font-variation-settings: 'opsz' 72;
  letter-spacing: -0.02em;
  line-height: 1.05;
}

/* Heading 1 */
.text-h1 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.5rem, 5vw, 4rem);
  font-variation-settings: 'opsz' 72;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

/* Heading 2 */
.text-h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-variation-settings: 'opsz' 24;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

/* Heading 3 */
.text-h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.1rem, 2vw, 1.35rem);
  font-variation-settings: 'opsz' 20;
  letter-spacing: -0.01em;
  line-height: 1.3;
}

/* Heading 4 */
.text-h4 {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.4;
}

/* Heading 5 */
.text-h5 {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.875rem;
  letter-spacing: 0.04em;
  line-height: 1.4;
}

/* Body */
.text-body    { font-family: var(--font-body); font-weight: 400; font-size: 1rem;      line-height: 1.7; }
.text-body-lg { font-family: var(--font-body); font-weight: 400; font-size: 1.125rem;  line-height: 1.7; }
.text-body-sm { font-family: var(--font-body); font-weight: 400; font-size: 0.875rem;  line-height: 1.7; }
.text-label   { font-family: var(--font-body); font-weight: 600; font-size: 0.75rem; }
.text-caption { font-family: var(--font-body); font-weight: 400; font-size: 0.75rem;  line-height: 1.6; }

/* Mono */
.text-mono { font-family: var(--font-mono); font-weight: 400; font-size: 0.8125rem; line-height: 1.6; }

Usage Rules

Accent Emphasis

Use <em> inside any heading to highlight a word or phrase in the accent color. Works across all themes and surfaces — the accent token adapts automatically.

Build faster with Farn.

Compatible with any heading class — .text-display, .text-h1, .text-h2, etc.

CSS
em {
  font-style: normal;
  color: var(--color-accent);
}

Reference

Heading styles spec
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
Mono & code

--font-mono is JetBrains Mono, loaded at weights 400 and 500. Use it exclusively for code — never decorative text. Coding ligatures (=>, !=, -->) are enabled by default. To disable: font-variant-ligatures: none.

ElementContextCSS
<code>Inline code in prosefont-family: var(--font-mono); font-size: 0.875em
<pre><code>Code blocksfont-family: var(--font-mono); font-size: 0.8125rem; line-height: 1.6

Inline code uses em so it scales with surrounding text size. Block code uses rem for a fixed 13px baseline.

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

All headings use clamp() — no hard breakpoint jumps. DocLayout applies these to the base h1h3 elements.

UI Text Scale

Four size tokens for component CSS — inputs, labels, buttons, badges, metadata. Distinct from the heading/body utility classes above: those encode full typographic styles (family, weight, opsz, line-height); these are raw size values for overriding in component contexts. All component tokens (--btn-font-size,--input-font-size, etc.) reference these. Defined intokens/typography.css.

TokenValuepxUsed for
--text-2xs0.6875rem11Badge labels, overline captions (--badge-font-size)
--text-xs0.75rem12Tooltips, metadata, small btn, role text (--tooltip-font-size, --btn-sm-font-size)
--text-sm0.875rem14UI text: inputs, labels, buttons, tabs, tables (--input-font-size, --btn-font-size, --tab-font-size)
--text-base1rem16Body text, accordion content (--accordion-font-size)
Loading fonts

Self-host the WOFF2 files from the Farn repo and declare them with @font-face — no requests to third-party servers. See Getting Started › Load Fonts for the full declarations.

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url('/fonts/fraunces-latin-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/instrument-sans-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('/fonts/jetbrains-mono-latin.woff2') format('woff2');
}