Design system · Prism
Steel at rest, colour on touch.
Prism is the design system behind this site. At rest everything is monochrome — charcoal ground, white text, a muted steel accent. On hover, any interactive element draws one fresh random pastel. Colour is never a brand hue and never a resting state; it’s a reward for touch. Try the headline.
OKLCH tokens · Geist / Geist Mono / Newsreader · no framework, no build step · one style block per page · AA by default
Principles
01Editorial, not appy.
Generous whitespace, a strong type hierarchy, hairline rules instead of boxes and shadows. Content leads; chrome recedes.
Colour is earned.
One steel accent at rest. A random pastel on hover — the Prism interaction. If everything is accented, nothing is.
Mono for metadata, serif for voice.
Geist Mono carries eyebrows, years, counts and labels. Newsreader italic carries the human voice. Geist does everything else.
Accessible by default.
AA contrast, visible focus, 44px touch targets, reduced-motion and high-contrast honoured, semantic landmarks everywhere.
Motion is a whisper.
Short, eased, optional. Nothing bounces or demands attention — and everything switches off under prefers-reduced-motion.
Colour
02Nine tokens, defined once in a shared stylesheet, in OKLCH. Neutrals are true greys — zero chroma — so the pastels have the only say. Steel is the single accent that’s allowed to rest. The swatches and the values below are read live from that stylesheet — edit it once and this page rewrites itself.
Prism — the signature interaction
03Named for a prism splitting neutral light: steel in, a random band of colour out. On every hover the site deals one fresh pastel — a hue drawn at random from all 360°, kept light enough to read on the dark ground.
There is no per-component CSS. A few lines of JavaScript write the pastel straight into the accent tokens on the hovered element, and clear them on mouse-out. Because the whole site already styles its hover states with var(--accent), every component prisms automatically — links, buttons, cards, diagrams, the headline above.
Two rules keep it honest: on dark surfaces the pastel may colour text; on light fills it goes to the fill or border instead, never the text. And one object gets one pastel — a card and its title never split the spectrum.
Hover anything — every touch deals a new colour
The spectrum it draws from
The whole mechanism
/* motion.js — on mouseover */ const h = Math.floor(Math.random() * 360); const pastel = `hsl(${h} 70% 82%)`; el.style.setProperty('--accent', pastel); el.style.setProperty('--accent-text', pastel); /* every var(--accent) hover rule on the site now prisms — for free */
Typography
04The decisions that matter sit below the UI.
The serif carries the human voice.
Eyebrows · years · counts · labels
Body copy stays quiet and readable: sixteen pixels, a relaxed leading, and a measure that never stretches past what an eye can comfortably track back from.
Components
05All live — these are the real shared components, not pictures of them. Every one prisms on hover.
Buttons
The signature morph: a rounded rectangle at rest that becomes a pill on hover. Primary fills; secondary only ever strokes.
Segmented control
Selected is always black, never accent — so a hovered and a selected segment never look alike.
Tags
Body copy, sentence case, hairline pill. Mono is reserved for true metadata, so tags never use it.
Live eyebrow
Available now · London, UK
The pulsing dot marks something live. It opens the hero of every page — and stops pulsing under reduced motion.
Arrow bullets
- The house bullet is an arrow, never a disc
- Geist 500, steel, hanging indent
- One arrow style everywhere on the site
Lists, footer links and “next” affordances all share the same → — one arrow, one weight, one colour.
Link rows
Full-width rows keep a grey underline; only the arrow carries the accent, and it slides on hover.
Motion & access
06Signature moves
- CTA radius morph — rectangle to pill, 0.18s ease-out
- Prism — one fresh pastel per hover, cleared on leave
- Headline words reveal line by line, thicken on hover
- Footer links lean toward the cursor (magnetic)
- Live dot pulse — 1.8s, ease-out, infinite
- Durations 0.15–0.35s; nothing ever bounces
Non-negotiables
- AA contrast everywhere — small accent text uses its own token
- prefers-reduced-motion switches every animation off
- prefers-contrast deepens muted text, lines and accents
- Visible focus: 2px accent outline, offset 3px
- Touch targets ≥44px, even on 28px visual controls
- Skip link, semantic landmarks, stepped headings