06
4 min
Color
Twelve slightly different grays and a blue that drifts across the app. That's not a palette. That's residue.
Build a ramp first: one hue, stepped from 50 to 900. Those steps are facts. Then map semantic roles onto them. primary, background, foreground, border, muted, destructive, success, warning. Components use the roles. They never touch a ramp step.
Contrast is a readability problem, not a token-structure problem. Grade covers the ratios. This lesson is the wiring.
Pick a step. Change it. Watch every role that points at it, and the button that points at the role.
Blue ramp
primary→ blue-600
background→ slate-50
foreground→ slate-900
border→ slate-200
muted→ slate-200
destructive→ red-600
success→ green-600
warning→ amber-500
Roles, not ramp steps. The button asks for primary.
You edited blue-600, not the button. primaryfollowed. That's a ramp doing its job.