Foundation
One source, three consumers.
These live in lib/patterns/design-tokens.ts. The stylesheet declares them, lib/gsap.ts derives its durations from the same numbers so GSAP and CSS cannot disagree, and the MCP serves them to agents. pnpm check fails if any of the three drifts.
Motion
Durations and easings tuned for large moving type and full-bleed media. Long, low-acceleration curves read as considered; short bouncy curves read as a toy. `lib/gsap.ts` derives its GSAP durations from these exact values.
--ease-out-expo- cubic-bezier(0.16, 1, 0.3, 1)
- The workhorse. Entrances, reveals, and anything that should arrive decisively and settle without overshoot. Mirrors GSAP `expo.out`.
--ease-in-out-quart- cubic-bezier(0.76, 0, 0.24, 1)
- Symmetric moves: curtains, pins, page transitions. Mirrors GSAP `power4.inOut`.
--ease-out-quad- cubic-bezier(0.5, 1, 0.89, 1)
- Hover and cursor feedback, where anything longer than a breath feels laggy.
--dur-instant- 0.12s
- Hover state changes, cursor scale, underline draw.
--dur-micro- 0.4s
- Small element entrances, nav condensation, magnetic release. GSAP `DUR.micro`. (was --dur-quick)
--dur-reveal- 0.95s
- The default reveal duration for a line of type or a single card. GSAP `DUR.reveal`. (was --dur-base)
--dur-curtain- 1.1s
- Full-bleed media reveals, curtain transitions, preloader exits. GSAP `DUR.curtain`. (was --dur-slow)
--stagger- 0.08s
- Delay between consecutive lines of a masked headline. GSAP `DUR.stagger`. (was --stagger-line)
--stagger-grid- 0.06s
- Delay between consecutive grid cells entering the viewport.
--parallax-depth- 0.15
- Unitless multiplier applied to scroll delta for background media. Above ~0.3 the effect stops reading as depth and starts reading as lag.
Typography
A fluid scale with very few steps and very big jumps. The direction depends on one headline being genuinely enormous rather than several being moderately large — there is deliberately no mid-sized step.
--fs-display- clamp(3rem, 12vw, 12.5rem)
- The single hero statement. One per page. (was --type-display)
--fs-h1- clamp(2.5rem, 6vw, 6rem)
- Section openers below the hero. (was --type-h1)
--fs-h2- clamp(2.2rem, 6vw, 5.5rem)
- Sub-section headings. (was --type-h2)
--fs-body- clamp(1rem, 1.05vw, 1.125rem)
- Running text. Keep measure between 55 and 72 characters. (was --type-body)
--fs-label- clamp(0.68rem, 0.74vw, 0.8rem)
- Index numbers, metadata, cursor labels, eyebrow rows. Mono, uppercase. (was --type-caption)
--leading-display- 0.9
- Display type sits tight. Anything at or above 1.0 loses the block-of-type quality the direction relies on.
--leading-body- 1.55
- Running text.
--tracking-display- -0.035em
- Negative tracking on display sizes only. Never on body or label.
--tracking-caption- 0.15em
- Positive tracking with uppercase for metadata and eyebrow labels.
Colour
Near-monochrome with one accent, dual-mode. Every colour is theme-relative: flipping `data-theme` on `<html>` repaints the page because Tailwind utilities map to these live variables through `@theme inline`.
--bg- #0a0a0a
- Page background. Never pure black — this is the dark-cinematic canvas. (was --paper)
--bg-2- #121212
- Raised surfaces: cards, demo frames, code blocks.
--ink- #f3f1ec
- Foreground. Warm off-white on dark, near-black on light.
--ink-dim- #8a8781
- Body copy, captions, anything secondary.
--ink-faint- #47453f
- Disabled and decorative text. Check contrast before using for content.
--accent- #d7ff3e
- Exactly one accent, used for focus rings, the cursor, and at most one CTA.
--accent-2- #7087f7
- The rare second accent. Reserve for data or state, never decoration.
--line- rgba(243, 241, 236, 0.14)
- Hairlines and dividers. (was --rule)
--bg-inverse- #f4f2ed
- Background of a section that inverts against the page. Used by scroll-colour inversion. (was --paper-inverse)
--ink-inverse- #0f0e0c
- Foreground on an inverted section.
--veil- color-mix(in oklab, #0a0a0a 55%, transparent)
- Scrim over media when text sits on top of it. Deliberately dark in both themes — it exists to make type readable over an image, not to match the canvas.
Space
A fluid spacing ramp. Sections breathe far more than components do.
--space-2xs- 0.5rem
- Inline gaps inside a control.
--space-xs- 0.75rem
- Label to value.
--space-sm- 1.25rem
- Stacked text blocks.
--space-md- 2rem
- Component internal padding.
--space-lg- clamp(3rem, 6vw, 6rem)
- Between components.
--space-xl- clamp(6rem, 14vh, 12rem)
- Between page sections.
--gutter- clamp(1.25rem, 4vw, 4rem)
- Page side gutter. Full-bleed media ignores it; everything else respects it.
Layout
Grid, measure, and the z-index ladder. The grid exists so that breaking it is legible as a decision rather than an accident.
--grid-columns- 12
- Column count at desktop. 6 at tablet, 4 at mobile.
--grid-gap- clamp(1rem, 1.6vw, 2rem)
- Gap between grid columns.
--measure- 62ch
- Maximum width of a running-text column.
--wrap-max- 1440px
- Maximum content width before the gutter takes over.
--frame-radius- 0px
- Square corners by default. The direction reads as print, and print has no border radius.
--z-nav- 50
- Sticky navigation.
--z-grain- 60
- Film-grain overlay.
--z-cursor- 70
- Custom cursor, above the grain.
--z-curtain- 100
- Route curtain and preloader.