Roles
Eleven roles, derived rather than hand-picked, at the shipped configuration
($scale-base: 1rem, $scale-ratio: 1.25, $leading-base: 1.5).
| Role | Step | Size | Leading | Tracking | Measure | Lead | Flow |
|---|---|---|---|---|---|---|---|
display |
7 | 4.7684rem |
1.1 | -0.02254em |
14ch | 3rem |
1.5rem |
h1 |
6 | 3.8147rem |
1.1 | -0.01932em |
17ch | 3rem |
0.75rem |
h2 |
5 | 3.0518rem |
1.135 | -0.0161em |
21ch | 3rem |
0.75rem |
h3 |
4 | 2.4414rem |
1.2 | -0.01288em |
27ch | 3rem |
0.75rem |
h4 |
3 | 1.9531rem |
1.269 | -0.00966em |
33ch | 3rem |
0.75rem |
h5 |
2 | 1.5625rem |
1.342 | -0.00644em |
42ch | 3rem |
0.75rem |
h6 |
1 | 1.25rem |
1.419 | -0.00322em |
52ch | 3rem |
0.75rem |
lead |
1 | 1.25rem |
1.419 | -0.00322em |
52ch | 0rem |
1.5rem |
body |
0 | 1rem |
1.5 | 0em |
65ch | 0rem |
1.5rem |
caption |
-1 | 0.8rem |
1.5 | 0.00322em |
80ch | 0.75rem |
1.5rem |
fine |
-2 | 0.64rem |
1.5 | 0.00644em |
80ch | 0.75rem |
1.5rem |
code |
0 | 1rem |
1.5 | 0em |
65ch | 0rem |
1.5rem |
Sizes: body at step 0, every heading above it. This makes “no heading
collides with body text” true by construction at any ratio greater than 1.
Below body there are two rungs and no more: caption at -1 and fine at
-2 — the small-text layer under a caption (a nav link, an eyebrow, a table
header, a byline). fine carries no kind of its own; it shares caption’s.
The scale stops at -2, and that is measured rather than chosen — nothing
enforces it. The fluent range for continuous reading spans 0.2° to 2° of
angular x-height; the bottom of that band works out to about 0.641rem at a
16px root, and at the shipped ratio step -2 sits just under it. It is stated
rather than guarded, because the bound is angular and a CSS length only
crosses it at an assumed viewing distance. Full derivation: docs/scale-floor.md.
Leading is derived from the size, clamped to [1.1, $leading-base].
Tracking is zero at body, tighter above it and looser below, from the log
of the size ratio. Measure is derived from the size, not the ratio —
size × measure held constant, clamped into the 13-80 character band.
code takes a line advance instead of a leading ratio. --type-advance-code
is one rhythm unit, so an n-line code block is exactly n rhythm units tall.
The role vocabulary
Every field a role may declare, and what governs it.
| Key | Unit | Required | Notes |
|---|---|---|---|
size |
root-relative | yes | rem, respects the reader’s font-size preference |
leading |
unitless | yes | Inherits as a ratio; the script layer can multiply it |
tracking |
em |
yes | Tracks the size it is applied to |
measure |
unitless | yes | A character count, validated against 13-80 on emit |
weight |
keyword or 1-1000 | yes | CSS Fonts 4, or a $font-weights name |
lead |
relative | yes | Space before the block. rem when derived |
flow |
relative | yes | Space after the block. rem when derived |
family |
font stack | no | code always; every role when $font-family-base is set |
family-fallback |
font stack | no | The var() fallback behind it. code only |
wrap |
text-wrap value |
no | pretty on prose, balance above. Undeclared roles inherit |
advance |
root-relative | no | A fixed line advance, used instead of leading. code only |
size is held to a root-relative unit, narrower than relative(): the token
is declared once on :root and read by every element the role reaches, so an
em size would mean a different length at each nesting depth.