Skip to content

Sheet01 / 09 · Opening

TypeBricolage Grotesque 800 · clamped 2.5 to 7.4rem

Groundoklch(31% 0.08 40) · not black, never white

Contrast11.03:1 body · AAA

Craig Hawkes · Hamilton, Scotland · free and looking

I make shit look good, then I build it.

Because I spent far too long not trusting anybody else to do a decent job of either half. Fifteen years, six of them in print, on purpose.

Thirty attempts at this line. Thirty. Most were humble-bragging, the rest were trying too hard. This one's just true.

System Mode is this same site with the working out left in. Every claim gains the gate behind it, and the grid it was set on turns up underneath.

Sheet02 / 09 · The problem

Claim typeArgument · nothing here is testable

Measure62ch · two columns above 52rem

Groundoklch(93% 0.025 85) · bone, not white

The thing I keep being hired to fix

We went from 200kbps to 2000mbps, everything got fancier, usability got cluttered and overcomplicated.

Three decades on from documents anybody could open, it takes two megabytes of JavaScript to show you a paragraph that was already text. The scroll gets hijacked so a logo can rotate on the way past. Zoom gets switched off because it breaks the layout. There's a functioning industry selling a widget that makes an inaccessible site compliant without making it one bit easier to read.

Machines got faster every single year of that, and the whole gain went on decoration. Almost none of it is malicious, because checking who got locked out is boring and the cool shit is what gets shared. But the outcome stops caring what you meant. Somebody can't read the page, the reason is a contrast ratio that looked nicer, and your information is now behind a door with you holding the key.

Theme parks are made for people, but not disabled people. That is slowly changing. The web is going the other way, and it has better tools and more bandwidth than it has ever had.

Nobody sets out to lock people out. It just never gets checked, and unchecked always drifts one way.

Sheet03 / 09 · The whole job

Accentoklch(72% 0.17 55) · 7.02:1 against the ink

SourceBritish Dyslexia Association style guidance

NoteFull-bleed accent · used once, on purpose

The whole job

The web needs to be for everyone.

That's it. That's the job.

The British Dyslexia Association asks for dark text on a light background rather than black on pure white, because white dazzles. WCAG pushes the contrast up, the dyslexia guidance pushes it back down, the maximum turns out not to be the target, and somebody has to sit and work out which reader they are serving. That is a person's job, not a linter's. The ground on this page is not white.

Sheet04 / 09 · The method

Gatenpm run verify · fails the build, not a report

Checked byCI, on every commit, not by me

Found9 real defects in my own AAA claim

How I'd change what you ship

A statement is not a standard.

A standard you can only assert is a standard you haven't met yet, and you won't know which until something checks.

Nearly every company shipping an inaccessible site has an accessibility statement somewhere on it. Almost none have a test that could fail. A statement costs an afternoon. A gate costs you the argument, in public, the day it goes red, which is exactly why it works and exactly why nobody wants to write it.

Writing the gate is the work. I put one in front of my own AAA claim and it took the claim straight off me: nine real defects nothing else had caught, including an unnamed dialog sitting behind every sheet in the system. That is the version of this you actually want on your team.

Shipped as gates, not intentions: 360 contrast pairings on every run · 1,564 tests across 174 routes · 0 axe violations in both themes · AA everywhere, AAA on thirteen criteria, three exceptions published rather than quietly dropped · a colour-literal ratchet that only moves down · a check on the delivered CSS rather than the source, because the build was quietly flattening OKLCH to hex and nothing said a word.

This is the bit that makes people go quiet in interviews. Not the number, the fact that it can fail.

Sheet05 / 09 · The commercial case

Measured+80% mobile payments · 70% Apple Pay

SourceClient analytics · their numbers, not mine

ConstraintFCA-regulated · PCI-DSS · live throughout

Why this pays for itself

The accessibility fix and the money fix keep turning out to be the same fix.

A person in arrears, on a phone, being asked to type a sixteen digit card number into a debt collection form has several good reasons to give up. Removing those reasons is an accessibility job and a conversion job at the same time. Mobile payments went up 80%, and 70% of them came through Apple Pay.

