feat(design): warm↔cool gradient + edge-light response on chips

Operator feedback 2026-06-04: "increase the gradient in the
background that goes from our nice warm red to a nice purpley
blue. And then let's have the corners or the edges of our sections
respond as if those two are light sources."

Two coordinated changes that together create the "lit by two light
sources" effect.

1) Body gradient pushed harder + diagonal warm↔cool story
   (styles/globals.css body { ... } + [data-theme="dark"] body)

   - Dark theme:
     * Warm ember pool bottom-left: alpha 0.55 → 0.72, ellipse
       enlarged from 75%/55% to 95%/70%.
     * Top-right corner: switched from secondary ember + dim
       purple-magenta (0.26) to a unified bright purpley-blue pool
       (alpha 0.58, indigo→violet ramp, 90%/70% ellipse).
     * Base linear-gradient: 180deg vertical wash → 45deg diagonal
       (warm aubergine bottom-left → indigo top-right) so the whole
       page reads as one continuous warm↔cool dialogue, not just
       two corner pools.
   - Light theme:
     * Top-right gold accent replaced with purpley-blue (indigo
       0.42 → violet 0.20 → light violet 0.08) so both themes share
       the same diagonal story.
     * Bottom-left ember boosted (0.42 → 0.55, ellipse enlarged).
     * Base linear-gradient: 180deg → 45deg diagonal (warm-cream
       → cool-violet).

2) Edge-light tokens on every floating chip's shadow stack
   (styles/globals.css + components/Layout.js + components/ui/TopSearchBar.js)

   - New design tokens in :root and [data-theme="dark"]:
       --edge-light-warm  (offset -X +Y → glow on the chip's
                           bottom-left edge, matching the warm
                           ember light source)
       --edge-light-cool  (offset +X -Y → glow on the chip's
                           top-right edge, matching the cool
                           purpley-blue light source)
     Light: 0.16 warm / 0.12 cool. Dark: 0.34 warm / 0.28 cool.
   - .glass-panel and .glass-panel-strong shadow stacks updated to
     prepend the two edge-light tokens. Every glass surface in the
     app now picks up the directional rim glows from the body
     gradient without per-component changes (DailyEmberWidget,
     CommandPaletteModal popover, the logged-out sidebar Support/
     Theme tray, UserMenu dropdown, etc).
   - components/Layout.js nav-chip and components/ui/TopSearchBar.js
     inline boxShadow strings prepended with the same two tokens
     (they use inline styles rather than the .glass-panel class so
     they need the explicit shadow stack).

Result: the body now visibly transitions from warm ember (bottom-
left) through a neutral midpoint to purpley-blue (top-right). Every
floating chip's bottom-left and top-right edges pick up subtle
directional glow from the matching corner, reading as light wrapping
around the chip's rim from the two off-screen-ish light sources.

Tests:
- npm run test:run: 113/113
- npm run lint: 0 errors (1 pre-existing warning)
- npm run build: green

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Randall Stillwell 2026-06-04 12:20:55 -05:00
parent f3faeab788
commit 045ce88b6b
3 changed files with 121 additions and 61 deletions

View file

