Published August 1, 2026 · 6 min read
One typeface, two spacing units, one ornament and three content widths — plus the corrections the system needed along the way, including a contrast check that passed by 0.22 and why that was a coincidence rather than a margin.
This site has a design system, but it is a small one on purpose. One typeface. Two spacing units. One ornament. Three content widths. Most of what follows is a record of what was left out and why, because that is the part that is hard to reconstruct later.
Everything vertical derives from a single number. A 28px leading unit, and a half step at 14px. Section padding, gaps between grid rows, the space under a heading, the gap between a byline and the paragraph it labels — all of them are multiples or fractions of those two values rather than numbers picked per component.
--leading: 28px;
--half: 14px;
--edge: clamp(20px, 5vw, 72px);
--nav-height: calc(12px * 2 + 36px + 1px);The nav height is worth pausing on. It is derived rather than asserted: 12px of block padding on each side, a 36px control footprint, and a 1px bottom border. The mobile menu panel offsets itself by this value, and the two drifting apart leaves either a translucent gap under the bar or a panel clipped off the bottom of the screen. Writing it as arithmetic means changing the button size updates the panel automatically.
The horizontal gutter is fluid rather than stepped. clamp(20px, 5vw, 72px) means a phone gets 20px, a laptop gets whatever 5% of the viewport is, and anything above about 1440px is capped at 72px. There are no media queries involved in that, and no breakpoint where the gutter jumps.
Content sits in one of three widths, and the page declares which one it is on by setting a custom property that the shared column class reads.
export const CONTENT_WIDTH = {
reading: 900, // notes, privacy, terms, sitemap
caseStudy: 1100, // the case studies index and each case study
marketing: 1440, // home and booking
} as const;The navbar and the footer read the same variable, which is what keeps the logo and the footer columns aligned with the content between them. There is a subtlety here that took a while to find: both of those render outside the page's own element, so they never inherit the value a page sets and instead resolve a default declared alongside the column class. Change the tier on a page and the chrome follows only because that default is kept in step by hand.
There is one typeface, and the system enforces it harder than it looks. The heading token, the body token, the sans token and the mono token all resolve to the same family.
--font-heading: var(--font-archivo);
--font-body: var(--font-archivo);
--font-sans: var(--font-body);
--font-mono: var(--font-body);Aliasing mono is the deliberate part. Without it, the typography plugin styles code and pre elements from that token and pulls in the operating system monospace stack, so a fenced code block in a note would arrive in whatever face the reader's machine defaults to. Pointing it at the body font keeps every surface on one typeface, and the code blocks read as code from the tinted background and the border instead of from the letterforms.
The palette is near-black on near-white, and the secondary tones are opacity steps of the text colour rather than separate greys.
--color-bg: #fbfbfb;
--color-text: #000000;
--color-text-82: color-mix(in srgb, var(--color-text) 82%, transparent);
--color-text-78: color-mix(in srgb, var(--color-text) 78%, transparent);
--color-divider: color-mix(in srgb, #201e1d 10%, transparent);Deriving them with color-mix rather than hardcoding hex values means the whole secondary layer moves together if the base ever changes, and it makes the intent legible: 82% is body prose, 78% is supporting copy, and the lightest step carries labels.
That lightest step is where the system got a real correction. It was 55%, which composites to 4.72:1 against the background. WCAG AA asks for 4.5:1 on normal text, so it passed — by 0.22. That is not a margin, it is a coincidence, and it applied to every kicker, byline, meta row and footer heading on the site simultaneously. Any future darkening of the background or lightening of the text would have dropped the entire secondary layer below AA at once. Raised to 60%, it measures 5.68:1 and is still visibly subordinate to body prose.
The lesson generalises: a contrast check that passes is not the same as a contrast decision that holds. Measure the margin, not just the result.
The only ornament the system allows is a rule.
.rule2 {
height: 2px;
border: 0;
margin: 0;
background: var(--color-divider);
}Two pixels, no border, no radius, no shadow. It separates every band on every page. There is no card treatment, no panel, no elevation scale — where other systems would reach for a container, this one draws a line and relies on the spacing rhythm to do the grouping.
The site is light only, which makes one component interesting. The contact band at the bottom of the home page is permanently dark in a light-only design, and the sticky bar is a 40% tint of the page background over a blur, so whatever is behind it sets its tone. Passing over that band turned the bar mid-grey while its links stayed black. The fix is a local token inversion rather than a special-cased colour.
.nav[data-over-dark] {
--color-bg: #0d0d0d;
--color-text: #f2f2f2;
--color-divider: color-mix(in srgb, #f2f2f2 14%, transparent);
color: var(--color-text);
}Redefining the two base tokens on the bar means every child utility that references them — the links, the button fill, the border — flips without being touched individually. The divider has to be restated explicitly, because otherwise the bottom border keeps its light-mode value and the bar loses its edge exactly when it most needs one. The logo is a raster file, so it cannot follow tokens at all and is inverted with a filter instead.
What the system deliberately does not have is as much a part of it as what it does. No second typeface. No accent colour outside a single green status dot that is carrying meaning rather than decoration. No dark mode, which was built and then removed. No component library page, because with only about ten components used in three or more places, the inventory is thinner than the token system is.
The through line is that a small system is only cheap to maintain if the reasons are written down next to the code. Roughly a fifth of the lines in the component directory are comments, and almost none of them explain what the code does. They explain why a value is what it is, usually with a measurement attached, so the next person to touch it — including a future me — can tell a deliberate choice from an accident.
WCAG 2.1 contrast minimum: https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html
CSS color-mix: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix
CSS clamp: https://developer.mozilla.org/en-US/docs/Web/CSS/clamp
Custom properties: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
If this is the kind of problem you are dealing with — type safety, forms, or a codebase that keeps surprising you — a short call is the fastest way to find out whether I can help.