fix(design-system): compose rim + elevation tokens correctly (panels actually have chrome now) #99

Merged
varutasu merged 1 commit from fix-glass-panel-rim-shadow-composition into main 2026-06-03 23:49:06 -04:00
varutasu commented 2026-06-03 23:46:22 -04:00 (Migrated from github.com)

Why this exists

After PR #98 ("backdrop-filter now applies"), user reported deckhearth.com/dashboard still showed flat-looking panels. CDP diagnostic on the live page found the smoking gun:

```
panelComputed: {
bg: "rgba(254, 252, 248, 0.68)", // OK
border: "rgb(45, 24, 16) none 0px", // BROKEN — border-width is 0
boxShadow: "none" // BROKEN — entire declaration dropped
}
```

Backdrop-filter was finally being applied, but the panels had no border and no shadow — so they looked like flat color swatches sitting on a same-hue page background.

Root cause

I misused the rim + elevation tokens. They are complete box-shadow declarations, not raw color values:

```css
--rim-light-outer: 0 0 0 1px #2d181014; /* 1px-spread ring /
--rim-light-inner: inset 0 1px 0 0 #ffffffa6; /
inset white highlight /
--elevation-ambient: 0 4px 12px -2px #2d181014,
0 2px 4px -1px #2d18100a; /
2-layer drop shadow */
```

In PRs #97/#98 I wrote:

```css
.glass-panel {
border: 1px solid var(--rim-light-outer);
box-shadow: var(--elevation-ambient), inset 0 1px 0 var(--rim-light-inner);
}
```

Two mistakes:

  1. border: 1px solid var(--rim-light-outer) — the var expands to 0 0 0 1px #2d181014. CSS's border shorthand parses the first whitespace-separated token of the value as border-width"0" → 0px border. Result: no border.

  2. inset 0 1px 0 var(--rim-light-inner) — the var already starts with inset, so expansion gives inset 0 1px 0 inset 0 1px 0 0 #ffffffa6. Two inset keywords → invalid shadow layer → browser drops the entire box-shadow declaration (per CSS spec, one bad layer kills the whole property). Result: boxShadow: none.

Fix

The tokens are designed to be chained into a single box-shadow, exactly the way `` composes them at `components/ui/GlassSurface.js` lines 5–15:

```js
const shadowParts = [
'var(--rim-light-inner)',
'var(--rim-light-outer)',
'var(--elevation-ambient)',
];
// → boxShadow: shadowParts.join(', ')
```

So this PR replaces the broken `border` + nested-inset pattern with a clean chained shadow:

```css
.glass-panel {
background: var(--glass-surface-mid);
backdrop-filter: blur(12px) saturate(180%);
box-shadow:
var(--rim-light-inner),
var(--rim-light-outer),
var(--elevation-ambient);
}
```

After variable substitution this becomes a valid 4-layer shadow:

  1. Inset white top-highlight
  2. Outer 1px-spread dark hairline ring
  3. Soft ambient drop shadow (2 layers)

i.e. an actual glass card with visible chrome.

Maintainer comment added in CSS

A 25-line block comment above the two utility classes documents:

  • Why `border: 1px solid ` doesn't work for these tokens
  • Why `inset 0 1px 0 ` doesn't work for `--rim-light-inner`
  • The Lightning CSS quirks from PR #98 (still apply)

The next agent (human or AI) reading the CSS will be told exactly which two mistakes to NOT make.

Tests

  • `npm run build` — verified the compiled CSS now contains the chained box-shadow and the backdrop-filter (both prefixed + unprefixed)
  • Lint clean, vitest unaffected

Test plan

  • CI green
  • After promote, hard-refresh `deckhearth.com/dashboard` — stat cards should now have a visible top rim highlight, dark hairline outer ring, and soft drop shadow.
  • Same expected on `/admin/card-editor`, `/scanner`, `/card/[id]` price cards.

Made with Cursor

