Reference
Design system
The single source of truth, rendered in the real font. Every value on the site resolves to a token here. Premium comes from restraint, typography, and space, not decoration.
This page documents the system as built. Where it disagrees with the original design.md spec, this page wins: the spec still describes three typefaces, warm neutrals, and uppercase mono labels, none of which shipped.
01
Colour
Around 90% of the page is paper. Lime is a fill only, always carrying ink text, and it goes loud only on dark sections. One accent, no second brand hue.
On dark
Accent
Rules
- Lime is a fill only, and always carries ink text.
- Never lime text on paper. Never white text on lime.
- Links, marks, and focus rings on light surfaces use ink, not lime.
- One accent. Differentiate categories with labels, never a second hue.
- Lime appears about once per light view, and goes loud only on dark sections.
02
Typography
One typeface, PP Neue Montreal. Two weights, 400 and 500. Differentiate by size, weight, colour, and tracking, never by another family. Inverse tracking and inverse leading do most of the work. No italic, no serif accent word, and never all-caps or all-lower-case.
We take products from first idea to launched.Built to perform, not just look the part.
Measures
How the face is delivered
- Static per-weight instances, not the variable font. The variable file defaults its weight axis to 200, and WebKit does not reliably apply the CSS weight over it, so Safari and iOS rendered the whole site hairline.
- Three instances ship: 400 and 500 are the system. A 600 exists only for the Figma-literal Design Solutions section, which sits outside these tokens by design.
- Adding a weight means generating a new instance, not switching back to the variable file. Astro's Fonts API owns --font-display.
03
Spacing
Base unit 4px. Tight gaps for things that belong together, large gaps between distinct ideas. Air reads as expensive.
Layout
Container padding is clamp(1.2rem, 5vw, 4rem). Gaps run 8 to 12px for related elements, 48 to 96px between distinct ideas.
04
Radius and borders
Three radii for interface: pill, card, chip. Borders are 1px hairlines. The system is flat, no ambient shadows or glows, so depth comes from space and hairlines. One honest exception: the Figma-derived project cards on the home page and /work carry larger art-directed corners (16 to 40px) that predate --r-card and do not resolve to it. Treat those as art direction, not as a fourth step to reach for.
05
Motion
A few durations and eases, reused. Consistency is what makes expressive motion read as designed. Everything is gated behind reduced-motion.
Duration
Easing
06
Components
The small, shared set, all defined in base.css. Never hand-copy one into a component's scoped styles; extend the shared class instead.
6.1 Actions
Two primaries, chosen by the surface they sit on, plus one quiet secondary.
- .cta-badge is primary on light surfaces: ink pill, lime arrow badge nested left.
- .cta is primary on dark surfaces, where an ink pill would read ink-on-ink.
- Gloss is the one deliberate exception to the flat rule, and it belongs to the primaries only: the whole of .cta, and the arrow disc inside .cta-badge. Everything else stays flat.
6.2 Labels and metadata
The quiet scaffolding: what names a section, tags a card, or carries a figure.
What we believe
6.3 Surfaces
Where a section changes ground. Flat everywhere: separation comes from the surface tone and a hairline, never a shadow.
A card title
White on paper, one hairline, no shadow.
6.4 Section anatomy
Every section leads with an eyebrow, a label plus a short rule, then a two-tone statement, then content on a 1px hairline grid. Metadata rows sit at 12px in--soft, separated by middots or slashes.
07
Accessibility and motion gating
The floor, not the ceiling. These are non-negotiable.
- Focus ring: 2px solid ink, offset 3px, on every interactive element. It switches to lime on dark surfaces, and it is the only box-shadow the system allows.
- Motion is gated on html.anim, added pre-paint only when motion is allowed. Reduced-motion and no-JS both render the final state, with zero JS and no flash. Always include a failsafe that reveals content if setup throws.
- The shared entrance is .reveal, a one-shot fade and 16px rise. At most one or two pinned or scrubbed scenes per page.
- AA contrast, keyboard navigable, responsive to mobile.
Focus ring