Design System

Neutral greys, hairline rules, letterspaced small type, one pink, and motion that stays out of the way. Every value below is read from the site’s stylesheets at build time and every component is the real one, so this page cannot drift from the site.

01

Color

Two neutral palettes, no tint. Emphasis is contrast, not a hue: --accent is the highlight text color and selection inverts the text. Dark is the default; .theme-dark pins it to a subtree, which keeps the search dialog dark in the light theme.

Dark, default
  • --bg-primary #0a0a0a
  • --bg-secondary #161616
  • --bg-tertiary #222
  • --text-primary #ededed 16.9:1
  • --text-secondary #a3a3a3 7.8:1
  • --text-tertiary #818181 5.1:1
  • --text-highlight #fff 19.8:1
  • --border-primary #262626
  • --border-secondary #4d4d4d
  • --surface-hover #ffffff14
Paper
  • --bg-primary #f5f5f5
  • --bg-secondary #e7e7e7
  • --bg-tertiary #dcdcdc
  • --text-primary #111 17.3:1
  • --text-secondary #555 6.8:1
  • --text-tertiary #666 5.3:1
  • --text-highlight #000 19.3:1
  • --border-primary #d9d9d9
  • --border-secondary #a5a5a5
  • --surface-hover #00000010

Ratios are each text color on its own --bg-primary (WCAG 2).

02

Pink and blue

The only hue in the interface: a 6px pink swatch beside a kicker, shown here magnified and at actual size. The blue joins it only in the colophon. Never body text, never a wash, never a second palette.

Latest

  • Fluorescent Pink --ink #ff48b0
  • Blue --ink-offset #0078bf
03

Type

Three families, self-hosted through the Astro font pipeline, and only the cuts listed are loaded. Headings are set in the sans; the serif is an editorial accent.

  • PP Neue Montreal --ff-base 350 · 400 · 400 italic · 500 · 600 · 700 Everything: text, headings, labels and pills.
  • Instrument Serif --ff-serif 400 · 400 italic Editorial accent: work titles and quotes.
  • Geist Mono --ff-mono 400 · 500 Small type: specs, captions and numbers.

Weights

  • Aa Book 350 --font-weight-book Long-form reading
  • Aa Regular 400 --font-weight-regular Body text (default) and the home headline
  • Aa Italic 400 --font-weight-regular Emphasis in running text
  • Aa Medium 500 --font-weight-medium Labels and kickers
  • Aa SemiBold 600 --font-weight-semibold Card titles, strong
  • Aa Bold 700 --font-weight-bold Headings (--font-weight-heading)

Scale

  • --fs-xs clamp(0.72rem, 0.1vi + 0.68rem, 0.76rem) I design brand identities, illustrations and websites that are easy to understand, free of clutter and made to last.
  • --fs-sm clamp(0.9375rem, 0.25vi + 0.74rem, 0.96rem) I design brand identities, illustrations and websites that are easy to understand, free of clutter and made to last.
  • --fs-base clamp(1.125rem, 0.45vi + 0.89rem, 1.25rem) I design brand identities, illustrations and websites that are easy to understand, free of clutter and made to last.
  • --fs-md clamp(1.25rem, 0.76vi + 1.06rem, 1.67rem) I design brand identities, illustrations and websites that are easy to understand, free of clutter and made to last.
  • --fs-lg clamp(1.56rem, 1.2vi + 1.26rem, 2.22rem) I design brand identities, illustrations and websites that are easy to understand, free of clutter and made to last.
  • --fs-xl clamp(1.56rem, 0.9rem + 2.2vi, 2.75rem) I design brand identities, illustrations and websites that are easy to understand, free of clutter and made to last.
  • --fs-prose clamp(1.25rem, 0.875rem + 1.5vi, 1.5rem) I design brand identities, illustrations and websites that are easy to understand, free of clutter and made to last.
  • --fs-prose-lg clamp(1.1875rem, 1rem + 0.8vi, 1.625rem) I design brand identities, illustrations and websites that are easy to understand, free of clutter and made to last.

Fluid sizes with floors: small type never under 11.5px, small text never under 15px. The right column is the size at this viewport.

--font-weight-heading
700
--line-height-heading
1.1
--letter-spacing-heading
-0.02em
--line-height-base
calc(2ex + 6px)
04

Space & layout

A fixed step scale inside components, a fluid one for page rhythm. The gutter never drops under a display cutout.

Steps

  • --space-4xs 0.125rem · 2px
  • --space-3xs 0.25rem · 4px
  • --space-2xs 0.375rem · 6px
  • --space-xs 0.5rem · 8px
  • --space-s 0.75rem · 12px
  • --space-m 1rem · 16px
  • --space-l 1.5rem · 24px
  • --space-xl 2rem · 32px
  • --space-2xl 3rem · 48px

Fluid

  • --space-fluid-2xs clamp(0.375rem, 0.3182rem + 0.2424vi, 0.5rem)
  • --space-fluid-s clamp(0.75rem, 0.6364rem + 0.4848vi, 1rem)
  • --space-fluid-l clamp(1.5rem, 1.2727rem + 0.9697vi, 2rem)
  • --space-fluid-2xl clamp(3rem, 2.3182rem + 2.9091vi, 4.5rem)

