Design System

The system behind this portfolio. Every color, type style, and spacing value is defined once and used everywhere. Toggle the theme to see both modes.

Color Tokens

Eight tokens cover both themes. The palette comes from the about page: cream, burgundy, and rose.

Background

--bg

Light: #fffbf5

Dark: #1c1a16

Background Subtle

--bg-subtle

Light: #f0ebe1

Dark: #26231d

Surface

--surface

Light: #f5eee0

Dark: #302c24

Foreground

--fg

Light: #1c1a16

Dark: #fffbf5

Secondary

--fg-secondary

Light: #6b6459

Dark: #c2bab0

Accent

--accent

Light: #813746

Dark: #e36f86

On Accent

--on-accent

Light: #fffbf5

Dark: #1c1a16

Border

--border

Light: rgba(92,82,80,0.1)

Dark: rgba(176,168,158,0.1)

Uses alpha transparency so one token works on all three background layers.

Three-layer structure

Every page uses three background layers. Shadows mark the transitions between them. Cards sit on the middle layer.

--bg (nav, hero, footer)

--bg-subtle (content sections)

--surface (cards)

Accessibility

Every text and background combination passes WCAG 2.1 AA. All primary text hits AAA. Toggle the theme to see both modes live.

Aa

--fg on --bg

16.85:1 · AAA

16.85:1 · AAA

Aa

--fg on --bg-subtle

14.78:1 · AAA

15.19:1 · AAA

Aa

--fg on --surface

15.05:1 · AAA

13.48:1 · AAA

Aa

--fg-secondary on --bg

5.67:1 · AA

9.05:1 · AAA

Aa

--fg-secondary on --bg-subtle

4.97:1 · AA

8.16:1 · AAA

Aa

--fg-secondary on --surface

5.06:1 · AA

7.24:1 · AAA

Aa

--accent on --bg

7.93:1 · AAA

5.70:1 · AA

Aa

--accent on --bg-subtle

6.94:1 · AA

5.14:1 · AA

Aa

--accent on --surface

7.08:1 · AAA

4.55:1 · AA

Implementation

Skip link

"Skip to main content" hidden until keyboard focus. Lets screen reader and keyboard users bypass the nav.

Focus-visible

Accent-colored ring on keyboard focus only. No ring on mouse click. Consistent across all interactive elements.

Reduced motion

All animations and transitions disabled via prefers-reduced-motion: reduce. No partial reductions.

VoiceOver-safe animations

data-animate-y uses translateY only (no opacity) so headings are always discoverable by screen readers.

ARIA labels

Dynamic labels on theme toggle, hamburger menu, and email copy button. States update on interaction.

Semantic landmarks

nav, main, footer with aria-label on navigation regions. Sitemap uses labeled nav.

Focus trap

Mobile nav overlay traps keyboard focus within links and the hamburger button. Escape closes the overlay.

Color never alone

Status and emphasis always pair color with text or shape. No information conveyed through color alone (WCAG 1.4.1).

Typography

Three fonts that reference different moments in type history. Ogg for editorial warmth, rooted in calligraphy. Cabinet Grotesk for headings, with distinctive terminals that give it personality. Areal for body text, chosen for its readability and the extra space built into each letterform. Headlines scale fluidly with the viewport. Body text steps once at 768px.

Display 2XL

Cabinet Grotesk / clamp(48-96px)

The quick brown fox

Display XL

Cabinet Grotesk / clamp(40-80px)

The quick brown fox

Display LG

Cabinet Grotesk / clamp(32-60px)

The quick brown fox

Display MD

Cabinet Grotesk / clamp(24-36px)

The quick brown fox

Display SM

Cabinet Grotesk / clamp(20-24px)

The quick brown fox

Body

Areal / 16px / 20px

The quick brown fox

Label

Areal / 16px / 20px

UPPERCASE LABEL TEXT

Link

Areal / 16px / 20px

Badge

Areal / 16px / 20px

The quick brown fox

Meta

Areal / 14px

Small metadata text

Font families

Aa

Cabinet Grotesk

Display headings

Aa

Areal

Body, UI, labels

Aa

Ogg

Editorial accent

Code

The code element inherits its parent's font size and uses --fg-secondary text on a --surface background with a subtle border.

Example: use globals.css for token definitions and tailwind.config.js for utility mapping.

Spacing

4px base grid. Everything uses the standard Tailwind numeric scale.

4px t-1
8px t-2
12px t-3
16px t-4
24px t-6
32px t-8
48px t-12
64px t-16
96px t-24

Components

A small set of building blocks used across every page. No JavaScript shipped for any of them.

Button

Badge

Figma React Tailwind User Research Design Systems

Card

Card

Surface background with border for elevation. Shadows are reserved for section boundaries.

Media card

Tinted container for images and video.

Q&A Transcript Cards

Research conversation pairs. Question (me) on the right, tinted surface. Response (source) on the left with accent-colored left border and italic text. Used in case studies to show research artifacts in a human voice.

Me

Is this process standard across counties, or unique to you?

Greene County Tax Claim Bureau

“I have no idea if people do them different. That's the way we do them.”

Animations

All CSS. No animation libraries. Everything respects prefers-reduced-motion.

Scroll reveal

data-animate (fade + translateY) and data-animate-y (translateY only, VoiceOver safe for headings).

Theme transition

All color properties transition over 300ms. Toggle the theme to see it.