color slop
Color fails in familiar ways: a glow behind text, an accent that means nothing, grey body copy on a colored band, a headline that is a gradient. Each section puts the failing treatment (A) next to a working one (B) with the same content, live, and states the rule that settles it. Contrast ratios are measured with the WCAG formula on the exact hex pairs shown. Pattern source: impeccable.style/slop; the reasoning, demos and fixes are ours.
radial halo
A dark card puts a soft radial glow behind its content. The halo carries no information: it does not say what the card is, which part matters, or what to do. It also makes text sit on a fill whose brightness changes with position, so the same ink reads differently line to line. Depth on this site is a fill step, never light.
A: glow behind text
indexing complete
12,408 rows in 4.2s.
the purple bloom is the loudest thing in the card and says nothing; the body text crosses its edge.
B: flat fill, one rule
indexing complete
12,408 rows in 4.2s.
same content. the paper-quiet fill and a 1px rule carry the card; hierarchy comes from size and color.
<div className="flex flex-col items-center gap-2 rounded-lg border border-border bg-card p-6"><h4 className="text-lg">indexing complete</h4><p className="text-sm text-zinc-400">12,408 rows in 4.2s.</p><button className="rounded-md bg-emerald-600 px-4 py-2 text-sm">open table</button></div>
soft spotlight
A white spotlight dims everything outside its cone. The headline inside the hotspot and the body outside it use the same ink, but the reader sees two different contrast ratios depending on position. Attention is staged by decoration instead of by layout, and any content that moves out of the cone loses the stage.
A: one hot spot
indexing complete
12,408 rows in 4.2s.
the headline glows, the body and button sit in the falloff: same ink, three different effective contrasts.
B: even fill
indexing complete
12,408 rows in 4.2s.
same content. one fill, one contrast ratio everywhere; emphasis moves to size and the accent on the action.
<!-- one flat fill; no gradient layer under the content --><div className="... bg-card">...</div>
ai palette (purple/cyan)
Violet headings, a cyan-to-purple button, a blue link: the default AI-generated palette. Three accents means no accent is a signal, because nothing predicts which color marks what. An accent is a vocabulary: each color earns its place by carrying one assigned meaning, and everything else stays ink.
A: three unassigned accents
violet headline, cyan-purple button, blue link. which one is the action? the palette refuses to say.
B: one accent, one meaning
same content. emerald appears exactly once, on the action; prose links are primary; the headline is ink.
<h4 className="text-lg">indexing complete</h4> {/* ink, not a gradient */}<button className="rounded-md bg-emerald-600 px-4 py-2 text-sm">open table</button><a className="text-primary" href="/docs">read the docs</a> {/* prose link = primary */}
glowing accents on dark
The button is emerald and emits emerald light; the headline has a matching text-shadow. The glow competes with the state the color already carries: every state a control needs (hover, focus, disabled) is a solid-fill or ring change, so the light encodes nothing and draws the eye to whatever glows hardest, not to what matters.
A: light as emphasis
indexing complete
12,408 rows in 4.2s.
both the button and the headline emit; focus, hover and disabled now have no louder state left to move to.
B: solid fills, real states
indexing complete
12,408 rows in 4.2s.
same content. the button is a solid fill whose hover darkens and focus rings; nothing emits.
<button className="rounded-md bg-emerald-600 px-4 py-2 text-smhover:bg-emerald-500focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus:outline-none">open table</button>
gradient text
bg-clip-text turns a headline into a gradient swatch. Each letter gets a different weight of emphasis depending on where it sits in the ramp, so the sentence reads unevenly; transparent fill also forfeits the plain-ink rendering the rest of the page uses. If a word in the headline matters more, markup decides that, not a color ramp.
A: the headline is a swatch
indexing complete
12,408 rows in 4.2s.
'indexing' lands on violet, 'complete' on cyan: two moods in three words, and none of them chosen by the writer.
B: ink decides
indexing complete
12,408 rows in 4.2s.
same content. the headline is ink; if a word needs weight, it gets <strong>, which every reader's browser already understands.
<h4 className="text-lg">indexing <strong className="font-normal text-foreground">complete</strong></h4>
gray on color
A colored band gets the same zinc-400 body text the dark page uses. Grey was tuned against near-black paper; on a saturated fill it drops under the readable bar. Text on a colored fill uses that fill's -foreground pair, which the palette was built to guarantee.
A: zinc-400 on indigo-600
indexing complete
12,408 rows in 4.2s.
measured 2.45:1. under the 4.5:1 AA bar for 14px text by nearly half.
B: the fill's foreground
indexing complete
12,408 rows in 4.2s.
measured 5.10:1 with indigo-100 on the same indigo-600. the button flips to the page paper and passes at 6.91:1.
<div className="... bg-indigo-600"><h4 className="text-lg text-indigo-100">indexing complete</h4> {/* the fill's foreground */}<button className="bg-zinc-900 text-zinc-200">open table</button> {/* page paper flips back */}</div>
cream default
A card defaults to cream because warmth reads as craft. Cream is a palette decision wearing a default's clothes: it fights the system's paper, drags ink choices toward browns, and every other surface now has to justify not matching it. Paper is a token; picking a new one per card is how palettes rot.
A: a private paper
indexing complete
12,408 rows in 4.2s.
bg-[#faf7f0] with stone ink. its body text measures 4.48:1, passes, and still looks wrong next to every other card on the page.
B: the system's paper
indexing complete
12,408 rows in 4.2s.
same content on paper-quiet with the rule border. zinc-400 on zinc-900 measures 6.91:1 and matches every other card.
<div className="rounded-lg border border-border bg-card p-6">...</div>// paper-quiet for cards; the hex lives in @theme, not in the className
low contrast
Zinc-600 body text on zinc-900 looks quiet and measures 2.29:1, half the 4.5:1 bar WCAG sets for 14px text. Quiet comes from the muted token (zinc-400, 6.91:1), not from dipping under the floor; metadata that is allowed to recede uses the faint token at caption sizes and never for body copy.
A: 2.29:1
indexing complete
12,408 rows in 4.2s.
zinc-600 on zinc-900. fails AA for body text; the button label repeats the failure at 2.29:1.
B: 6.91:1
indexing complete
12,408 rows in 4.2s.
zinc-400 on the same zinc-900: passes AA with headroom. the headline is zinc-200 at 13.96:1.
/* body on paper-quiet */ .body { color: #a1a1aa } /* 6.91:1 on #18181b *//* headline on paper-quiet */ .head { color: #e4e4e7 } /* 13.96:1 *//* floor: 4.5:1 for 14px body, 3:1 for large text */