## Why this exists After PR #98 ("backdrop-filter now applies"), user reported `deckhearth.com/dashboard` still showed flat-looking panels. CDP diagnostic on the live page found the smoking gun: \`\`\` panelComputed: { bg: \"rgba(254, 252, 248, 0.68)\", // OK border: \"rgb(45, 24, 16) none 0px\", // BROKEN — border-width is 0 boxShadow: \"none\" // BROKEN — entire declaration dropped } \`\`\` Backdrop-filter was finally being applied, but the panels had **no border and no shadow** — so they looked like flat color swatches sitting on a same-hue page background. ## Root cause I misused the rim + elevation tokens. They are **complete box-shadow declarations**, not raw color values: \`\`\`css --rim-light-outer: 0 0 0 1px #2d181014; /* 1px-spread ring */ --rim-light-inner: inset 0 1px 0 0 #ffffffa6; /* inset white highlight */ --elevation-ambient: 0 4px 12px -2px #2d181014, 0 2px 4px -1px #2d18100a; /* 2-layer drop shadow */ \`\`\` In PRs #97/#98 I wrote: \`\`\`css .glass-panel { border: 1px solid var(--rim-light-outer); box-shadow: var(--elevation-ambient), inset 0 1px 0 var(--rim-light-inner); } \`\`\` Two mistakes: 1. **`border: 1px solid var(--rim-light-outer)`** — the var expands to `0 0 0 1px #2d181014`. CSS's border shorthand parses the first whitespace-separated token of the value as `border-width` → `"0"` → 0px border. Result: no border. 2. **`inset 0 1px 0 var(--rim-light-inner)`** — the var already starts with `inset`, so expansion gives `inset 0 1px 0 inset 0 1px 0 0 #ffffffa6`. Two `inset` keywords → invalid shadow layer → browser drops the entire box-shadow declaration (per CSS spec, one bad layer kills the whole property). Result: `boxShadow: none`. ## Fix The tokens are designed to be **chained into a single `box-shadow`**, exactly the way \`<GlassSurface>\` composes them at \`components/ui/GlassSurface.js\` lines 5–15: \`\`\`js const shadowParts = [ 'var(--rim-light-inner)', 'var(--rim-light-outer)', 'var(--elevation-ambient)', ]; // → boxShadow: shadowParts.join(', ') \`\`\` So this PR replaces the broken \`border\` + nested-inset pattern with a clean chained shadow: \`\`\`css .glass-panel { background: var(--glass-surface-mid); backdrop-filter: blur(12px) saturate(180%); box-shadow: var(--rim-light-inner), var(--rim-light-outer), var(--elevation-ambient); } \`\`\` After variable substitution this becomes a valid 4-layer shadow: 1. Inset white top-highlight 2. Outer 1px-spread dark hairline ring 3. Soft ambient drop shadow (2 layers) i.e. an actual glass card with visible chrome. ## Maintainer comment added in CSS A 25-line block comment above the two utility classes documents: - Why \`border: 1px solid <token>\` doesn't work for these tokens - Why \`inset 0 1px 0 <token>\` doesn't work for \`--rim-light-inner\` - The Lightning CSS quirks from PR #98 (still apply) The next agent (human or AI) reading the CSS will be told exactly which two mistakes to NOT make. ## Tests - \`npm run build\` — verified the compiled CSS now contains the chained box-shadow and the backdrop-filter (both prefixed + unprefixed) - Lint clean, vitest unaffected ## Test plan - [ ] CI green - [ ] After promote, hard-refresh \`deckhearth.com/dashboard\` — stat cards should now have a visible top rim highlight, dark hairline outer ring, and soft drop shadow. - [ ] Same expected on \`/admin/card-editor\`, \`/scanner\`, \`/card/[id]\` price cards. Made with [Cursor](https://cursor.com)
vercel[bot] commented 2026-06-03 23:46:24 -04:00 (Migrated from github.com)

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tcg-vault Ready Ready Preview, Comment Jun 4, 2026 3:46am

Request Review

