Long-form typography. Set .prose on the wrapper and author plain HTML inside it — headings, paragraphs, lists, quotes and code all get their rhythm without a class on a single child.
The prose block
Capped at 68 characters. Spacing comes from the owl selector — .prose > * + * — so every sibling gets top space and the first child gets none. That is what keeps the rhythm even when the content is generated from Markdown and you cannot add classes.
Live prose
Why the thin slice comes first
Most integration projects fail in the same place: the second week, when the first real payload arrives and it does not look like the documentation. A thin slice — one record, end to end, into production — surfaces that on day three instead of week six.
It also settles the arguments that otherwise run for a month. You cannot debate whether the queue can handle the volume once there is a queue handling volume, and you cannot debate the schema once a real record has been through it. See the patterns page for how this gets written up.
What goes in the slice
The smallest path that touches every system the final thing will touch. Not the simplest feature — the narrowest complete one. Specifically:
One real record from the real source, not a fixture
The actual transport, with the actual auth
Whatever the destination system does on write, including its side effects
One alert that fires when the thing breaks
Pointing at a person, not a channel
With enough context to act on at 3am
The slice is not a prototype. It is the first ten per cent of the real system, and it stays in production.
Delivery note, 2024
What it costs
Roughly a week, sometimes two if credentials are slow. That is real time, and it is the most common thing a client asks to skip. It is also the only week that reliably pays for itself — the alternative is discovering the same facts in week six with a deadline attached.
Run it with npm run slice and check the output against the schema in docs/contract.md before widening.
$ npm run slice -- --source=prod --limit=1
→ fetched 1 record (312 ms)
→ transformed (4 ms)
→ wrote to sink (89 ms)
✓ round trip 405 ms
A smaller heading
Used sparingly — a fourth level usually means the section wants splitting.
Phase
Duration
Output
Discovery
1–2 weeks
Written architecture
Thin slice
1 week
One path in production
Build
Fixed scope
The rest of the paths
Figures get a hairline border and a 16 px radius. The caption is small, quiet and left-aligned.
Footnotes and asides use <small>, which drops to 15 px and secondary ink.
Note that nothing inside <article class="prose"> carries a class. That is the point — Markdown output drops straight in.
Eyebrow, lead and quote
The three pieces that open a page. An eyebrow labels the section, the heading names it, and the lead makes the case for reading on.
Opening block
Case study — Logistics
A nightly batch that could not finish before morning
Route allocation ran for six hours and had started overlapping with the dispatch window. Replacing it with an event-driven allocator cut it to continuous, sub-second assignment.
We stopped planning around the batch. That changed more than the latency number did.
Head of Operations, on the first week after cutover
<p class="eyebrow">Case study — Logistics</p>
<h2 class="mt-3">A nightly batch that could not finish</h2>
<p class="lede mt-5">Route allocation ran for six hours…</p>
<blockquote class="quote">We stopped planning around the batch.</blockquote>
<p class="quote-note">Head of Operations</p>
Article header
Title capped at 20 characters-per-line for balance, with a metadata row beneath. The dots between metadata items are generated, not typed.
Header
Engineering
Why the thin slice comes first
6 March 20268 min readCharlie Tang Hoong
DeliveryIntegration
Code and keys
Inline code gets a sunken pill; blocks get a bordered well that scrolls sideways rather than wrapping. Keyboard keys get a physical bottom edge.
Code
Set the region with --region=ap-southeast-1, then press CtrlC to stop the watcher.
export DATABASE_URL="postgres://localhost:5432/app"
npm run migrate -- --to=latest
npm run slice -- --source=prod --limit=1
Code blocks never wrap. A wrapped shell command cannot be copied reliably, so the block scrolls instead.
Numbered steps
A methodology or a runbook. Numbers are generated with a CSS counter in the accent colour, set in mono with leading zeros so single and double digits align.
Steps
Frame the failure mode
Write down what breaking looks like before writing what working looks like. It is a faster route to the real constraints.
Ship a thin slice
One real record through every system the final thing will touch, into production.
Instrument before widening
If you cannot see the first path, you will not be able to debug the tenth.
Hand over as you go
Documentation written at the end is documentation nobody trusts.
Measure
Three caps, and the choice matters more than most typographic decisions: a line longer than about 75 characters loses the reader on the return sweep.
Class
Cap
Use
.measure-tight
56ch
Leads, section intros, quotes
.measure
68ch
Body copy — the default in .prose
.measure-wide
80ch
Dense reference text and tables only
Print
A CV and a case study both get printed. content.css ends with a print block that drops the header, footer, nav sheet, toasts and rail, forces black on white, keeps headings with their content and stops cards breaking across pages.