fix(ui): background no longer moves — static grid, three glow spots fading in and out on their own slow cycles (owner 2026-08-25)

This commit is contained in:
2026-08-25 09:43:19 -04:00
parent 1e6ae360e0
commit 025f57beb5
14 changed files with 1454 additions and 223 deletions
+66 -30
View File
@@ -57,18 +57,37 @@ body {
min-height: 100dvh;
}
/* ---------- Animated background (pure CSS, zero JS — phase 08) ---------- */
/* ---------- Animated background (pure CSS, zero JS — phase 08; reworked
phase 25: no movement, only fading light) ----------
Owner direction (2026-08-25, verbatim): "It should be smooth,
fluxuating, dimming and brightening, but not moving. Different bright
spots should slowly fade in and out."
- NO movement anywhere in the background: no grid drift, no
transform/scale, no background-position animation. The 44px/60s grid
drift (0.73px/s, diagonally down-right) rasterizes sub-pixel by
sub-pixel and reads as a once-per-second jitter; the 14s whole-layer
opacity+scale pulse reads as a uniform blink. Both are gone.
- Three independent soft glow spots, each fading in and out on its own
SLOW opacity-only cycle — 26s / 34s / 42s, ease-in-out, with negative
delays (-12s, -23s) so the cycles run out of phase (LCM 4641s: the
composite pattern effectively never repeats within a viewing
session). The total light fluxuates smoothly and irregularly.
- html::before / html::after join body::before / body::after as
background layers: <html> is the root stacking context, so their
z-index:-1 pseudo-elements paint ABOVE the var(--bg) canvas and
BELOW the transparent, non-stacking <body>'s content — the
no-occlusion contract (html owns the canvas, body stays
transparent) is unchanged.
- No filter (phase-08 no-blur perf anchor), no JS, no new assets;
opacity-only keyframes stay compositor-friendly.
- prefers-reduced-motion: reduce stills all four layers. */
/* Fine drifting grid: 44px cells, 1px lines at 60% --line alpha, masked
with a radial fade (visible across most of the viewport, fading to the
corners). The drift delta (44px) equals one cell, so the loop is
seamless.
Phase 22 fix (owner report 2026-08-24, roadmap A3): the original 35%
alpha + 25%-black mask made the 0.73px/s drift invisible in a real
viewport (measured: ~1.4/765 mean pixel change over 5s in the grid
zone) — only the glow swing was perceived, so the background read as
"just blinking". Higher line alpha + wider visible mask radius make the
same 60s one-cell drift clearly readable as smooth motion. */
/* Static grid texture: 44px cells, 1px lines at 60% --line alpha, masked
with a widened radial fade (visible across most of the viewport,
fading to the corners). Phase 25 (owner 2026-08-25): the grid drift is
REMOVED — the 0.73px/s sub-pixel drift rasterizes as a once-per-second
down-right jitter, and the owner wants no movement. The grid stays as
a still texture. */
body::before {
content: "";
position: fixed;
@@ -81,34 +100,50 @@ body::before {
background-size: 44px 44px;
-webkit-mask-image: radial-gradient(140% 110% at 50% 0%, black 40%, transparent 90%);
mask-image: radial-gradient(140% 110% at 50% 0%, black 40%, transparent 90%);
animation: bg-grid-drift 60s linear infinite;
}
@keyframes bg-grid-drift {
from { background-position: 0 0, 0 0; }
to { background-position: 44px 44px, 44px 44px; }
}
/* Two large, soft radial glows: indigo top-left, cyan bottom-right —
14s ease-in-out breathing (opacity + scale). No filter:blur (perf).
Phase 22 fix (owner report 2026-08-24, roadmap A3): the 0.65↔1 opacity
swing was the ONLY visible motion on the page, so it read as a blink.
Narrowed to 0.85↔1 — a gentle breathe, not a pulse. */
/* Glow spot A — the phase-08 indigo (top-left): one soft radial spot
fading in and out on its own 26s opacity-only cycle. */
body::after {
content: "";
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-image:
radial-gradient(circle 56rem at 12% 8%, rgb(109 120 242 / 0.14), transparent 62%),
radial-gradient(circle 60rem at 88% 92%, rgb(34 211 238 / 0.10), transparent 62%);
animation: bg-glow-breathe 14s ease-in-out infinite alternate;
background-image: radial-gradient(circle 56rem at 12% 8%, rgb(109 120 242 / 0.14), transparent 62%);
animation: bg-glow-a 26s ease-in-out infinite;
}
@keyframes bg-glow-breathe {
from { opacity: 0.85; transform: scale(1); }
to { opacity: 1; transform: scale(1.05); }
/* Glow spot B — the phase-08 cyan (bottom-right): 34s cycle, -12s delay
(out of phase with spot A). */
html::before {
content: "";
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-image: radial-gradient(circle 60rem at 88% 92%, rgb(34 211 238 / 0.10), transparent 62%);
animation: bg-glow-b 34s ease-in-out -12s infinite;
}
/* Glow spot C — a third indigo (bottom-left): 42s cycle, -23s delay
(out of phase with spots A and B). */
html::after {
content: "";
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-image: radial-gradient(circle 52rem at 14% 86%, rgb(109 120 242 / 0.09), transparent 62%);
animation: bg-glow-c 42s ease-in-out -23s infinite;
}
/* Opacity-only fades — nothing but opacity may appear in any bg-*
keyframe (the no-movement contract, phase 25). */
@keyframes bg-glow-a { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }
@keyframes bg-glow-b { 0%, 100% { opacity: 0.20; } 50% { opacity: 1; } }
@keyframes bg-glow-c { 0%, 100% { opacity: 0.15; } 50% { opacity: 1; } }
.container {
width: 100%;
max-width: 72rem;
@@ -797,9 +832,10 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
.spinner { animation-duration: 2s; }
}
/* The background layers are the only other motion on the page: under
reduced motion they go static (grid + glows remain, just still). */
reduced motion they go static (grid + glows remain, just still) — all
four layers (phase 25: the html::before / html::after spots join). */
@media (prefers-reduced-motion: reduce) {
body::before, body::after { animation: none; }
body::before, body::after, html::before, html::after { animation: none; }
}
/* ---------- Banners ---------- */