# Phase 78 — Static background (the animated glow layers are removed) **Source:** `TODO.md` L4 — "Remove the animated css background, it's too resource intensive" **Story:** n/a (TODO-derived — supersedes the fading-glow contract of `.agents/user_stories/background-no-motion.md` (phase 25), which itself superseded `background-animation.md` (phase 08)) **Context:** `frontend/assets/styles.css` (the background block, ~lines 70–155: the STATIC grid texture on `body::before`, the three opacity-fading glow spots on `body::after` / `html::before` / `html::after`, the `@keyframes bg-glow-a/b/c` blocks, and the `prefers-reduced-motion` rule that stills those layers), `tests/unit/test_background_animation.py` + `tests/unit/test_background_no_motion.py` (source-level pins of the glow contract), `tests/e2e/test_background_no_motion.py` (the phase-25 suite — computed-style fade assertions) + `tests/e2e/test_background_animation.py` (the phase-22 E2E repurposed as the phase-25 no-motion regression — same story, `background-no-motion.md` — its fade assertions directly contradicted by the new contract), `tests/e2e/test_dark_tech_theme.py` (palette assertions — must stay green UNCHANGED), `frontend/assets/themes/` (configurable theme files — the built-in palette is the scope; verify they carry no glow rules). ## Objective Delete the animated background: the three opacity-fading glow pseudo-layers and their keyframes stop existing — the owner reports they are too resource-intensive (the infinite CSS animations run continuously on every page, in every tab). The background becomes fully static: the 44px grid texture stays (it is static — zero animation cost). ## Owner decisions (chat, 2026-09-06 — recorded per AGENTS.md rule 3) - **A2 confirmed:** "the animated css background" = the three fading glow spots (the ONLY animated part of the background). The static grid (`body::before`) STAYS. If the owner later wants the grid gone too, that is a one-line follow-up — out of scope here. - Other UI animations (the mobile nav slide, modal fades, typing dots, …) are NOT the background — they stay untouched. ## Design (shared by both tasks) - `body::before` (the grid) stays BYTE-IDENTICAL: 44px cells, 1px lines at 60% `--line` alpha, the widened radial mask. - Deleted from `styles.css`: the `body::after`, `html::before`, and `html::after` glow rules; the three `@keyframes bg-glow-*` blocks; the `prefers-reduced-motion` rule whose only job was stilling these background layers — FIRST verify it references nothing else (if any non-background selector sits in it, strip only the background selectors). - The block's comment header (the phase-08/25 owner-direction prose) is replaced with a 3–4 line phase-78 note: the animated layers were removed at owner direction (TODO.md L4) as too resource-intensive; the static grid remains. - **Test rewrites (the house pattern — the premise changed, so the suites pin the NEW contract; the phase-76 precedent rewrote the phase-20 suite the same way):** - `tests/unit/test_background_no_motion.py` → rewritten as the static-contract source pin: no `@keyframes bg-glow-*` in `styles.css`; none of the four pseudo-element selectors (`body::before/after`, `html::before/after`) carries an `animation:` declaration; `body::before` (the grid) is present with its 44px `background-size` and no animation. - `tests/unit/test_background_animation.py` → **DELETED** (the phase-25 unit source-pin suite — its entire premise, three fading glows / exactly three `bg-glow-*` keyframe blocks, is gone; superseded chain 08 → 25 → 78). - `tests/e2e/test_background_no_motion.py` → rewritten: Playwright computed-style checks — the three glow pseudo-elements report `animation-name: none` and no background-image; `body::before` still carries the grid background. Docstring updated to the phase-78 contract. - `tests/e2e/test_background_animation.py` → **DELETED** (the phase-22 E2E repurposed as the phase-25 regression — its premise, that the glow layers fade, is removed; its story (`background-no-motion.md`) is carried on by the rewritten `test_background_no_motion.py`, the single story suite going forward). - `tests/e2e/test_dark_tech_theme.py` must stay green UNCHANGED — the PALETTE is untouched; only the light spots go. - `tests/unit/test_themes.py` + `frontend/assets/themes/indigo.css` — verify no glow/keyframe carry-over; if a theme file re-introduces animated background layers, the owner's direction applies to the whole background (report before deviating — the built-in palette is the confirmed scope). ## Dependencies — (none) ## Tasks 1. `01_remove_glow_layers.md` — the CSS deletion + the four test-file rewrites/deletions. 2. `02_regression_sweep_commit.md` — theme + smoke E2E, the visual check, the full gate, the atomic commit. ## Testing & Quality - Unit: the rewritten source-pin file + `tests/unit/test_themes.py` green. - E2E: the rewritten static-background suite in isolation (DB up) + `test_dark_tech_theme.py` + `test_smoke.py` unchanged-green. - Coverage: **>90%** on `app/` (CSS-only phase — the floor is preserved). ## Completion Criteria - [ ] No `animation` / `@keyframes` remains for the background in `styles.css` (`rg "bg-glow" frontend/ tests/ app/` → zero hits); the grid renders as before (visual check in a real browser). - [ ] The rewritten suites are green; the deleted suites are gone; `test_dark_tech_theme.py` green UNCHANGED. - [ ] `uv run pytest` green; `uv run pytest --cov=app --cov-report=term-missing` >90%; `uv run ruff check . && uv run pyright` clean. - [ ] One atomic `--no-gpg-sign` Conventional-Commits commit (e.g. `perf(ui): remove the animated background glow layers — static grid only`); phase dir moved to `.agents/phases/complete/`.