swarm-ui: fix WCAG contrast failures in the light-theme accent slots

argus review: the literal Catppuccin Latte accent hexes (base08-0F)
fail badly as StatusChip fill-text (green/amber/red/yellow on
--purple-dim/base03: 1.4:1-3:1, need 4.5:1) and even as plain text on
--bg/base00 in the agent/dashboard packages that also import this file
(2.3:1-4.8:1). Root cause: Latte's own accents are calibrated against
Lattes near-white base/crust, not a mid-gray surface1; the Mocha row
does not hit this because Mochas pastel accents are already light, so
they contrast fine against a dark surface1 - Lattes saturated-but-mid
accents do not have the same headroom against Lattes own lighter
surface1.

Fix: darken each accent slot from stock Latte (same hue/saturation,
lower HSL lightness via binary search) until real WCAG contrast against
base03 clears 4.5:1 with margin - verified this also clears >7:1
against base00, so both the swarm-ui chip case and the plain-text case
elsewhere are covered by one set of values. base00-07 stay stock Latte
(no contrast role, just surfaces/foreground). Yellow and peach read
closer to olive/brown than a bright yellow/orange once darkened this
far - an inherent property of darkening a warm hue in sRGB, not a
mapping mistake; boosting saturation further did not rescue it
(checked).

Verified with headless-chromium screenshots against the built swarm-ui
bundle: StatusChip text (the exact case argus flagged) and every chip
tone on /components now read clearly.
This commit is contained in:
iris 2026-08-18 22:57:47 +02:00 committed by mara
commit 72e087b086
2 changed files with 53 additions and 20 deletions

View file

@ -18,12 +18,17 @@ for the raw `--baseNN` slots directly. (`base.css` holds only the shared
`body` typography — it references the palette but no longer defines it.)
`colors.css` ships two rows of the same 16 slots: an unconditional
Catppuccin Mocha (dark) default, and a Catppuccin Latte (light) row gated
behind `@media (prefers-color-scheme: light)` — both ported through the
Catppuccin Mocha (dark) default, and a Catppuccin-Latte-derived (light)
row gated behind `@media (prefers-color-scheme: light)` — both use the
identical slot mapping, so which row is active never changes what a slot
means. This is the OS/browser-level default only; it's what a client with
no more specific theme decision gets (see "Theme swapping" below for how a
stylix deployment or a future per-user override supersede it).
means. The light row's `base00`-`base07` (surfaces/foreground) are stock
Latte hexes; `base08`-`base0F` (the eight chromatic slots) are darkened
from stock Latte to actually clear WCAG AA against how this app uses
them (real contrast failures found in review — see the comment above
those declarations in `colors.css` for the numbers and why). This is the
OS/browser-level default only; it's what a client with no more specific
theme decision gets (see "Theme swapping" below for how a stylix
deployment or a future per-user override supersede it).
Both are deliberately standalone, not `@import`ed into the page bundles:
each package re-exports them (`src/{colors,theme}.css`