Foundations
Typography
General Sans for prose and UI, JetBrains Mono for every token name, hex value and ratio. The monospace is not an accent here — it carries most of the load-bearing text on this site.
Two faces, and what each is for
The split is not decorative. Anything that is a value — a token name, a hex, a measured ratio, a keyboard key — is monospaced, because those are things a reader compares character by character and often copies. Anything that is an argument is set in the sans.
That rule is why the mono is self-hosted and the sans is not. If the CDN is unreachable, prose falls back to a system sans and reads fine; a hex value in a proportional fallback is genuinely harder to scan.
General Sans — the argument
JetBrains Mono — --ht-informational-content · #3D4A6B · 7.62:1
The scale
Seven sizes, and the ratio between neighbours is small on purpose. A dramatic scale is for pages that are read once; this is for software someone has open all day, where a heading only needs to be findable, not loud. Body is 15px rather than 16 because the measure is narrower than an article's.
| Token | rem | px | Use |
|---|---|---|---|
| --ht-type-xs | 0.6875rem | 11px | Eyebrows, table meta, badge text. Never a sentence. |
| --ht-type-sm | 0.8125rem | 13px | Dense UI — table cells, controls, captions. |
| --ht-type-base | 0.9375rem | 15px | Body copy and everything unspecified. |
| --ht-type-md | 1.0625rem | 17px | Page leads and callout text. |
| --ht-type-lg | 1.25rem | 20px | Section headings (h2). |
| --ht-type-xl | 1.5rem | 24px | Page headings (h1) on interior pages. |
| --ht-type-2xl | 2rem | 32px | The overview title, and nothing else. |
Line height and measure
Generous in prose, tight in data. The same line-height for both is the most common typographic mistake in documentation.
| Token | Value | Applies to |
|---|---|---|
| --ht-leading-tight | 1.2 | Display sizes, where the default gap already looks like a paragraph break. |
| --ht-leading-snug | 1.35 | Headings and multi-line labels. |
| --ht-leading-normal | 1.5 | UI text, table cells, anything scanned rather than read. |
| --ht-leading-prose | 1.65 | Paragraphs. The only tier meant for continuous reading. |
| --ht-measure-prose | 68ch | Body copy. Past roughly 75ch the eye loses the start of the next line. |
| --ht-measure-narrow | 52ch | Callouts and captions, where a shorter line reads as an aside. |
Line length, in characters. Anything past 75ch costs the reader a return sweep on every line.
Using it
Set size and line height from tokens together. Picking a size and leaving line height to inherit is how documentation ends up with 15px body copy at 1.2 — technically legible, exhausting after twenty minutes.
/* Continuous reading */
.prose p {
font-size: var(--ht-type-base);
line-height: var(--ht-leading-prose);
max-width: var(--ht-measure-prose);
}
/* Scanned, not read — tighter, and no measure limit */
.table td {
font-size: var(--ht-type-sm);
line-height: var(--ht-leading-normal);
} When not to reach for a bigger size
- To signal importance. Use a semantic role, or put the thing first. Size is a poor carrier of meaning and no carrier at all for a screen reader.
- To fill space. If a panel looks empty, the answer is usually less padding, not larger type.
- For a number that must be compared. Oversized figures stop being comparable across rows. Keep them at sm and use tabular numerals.