Style guide
The visual language of this project, rendered live from the same tokens the site uses — so what you see here is exactly what ships. Colours follow your system's light/dark preference.
Color
Every colour is a semantic token declared once with
light-dark(light, dark), so themes flip with no
duplication. Hex pairs below read light · dark.
Brand
- --color-primary #2563eb · #3b82f6
- --color-primary-hover #1d4ed8 · #60a5fa
- --color-accent #7c3aed · #a78bfa
--gradient-accent — primary → accent, used by demo
components and image fallbacks. The logo itself uses flat ink and
accent tokens (see Logo & naming below).
Surfaces
- --color-bg #ffffff · #0f0f0f
- --color-bg-subtle #f5f5f5 · #1a1a1a
- --color-surface #ffffff · #1e1e1e
- --color-border #e0e0e0 · #2e2e2e
Text
- --color-text #111111 · #f0f0f0
- --color-text-subtle #555555 · #a0a0a0
Status
- --color-success #16a34a · #4ade80
- --color-warning #d97706 · #fbbf24
- --color-error #dc2626 · #f87171
- --color-info #0284c7 · #38bdf8
Site chrome
The page chrome (paper, grid, frame, registration ticks, title
block) reads its own token set, derived from the semantic tokens
above in blueprint.css — so every theme preset,
CVD variant, and contrast setting re-inks it with no extra rules.
- --bp-sheet = --color-surface
- --bp-ink = --color-text
- --bp-accent = --color-primary
- --bp-frame primary 42% mix
- --bp-redline = --color-error
Theming
A theme is two OKLCH seeds — --seed-surface and
--seed-accent — plus optional --mix-*
contrast strengths; theming/engine.css derives the
full contrast-safe palette from them (text flips to black or
white against its seed, greys mix toward the text). The cards
below render from their real .theme-* classes, so
this page can't drift from the shipped values.
-
Default
.surface -
Ocean
.theme-ocean -
Midnight
.theme-midnight -
Sunset
.theme-sunset -
Cobalt
.theme-cobalt -
Teal
.theme-teal -
Amber
.theme-amber -
Contrast light
.theme-contrast-light -
Contrast dark
.theme-contrast-dark
Cobalt, Teal, and Amber are tuned for colour-vision deficiency —
lightness carries the signal, never hue alone. The Contrast pair
raises the engine's --mix-* strengths and widens the
focus ring: high contrast as data, not a duplicate palette. All
eight ship in the site header's theme panel, persisted with a
no-flash reload.
Typography
System sans for prose, JetBrains Mono for code and labels. Display
sizes are fluid (clamp()) so headings scale with the
viewport — no breakpoints.
- Sans
- system-ui — the platform's own UI typeface
- Mono
- JetBrains Mono — code, tokens, eyebrows
- Display--text-display · 800
- Heading 4xl--text-4xl · 2.25rem
- Heading 3xl--text-3xl · 1.875rem
- Heading 2xl--text-2xl · 1.5rem
- Heading xl--text-xl · 1.25rem
- Large body--text-lg · 1.125rem
- Base body--text-base · 1rem
- Small / captions--text-sm · 0.875rem
Spacing
A rem-based scale (token = rem × 4). The same rhythm drives gaps, padding, and the generous section breaks.
- --space-1 · 0.25rem
- --space-2 · 0.5rem
- --space-3 · 0.75rem
- --space-4 · 1rem
- --space-6 · 1.5rem
- --space-8 · 2rem
- --space-12 · 3rem
- --space-16 · 4rem
- --space-24 · 6rem
Radius & elevation
- sm · 0.25rem
- md · 0.5rem
- lg · 0.75rem
- xl · 1rem
- full
- --shadow-sm
- --shadow-md
- --shadow-lg
Motion
Durations and easings are tokens so reduced-motion overrides work from one source. Hover the swatch to feel each curve; it holds still if you've asked your system to reduce motion.
- fast · 150ms
- normal · 250ms
- slow · 400ms
Focus & elements
Bare elements, styled only by the foundation. Tab through them — the
focus ring (--focus-ring-*) is consistent and never
removed.
inline code
Principles
- Accessibility wins the cascade. User-preference layers (reduced motion, high contrast, forced colours) sit last in the
@layerorder, so they always override aesthetics. - Built in, not bolted on. Reach for the platform first; add JavaScript only when CSS and semantic HTML genuinely can't.
- One source of truth. Colours, spacing, type, and motion are tokens — never hard-coded values.
- Progressive enhancement. Modern features are wrapped in
@supportsso unsupported browsers degrade, never break. - Never remove focus. The focus ring is part of the brand, not an eyesore to suppress.
Logo & naming
The mark is the numeronym a11y drawn with drafting instruments: a compass-drawn single-storey a (its center prick left in), two ruled lines standing in for the 11, and a straightedge y. Read fast, it also says ally — both readings are intended. Strokes overshoot only where they end in open air; everything sits on a shared baseline and x-height.
In the site header the mark is inline SVG on the ink and accent
tokens, so it re-inks with every theme and flattens to a single
color in forced-colors mode. The favicon adapts to light and dark
with its own media query, and every raster asset (app icons, the
link-preview image) is generated from one definition in
scripts/gen-icons.mjs.
The name is Accessible by default —
a11y-foundation is the repository, not the brand.