# Sprint 7 — Design Refresh: Terminal-SOC Aesthetic > Branch : `sprint/7-design` · Worktree : `.claude/worktrees/sprint-7-design` · Base : `main` @ `e27babe` ## §0 — Binding decisions (locked with user, 2026-06-09) 1. **Visual direction**: Bloomberg / Terminal-SOC — dense, brutalist, semantic colors strong, no ornament. 2. **Border-radius**: **0 everywhere** except status pills (`rounded-pill`) and avatars (round). All buttons, cards, modals, inputs, dropdowns, tables, tags → angular. 3. **Palette**: KEEP current (`#024ad8` primary blue, `slab #111827`, `canvas/paper/cloud/fog/ink` light+dark vars). ADD semantic tokens `success-green` + `warn-amber` (confirmed scope add — needed for SOC-grade status legibility on dashboards and badges). 4. **Scope**: Refonte globale en 1 sprint (all 8 pages + 17 components + tokens + DESIGN.md). 5. **Monospace**: data-only — JetBrains Mono for IDs, dates ISO, commands, execution output, MITRE techniques, metrics. Inter stays for body/labels/headers. 6. **Mono font**: JetBrains Mono, bundled locally via `@fontsource-variable/jetbrains-mono` (consistent with existing Inter bundle). 7. **Modes**: KEEP light + dark both. Toggle stays. 8. **Animations**: **Brutalist — zero transition**. Remove all `transition-*` utilities, focus rings sharp, hover instantaneous. 9. **Display scale reduction**: locked. `display-xxl 72→40`, `display-xl 56→32`, `display-lg 44→28`, `display-md 32→24`, `display-sm 24→20`, `display-xs 20→16`. Headers stay modest in terminal aesthetic — no editorial flourish at hero scale. ## §1 — Pre-work checks (team-lead, before dispatch) - [ ] Confirm `tasks/lessons.md` has nothing contradicting this brief - [ ] Verify uncommitted `.claude/agents/frontend-builder.md` patch (Skill mandatory) is restored in worktree — sprint hygiene - [ ] Send plan to **spec-reviewer** for 2-pass approval (vs SPEC.md, vs §0 binding decisions). MUST be APPROVED before any code touches `frontend/`. - [ ] After approval: dispatch frontend-builder with this todo as brief. ## §2 — Sprint hygiene (commit #1) - [ ] `chore(agents): frontend-builder must invoke Skill frontend-design before UI work` — lands BEFORE design work so the agent itself triggers the Skill on first call this sprint. ## §3 — Foundation: DESIGN.md + tokens (commits #2–#4) ### §3.1 DESIGN.md rewrite (commit #2) - [ ] Replace current HP-catalog doc (346 lines, off-brand) with terminal-SOC spec covering: - **Overview**: brutalist BAS Purple Team console, angular surfaces, semantic color signals, data-monospace hybrid - **Colors**: keep all existing tokens with **role redefinition** for terminal-SOC context. Primary = neutral action. Bloom-deep/coral = destructive/alert. ADD `success` (green) + `warn` (amber) — locked §0 D3 — with light + dark variants and WCAG AA contrast on slab and canvas surfaces - **Typography**: Inter (body/headers/labels) + JetBrains Mono (data). Concrete tier table with size/weight/line-height - **Layout**: tighter spacing (replace `section 80px` → `section 48px`; halve card padding on dense surfaces) - **Shapes**: ALL radii = 0 except `rounded-pill` reserved for status badges and avatars - **Components**: re-document `btn-*`, `text-input`, `card-*`, `badge-*`, `nav-*`, `modal-*` with brutalist specs (no shadow, hairline borders, zero transition) - **Do's/Don'ts**: zero rounded on conteneurs; zero transitions; semantic colors only on status surfaces; mono ONLY for data, never headers - **Iteration guide** - [ ] Doc lives in English (in-repo). ### §3.2 Tailwind token refresh (commit #3) - [ ] `frontend/tailwind.config.ts`: - `borderRadius`: keep `none: 0`, keep `pill: 9999px`. Drop or stop using `xs/sm/md/lg/xl` for surfaces — keep only if a badge variant needs `2px` - ADD `fontFamily.mono`: `['JetBrains Mono Variable', 'JetBrains Mono', 'ui-monospace', 'monospace']` - ADD semantic colors (locked §0): `success: { DEFAULT, soft }` (green) + `warn: { DEFAULT, soft }` (amber). Pull dark-mode variants from CSS vars too. Suggested anchors — `success #16a34a` (dark `#22c55e`), `warn #d97706` (dark `#f59e0b`); design-reviewer audits WCAG AA at both modes. - Reduce `display-*` scale (locked §0): `display-xxl 72px → 40px`, `display-xl 56→32`, `display-lg 44→28`, `display-md 32→24`, `display-sm 24→20`, `display-xs 20→16` — terminal headers are modest - Drop `tracking[0.7px]` and uppercase from `button-md` (still ALLCAPS via class but no letter-spacing) - Drop shadow tokens or keep but ensure no component class applies them - [ ] `frontend/src/styles/index.css`: - Drop `font-size: 16.5px` root bump (back to `16px` standard) - Set body `line-height: 1.4`, tighten headings to 1.1 - Rewrite `.btn-primary/ink/outline/outline-ink`: `rounded-none`, NO `transition-colors`, keep `uppercase`, drop `tracking-[0.7px]`, keep `h-11` (touch target) - Rewrite `.text-input`: `rounded-none`, focus border-primary sharp (no halo), no transition - Rewrite `.card-product` and any `.card-*`: `rounded-none`, no shadow, 1px hairline border for separation - Rewrite `.badge-pill-*`: keep `rounded-pill` ONLY here (status badges); strip uppercase if applied - Rewrite `.modal-backdrop`: same dark backdrop, no rounded for the modal frame itself - ADD `.mono` utility or rely on Tailwind's `font-mono` (preferred) for data cells ### §3.3 JetBrains Mono bundle (commit #4) - [ ] `cd frontend && npm i @fontsource-variable/jetbrains-mono` - [ ] `frontend/src/styles/fonts.css`: add `@import '@fontsource-variable/jetbrains-mono'` - [ ] No CDN. Confirms via `npm ls @fontsource-variable/jetbrains-mono`. ## §4 — Component sweep (commit #5) Rule: `rounded-*` → `rounded-none` unless explicitly an avatar or status pill; remove `transition-*`; data text → `font-mono`. - [ ] `Layout.tsx`: nav-bar/utility-strip already angular — confirm. Remove `transition-colors` on theme button and hover-underline transitions. Mono font for any data label exposed (e.g. user.role pill). - [ ] `StatusBadge.tsx`: KEEP rounded → switch to `rounded-pill` (it's a status pill, locked exception). Audit semantic mapping (planned/active/closed → semantic tokens once added). - [ ] `SimulationStatusBadge.tsx`: same — `rounded-pill`, semantic colors aligned with new tokens. - [ ] `FormField.tsx`: angular inputs (already via `.text-input` recipe — confirm). - [ ] `EmptyState.tsx`: angular wrapper. No rounded illustration container. - [ ] `ErrorState.tsx`: angular. Bloom-deep border-left if signalling. - [ ] `LoadingState.tsx`: drop any rounded spinner background. Spinner shape ok. - [ ] `ConfirmDialog.tsx`: angular modal. Buttons via new `.btn-*` recipes. - [ ] `Toast.tsx`: angular. Semantic color border-left strip. - [ ] `ExportEngagementButton.tsx` (sprint 6): angular dropdown menu. Audit `rounded-*` in the menu/item classes. - [ ] `MitreMatrixModal.tsx`: angular modal. Cells already grid — confirm no rounded. - [ ] `MitreTechniquePicker.tsx`: angular dropdown. - [ ] `MitreTechniquesField.tsx`: angular chips. - [ ] `MitreTechniqueTag.tsx`: angular tag (NOT pill — terminal tag, not a status). Decide once and apply consistently across MITRE surfaces. - [ ] `TemplatePickerModal.tsx`: angular modal. - [ ] `SimulationList.tsx`: angular table. Data cells (commands, executed_at, MITRE techniques) → `font-mono`. - [ ] `ProtectedRoute.tsx`: no visual surface, skip. ## §5 — Page sweep (commit #6) For each page: header/body/footer review, replace rounded card containers with angular hairline-bordered containers, ensure data cells use mono. - [ ] `LoginPage.tsx`: angular form card. Drop ornament. - [ ] `EngagementsListPage.tsx`: angular table container (currently `.card-product` with rounded-xl). Data cells (dates) → mono. - [ ] `EngagementDetailPage.tsx`: angular header section. Engagement metadata (start/end dates, IDs, created_at) in mono. Simulations table covered via SimulationList. - [ ] `EngagementFormPage.tsx`: angular form. Date inputs ok. - [ ] `SimulationFormPage.tsx`: angular form. Commands textarea → mono. - [ ] `TemplatesListPage.tsx`: angular list. - [ ] `TemplateFormPage.tsx`: angular form. Commands field → mono. - [ ] `UsersAdminPage.tsx`: angular table. Username column → mono (it's an ID). ## §6 — Test refresh (commit #7) - [ ] `cd frontend && npm run test -- --run` — identify failing assertions on class names (`rounded-xl`, `card-product`, etc.). Update tests to use semantic queries (role, name, data-testid) where possible; if test asserts on visual class, update assertion to the new class. - [ ] No new vitest tests added (visual sprint, behavior unchanged). - [ ] Playwright e2e: should be `data-testid`-driven — run full suite to confirm no regression. If breakage, fix the testid not the test logic. ## §7 — Reviews - [ ] **spec-reviewer** (pre-dispatch, §1): plan validated vs SPEC.md and §0 binding decisions - [ ] **frontend-builder** (§2-§6): implements, runs typecheck/lint/test, delivers screenshots for design-reviewer (every page + key states, light+dark) - [ ] **design-reviewer** (post-frontend): reviews screenshots + diff vs new DESIGN.md. Brutalist consistency, mono-discipline (only data), zero-rounded discipline. - [ ] **code-reviewer** (post-design): reviews frontend diff for duplication, lost reuse, dead code. - [ ] **test-verifier**: skipped this sprint (no new US, no behavior change). - [ ] **backend-builder**: idle, no work this sprint. ## §8 — Git workflow - [ ] Branch: `sprint/7-design` (already created from origin/main) - [ ] Commits: conventional, one per logical group (§2 to §7) - [ ] PR via `make open-pr` (Gitea pattern, per memory) - [ ] PR body in `tasks/pr-body-sprint-7.md` - [ ] CHANGELOG.md sprint 7 section ## §9 — Risks & mitigations - **R1 — Tests break en masse**: many vitest specs may assert on class strings (e.g., `rounded-xl` on cards). Mitigation: update assertions to semantic queries; budget half a phase to test repair. - **R2 — Dark mode contrast lost**: angular + new semantic colors may break WCAG AA contrast on dark slab. Mitigation: design-reviewer audits both modes; adjust the dark variant hex to meet WCAG AA. Rollback the success/warn family only if no accessible green/amber is achievable on the dark slab. - **R3 — Mono overflow**: JetBrains Mono is wider than Inter at same px. Cell widths in tables may overflow. Mitigation: keep `table-layout: fixed` and `word-break: break-word` (pattern reused from PDF export CSS sprint 6). - **R4 — DESIGN.md rewrite churn**: replacing 346 lines is a big diff. Mitigation: rewrite atomically in commit #2, keep token names consistent so downstream commits don't drift. - **R5 — User taste mismatch**: "Bloomberg/SOC" may not match user's mental image. Mitigation: design-reviewer screenshots → user check-in BEFORE merge. ## §10 — Definition of Done - [ ] All §0 decisions reflected in DESIGN.md + tokens + components + pages - [ ] `npm run typecheck` clean - [ ] `npm run lint` clean - [ ] `npm run test -- --run` all green - [ ] Backend untouched — `git diff origin/main -- backend/` empty - [ ] Playwright e2e green (223 baseline preserved) - [ ] Screenshots delivered (light + dark) for every page + key states - [ ] DESIGN.md rewritten, no HP/Forma/wordmark/chevron references - [ ] CHANGELOG.md sprint 7 section - [ ] PR opened on Gitea - [ ] User merges PR → sprint closed → team idle ready for sprint 8 ## §11 — Lessons being applied from prior sprints - **SPEC/DESIGN commit-first**: DESIGN.md rewrite is commit #2 (after sprint hygiene). No design churn mid-sprint. - **spec-reviewer 2-pass**: APPROVED before dispatch, not after. - **Team idle policy**: 6 agents already mounted, no shutdown until PR merged. - **frontend-builder MUST invoke `Skill frontend-design`** before UI work (the patch commits as #1, takes effect immediately for the same sprint).