Design system
This is the living design vocabulary for clmartin.dev. Every component on the site is rendered here from the same CSS it uses in production, so if something's broken, it shows up here first. I built this page as much for myself as for you. It's how I keep the rest of the site honest.
Colour tokens
5 colours, deliberately fewOne accent, one text, one muted text, one border, one background. Anything more and I start making excuses.
Typography
Trebuchet MS stackBody is Trebuchet MS with a system fallback stack. Code is JetBrains Mono (loaded locally where it appears). Line-height 1.5, base 1em. Nothing exotic. The goal is legibility, not flair.
Shadows stretched long across the road.
Shadows stretched long across the road.
Shadows stretched long across the road.
Shadows stretched long across the road.
Shadows stretched long across the road, chasing the last light of day as the hills folded into dusk.
print("Hello youuuu!")
Links
.underline-linkSolid 1.5px pumpkin underline, 4px offset. Hover thickens to 2.5px and the text lightens. Used on every inline link in prose. I tried a wavy underline early on. It looked cute for ten seconds and then started feeling like a spell-check squiggle.
Here's an inline sentence with an underline-link example so you can hover it and see the thickness transition.
Section heading
.section-headingEvery section on the site opens with a flex row: the heading on the left, optional meta on the right, a grey 1px underline, and a short pumpkin accent bar anchored to the h2. It's the one piece of ornament I allow myself.
Cards
.card / .card-liftOne base: 1px grey border, 0.5rem radius, pumpkin border on hover. Optional .card-lift adds a 2px translateY on hover, gated behind prefers-reduced-motion. Everything else (padding, gap, internal layout) is
per-page.
Hover me. The border lights up.
Hover me. Same border, plus a subtle lift.
Tags
.tagSmall bordered pills. Used for stack labels on project cards and anywhere a short one-word metadata chip is useful.
Call-to-action buttons
.cta-primary / .cta-secondaryTwo flavours: a filled pumpkin primary and an outlined secondary. The primary inverts on hover (fill drops, text becomes pumpkin) rather than darkening. Keeps things calm.
Lists
global default: unstyledDefault ul/ol have no bullets. Most lists on the site are
semantic groupings that don't need them. Blog posts opt back into bullets via the .blog-post scope.
- No bullets
- No padding
- Semantic grouping only
- Bullets back on
- Indented for prose
- Feels like an article
Why these choices
- One accent colour. Dark pumpkin (#ab4e11) is the only non-neutral on the site. Every hover, underline, and CTA pulls from it. If I ever find myself reaching for a second accent, that's a sign I'm trying to paper over a structural problem.
- Dark by default, no toggle. I work in the dark. The site matches. A theme toggle is a lot of maintenance for a 2-minute visitor, and the one-colour palette doesn't translate cleanly to light mode anyway.
- Solid underlines, not wavy. Wavy underlines read as errors (spell-check, linter warnings) and get noisy over long paragraphs. Solid + offset is calmer.
- Cards over shadows. Every card is just a border with a hover colour change. No box-shadows, no gradients. Borders scale cleanly on any background and don't introduce a light source the rest of the page has to honour.
- Reduced motion honoured. The card hover lift and external-link glyph
nudge are both gated behind
prefers-reduced-motion: no-preference. Motion should be a bonus, not a requirement. - One font family. Trebuchet MS for everything except monospace code blocks. No custom font loading, no FOUT, no layout shift.