Style guide
The logo, literal.
The file the owner uploaded, shown as shipped. Everything brand-shaped on this site is derived from its pixels: the palette is sampled from it (scripts/sample-logo.mjs), and the mark in the header, footer and social image is cropped from it with the background removed (scripts/derive-logo.mjs). Nothing hand-drawn remains except the favicon, which needs vector at 16px and matches the sampled stops.
From the logo and the docket book.
Every text/background pair meets WCAG 2.1 AA, and it is measured on the rendered page, not calculated from the tokens — run npm run audit:contrast. That distinction matters: a token reading #F3F4F1 looks like 16:1 right up until a component passes it through color-mix(), and only the render knows the answer.
Two tokens people reach for interchangeably and should not: --rule is the hairline of the grid at 1.4:1, which is fine for a decorative line and illegal for a field border. Field borders are interface elements and need 3:1 (WCAG 1.4.11), so they use --rule-strong.
Three voices, one fluid scale.
Sizes interpolate with clamp() between 360px and 1440px, so there is not a single font-size media query in the stylesheet. Which typeface a step speaks in is part of the system, not a free choice — see the label above each specimen.
A 4px scale with names.
Named, not numbered, so nobody has to remember whether 5 was 20px or 24px.
Buttons and controls.
Three rules, no exceptions.
- Nothing animates for longer than 320ms. Past that it reads as the site being slow.
- Nothing travels further than 20px. A reveal you notice is a reveal that is wrong.
- prefers-reduced-motion disables all of it, and the content stays visible. A reveal that switches off leaving
opacity:0is a blank page, not an accessibility feature.
One easing curve throughout: cubic-bezier(0.22, 1, 0.36, 1), which settles rather than brakes.
Four things that will bite you.
No inline styles
The CSP has no style-src 'unsafe-inline', so a style="…" attribute is refused by the browser — silently, with no visible error. Add a class instead. This already caused one real bug: the alternating project layout did nothing for a while.
No colour literals outside tokens
Every colour comes from 01-tokens.css. A hex code anywhere else breaks dark mode and cannot be rebranded. If you need a colour that does not exist, add a token.
Components inherit colour
Anything reused on both light and inverse surfaces must use inherit, not var(--ink). Hard-coding it put black text on the black footer once already.
Heading levels are arguments
Components that render a heading take a level option, because heading order must not skip (WCAG 1.3.1). npm run check fails the build when it does.