Skip to content

WIP β€” fix(skins): Liquid light contrast pass (Mood Radio + About + scan)#278

Closed
InstaZDLL wants to merge 2 commits into
mainfrom
wip/skin-liquid-light-contrast
Closed

WIP β€” fix(skins): Liquid light contrast pass (Mood Radio + About + scan)#278
InstaZDLL wants to merge 2 commits into
mainfrom
wip/skin-liquid-light-contrast

Conversation

@InstaZDLL

Copy link
Copy Markdown
Owner

Status: draft / WIP β€” first attempt landed and reverted on main, opening this PR to iterate without churning the changelog.

Symptoms (Liquid light skin, after v1.5.0 ship)

  1. Mood Radio tiles β€” cards render as faint pastels (Focus / Chill / Workout / Party / Sleep). Hardcoded white text dissolves into the pale tile bg.
  2. About hero β€” "WaveFlow" wordmark, "Cross-platform HD music player" subtitle, "Developed by WaveFlow Team" footer all paint grey-on-grey because the dark gradient body gets neutralised by the Liquid surface chain and the inherited `text-white` propagates down to every child.

First-pass attempt (cherry-picked from debc42f)

  • Mood Radio: bumped the 5 mood gradients' internal alphas from 0.55 β†’ 1.0 in `:not(.dark)` so the colored ::before layer fully saturates (the previous fix only bumped `opacity: 0.55 β†’ 0.95` on the pseudo, but the gradient stops themselves still ran at 0.55 alpha β€” net 0.52, basically unchanged).
  • About hero: added a `.text-white` β†’ `--liq-ink` neutralisation in `:not(.dark)` mode, excluding 12 colored-bg utility prefixes (bg-emerald / bg-violet / bg-indigo / bg-blue-5 / bg-blue-6 / bg-purple / bg-fuchsia / bg-pink / bg-rose / bg-amber / bg-orange / bg-sky / bg-cyan) plus the mood tile container so intentional white pills (v1.5.0 emerald badge, action chips) keep their contrast.

Why this isn't enough yet

User-tested in the live app and reported:

  • Mood Radio tiles still pale despite the gradient alpha bump β†’ suspect the tile body's `backdrop-filter` + `z-index: -1` of `::before` is stacking the gradient behind the glass tint at a paint layer that gets blurred / occluded
  • About text still grey-on-grey β†’ the `.text-white` override doesn't catch every descendant; some text uses `text-zinc-400` (subtitle) and `text-zinc-500` (license meta + Developed by) which Liquid does map but to `--liq-muted` which is rgb(102 102 106) β€” still low contrast against light glass

Next iterations to try

  • Move Mood Radio gradient to the tile's own `background-image` (not ::before) to bypass the z-index / backdrop-filter interaction
  • Add a `isolation: isolate` on the tile so the ::before stacks correctly
  • Tighten Liquid-light text colors: `text-zinc-400` β†’ darker than `--liq-muted` (currently 102 102 106 β‰ˆ 40% lightness); maybe rgb(63 63 70) or use `--liq-ink` for body copy
  • Audit the About hero specifically β€” its dark gradient body should NOT be neutralised by Liquid surface rules at all (the design intent is dark block); add a `:not(.about-hero)` carve-out or move the hero to a skin-aware token
  • Same audit for `text-zinc-500` (used by the v1.5.0 pill metadata + license line)

Test plan

  • Liquid light: Mood Radio tiles fully saturated, white text reads cleanly
  • Liquid light: About hero shows dark text on light glass OR white text on dark hero (pick one and commit)
  • Liquid dark: all unchanged
  • Studio / Editorial / Lounge / Pulse: no regression
  • AboutView keyboard nav + screen reader still OK

Two related regressions reported on the Liquid light skin after v1.5.0:

1. **Mood Radio cards still pale** β€” the previous fix (#275) bumped
   the `::before` opacity from 0.55 to 0.95, but the gradient itself
   uses `rgb(X Y Z / 0.55)` per stop, and the two alphas multiply
   (0.55 Γ— 0.95 = 0.52, basically the original). Bump the gradient
   internal alphas to 1.0 in light mode so the 5 cards become
   saturated colored surfaces that the hardcoded white text actually
   reads on. Dark mode keeps the original translucent gradients β€”
   the dark page makes them pop on its own.

2. **About hero invisible** β€” `AboutView` ships the hero with
   `<div className="... bg-linear-to-br from-zinc-900 ... text-white">`.
   The dark gradient body is the design intent (white text on dark
   block, Studio works perfectly). In Liquid light the surrounding
   aurora bleeds through and inherited `text-white` propagates down
   to every text child β†’ invisible. Remap `.text-white` to
   `--liq-ink` in light mode, excluding elements that ALSO carry a
   saturated colored bg (emerald pills, mood tiles, etc.) where the
   white is intentional. The exclusion chain matches the colors
   already used by intentional-white components across the app.

Both ship under `:not(.dark)` so dark Liquid stays unchanged.
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

βš™οΈ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 06dd5e71-3f42-452d-912b-88ed01d6f023

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • πŸ” Trigger review
✨ Finishing Touches
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wip/skin-liquid-light-contrast

Comment @coderabbitai help to get the list of available commands and usage tips.

@InstaZDLL InstaZDLL added scope: frontend React/Vite frontend (src/) size: m 50-200 lines labels Jun 20, 2026
@InstaZDLL InstaZDLL self-assigned this Jun 20, 2026
…iquid light)

User reports the Mood Radio tiles flicker β€” sometimes saturated as
designed, sometimes pale-white again. Investigation pointed at the
::before pseudo route being fragile against three runtime races:

1. **Theme/skin re-application on profile load** β€” ThemeContext
   reads the active profile's DB row on mount + on every profile
   switch (ThemeContext.tsx:111), which calls applyTheme() and
   toggles the `.dark` class. During the gap between cached-theme
   apply and DB-theme apply, `:not(.dark)` can stop matching and
   the ::before-based rule falls back to the 0.55-alpha gradient.
2. **View transitions on theme toggle** β€” setThemeId triggers
   `document.startViewTransition` which snapshots the paint for
   ~300ms. If the snapshot caught a state where my rule wasn't
   matching, the tile stays pale until the transition tears down.
3. **240ms opacity transition on ::before** β€” the pseudo has a
   transition: opacity, so even when the rule matches again the
   tiles fade back in slowly, giving a "blinks white" impression.

Fix: paint the saturated gradient directly on the tile element
(background-image, !important) instead of via the pseudo, and
display: none the ::before in light mode so the two layers don't
double-stack. Element-level paint isn't subject to z-index/stacking
gymnastics, isn't affected by the transition on the pseudo, and
survives the .dark flips during profile load. Dark mode keeps the
existing ::before route unchanged β€” there it works because the dark
page makes the translucent gradient pop on its own.
@InstaZDLL

Copy link
Copy Markdown
Owner Author

Closing β€” the ::before/:not(.dark) approach has runtime races (theme/skin re-application on profile load, view-transition snapshots, opacity transition flicker). Starting over with a cleaner approach when we have bandwidth.

@InstaZDLL InstaZDLL closed this Jun 20, 2026
@InstaZDLL InstaZDLL deleted the wip/skin-liquid-light-contrast branch June 20, 2026 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: frontend React/Vite frontend (src/) size: m 50-200 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant