Design system

The actual tokens and primitives this site renders with, imported from the same code the pages use, so this page cannot drift from reality. Quiet, typography-led, near-monochrome with one accent.

Principles

  1. Typography does the design: hierarchy from size, weight, and space, not boxes.
  2. One accent colour, spent sparingly on links and selection.
  3. Hairline borders separate; backgrounds stay out of the way.
  4. Every element earns its place. If it doesn't inform, it goes.
  5. Server-rendered and semantic first; scripts only enhance.

Colour

Tokens are OKLCH with a 140° green hue thread. Toggle the theme to see both modes:

Type

Newsreader (serif) for display, Geist for body and UI, Geist Mono for code and data. Body measure caps at 65ch via max-w-prose.

Page titlePage title
Section headingSection heading
Entry headingEntry heading
BodyBody text at a comfortable measure.
Small bodyCV bullets and dense content.
MetaSecondary information
Fine printTimestamps, utility links

Layout

One column. The page shell (header, stats bar, main, footer) is max-w-5xl so desktop space is used; the CV alone stays max-w-3xl for a document-like measure. Prose always caps at max-w-prose regardless of shell width. Dated entries use the two-column entry-grid pattern with an 8.5rem date gutter, stacking on mobile.

Spacing rhythm

Primitives

TextLink · accent / quiet / ink

Button · primary / secondary / ghost

SegmentedControl · version toggle (links, aria-current)

BlogToc · post table of contents (h2/h3, nested)

TextInput · Select · Checkbox

EntryGrid · dated entries (CV, education, lists)

Aug 2023 – Jul 2026

Entry heading

Organisation · context note

Body content sits in the right column; the left gutter carries the date in tabular figures.

MetaText · DateStamp

Secondary information

Divided list (repo table rows)

  • first itemTypeScript · Jul 2026
  • second itemTypeScript · Jul 2026

Prose (blog posts)

Long-form content uses prose-quiet: comfortable line height, accent links, and surface-tinted code blocks.

pnpm build

Selection

Select this sentence to see the accent selection colour.

Iconography

Brand icons use official simple-icons paths; the mail icon is custom to match the hairline style. All render at 16px (12px inline), take currentColor, and are aria-hidden with an accessible label on the surrounding link.

Focus

Keyboard focus gets a 2px accent ring with 2px offset via a global :focus-visiblerule; pointer clicks don't. The palette input is the exception: it fills its dialog edge-to-edge, so instead of a ring its bottom hairline turns accent on focus. Tab to the button to see the ring:

Motion

Motion is limited to colour and opacity transitions on hover — no movement, no entrances. Everything is disabled under prefers-reduced-motion.

Hover: muted → ink