back home
design system v2.0.0

design.

Clean card-based minimal. Light-first, near-white surfaces, one blue primary, five accent hues that each own a section.

Every sample here is rendered from src/design/tokens.json. No hardcoded values, so it cannot go stale.

01

color

surface

backgrounds and edges. what things sit on.

#fafafa#0a0a0a

page background base

#f0f4ff#0d0d14

page gradient midpoint

#e8ecf8#0a0f1a

page gradient end

#ffffff#141414

raised card surface

#f1f5f9#1c1c1f

inset wells, code blocks

#e2e8f0#27272a

hairlines, card borders

content

text. three weights of emphasis, all AA on every surface.

#1a1a1a#fafafa

primary text

#5b6674#a1a1aa

secondary text, captions

#626b78#8b8b93

tertiary text, metadata

brand

the one blue. links, CTAs, focus rings.

#2563eb#60a5fa

links, CTAs, focus ring

#1d4ed8#93c5fd

accent text on light surfaces (AA-safe)

#ffffff#0a0a0a

label sitting on an accent fill

section

one hue per bento section. fills and dots, never body text.

#f59e0b#fbbf24

sights section accent. Fills and dots only.

#38bdf8#7dd3fc

sounds section accent. Fills and dots only.

#34d399#6ee7b7

curiosity section accent, live status. Fills and dots only.

#c084fc#d8b4fe

creativity section accent. Fills and dots only.

#ef4444#f87171

destructive fill

#935f07#fbbf24

sights TEXT on its own tint (AA-safe)

#227195#7dd3fc

sounds TEXT on its own tint (AA-safe)

#1e7857#6ee7b7

curiosity TEXT on its own tint (AA-safe)

#7f57a6#d8b4fe

creativity TEXT on its own tint (AA-safe)

#c81e1e#fca5a5

destructive TEXT (AA-safe on card)

accent ramp

fixed tints of the primary. components use sunrise-600 for hover fills.

50
100
200
300
400
500
600
700
800
900
02

type

families

--font-display

Adam Pang . 2026

Space Grotesk 700. Headings.

--font-body

Adam Pang . 2026

Lato 300/400/700. Prose.

--font-mono

Adam Pang . 2026

JetBrains Mono. Numerals, labels.

scale

--text-caption
0.75rem / 1.4

12px. Metadata, footnotes.

--text-label
0.8125rem / 1.4

13px. Eyebrows, nav.

--text-body
1rem / 1.65

16px. Default prose.

--text-lead
1.125rem / 1.6

18px. Intro paragraphs.

--text-h3
1.5rem / 1.2

24px. Card titles.

--text-h2
1.875rem / 1.15

30px. Section titles.

--text-h1
2.25rem / 0.95

36px. Page title. 3rem at sm+.

tracking

--tracking-tightest-0.02emdisplay headings
--tracking-tighter-0.01emsubheads
--tracking-label0.12emuppercase eyebrows
--tracking-wide0.22emuppercase kickers
03

space

a 4px base step. mobile gutters and card padding use --space-5, opening to --space-6 at sm+.

--space-1
0.25rem
4px. Icon gap.
--space-2
0.5rem
8px. Inline gap.
--space-3
0.75rem
12px. Tight stack.
--space-4
1rem
16px. Default stack.
--space-5
1.25rem
20px. Card padding, mobile gutter.
--space-6
1.5rem
24px. Card padding at sm+.
--space-8
2rem
32px. Between subsections.
--space-10
2.5rem
40px. Between sections.
--space-14
3.5rem
56px. Page top/bottom at sm+.
04

radius + shadow

radius

--radius-sm
8px
badges, small chips
--radius-md
12px
inputs, small cards
--radius-lg
16px
cards. The default container.
--radius-full
9999px
buttons, pills, avatars

shadow

--shadow-card
resting card
--shadow-card-md
hover lift
--shadow-card-lg
modal, popover
05

components

hover and press the real controls, and tab through them to see :focus-visible, a 2px accent outline at 3px offset set globally. States marked simulated are frozen copies so the styling is visible without a pointer.

button

rounded-full, accent fill. the primary CTA.

default
hover
simulated
active
simulated
focus-visible
simulated
disabled

button . secondary

card surface, hairline border. the alternative action.

default
hover
simulated
active
simulated
focus-visible
simulated
disabled

link

1px underline, hairline decoration until hover.

hover
simulated
visited
simulated
focus-visible
simulated

input

these are real inputs. click and tab through them.

badge

status pill. section hues as fills, never as text.

default
default
live
live
shipping
shipping
building
building

card

--color-card on --color-line at --radius-lg. the standard container.

resting

shadow-card, no transform

live

hover

lift 2px, accent border, shadow-card-lg

live
06

motion

one easing curve everywhere. all of it collapses to 0ms under prefers-reduced-motion: reduce, enforced globally rather than per component.

--motion-easecubic-bezier(0.16, 1, 0.3, 1)the one easing curve
--motion-duration-micro200mshover, color change
--motion-duration-state400msstate transition
--motion-duration-reveal700msscroll reveal
--motion-lift-2pxhover translateY
for agents

building something on-brand?

Fetch the tokens rather than reading hexes off this page. Both files are generated from the same source in the same build, are CORS-open, and carry every value shown above.

curl https://adampang.com/design/tokens.json
curl https://adampang.com/design/tokens.css

three rules that keep work on-brand

  1. 01Reference the variable, never the hex. Write var(--color-fg), not #1a1a1a. Every token is mode-aware, so one reference is correct in both themes. A literal hex is right in one mode and wrong in the other.
  2. 02One accent, one hue per section. --color-accent owns links, CTAs, and focus. Section hues are decorative fills and dots. Never set body text in one: at ~2:1 on white they fail AA, which is why --color-alert-ink exists separately from --color-alert.
  3. 03Three text weights, no opacity. --color-fg, --color-muted, --color-faint. Do not dim text with opacity to invent a fourth. That is exactly what failed AA here: text-ink/55 measured 3.90:1 against a 4.5:1 requirement.

Identity data lives at /api/profile.json and /llms.txt.