Note

Portfolio design system

This site was designed in public, decision by decision, with each choice written down before implementation rather than after. This experiment is the record of that process.

Color palette exploration from the design surface session
Terracotta won over periwinkle and dusty rose — warmth without nostalgia.

What got decided and why

The short version: Instrument Sans for display type and UI because it's clean without being personality-free. Newsreader for body prose because the serif/sans contrast with headings reads well and the voice fits long-form notes — even if sans felt faster in a side-by-side test. Terracotta as the primary accent because the palette needed warmth and the alternatives were either too cold (periwinkle) or too on-the-nose (dusty rose, which got replaced).

Body copy runs at --text-body: 1.3125rem with --leading-relaxed: 1.8. Newsreader reads smaller than sans at the same CSS size, so those values are paired intentionally — don't shrink them without checking in context.

List rows (ContentList on the home page and in search) use --text-h3 titles and --text-sm summaries — same hierarchy as cards and tag results, not the smaller scale list items had at first.

The 90s web nod stayed in the color palette only.

Stack decisions

CSS Modules over Tailwind, MDX file-based over a headless CMS, Linode VPS over Vercel. All of these have notes.

Code blocks

Syntax highlighting via highlight.js — scoped themes in hljs-themes.css, rendered through the CodeBlock MDX component.

/* Shared via .prose in styles/utils.css — applied to MDX body wrappers */
.prose code {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  background: var(--color-surface-raised);
  padding: 0.15em 0.4em;
  border-radius: var(--radius-sm);
  color: var(--color-text-secondary);
}

/* Code blocks — rendered by CodeBlock component via MDX custom components */
.prose pre {
  margin: 0;
  padding: 0;
  background: none;
  border-left: none;
  border-radius: 0;
  overflow-x: auto;
}

/* Reset inline code styles inside code blocks — prevents
   the inline code background from applying inside pre blocks */
.prose pre code {
  background: none;
  padding: 0;
  border-radius: 0;
  font-size: inherit;
}