Reviewed by /design-review on 2026-05-22 against the live admin (/admin/, /admin/observability/, /admin/replay/). Audited via CDP through real Chrome behind Cloudflare Access. Two outside-voice passes (Codex source audit + Claude consistency subagent) added to the live findings.
Full audit + screenshots + baseline.json live in ~/.gstack/projects/dghauri0-ihnyc-rc-cal-landing/designs/design-audit-20260522/ on the operator’s machine. This doc is the durable summary that should outlive that local artifact.
Baseline
| Metric | Grade | Notes |
|---|---|---|
| Design Score | B- | Solid information design; sloppy plumbing underneath |
| AI Slop Score | A | No purple gradients, no icon-circle SaaS template look, no decorative blobs |
| Visual Hierarchy | B | KPI numbers dominate correctly |
| Typography | C+ | Inverted h1/h2/h3 sizes; h3 drifts between 13px and 15px across pages |
| Color & Contrast | A- | Coherent slate-on-white + 4-color semantic system |
| Spacing & Layout | C+ | Magic-number padding everywhere; KPI strip chrome drifts admin/replay vs observability |
| Interaction States | D | No :focus-visible rings; drawer aria-hidden but DOM-present; rows mouse-only |
| Responsive | C | Admin has column-toggle; observability and replay don’t |
| Performance | A | LCP 275ms, no CLS |
Findings (18 total)
4 HIGH, 8 MEDIUM, 6 POLISH. Five carry cross-model confidence (both Codex and the Claude subagent flagged independently): triplicated CSS tokens, missing focus rings, shell drift across pages, ship-dark jargon in UI, deliverability grid hard-coded 6-up.
The single biggest revelation: each of the three admin pages re-declares the same :root color token block inline, plus the same [data-theme="dark"] override block. They’re identical today only by discipline — a --accent-soft tweak today is a 3-place edit that will eventually drift.
What shipped this pass (PR #9)
Tier A (quick wins, no functional behavior change) + Tier B (keyboard a11y, additive only). Seven atomic commits, one per finding:
| Finding | Type | Effect |
|---|---|---|
F-004 ship-dark → flag off | copy | Removes dev jargon from observability status pill |
| F-006 Sparkline axis separator | copy | 30d ago · today instead of visually colliding “30d agotoday” in narrow drawer |
| F-015 Drop emoji from Test Mixpanel | copy | Operator UI shouldn’t lean on emoji for visual signal |
| F-013 Drop label pills from deliverability tiles | content | Pills previously always rendered green regardless of value, miscommunicating “everything healthy” when actually “no data yet” |
F-001 :focus-visible rings | a11y CSS | :where() selector keeps specificity at 0; mouse interactions unchanged; keyboard users finally see focus |
F-002 Drawer inert when closed + focus management | a11y JS | Closed drawer is no longer tab-reachable; open captures activator, close restores focus |
| F-011 Rows keyboard-actionable | a11y HTML+JS | tabindex=0 role=button + Enter/Space keydown mirroring click path with same kebab/menu skip rules |
Decisions held during triage
| Decision | Chosen | Alternative rejected |
|---|---|---|
F-016 /admin/* CSP block in _headers | Defer — touching CSP near Cloudflare Access gating needs its own deploy-test cycle per ops rules | Add default-src 'self'; img-src 'self' data:; … inline now |
F-015a Ghosts filter chip → Inactive | Keep “Ghosts” — operator-chosen term with clear tooltip (“Active+unrevoked tokens that haven’t fetched in 30+ days”) | Rename to neutral “Inactive” / “Lapsed” / “Dormant” |
F-017 h2.section:first-child margin reset on admin | Keep current 26px top margin — reads as intentional breathing room under the anomaly banner | Match obs/replay behavior |
| Big system fixes (F-003, F-005, F-007, F-008, F-009, F-010, F-012) | Defer to dedicated Tier C PR | Bundle into this PR |
Admin UI conventions (preserve when editing)
These are now load-bearing. Future edits to public/admin/**/*.html should keep them.
-
:focus-visiblering is universal. Every interactive element (buttons, links, inputs, selects, summary,[tabindex]) gets a 2px--accentoutline via a:where()rule placed near the top of each page’s<style>block. Do not addoutline: noneon:focuswithout replacing with a:focus-visiblerule. -
Drawer is
inertwhen closed. Always toggle theinertattribute alongsidearia-hiddenso closed drawer controls aren’t tab-reachable. On open, capturedocument.activeElement; focus the drawer’s close button. On close, restore focus to the captured element. -
Subs table rows are activators, not decorations. Each
<tr data-token-id>carriestabindex="0",role="button", andaria-label. The page-level keydown handler mirrors the click path’s skip rules for kebab/menu/inline-action descendants. -
Status pills mean state, not labels. A pill that always renders green regardless of value is decoration, not signal — drop it. The deliverability tiles followed this rule after F-013; new tiles should too.
Tier C — known deferred work (next PR)
Listed in priority order. The first item is the unlock for most of the others.
- F-005 Extract
/public/admin/_admin.css— single<link rel="stylesheet">per page, hosts the token block, dark-theme override, focus-visible rule, KPI chrome, section headings, skeleton utility. ~300 LOC of duplication collapses; F-001 stops being three identical CSS additions. - F-003 Heading hierarchy rework. Rename
h2.section→<p class="eyebrow">(it’s a label, not a heading). Introduce real per-page<h2>page titles (Admin / Observability / Replay) at 18–20px semibold. Demoteh1.app-titleto non-heading or hide from AT. - F-007 Consolidate KPI strip chrome — promote the admin/replay “stitched strip” pattern, remove
.health-cardborder chrome from observability. - F-008 Deliverability grid →
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr))so the 6-tile row wraps gracefully at narrow viewports. - F-009 Skeleton-loader utility. Observability’s first viewport currently reads as broken for ~200ms while five “Loading…” placeholders sit empty.
- F-010 Touch-target standardization. Introduce
--touch-min: 32pxtoken; tab links currently 22px on admin/replay vs 26px on observability. - F-012 Mobile responsive overhaul — extend admin’s column-toggle to replay and observability.
- F-014 Drawer “active (token revoked)” status — separate fields instead of internally-contradictory parenthetical.
- F-016
/admin/*CSP block (see Decisions above). - F-018 Default sort — surface healthy active subs above revoked/expired rows so first-impression isn’t a wall of red status pills.