Layout

--gutter
max(clamp(1.25rem, 3vw, 2.5rem), env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px))
--page-width
2048px
--dock-clearance
6.75rem
05

Radius & rules

Two radii plus pill. A button sits one step under its card, so the pair stays concentric.

  • --radius-sm 6px
  • --radius-md 0.5rem
  • --radius-pill 9999px
  • 6 + 2 = 8 Concentric --radius-card · --space-4xs
--radius-card
var(--radius-md)
--button-radius
var(--radius-sm)

Borders

  • --border-width-hairline 1px
  • --border-width-strong 2px
06

Motion

Short, plain transitions for chrome; authored curves only where something travels. Play runs every row at once. With reduced motion nothing travels.

Durations

  • --duration-instant 100ms
  • --duration-fast 150ms
  • --duration-base 200ms
  • --duration-moderate 250ms
  • --duration-slow 300ms
  • --duration-slower 400ms
  • --duration-slowest 500ms

Curves

  • --ease-default ease
  • --ease-in ease-in
  • --ease-out ease-out
  • --ease-in-out ease-in-out
  • --ease-standard cubic-bezier(0.4, 0, 0.2, 1)
  • --ease-accelerate cubic-bezier(0.4, 0, 1, 1)
  • --ease-out-quad cubic-bezier(0.25, 0.46, 0.45, 0.94)
  • --ease-out-quint cubic-bezier(0.22, 1, 0.36, 1)
  • --ease-out-expo cubic-bezier(0.16, 1, 0.3, 1)
  • --ease-out-back cubic-bezier(0.175, 0.885, 0.32, 1.275)
  • --ease-sheet cubic-bezier(0.32, 0.72, 0, 1)
  • --ease-in-out-strong cubic-bezier(0.8, 0.01, 0.11, 0.98)

Shorthands

--transition-fast
var(--duration-fast) var(--ease-default)
--transition-base
var(--duration-base) var(--ease-default)
--lift-distance
-10px
07

Layers

Fixed chrome from back to front. On a phone the bottom fade sits under the dock and the top fade over it; on a wider screen the masthead takes their place. The menu clears them all. Skip link, theme-swap snapshot and cursor always win.

  1. 10000 --z-cursor
  2. 9999 --z-theme-transition
  3. 2000 --z-skip-link
  4. 1002 --z-menu-toggle
  5. 1001 --z-menu
  6. 1000 --z-fade-top
  7. 999 --z-masthead
  8. 999 --z-dock
  9. 900 --z-fade-bottom
08

Touch targets

24px is the floor everywhere and --tap-target-size on a coarse pointer. Hit areas grow; the drawn shape and the row spacing do not move.

Grid
  • Text buttons reach 24px with padding that does not move the line; on touch an unpainted ::after carries the hit area to 44px.
  • Social links use the same strip as ::before, and the 28px video control grows to 44px.
  • Small standalone links take 4px of padding and -4px of margin: bigger target, same layout.
09

Components

Live, rendered with the site’s own components and classes.

A text link with a faint hairline underline that firms up on hover and focus. The links to the current page and to its section have none, and only the section link reacts to hover.

Index

The works lenses as a line of type, each counted in Geist Mono at the cap line. Selected is the highlight color with an underline; the grid and list switch uses the same text buttons at the small size.

Quiet caps with ↗ for off-site links. The email address comes first, written out; clicking it copies it and says so.

Small type

Kickers, spec blocks and captions at --fs-xs in --text-tertiary, in letterspaced caps or Geist Mono.

Selected

Type
PP Neue Montreal, Instrument Serif, Geist Mono
Accent colours
Fluorescent pink and blue

Fig. 1 Astro (pages) + Contentful (content management)

Video

Muted loops load near the viewport. One control pauses every loop on the site and remembers it; with reduced motion the poster stays.

A native dialog pinned to the dark palette in both themes, floating on a dark veil. ⌘ K opens it from anywhere.

⌘ K

Cursor lens

A fine pointer gets a custom cursor. Over “view” and “read” it turns into a frosted lens, the one glass surface on the site.

Point here

Dock

The floating bar at the foot of every page on a phone: the four pages, plus the theme switch and the contact links where they fit. A wider window moves the pages and the switch into the masthead and leaves the contact links to the footer. --dock-clearance keeps content and keyboard focus above it.

--z-dock
999
--dock-clearance
6.75rem
10

Rules

Interaction

  • Keyboard first: Full support per WAI-ARIA. Visible focus rings are mandatory.
  • Touch targets: 24px minimum, 44px on touch.
  • Feedback: Status messages are announced politely. Loading states keep their label.

Typography & layout

  • Optical alignment: Adjust by ±1px when perception beats geometry.
  • Text glue: Use non-breaking spaces for terms like 10 MB and ⌘ K.
  • Line height: Headings 1.1; body calc(2ex + 6px), which tracks the x-height.

Accessibility

  • Contrast: Meet APCA contrast, and raise it on hover and focus.
  • Motion: Respect prefers-reduced-motion. Animate transform and opacity only.
  • Semantics: Use native elements (`button`, `a`, `dialog`) before ARIA.