@ -845,14 +845,24 @@ export default function Layout({ children, user = null, showSearch = false }) {
className="hidden md:flex md:flex-col md:gap-4 w-64"
aria-label="Sidebar"
>
{/* Nav chip */}
{/* Nav chip. 2026-06-04 two-light-source pass: prepended the
two edge-light tokens so the nav chip's bottom-left and
top-right edges pick up warm + cool directional glows from
the matching corners of the body gradient the chip
visually "responds" to the two light sources the operator
asked for. The chip is positioned at the top-left of the
viewport so it sits closer to the warm light source; that's
a coincidence of layout, not something the token reacts to,
but the warm glow does naturally read stronger on this chip
because the warm source is right there. */}
<div
className="flex-1 flex flex-col md:rounded-3xl md:overflow-hidden min-h-0"
style={{
background: 'var(--glass-surface-mid)',
backdropFilter: 'blur(var(--glass-blur-mid)) saturate(var(--glass-saturate))',
WebkitBackdropFilter: 'blur(var(--glass-blur-mid)) saturate(var(--glass-saturate))',
boxShadow: 'var(--rim-light-inner), var(--elevation-ambient)',
boxShadow:
'var(--edge-light-warm), var(--edge-light-cool), var(--rim-light-inner), var(--elevation-ambient)',
}}
>
<div className="p-4 h-full flex flex-col w-full">

View file

@ -315,7 +315,15 @@ export default function TopSearchBar({
background: 'var(--glass-surface-mid)',
backdropFilter: 'blur(12px) saturate(180%)',
WebkitBackdropFilter: 'blur(12px) saturate(180%)',
boxShadow: 'var(--rim-light-inner), var(--elevation-ambient)',
// 2026-06-04 two-light-source pass: prepended edge-light
// tokens so the header's bottom-left and top-right edges
// pick up warm + cool directional glows. The header sits
// near the top-right of the viewport so the cool source
// reads stronger on it (the purple light is right above);
// the warm rim still appears on the bottom-left edge of the
// chip, just dimmer at this distance from the ember pool.
boxShadow:
'var(--edge-light-warm), var(--edge-light-cool), var(--rim-light-inner), var(--elevation-ambient)',
}}
>
{/* Search affordance read-only-ish input that opens the

View file

@ -200,47 +200,52 @@ body {
}
/* Apply theme colors.
The hearth gradient: a soft warm wash that gives glass surfaces a real
substrate to blur and distort. Without this the page bg is flat warm-
white and the blur is functionally invisible (the chief reason the
first 3 redesign PRs landed but the user said "still looks the same").
Two layers:
- A radial ember glow biased to the bottom-left (the seat of a fire)
- A soft vertical gradient from cooler-top to warmer-bottom
Fixed attachment so scrolling content slides over the gradient rather
than pulling it along that's what gives glass surfaces their
parallax-blur behavior. */
The hearth gradient: two diagonal light sources that the floating
chrome chips visually "respond" to via the --edge-light-warm /
--edge-light-cool design tokens (defined further down in :root /
[data-theme="dark"]).
- Warm ember light source: bottom-left of the viewport.
- Cool purpley-blue light source: top-right of the viewport.
The base linear-gradient runs along the same 45deg diagonal between
the two sources so the page itself reads as a single continuous
wash, not just two corner pools on a flat substrate. Pushed harder
2026-06-04 per operator feedback ("increase the gradient in the
background that goes from our nice warm red to a nice purpley
blue") alphas roughly doubled vs the prior pass, ellipses
enlarged, and the top-right corner switched from gold to
purpley-blue on light theme so both themes carry the same warm
cool diagonal story.
Fixed attachment so scrolling content slides over the gradient
rather than pulling it along that's what gives glass surfaces
their parallax-blur behavior. */
body {
background-color: var(--bg-primary-light);
background-image:
/* Bright amber ember pool, bottom-left — "seat of the fire". */
/* Warm ember pool, bottom-left — primary light source. */
radial-gradient(
ellipse 75% 55% at 8% 108%,
rgba(255, 110, 0, 0.42) 0%,
rgba(255, 140, 30, 0.22) 28%,
rgba(255, 171, 64, 0.08) 55%,
transparent 78%
ellipse 90% 65% at 5% 110%,
rgba(255, 95, 0, 0.55) 0%,
rgba(255, 130, 25, 0.28) 28%,
rgba(255, 171, 64, 0.10) 55%,
transparent 80%
),
/* Secondary amber, bottom-right — balances wide displays. */
/* Purpley-blue pool, top-right secondary light source (replaces
the prior gold accent). Indigoviolet so the chip rims that
respond to this source via --edge-light-cool read as cool. */
radial-gradient(
ellipse 60% 50% at 98% 105%,
rgba(255, 130, 20, 0.30) 0%,
rgba(255, 171, 64, 0.10) 45%,
transparent 72%
ellipse 85% 65% at 100% -8%,
rgba(99, 102, 241, 0.42) 0%,
rgba(124, 58, 237, 0.20) 30%,
rgba(167, 139, 250, 0.08) 58%,
transparent 80%
),
/* Gold accent, top-right — "smoke catching last light". */
radial-gradient(
ellipse 60% 45% at 95% -8%,
rgba(255, 171, 64, 0.24) 0%,
rgba(255, 200, 110, 0.08) 40%,
transparent 68%
),
/* Base wash: cooler-cream top → warmer-amber-tinted bottom. */
/* Base diagonal wash: warm-cream bottom-left cool-violet top-right.
45deg = bottom-left top-right (matches the two light sources). */
linear-gradient(
180deg,
rgba(254, 252, 248, 1) 0%,
rgba(252, 244, 230, 1) 55%,
rgba(250, 233, 210, 1) 100%
45deg,
rgba(255, 240, 220, 1) 0%,
rgba(252, 244, 230, 1) 50%,
rgba(230, 232, 252, 1) 100%
);
background-attachment: fixed;
color: var(--text-primary-light);
@ -249,36 +254,36 @@ body {
[data-theme="dark"] body {
background-color: var(--bg-primary-dark);
background-image:
/* Bright ember-red pool, bottom-left the operator mockup's
defining visual. High alpha against deep navy makes it glow. */
/* Warm ember-red pool, bottom-left primary light source.
Pushed to 0.72 (was 0.55) so the operator's "nice warm red"
reads as a real glow against deep navy. */
radial-gradient(
ellipse 75% 55% at 8% 108%,
rgba(255, 75, 30, 0.55) 0%,
rgba(255, 110, 0, 0.30) 25%,
rgba(255, 140, 30, 0.10) 55%,
transparent 78%
ellipse 95% 70% at 5% 110%,
rgba(255, 65, 25, 0.72) 0%,
rgba(255, 95, 0, 0.42) 24%,
rgba(255, 130, 30, 0.16) 52%,
transparent 80%
),
/* Secondary ember, bottom-right. */
/* Purpley-blue pool, top-right secondary light source. Pushed
to 0.58 (was 0.26) + a more saturated indigoviolet ramp so
the corner reads unambiguously as the second light source the
chip rims respond to. */
radial-gradient(
ellipse 60% 50% at 98% 105%,
rgba(255, 110, 30, 0.36) 0%,
rgba(255, 140, 50, 0.12) 45%,
transparent 72%
ellipse 90% 70% at 100% -10%,
rgba(139, 92, 246, 0.58) 0%,
rgba(99, 102, 241, 0.32) 28%,
rgba(168, 85, 247, 0.12) 55%,
transparent 82%
),
/* Purple-magenta accent, top-right the "cosmic" highlight from
the mockup's dark variant. Brings TCG/celestial brand energy. */
radial-gradient(
ellipse 65% 50% at 95% -8%,
rgba(168, 85, 247, 0.26) 0%,
rgba(124, 58, 237, 0.10) 40%,
transparent 68%
),
/* Subtle vertical wash: pure deep navy → slightly purpler bottom. */
/* Base diagonal wash: warm-tinted deep aubergine bottom-left
cool-tinted deep indigo top-right. 45deg matches the light
sources. The midpoint stays near the previous deep-navy so
chrome surfaces still have a calm substrate to blur against. */
linear-gradient(
180deg,
rgba(13, 14, 26, 1) 0%,
rgba(17, 18, 38, 1) 55%,
rgba(22, 18, 45, 1) 100%
45deg,
rgba(40, 16, 22, 1) 0%,
rgba(17, 18, 38, 1) 50%,
rgba(28, 22, 58, 1) 100%
);
background-attachment: fixed;
color: var(--text-primary-dark);
@ -340,6 +345,21 @@ body {
--bg-primary-rgb: 254, 252, 248;
--bg-secondary-rgb: 247, 243, 237;
--bg-tertiary-rgb: 240, 230, 214;
/* Two-light-source edge glow tokens (2026-06-04 operator request:
"let's have the corners or the edges of our sections respond as
if those two are light sources").
Each token is a complete box-shadow declaration with the offset
pointing toward the matching light source the colored shadow
bleeds outward from the chip's bottom-left edge (warm) and top-
right edge (cool), reading as light catching on the rim.
Light theme alphas are softer; the dark theme override below
bumps them since the deeper substrate can absorb more saturation
before the effect over-reads. Compose into chip shadow stacks
ahead of rim-light-inner + elevation tokens so the directional
glow is the dominant edge cue. */
--edge-light-warm: -6px 6px 18px rgba(255, 110, 0, 0.16);
--edge-light-cool: 6px -6px 18px rgba(99, 102, 241, 0.12);
}
/* Dark theme variables */
@ -366,6 +386,13 @@ body {
--input-border: var(--input-border-dark);
--input-text: var(--input-text-dark);
--input-placeholder: var(--input-placeholder-dark);
/* Dark-theme edge glows alphas bumped since the deeper substrate
can take more saturation before reading as garish, and so the
"lit by ember + lit by purple" effect carries on dark theme (the
default for first-time visitors). See :root for full rationale. */
--edge-light-warm: -8px 8px 26px rgba(255, 110, 30, 0.34);
--edge-light-cool: 8px -8px 26px rgba(139, 92, 246, 0.28);
}
/* Custom component styles - Fire-themed */
@ -724,10 +751,23 @@ body {
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 panels the canonical floating-chrome surface. 2026-06-04
two-light-source pass: `--edge-light-warm` (offset toward bottom-
left) and `--edge-light-cool` (offset toward top-right) lead the
shadow stack so every glass surface picks up the directional rim
glows from the matching corners of the body gradient. Order
matters directional glows must paint OUTSIDE the structural
elevation shadow, so they sit at the top of the stack (CSS paints
the LAST listed shadow lowest visually, but for box-shadow the
list order doesn't matter for compositing what matters is each
shadow's geometry. They're listed warmcoolrimelevation as a
readability convention). */
.glass-panel {
background: var(--glass-surface-mid);
backdrop-filter: blur(12px) saturate(180%);
box-shadow:
var(--edge-light-warm),
var(--edge-light-cool),
var(--rim-light-inner),
var(--rim-light-outer),
var(--elevation-ambient);
@ -737,6 +777,8 @@ body {
background: var(--glass-surface-high);
backdrop-filter: blur(20px) saturate(180%);
box-shadow:
var(--edge-light-warm),
var(--edge-light-cool),
var(--rim-light-inner),
var(--rim-light-outer),
var(--elevation-pronounced);