// page-work.jsx — Work index page const WorkCSS = ` .page .wk-grid{ padding:60px 56px 80px; display:grid; grid-template-columns:repeat(3,1fr); gap:32px 24px; } .page .wk-card{ display:block; text-decoration:none; color:inherit; } .page .wk-card .img{ aspect-ratio:4/3; border-radius:6px; overflow:hidden; background:var(--paper); transition:transform .35s; } .page .wk-card .img img{ width:100%; height:100%; object-fit:cover; display:block; } .page .wk-card:hover .img{ transform:translateY(-4px) rotate(-.5deg); box-shadow:0 30px 60px -25px rgba(0,0,0,.3); } .page .wk-card .meta{ display:flex; justify-content:space-between; align-items:baseline; margin-top:14px; } .page .wk-card h3{ font-family:'Instrument Serif',serif; font-style:italic; font-size:32px; line-height:1; margin:0; } .page .wk-card .yr{ font-family:'JetBrains Mono',monospace; font-size:12px; color:var(--ink-soft); } .page .wk-card .sub{ font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.06em; color:var(--ink-soft); margin-top:4px; } .page .wk-filters{ display:flex; gap:8px; padding:24px 56px; border-top:1px solid var(--rule); border-bottom:1px solid var(--rule); align-items:center; flex-wrap:wrap; } .page .wk-filters .label{ font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-soft); margin-right:12px; } .page .wk-filters .chip{ padding:7px 14px; border:1px solid var(--rule); border-radius:999px; font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.08em; text-transform:uppercase; cursor:pointer; } .page .wk-filters .chip.on{ background:var(--ink); color:var(--bg); border-color:var(--ink); } .page .wk-stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:24px; padding:80px 56px; border-top:1px solid var(--rule); text-align:center; } .page .wk-stats .stat{ display:flex; flex-direction:column; align-items:center; gap:0; } .page .wk-stats .stat .n{ font-family:'Instrument Serif',serif; font-style:italic; font-size:96px; line-height:1; color:var(--terra); } .page .wk-stats .stat .l{ font-family:'JetBrains Mono',monospace; font-size:12px; letter-spacing:.12em; color:var(--ink-soft); text-transform:uppercase; margin-top:8px; } `; function WorkPage(){ const [filter, setFilter] = React.useState('All'); const filters = ['All','Squarespace','Shopify','WordPress','Webflow']; const filtered = filter==='All' ? PROJECTS : PROJECTS.filter(p=>p.platform===filter); return (
Selected work · 2015 — 2026

A small collection
of nice websites.

{PROJECTS.length} recent projects, organised mostly by year. Click any to read the case study.

each one shipped
on time
portfolio ↓
Filter by {filters.map(f => ( setFilter(f)}>{f} ))} Showing {filtered.length} of {PROJECTS.length}
{filtered.map(p => (
{p.name

{p.name}

{p.year}
{p.kind} · {p.platform}
))}
the proof
is in here ↓
140+
sites shipped
11
years independent
3
platforms, fluently
0
retainers I regret
let's chat ✨

Have a project in mind?

Tell me about it. I respond within a day, usually faster.

Get in touch ↗
); } ReactDOM.createRoot(document.getElementById('root')).render();