Design system

Tokens

The raw CSS custom properties exposed by <code>src/css/global/variables.css</code>. Foundations describes how each token is used; this section is the flat reference.

Color tokens

Every --color-*, --glass-*, and --gradient-* token from variables.css. Source values are oklch() for perceptual lightness; transparency is expressed in-channel (oklch(… / 0.6)) rather than as a separate alpha token. For deeper context on how the palette composes — brand vs neutral vs surface — see Foundations › Colour.

Brand

--color-blue
oklch(66.623% 0.1177 217.10)
#0aa5c3
--color-blue-light
oklch(77.31% 0.13351 211.702)
#0bcbe6
--color-blue-dark oklch(58.216% 0.1005 212.646)
--color-green
oklch(77.183% 0.1766 131.692)
#8acb46
--color-green-dark oklch(64.020% 0.1502 131.396)

Neutral ramp

--color-white oklch(96.826% 0.0069 247.896)
--color-grey-50 oklch(20.768% 0.0398 265.755)
--color-grey-100 oklch(23.157% 0.0398 262.510)
--color-grey-200 oklch(27.950% 0.0368 260.031)
--color-grey-300 oklch(37.170% 0.0392 257.287)
--color-grey-400 oklch(71.067% 0.0351 256.788)
--color-grey-500 oklch(55.439% 0.0407 257.417)
--color-grey-600 oklch(86.898% 0.0198 252.894)
--color-grey-700 oklch(92.876% 0.0126 255.508)
--color-grey-800 oklch(96.826% 0.0069 247.896)
--color-grey-900 oklch(98.415% 0.0034 247.858)

Lightness is the first OKLCH channel — in this dark palette, low numbers are deep panels and high numbers are bright text. The opposite of a Tailwind ramp.

Surfaces

--color-body-bg oklch(16.140% 0.0289 266.826)
--color-surface-solid oklch(18.020% 0.0325 266.625)
--color-header-solid-bg oklch(16.140% 0.0289 266.826 / 0.95)

Text

--color-text oklch(86.898% 0.0198 252.894)
--color-text-muted oklch(71.067% 0.0351 256.788)
--color-heading oklch(96.826% 0.0069 247.896)

Glass

--glass-bg oklch(20.768% 0.0398 265.755 / 0.6)
--glass-bg-light oklch(20.768% 0.0398 265.755 / 0.4)
--glass-border oklch(71.067% 0.0351 256.788 / 0.12)
--glass-border-hover oklch(71.067% 0.0351 256.788 / 0.22)
--glass-blur 1rem

Gradients

--gradient-accent linear-gradient(135deg, blue/grey 0-10%, green/grey 90-100%)
--gradient-accent-shimmer linear-gradient(90deg, blue, green, green, blue)

The shimmer gradient pairs with background-size: 200% 100% and an animation: shimmer… keyframe to produce the looping accent. See it live on the animations page.

Grid & shimmer accents

--color-grid-line oklch(71.067% 0.0351 256.788 / 0.08)
--color-grid-line-light oklch(71.067% 0.0351 256.788 / 0.06)
--color-shimmer oklch(100% 0 none / 0.25)

Decorative opacities

Numeric tokens consumed by the hero blob field and other layered backdrop washes. Tune these per surface to dial intensity up or down without changing the base colours.

--hero-blob-blue-1 0.18
--hero-blob-blue-2 0.12
--hero-blob-green-1 0.15
--hero-blob-green-2 0.10
--bg-blue-1 0.10
--bg-blue-2 0.06
--bg-green-1 0.07
--bg-green-2 0.05

Hero signal canvas

Read by src/js/hero-signals.js at runtime to colour the trail dots. Splitting the colour into r/g/b channels lets the canvas pre-compute the alpha lookup without parsing strings every frame. See Brand › Illustration for the recipe.

--signal-trail-r 10
--signal-trail-g 165
--signal-trail-b 195
--signal-trail-multiplier 0.4
--signal-dot oklch(66.623% 0.1177 217.10 / 0.5)

Components

Single-component tokens kept here rather than in the component CSS so they live alongside the rest of the palette.

--benefits-card-bg oklch(20.768% 0.0398 265.755 / 0.6)
--partner-item-bg oklch(26.48% 0.01276 243.42)
--partner-logo-opacity 0.5
--partner-logo-hover-opacity 0.85

Filter tokens (--partner-logo-filter, --partner-logo-hover-filter) drive the partner-logo greyscale-to-colour transition; they have no visual swatch since they describe an image filter, not a colour.

Type tokens

Two family tokens and a 12-step modular size scale, all in variables.css. Sizes are in rem so they respect the user’s root font size; the scale isn’t a strict ratio — spacing between steps tightens at the small end and opens up at the display end so headlines have room to breathe. For the family rationale and weight inventory, see Foundations › Typography.

Families

--font-text Aa Bb 0 1 2
--font-heading Aa Bb 0 1 2

Size scale

--font-size-xs 0.75 rem · Aa
--font-size-sm 0.875 rem · Aa
--font-size-base 1 rem · Aa
--font-size-lg 1.125 rem · Aa
--font-size-xl 1.25 rem · Aa
--font-size-2xl 1.5 rem · Aa
--font-size-3xl 1.875 rem · Aa
--font-size-4xl 2.25 rem · Aa
--font-size-5xl 3 rem · Aa
--font-size-6xl 3.75 rem · Aa
--font-size-7xl 4.5 rem · Aa
--font-size-8xl 5.5 rem · Aa

Spacing tokens

Twelve steps on a 0.25 rem base, with a 7th-step skip from --space-6 to --space-8 — a deliberate gap, since 1.75 rem is a value the layout never needs. Use these for every margin, padding, and gap; never fall back to raw rem or px. For the rhythm rationale see Foundations › Spacing.

--space-1 0.25 rem · 4 px
--space-2 0.5 rem · 8 px
--space-3 0.75 rem · 12 px
--space-4 1 rem · 16 px
--space-5 1.25 rem · 20 px
--space-6 1.5 rem · 24 px
--space-8 2 rem · 32 px
--space-10 2.5 rem · 40 px
--space-12 3 rem · 48 px
--space-16 4 rem · 64 px
--space-20 5 rem · 80 px
--space-24 6 rem · 96 px

Adjacent dimensional tokens. Border radii (--radius-sm through --radius-2xl + --radius-full) and shadows (--shadow-sm through --shadow-xl + --shadow-glow) are documented under Foundations › Radii and Foundations › Shadows with their visual specimens, since both read better as showcases than as a flat list.

Motion tokens

Three transition tokens and one stack of z-index layers. Easing is hard-coded as ease on every transition — the spec doesn’t expose a custom-curve token because every callsite that wants something more expressive (the gradient shimmer, the pulse rings, the blob drifts) defines its own keyframe rather than tweaking a global. For the full motion catalogue (named keyframes, hover lifts, scroll-triggered entry) see Animations.

Transitions

--transition-fast 150 ms ease
--transition-base 250 ms ease
--transition-slow 400 ms ease

fast for hover colour swaps and underline accents. base for the skip-link reveal, the dropdown panel fade, and most state changes. slow for the staggered fade-in on the contact page and any decorative scroll-triggered entry. The demo bars above honour prefers-reduced-motion and freeze when set.

Z-index layers

A four-step stack. Treat the named layer as the contract — never write a raw z-index value in component CSS, even for “just one notch above the header”.

--z-background -1
--z-content 1
--z-header 100
--z-overlay 200
--z-modal 300