Files
brain-of-reese/.agents/user_stories/dark-tech-theme.md
T
ducoterra dbf2af26c6 refactor(agents): migrate .agent/ planning tree to .agents/
Standardize on the .agents/ directory (shared with project skills):
phases/, user_stories/, reports/, screenshots/, validate.sh, and
phase-sessions/ + pipeline.log all move to .agents/ (git mv preserves
history; runtime artifacts move alongside).

Updates every reference in AGENTS.md, README.md, .gitignore, app
docstrings, and test story headers. Historical KB content in data/
and the runtime pipeline.log transcript are left untouched.
2026-09-05 10:57:07 -04:00

4.2 KiB

Story: Dark Tech Theme

Phase: 08_story_dark_tech_theme.md · E2E: tests/e2e/test_dark_tech_theme.py

Narrative

As a user, I want Brain of Reese to look like a serious piece of my infrastructure — dark, technical, free of emojis, with a subtly animated background — so the app feels at home next to my dashboards and is comfortable to use at night, instead of a generic light-mode chat widget.

  • Given the v1 UI (light palette, emoji avatars/brand/favicon, static background)
  • When the theme phase is complete
  • Then every page is dark with a tech aesthetic, no emoji appear anywhere in the UI chrome, a subtle pure-CSS animated background (drifting grid + breathing glows) is visible but never distracting, all layout metrics and behavior are unchanged, and WCAG 2.1 AA still holds on the new palette.

Acceptance criteria

  1. Dark palette (tokens in the phase file) applied to both pages (/, /sources.html); every text/background pair ≥4.5:1 — computed, not eyeballed.
  2. Zero emoji in UI chrome — HTML templates, JS-rendered chrome, favicon, CSS — replaced by inline SVG glyphs. An integration test enforces this as a permanent regression guard.
  3. Subtly animated background: a fine drifting grid + two slow breathing radial glows, pure CSS, zero JS, pointer-events: none, never blocking or dimming content.
  4. prefers-reduced-motion: reduce → background animations disabled (static grid + glows remain).
  5. No-CDN invariant holds on both pages (all script/link refs local or data:).
  6. Layout metrics unchanged (PLAN §7.1): 72rem frame, 46rem centered chat column, full-width Sources table, mobile rules; behavior unchanged (chat state machine, chips, banners).
  7. WCAG 2.1 AA: landmarks, labels, skip link, :focus-visible, live regions intact on the new palette.
  8. LLM answer content is out of scope (the model may output anything; the rule binds UI chrome only).
  9. Whole pytest suite green, app/ coverage >90%, story E2E green in isolation.

UI Visualization & Structure

  • Palette (all pairs computed, ≥4.5:1): page #0a0e17, surface #121a2e, ink #e8ebf4 (14.5:1 on surface), ink-soft #9aa4bd (6.9:1), line #26304a, brand #6d78f2 with dark text #0a0e17 (5.2:1 — white on brand is 3.7:1, forbidden for text), brand-soft #232b52 + brand-ink #a5b4fc (6.9:1), deflection #2b2110/#fbbf24 (9.5:1) + border #f59e0b, error #2d1318/#fca5a5 (9.1:1), ok #10241b/#6ee7a8 (10.6:1).
  • Busy button keeps its #a5b4fc background (the existing unit test asserts the token) with a dark arc (#0a0e17, 9.7:1).
  • Avatars: brain → inline SVG circuit-node glyph; user → minimal silhouette SVG; aria-hidden retained.
  • Favicon / brand mark: tech SVG mark (hex + node), still an inline data: URI (no CDN).
  • Tech details: mono wordmark + stat values, 1px --line borders, radii 10px/6px, a 2px brand→cyan gradient hairline under the sticky header.
  • Background: body::before grid (44px cells, ~35% alpha 1px lines, radial mask fade, 60s seamless diagonal drift); body::after two radial glows (indigo ~14% top-left, cyan ~10% bottom-right, 14s breathing). Both position: fixed; inset: 0; pointer-events: none.

Playwright Mapping Rule

Test Scenario → tests/e2e/test_dark_tech_theme.py (mock LLM, seeded KB):

  1. test_dark_palette_and_contrast — body background is rgb(10, 14, 23); computed ink-on-surface and brand-button text/background pairs ≥4.5:1 (same contrast helper as Phase 07).
  2. test_no_emoji_in_chrome — neither page's document.body.innerText nor raw outerHTML contains any emoji code point.
  3. test_animated_background — computed style of body::before has a non-none background-image and animation-name; body::after animates too.
  4. test_reduced_motion_honored — a browser context created with reduced_motion="reduce" → animation-name: none on both layers.
  5. test_behavior_unchanged_smoke — on-topic question streams an answer + a source chip + the send button recovers (state machine intact under the new skin).
  6. test_all_assets_local — every script[src] / link[href] on both pages is relative or data: (no CDN).