That flow had four screens because those two jobs belonged to two different people. Almost every expensive problem I get called into lives in that gap. Design says it's an engineering problem, engineering says it's a design one, and it sits there for a year with nobody's name against it. I can hold both halves, which is the only reason I can see it at all.

SagePay to Fiserv, finished solo after roughly half a dozen developers had left it short of testing: tokenisation, digital wallets, HMAC-SHA256, 3D Secure, store ID routing, 2,046 lines of C# I hadn't written since 2016, against a PCI-DSS estate of 97+ stored procedures that never stopped taking live money. Zero failed cutovers.

Nobody's posting a Fiserv gateway on Dribbble with a nice gradient behind it. It still moved more money than anything I've made.

Sheet06 / 09 · The work

OrderBy what it proves, not by date

Span2016 to now · 6 posts, 3 current

StackNext.js · React Aria · OKLCH · Playwright · C#

Fifteen years, in the order that matters

The work, by what it proves rather than by when it happened.

A design system, then payment infrastructure, then the side research. They're not the same size and aren't billed as though they are.

inclusive.io

Co-founder. An accessibility-gated design system and a navigable ATS product, built on my own across two full rebuilds. The best thing I've made, and the only reason I can say so is that something other than me checks it.

  • 117Components
  • 26ATS Workflows
  • 174Routes Audited
  • 0Axe Violations

117 components · 26 ATS workflows · 174 routes audited · 1,564 tests · 360 contrast pairings per run · 0 axe violations, both themes · three-tier W3C DTCG tokens in OKLCH holding 280px to 5K · React Aria · Feb 2024 to now

BPO Collections

Hired to make an FCA-regulated collections site accessible, then asked to take on the payment migration instead. Least fashionable work I've done and easily the most useful: when it breaks it isn't an ugly page, it's somebody already in arrears who can't get the payment through.

  • 80%More mobile payments
  • 70%Of those on Apple Pay
  • 2,046Lines of C# written
  • 0Failed cutovers

Full stack, Sept 2025 to Apr 2026 · four screens to one · 80% more mobile payments, 70% Apple Pay · Fiserv end to end · legacy ASP.NET onto a typed Next.js stack · 0 failed cutovers

Head of Web

Owning a revenue number is different from contributing to one. It means the funnel breaking is your problem at nine on a Sunday, and every argument about page speed, form length and one more tracking script lands on your desk. Most technical decisions turn out to be staffing decisions in a costume.

  • 3Hired
  • 7Co-managed
  • 60%Open rates up
  • 27%Cold replies up

Paul McFadden Wealth, Dec 2022 to Jan 2024 · personally accountable for £10m+ of web revenue · hired three, co-managed seven · open rates up 60%, cold-outreach replies up 27%

Quoin, and six years in print

Print's had baseline grids since metal type; the web has never had one. Nobody asked me for it and I built it anyway, which tells you most of what you need to know. The six years before it are why the build half is any good. One shot, it goes on a press, and a wrong bleed arrives as a room full of boxes.

  • 112Of 134, seated
  • 0Sizes a fit has to change
  • 76msTo fit, with no browser
  • 4th of 9Coherence vs design systems

Quoin v1.26.0 · fits the design before the CSS exists · 112 of 134 seated on this page, 0 sizes changed, 76ms with no browser, 26 kB, no dependencies, MIT · NOVAVAPES 2016 to 2022, graphic designer to brand lead · DesignBuddy UK, 50+ clients since 2017

Every other number here is checked by something. This bit isn't. It's the only part of the site that's an opinion rather than a measurement, so it gets to have an edge. Wrote it angry. Took the swearing out on the read-back and then put all of it straight back in.

Sheet07 / 09 · How I got here

OrderDeveloper first, design in the middle

SkillsListed only if shipped, no bars

Sourcesrc/data/about.ts · src/data/skills.ts

How I got here

You can't see a foundation. You only ever see what happens when there wasn't one.

