Design system · v1

The system behind this site.

Everything below renders from the same tokens and components as the rest of the site. Colour values and contrast ratios are read from the live CSS, so this page can't drift out of date.

01Colour

Ink, paper & electric cobalt

Seven semantic tokens, stored as RGB channels so Tailwind can apply opacity (bg-fg/10). Components only reference roles, never raw colours.

Dark mode swaps cobalt for a lighter periwinkle to keep contrast, and accent-inverse covers the inverted panels where the accent sits on ink. Click any swatch to copy its hex.

light

.light

Contrast · WCAG 2.2

  • fg / bgBody copy—
  • muted / bgDescriptions, labels—
  • accent / bgItalic accent headings—
  • accent-fg / accentPrimary button, hover rows—
  • bg / fgMarquee, CTA panel—
  • accent-inverse / fgAccent inside CTA panel—

dark

.dark

Contrast · WCAG 2.2

  • fg / bgBody copy—
  • muted / bgDescriptions, labels—
  • accent / bgItalic accent headings—
  • accent-fg / accentPrimary button, hover rows—
  • bg / fgMarquee, CTA panel—
  • accent-inverse / fgAccent inside CTA panel—
02Typography
Aa

Bricolage Grotesque

Display & body

font-display / font-sans

Aa

Instrument Serif

Italic accents

font-serif

Aa

JetBrains Mono

Labels, data, code

font-mono

  • text-mega

    clamp(52px → 160px) · 0.88 · -0.045em

    Mega

  • text-huge

    clamp(40px → 88px) · 0.95 · -0.035em

    Huge headline

  • text-5xl

    48px · statements

    Statement copy

  • text-3xl

    30px · role titles

    Senior Developer

  • text-xl

    20px · lead

    Lead paragraph for introductions.

  • text-base

    16px · body

    Body copy for descriptions and supporting detail.

  • .eyebrow

    12px mono · 0.18em · uppercase

    01 — Section label

Pairing in use

Grotesque for weight, serif for voice.

Headlines lead in a heavy grotesque; one or two words switch to an italic serif in the accent colour to add emphasis and personality.

03Spacing & shape

Radius

  • rounded-md

    6px

    Skill chips

  • rounded-xl

    12px

    Inputs

  • rounded-2xl

    16px

    Skill cards

  • rounded-[1.5rem]

    24px

    Form panel

  • rounded-[2rem]

    32px

    CTA panel

  • rounded-full

    9999px

    Buttons, tags, nav

Layout & rhythm

  • px-5 → px-1220 → 48pxPage gutter (mobile → desktop)
  • py-24 → py-3296 → 128pxSection rhythm
  • max-w-7xl1280pxContent width
  • gap-416pxCard grids
04Components

Button

<Button variant=… />
primary
solid
outline
ghost
focus-visible
disabled
disabled · outline

Hover the primary button for the lift and accent glow. Press Tab to see real focus rings.

Text input

<TextInput />

Textarea

<Textarea />

Tags & chips

reactnext.jsseoproject tag
TypeScripta11yJestskill chip
Availablestatus badge

Section eyebrow

<Section index label />
01Selected work

Every section opens with a numbered mono label and a hairline rule, giving the page an editorial index.

05Motion

Quick, confident, never in the way.

Motion is reserved for feedback and a little personality. Everything ambient (the marquee and the pulsing status dot) stops under prefers-reduced-motion.

  • Hover fillscale-y 0 → 1 · 500ms · cubic-bezier(0.22, 1, 0.36, 1)Project rows
  • LifttranslateY(-2px) + accent glow · 200msPrimary button
  • MarqueetranslateX(0 → -50%) · 40s linear ∞ · pauses on hoverTech stack strip; static wrapped list under reduced motion
  • Arrow turnrotate(45deg) · 300msProject link icons
  • Theme swapcolors · 300msBody, all tokens

Try it · hover on desktop, press on touch

00Hover fill

Marquee · hover to pause

  • Tokens
  • Type
  • Shape
  • Components
  • Motion
  • Contrast
  • Dark mode
  • Accessibility