[vc]: #K8gtrqHwZ3ya0NTqmFBc5/v65xg3aR37tsgFTqiq4i0=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ0Y2ctdmF1bHQiLCJwcm9qZWN0SWQiOiJwcmpfRjZXOEVvRkd3Y0g3aWVGcnRvRlNlOXdVVkFhNSIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9yYW5kYWxsLXN0aWxsd2VsbHMtcHJvamVjdHMvdGNnLXZhdWx0L0o3TlBHSE1uZU4yVjRkdGZhMzhzUWFrV2FEMUciLCJwcmV2aWV3VXJsIjoidGNnLXZhdWx0LWdpdC1maXgtZ2xhc3MtcGFuZS03YzQ0NWUtcmFuZGFsbC1zdGlsbHdlbGxzLXByb2plY3RzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiREVQTE9ZRUQiLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoidGNnLXZhdWx0LWdpdC1maXgtZ2xhc3MtcGFuZS03YzQ0NWUtcmFuZGFsbC1zdGlsbHdlbGxzLXByb2plY3RzLnZlcmNlbC5hcHAifSwicm9vdERpcmVjdG9yeSI6bnVsbH1dLCJyZXF1ZXN0UmV2aWV3VXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3ZlcmNlbC1hZ2VudC9yZXF1ZXN0LXJldmlldz9vd25lcj12YXJ1dGFzdSZyZXBvPXRjZy12YXVsdCZwcj05OSJ9 The latest updates on your projects. Learn more about [Vercel for GitHub](https://vercel.link/github-learn-more). | Project | Deployment | Actions | Updated (UTC) | | :--- | :----- | :------ | :------ | | [tcg-vault](https://vercel.com/randall-stillwells-projects/tcg-vault) | ![Ready](https://vercel.com/static/status/ready.svg) [Ready](https://vercel.com/randall-stillwells-projects/tcg-vault/J7NPGHMneN2V4dtfa38sQakWaD1G) | [Preview](https://tcg-vault-git-fix-glass-pane-7c445e-randall-stillwells-projects.vercel.app), [Comment](https://vercel.live/open-feedback/tcg-vault-git-fix-glass-pane-7c445e-randall-stillwells-projects.vercel.app?via=pr-comment-feedback-link) | Jun 4, 2026 3:46am | <a href="https://vercel.com/vercel-agent/request-review?owner=varutasu&repo=tcg-vault&pr=99" rel="noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://agents-vade-review.vercel.sh/request-review-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://agents-vade-review.vercel.sh/request-review-light.svg"><img src="https://agents-vade-review.vercel.sh/request-review-light.svg" alt="Request Review"></picture></a>
github-actions[bot] commented 2026-06-03 23:46:33 -04:00 (Migrated from github.com)

Pipeline Health

Build + CI gates

Gate Status
Vercel build (Preview) pass
CI: Lint pass
CI: Schema map fresh skipped
Preview smoke pass
Visual diff pass

Build runs on Vercel; this CI runs lint and schema-map drift only (no duplicate build).

Role reports

Role Status
Reviewer report pending
A11y audit pending
Design system audit pending

See individual comments above for details. This rollup updates automatically.

<!-- pipeline-rollup --> ## Pipeline Health ### Build + CI gates | Gate | Status | | --- | --- | | Vercel build (Preview) | ✅ pass | | CI: Lint | ✅ pass | | CI: Schema map fresh | ❌ skipped | | Preview smoke | ✅ pass | | Visual diff | ✅ pass | _Build runs on Vercel; this CI runs lint and schema-map drift only (no duplicate build)._ ### Role reports | Role | Status | | --- | --- | | Reviewer report | ⏳ pending | | A11y audit | ⏳ pending | | Design system audit | ⏳ pending | See individual comments above for details. This rollup updates automatically.
github-actions[bot] commented 2026-06-03 23:47:36 -04:00 (Migrated from github.com)

Visual Diff

Screenshots and diffs uploaded as artifacts: view run

If intentional changes: update snapshots locally with npx playwright test --project=visual --update-snapshots and commit.

## Visual Diff Screenshots and diffs uploaded as artifacts: [view run](https://github.com/varutasu/tcg-vault/actions/runs/26929200792) If intentional changes: update snapshots locally with `npx playwright test --project=visual --update-snapshots` and commit.
Sign in to join this conversation.
No description provided.