I started building for the web at fourteen and had the degree by nineteen. Then I couldn't get a job doing it. A few years of freelance and whatever else paid, by the end of which I'd had enough of the industry entirely, so I retrained as a graphic designer and did that properly for six years instead. I came back to code in 2020 and spent the guts of a year rebuilding everything I'd let go rusty. So this isn't a designer who learned to build, it's the other way round, and the six years in the middle are the whole point.

Frontend Core
React · Next.js · TypeScript · Tailwind CSS · HTML/CSS · JavaScript
Frameworks & Libraries
Angular · React Aria / React Stately · Radix UI · HeroUI · ShadCN · React Hook Form + Zod · Framer Motion · GSAP
Design Systems
Design Tokens (W3C DTCG) · OKLCH Colour · Atomic Design · Component APIs · Storybook · Figma plugin development
Version Control & CI/CD
Git · GitHub / GitHub Actions · CI/CD pipelines · Trunk-based workflow · Semantic commits (commitlint, husky) · Automated release gates
Deployment & Platform
Vercel · Preview and production environments · Cutover and rollback runbooks · Zero-downtime migration · Environment and secret management · IIS / Windows Server (legacy estates)
Shipping & Release
npm package publishing · Turborepo monorepos · Changesets versioning · publint / are-the-types-wrong · knip, syncpack
Backend & Infrastructure
Node.js · ASP.NET (VB.NET & C#) · SQL Server / T-SQL · REST APIs · Payment gateways (Fiserv) · PCI-DSS estates
Testing & Accessibility
WCAG 2.2 (AA gated, AAA where it holds) · axe-core / jest-axe · Playwright · Vitest / Jest · Testing Library · Lighthouse CI · Pa11y · Chromatic
Research & Documentation
Technical documentation · Design system specification · Competitive and standards research · Accessibility auditing · Handover and onboarding packs · Architecture decision records
Design & Creative
UI/UX Design · Adobe Creative Suite · Brand Identity · Prototyping · Art Direction · Typography
AI & Agent Systems
LLM providers (OpenAI, Anthropic, Google) · Prompt & context design · MCP servers · Cursor agent workflows · Tool calling & evaluation · llms.txt / AEO
AI & Agent Systems The speed is real and so is the rubbish, and the difference between them is entirely whether somebody read the thing before it went out. I run agent sessions the way I run builds. Tight brief, obvious done-state, nothing ships that I haven't read end to end. The skills and MCP servers and rules sitting in this repo are there because without them the work wanders off and comes back sounding like everybody else. Which is the one thing I'm not interested in being.

Best thing about years in print? You learn quickly that design isn't pixels. It's whether somebody actually lifts the thing off a shelf in a shop. No hover state is saving you there. Everything I build still starts with that question.

Sheet08 / 09 · Open non-conformances

Count53 · ratchet, down only

StatusOpen, published, not deleted

Also2 level A failures, live for months

The bit most people delete before you arrive

53 things on this site are still wrong.

53 colour literals bypass my own theme. I could have quietly fixed them before you got here. It's on the page because a portfolio that only shows the bits that worked is a showreel, and because if you're hiring at this level the useful question isn't whether somebody has open defects, it's whether they can tell you the number without being asked twice.

I also claimed AAA for eight months while the test that checks it had never once loaded. Eight typefaces gave me the same number and I read it as consistency; every measurement was against a font that had never loaded. A control that can't fail will agree with you three times in a row and sound authoritative doing it.

Ratchet: down only, one commit at a time, in public. A full audit of this build found fourteen more, nine fixed the same day, and two were level A failures that had been live for months because the suite only ever ran at one screen width. All of it is written up rather than deleted.

Every honest number on here started out as a worse one I'd talked myself out of publishing.

Sheet09 / 09 · Enquiries

ReplyInside the hour, by a person

Open toContract or permanent · lead or principal

Not on this sitePreloaders · hamburger menus · carousels

Enquiries

Tell me what's breaking.

If you already know which detail it is, say so in the first line and we'll skip the discovery call. I read every email that comes in. If it's a template I'll know, because you all use the same three openers.

No preloaders, no hamburger menus. Neither's on here and neither ever will be. That's not restraint, that's just not doing the stupid thing.