davidsuker.com · design system

The system

The living style guide — every design token and every component, in every state. It's built from the tokens it documents (every value in rem, never px; no hard-coded colors or sizes), so the page is itself the proof.

Tab through this page. Every focusable element has a designed :focus-visible ring; hover and press controls to see their states; all motion honors prefers-reduced-motion.

Palette

Warm-neutral base, one terracotta accent. Every text and UI pairing meets WCAG 2.2 AA (text 4.5:1, UI 3:1); ratios noted under each chip.

Warm neutrals

  • --color-bg#faf8f5Page backgroundground
  • --color-surface#ffffffCards / panels17.1:1 text
  • --color-surface-subtle#f3efeaRecessed / rows15.0:1 text
  • --color-text#1f1b17Primary text16.1:1 on bg
  • --color-text-muted#5c544bSecondary text7.0:1 on bg
  • --color-border#e4ded6Decorative dividersnon-text
  • --color-border-strong#8c8073UI boundary3.6:1 on bg

Terracotta accent

  • --color-accent#a8481fLinks / accent / fills5.5:1 on bg
  • --color-accent-hover#8a3a18Hover / active7.3:1 on bg
  • --color-on-accent#ffffffText on accent fill5.8:1 on accent

Typography

Two self-hosted families (latin woff2): Source Serif 4 for reading/body copy (--font-serif), Inter for headings, UI and data labels (--font-sans). Code uses the system monospace stack.

Serif · body · --font-serif

Design & build, from the type scale to the cloud deploy.

Regular 400 · Italic 400 · Semibold 600 · Bold 700

Sans · UI · --font-sans

Design & build, from the type scale to the cloud deploy.

400500600700

Type scale (body face)

  • Design & build, from the type scale to the cloud deploy --font-size-3xl · 2.887rem · 46px
  • Design & build, from the type scale to the cloud deploy --font-size-2xl · 2.281rem · 36px
  • Design & build, from the type scale to the cloud deploy --font-size-xl · 1.802rem · 29px
  • Design & build, from the type scale to the cloud deploy --font-size-lg · 1.424rem · 23px
  • Design & build, from the type scale to the cloud deploy --font-size-md · 1.125rem · 18px
  • Design & build, from the type scale to the cloud deploy --font-size-base · 1rem · 16px
  • Design & build, from the type scale to the cloud deploy --font-size-sm · 0.889rem · 14px
  • Design & build, from the type scale to the cloud deploy --font-size-xs · 0.79rem · 13px

Prose

How rendered markdown reads — serif body, sans headings, generous line-height, a constrained measure. Content pages (reading notes, project write-ups) inherit this .prose layer.

A working proof, not a mockup

The site is built as a design system: tokens are the single source of truth, and every component consumes them rather than hard-coding a color or a size. Body copy is set in Source Serif 4, a transitional serif chosen for comfortable long-form reading.

Whitespace is the aesthetic. Favor generous margins and breathing room over decoration.

Headings switch to Inter for a crisp, systematic feel, while inline tokens such as --color-accent render in monospace so code reads as code. Lists stay comfortable:

  • Measure caps near 66 characters for readability.
  • Line-height opens up to 1.7 for running text.
  • Links carry the terracotta accent with an offset underline.
.button {
  color: var(--color-on-accent);
  background: var(--color-accent);
}

Spacing

4px-base scale expressed in rem. Layouts use tokens only — no arbitrary values.

  • --space-3xs · 0.25rem · 4px
  • --space-2xs · 0.5rem · 8px
  • --space-xs · 0.75rem · 12px
  • --space-sm · 1rem · 16px
  • --space-md · 1.5rem · 24px
  • --space-lg · 2rem · 32px
  • --space-xl · 3rem · 48px
  • --space-2xl · 4rem · 64px
  • --space-3xl · 6rem · 96px

Radius

sm · 0.25rem
md · 0.5rem
lg · 0.75rem

Elevation

sm
md
lg

Motion

Surgical only, and gated behind prefers-reduced-motion. Hover or focus the button — with reduced motion requested, the change is instant.

fast 120ms · base 200ms · slow 320ms · easing cubic-bezier(0.2, 0, 0, 1)

Components

Each interactive component in its states. Hover, tab to focus, and press to see the live hover / :focus-visible / active states — this page is the interaction-craft proof.

Button — primary

Button — secondary

Default, hover, :focus-visible and active are live — tab to a control, hover it, press it. Disabled and loading are the fixed instances above; disabled is conveyed by disabled/aria-disabled, not color alone.

Links

Inline links inherit the accent with an offset underline — a link in running text — each with a live hover and :focus-visible state. Standalone examples (tab to them):

AppButton — props
PropTypeDefaultNotes
variant'primary' | 'secondary''primary'Visual weight.
tostringInternal route → renders NuxtLink.
hrefstringExternal / mailto → renders an anchor.
type'button' | 'submit''button'Only when rendering a <button>.
disabledbooleanfalseSets disabled / aria-disabled.
loadingbooleanfalseShows spinner, sets aria-busy, blocks activation.

Slot: default = label. Renders <button> by default, or <NuxtLink>/<a> when to/href is set.

© 2026 David Suker