Skip to content

Fix pink header in chromatic light palettes (mix alpha in oklab, not oklch)#284

Merged
SawyerHood merged 1 commit into
mainfrom
bb/adjust-light-mode-header-thr_g3c8ks6ea7
Jun 20, 2026
Merged

Fix pink header in chromatic light palettes (mix alpha in oklab, not oklch)#284
SawyerHood merged 1 commit into
mainfrom
bb/adjust-light-mode-header-thr_g3c8ks6ea7

Conversation

@SawyerHood

Copy link
Copy Markdown
Collaborator

Problem

In Light mode, the Nord and Dracula palettes (and any non-gray palette) rendered the app header (bg-surface-scrim) with a pink/warm tint that didn't match the cool body. Every new palette hit this, so it was a systematic derivation bug rather than a per-theme mistake.

Root cause

Translucent tokens were derived with color-mix(in oklch, <color>, transparent). Mixing a color with transparent in a polar space drops the result hue to none, which renders as hue 0 (red) while the chroma survives. Chromium computes, for Nord's canvas:

color-mix(in oklch, #eceff4 92%, transparent) → oklch(0.95127 0.00741954 none / 0.92)

Composited over the canvas that's [243,237,240] (pink). The default palette escaped only because its anchors are oklch(1 0 0) — chroma exactly 0, so there's no hue to lose.

Fix

Mix translucency in oklab (rectangular — carries the hue through). Verified: color-mix(in oklab, #eceff4 92%, transparent) over canvas → [236,239,245], matching the cool body. Opaque color→canvas mixes correctly stay oklch.

Touched (light + dark): --surface-scrim, --state-hover/active, --surface-recessed/raised/destructive/destructive-border/selected/selected-border in theme.css, plus the scrollbar thumbs in app.css.

This is the systematic fix: palettes only set opaque anchors and never touch these derived tokens, so every current and future palette is correct by construction.

Tests

  • Updated the ramp-parser regex in theme.test.ts to accept oklab for the translucent tokens.
  • Added a regression guard that fails if color-mix(in oklch, …, transparent) is reintroduced.
  • pnpm exec turbo run test --filter=@bb/app -- theme.test.ts → 17 passed.
  • Verified the rendered scrim color in Chromium before/after via a minimal reproduction.

Notes

Out of scope: apps/landing/src/styles.css has the same pattern (~24 spots), but it's the marketing site — not palette-driven, and mostly dark box-shadows where the hue shift is imperceptible. Worth a follow-up sweep for full consistency.

🤖 Generated with Claude Code

Translucent theme tokens were derived with `color-mix(in oklch, <color>,
transparent)`. Mixing with `transparent` in a polar space drops the result
hue to `none`, which renders as hue 0 (red): the chroma survives, so any
palette whose canvas/ink/primary isn't pure gray got a pink-tinted header
(--surface-scrim), hover, and selection. The default palette escaped only
because its anchors are chroma-0.

Mix translucency in oklab (rectangular — carries the hue through) instead.
Opaque color->canvas mixes stay oklch. Covers --surface-scrim,
--state-hover/active, --surface-recessed/raised/destructive/selected and
their borders in theme.css, plus the scrollbar thumbs in app.css.

Add a theme.test.ts guard that fails if `color-mix(in oklch, ...,
transparent)` is reintroduced, so future palettes stay correct by
construction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@SawyerHood SawyerHood merged commit 7f6296e into main Jun 20, 2026
6 checks passed
@SawyerHood SawyerHood deleted the bb/adjust-light-mode-header-thr_g3c8ks6ea7 branch June 20, 2026 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant