Content and reading surfaces
Some screens are documents, not tools. They get the same system and a different rhythm.
A page is one Markdown file
components/brand/markdown.tsx renders it. Never hand-build a content page
out of utility classes — the second writer will use different ones and the
two pages will drift within a month. Everything below is decided once, in that
file:
| Element | Treatment |
|---|---|
# and ## | text-display, 600, 40 px above / 12 px below, first:mt-0 |
### | text-section, 600, 28 px above |
#### and deeper | mono caps in secondary ink — a label, not a smaller heading |
paragraph, list | text-body, capped at 76 characters, 12 px rhythm |
link | --accent-ink, underlined, underline-offset-2, un-underlines on hover; external links get target="_blank" rel="noreferrer" |
quote | the bracket device — never a tinted box with a coloured left edge |
inline code | sunken surface, mono at 0.92em, 10 px radius |
code block | card surface, 1px border, 16 px radius, 16 px padding, own x-scroll |
table | the real Table with stickyHeader={false} — a table in prose looks exactly like a table in a tool |
table cell in prose | valign="top", caption size, 62-character cap, text-pretty |
image | 16 px radius, 1px border, max-w-full |
rule | 32 px of air, --border |
Headings carry a slugified id and scroll-mt-20, so a deep link lands below
the sticky header instead of under it.
Depends on react-markdown and remark-gfm. No content pages? Delete the
file and both dependencies.
The measure
76 characters for prose, 62 inside a table cell. It is the same cap the tool screens use for their descriptions, which is why a documentation page and an overview page feel like one product.
Reading vs Source
A content page that is copied from somewhere upstream is worth showing as it is: a Reading view (a written lede plus the rendered body) and a Source view (the raw file). One file, two views, nothing to keep in sync. If the upstream still changes, hash it and fail a check when it moves — do not build a sync step, because a sync is what re-creates two sources.
Where content lives
One directory of Markdown, one loader, and the navigation is built from the directory — not from a second list in code. A page that exists is a file that exists.