This site is plain HTML, CSS and a little JavaScript, built with Claude Code and held to its rules by checks that fail a change, not by notes I hope to remember.
Type
Cormorant Garamond
Jost
Headings are set in Cormorant Garamond and body text in Jost. Both are hosted on this domain, so no font request goes anywhere else, and every size is set in rem, so the whole page follows the text size a reader has chosen in their browser.
Colour and contrast
A sage ground, near-black ink at three strengths, and one terracotta accent. The neutrals share a green-grey hue and the accent sits far from it, so the accent reads as a colour rather than as a browner shade of the text.
The table reads every colour from the stylesheet as this page loads and measures it against the ground, so it cannot drift from the site it describes.
| Swatch | Token | Value | Against the ground |
|---|
Motion
Movement is meant to go unnoticed. Everything moves for between 150 and 900 milliseconds, easing out, and things scrolling into view start from 85% opacity rather than from nothing, so an unseen section never looks like it failed to load. Each plays once. With reduced motion set, everything appears at rest.
There are two written exceptions. The lead clip on the homepage plays again when it comes back into view, and a chart comparing two lengths of time grows its bars at a fixed rate, so the animation's own length carries the comparison.
Accessibility
Every page has a skip link, visible focus styles, meaningful alt text on every image and headings in order. Text colours meet WCAG AA against the ground, which the table above measures rather than asserts.
Stack
No framework, no bundler and no runtime dependency: one stylesheet and a few small scripts. Publishing is a copy step that ships only the files named on an allow-list, so a working file in the repository never goes live by accident. Netlify hosts the site, and GoatCounter counts page views without cookies, which is why there is no consent banner.
Checks
Rules that matter run as checks on every pull request. A change fails if it adds an em dash, writes a colour outside the stylesheet's tokens, makes any page wider than a phone's screen at five widths from 320 to 414px, or leaves the CV out of step with its source. Before a design change merges, a visual comparison renders every page from the last version and this one and lists each element that moved.
The overflow check exists because a 29px overflow once shipped on every page at 390px and stayed live until someone measured it by hand.
Made with Claude Code
I build this site with Claude Code. I set the direction and make the calls; Claude Code writes the code, runs the checks and renders before-and-after comparisons for me to judge. The rules it works to live in the repository's own instructions, and when something goes wrong we write it up and, where we can, turn the lesson into a check rather than a reminder.