# Typography craft rules

Universal typography rules that apply on top of any `DESIGN.md`. The
active design system decides *which* fonts; this file decides *how* they
behave at every size.

## Type scale

Use a multiplicative scale (1.2 or 1.25). Cap at 6–8 sizes per artifact.

| Role | Range |
|---|---|
| Display | 48–72 px |
| H1 | 32–48 px |
| H2 | 24–32 px |
| H3 | 20–24 px |
| Body | 15–18 px |
| Small | 13–14 px |
| Caption | 11–12 px |

## Line height (leading)

| Text size | Line height |
|---|---|
| Display / H1 (≥32 px) | `1.0`–`1.2` (tight) |
| Body (15–18 px) | `1.5`–`1.6` |
| Small (≤14 px) | `1.5` |

## Letter-spacing — the rule that makes or breaks craft

This is the single most-skipped rule in AI-generated design. **No
exceptions.**

| Context | Letter-spacing |
|---|---|
| Body text (14–18 px) | `0` (default) |
| Small text (11–13 px) | `0.01em` to `0.02em` (positive) |
| UI labels and button text | `0.02em` |
| **ALL CAPS** | **`0.06em` to `0.1em` (required)** |
| Headings 32 px+ | `-0.01em` to `-0.02em` |
| Display 48 px+ | `-0.02em` to `-0.03em` |

ALL CAPS without positive tracking looks cramped and amateur. Display
text without negative tracking looks loose and weak. These two failures
are the most reliable AI-slop tells.

The `0.06em` floor is not arbitrary: it is the empirical lower bound
that print and web typographers have converged on for uppercase
tracking (cf. Bringhurst's *Elements of Typographic Style* §3.2.7,
which recommends 5–10% of the em for caps; modern screen practice
rounds the lower end to 0.06em). Anything tighter and the counters
collide on screen; the upper bound `0.1em` keeps the word from
disintegrating into letters.

## Font pairing

- Maximum 2 typefaces per artifact (display + body, or one variable face
  used at multiple weights).
- Always declare a system fallback chain. If the active `DESIGN.md`
  ships a webfont URL, the fallback must still produce a coherent look.
- Never set `font-family: system-ui` alone on a heading — that is the
  textbook AI default; always pair it with an intentional first choice.

## Line length

Limit body copy to **50–75 characters** per line. In CSS:
`max-width: 65ch` is a safe default.

## Three-weight system

Most well-crafted UIs use exactly 3 weights:
- **Read** (400 / 450) — body copy
- **Emphasize** (510 / 550) — UI text, labels, navigation
- **Announce** (590 / 600) — headlines, buttons

Weight 700+ is rarely needed. If your design uses bold for "emphasis on
emphasis," it likely lacks weight discipline elsewhere.

## Common mistakes (lint these)

- ALL CAPS without `letter-spacing` ≥ `0.06em`.
- Display text (≥32 px) without negative tracking.
- More than 3 type sizes visible above the fold.
- Mixed serif and slab on the same screen without a clear role split.
- Body copy in `text-align: justify` (creates rivers; never use on the web).

## SenWeaverCoding production additions

Modern, self-contained techniques that raise the typographic bar without
adding dependencies — safe inside the sandboxed canvas iframe.

- **Fluid display type with `clamp()`.** Headlines should scale with the
  viewport, not jump at breakpoints:
  `font-size: clamp(2rem, 1.2rem + 3vw, 4.5rem)`. Pair with the negative
  tracking from the table above so big sizes stay tight.
- **Balance and prettify wrapping.** `text-wrap: balance` on headings (≤4
  lines) prevents one orphan word on its own line; `text-wrap: pretty` on
  body copy removes single-word last lines. Both are progressive — they
  no-op where unsupported.
- **Tabular figures for any aligned numbers.** Tables, dashboards,
  pricing, timers, and stat blocks must set
  `font-variant-numeric: tabular-nums` (or `font-feature-settings: "tnum"`)
  so digits stop shifting between rows. Proportional figures only in prose.
- **Optical sizing for variable fonts.** When the active font is variable,
  let `font-optical-sizing: auto` adjust contrast at display sizes.
- **Hanging punctuation & quotes.** Use real quotes/dashes (`"" '' — –`),
  never straight quotes, and never a hyphen where an en/em dash belongs.
- **Reading length on touch.** `65ch` is the desktop ceiling; on narrow
  mobile, size body to 16px+ so iOS does not zoom inputs and lines stay
  45–60ch.
