fix(design-system): compose rim + elevation tokens as chained box-shadow (#99)
User reported after PR #98 ("backdrop-filter now applies") that the dashboard glass panels still looked identical to solid cards. Browser CDP diagnostic on production found the root cause: the .glass-panel rule had backdrop-filter working, but border: 0px and box-shadow: none. Why both were missing: 1) `border: 1px solid var(--rim-light-outer)` — the --rim-light-outer token is a complete box-shadow declaration (`0 0 0 1px #2d181014`), NOT a color value. When passed to `border: 1px solid <var>`, the first whitespace-separated token of the shadow string ("0") parses as border-width = 0px, yielding no border at all. 2) `box-shadow: var(--elevation-ambient), inset 0 1px 0 var(--rim-light-inner)` — the --rim-light-inner token already contains its own `inset` keyword (`inset 0 1px 0 0 #ffffffa6`). Wrapping it in another `inset 0 1px 0 ...` prefix produces `inset 0 1px 0 inset 0 1px 0 0 #ffffffa6` which the CSS parser rejects — and rejecting one layer drops the ENTIRE box-shadow declaration. That's why `getComputedStyle().boxShadow === 'none'`. Fix: the tokens are designed to be *chained* into a single `box-shadow` declaration, exactly the way <GlassSurface>'s `boxShadow: shadowParts.join(', ')` composes them (see components/ui/GlassSurface.js lines 5-15). Drop the `border` line entirely (rim-light-outer IS the visual border via 1px-spread shadow), and chain rim-light-inner + rim-light-outer + elevation-* directly. Verified by `npm run build` — compiled CSS now has all three: - background - backdrop-filter (+ -webkit- prefix from autoprefixer) - box-shadow with all 4 layers correctly chained This will produce a visible: top inset rim highlight, dark hairline outer ring, soft ambient drop shadow — i.e. an actual glass card. Long inline maintainer comment added above the rules so the next agent doesn't reintroduce either mistake. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
40e00e57c6
commit
4228a777c6
1 changed files with 34 additions and 18 deletions
|
|
@ -439,31 +439,47 @@ body {
|
|||
from Tailwind (the class itself doesn't set border-radius
|
||||
because consumers vary between rounded-xl and rounded-2xl).
|
||||
============================================================ */
|
||||
/* IMPORTANT — backdrop-filter quirks with Next.js 16's Lightning CSS:
|
||||
/* IMPORTANT — composing rim + elevation tokens correctly.
|
||||
The --rim-light-outer / --rim-light-inner / --elevation-* tokens are
|
||||
COMPLETE box-shadow declarations (each contains offset/spread/color or
|
||||
the `inset` keyword), not raw color values. They are designed to be
|
||||
*chained into a single box-shadow*, exactly the way <GlassSurface>'s
|
||||
`boxShadow: shadowParts.join(', ')` composes them. Do NOT use
|
||||
`border: 1px solid var(--rim-light-outer)` — that parses
|
||||
`border-width` from the first token of the shadow string ("0"), which
|
||||
yields a 0px border. And do NOT wrap --rim-light-inner in another
|
||||
`inset 0 1px 0` prefix — the token already contains its own `inset`
|
||||
keyword, so wrapping produces invalid syntax that the browser drops
|
||||
the entire box-shadow declaration for. PR #98 had both mistakes,
|
||||
which is why the panels in PR #97/#98 had neither visible border nor
|
||||
drop shadow despite the backdrop-filter being correct.
|
||||
|
||||
Backdrop-filter quirks with Next.js 16's Lightning CSS (also relevant):
|
||||
1) `backdrop-filter: blur(var(--X)) saturate(var(--Y))` is silently
|
||||
stripped from the compiled CSS (same root cause that emptied
|
||||
`.mobile-nav-backdrop` in production). Use LITERAL values.
|
||||
2) Writing both `backdrop-filter` and `-webkit-backdrop-filter` with
|
||||
identical values triggers Lightning CSS's de-dup; it keeps only the
|
||||
`-webkit-` form which Chrome/Edge/Firefox ignore. Write only the
|
||||
unprefixed `backdrop-filter` and let Lightning CSS's autoprefixer
|
||||
add the vendor prefix per browserslist (it does for ios_saf <18).
|
||||
If the blur radii ever need to change, change them here AND in the
|
||||
matching --glass-blur-* tokens (kept for `<GlassSurface>` JSX consumers
|
||||
which set `backdropFilter` via inline style — those are unaffected by
|
||||
the Lightning CSS optimizer). */
|
||||
stripped (var() inside function args breaks the optimizer). Use
|
||||
LITERAL values here. Tokens stay in :root for the <GlassSurface>
|
||||
JSX primitive which sets backdropFilter via inline style.
|
||||
2) Writing both `backdrop-filter` AND `-webkit-backdrop-filter` with
|
||||
identical values triggers Lightning CSS's buggy de-dup; it keeps
|
||||
only the `-webkit-` form which modern browsers ignore. Write only
|
||||
the unprefixed form; Lightning CSS's autoprefixer adds the prefix
|
||||
per browserslist (ios_saf <18 still needs it). */
|
||||
.glass-panel {
|
||||
background-color: var(--glass-surface-mid);
|
||||
background: var(--glass-surface-mid);
|
||||
backdrop-filter: blur(12px) saturate(180%);
|
||||
border: 1px solid var(--rim-light-outer);
|
||||
box-shadow: var(--elevation-ambient), inset 0 1px 0 var(--rim-light-inner);
|
||||
box-shadow:
|
||||
var(--rim-light-inner),
|
||||
var(--rim-light-outer),
|
||||
var(--elevation-ambient);
|
||||
}
|
||||
|
||||
.glass-panel-strong {
|
||||
background-color: var(--glass-surface-high);
|
||||
background: var(--glass-surface-high);
|
||||
backdrop-filter: blur(20px) saturate(180%);
|
||||
border: 1px solid var(--rim-light-outer);
|
||||
box-shadow: var(--elevation-pronounced), inset 0 1px 0 var(--rim-light-inner);
|
||||
box-shadow:
|
||||
var(--rim-light-inner),
|
||||
var(--rim-light-outer),
|
||||
var(--elevation-pronounced);
|
||||
}
|
||||
|
||||
/* Gradient text effects — Deck Hearth warm palette only.
|
||||
|
|
|
|||
Loading…
Reference in a new issue