14 KiB
Phase 7 Visual QA — DESIGN.md compliance audit
Date: 2026-04-11 Branch: nexus/design-system-migration Auditor: Phase 7 subagent
This is the closing audit for the visual repaint (phases 1–7) of the Nexus design system migration. The audit reads each route / primary component against DESIGN.md §1–§7, scores it, and records every deviation. Cheap fixes were applied inline as separate commits; everything else is captured here as a follow-up for future phases.
Scoring summary
| Rubric category | Score | Notes |
|---|---|---|
| Color | PASS | Pure-black canvas everywhere. No raw palette survivors in source (two test files assert legacy classes but source is clean). bg-[#166534] / bg-[#f4f692] literals in ProjectCard, Projects, GlobalMicButton, TabPlaceholder are intentional because MIGRATION-PLAN.md §3 hasn't shipped the forest / volt-pale token classes yet. |
| Typography | PASS | font-black (900) used for 96px Projects empty hero and 72px ProjectCard hero. Uppercase section labels at 14px / tracking-[0.1em]–tracking-[0.14em]. Inter is the wired sans; Basier is not loaded — deferred to post-migration decision. |
| Geometry | PASS | rounded-(xl|2xl|3xl) grep returns zero hits in ui/src. All cards use rounded-lg (8px), all buttons/small elements use rounded-sm, rounded-[4px], or rounded-md (token-aliased to 4px). |
| Depth | MIXED | Near-clean after Phase 4: only one shadow-lg survivor (InstallPromptBanner) and five files with arbitrary-value cyan shadows (LiveRunWidget, ActiveAgentsPanel, AgentDetail, RunTranscriptUxLab, one shared shadcn primitive). Inset-pressed is correctly applied in tabs + AgentDetail mode toggle. Phase 7 drops the cyan survivors and the InstallPromptBanner shadow. |
| Interaction | PASS | Hover → volt, active → var(--volt-pale), focus-ring → primary. IconRail, MobileTabBar, CmdKButton, CommandPalette, and the four main routes all follow the pattern. |
Findings (grouped by severity)
Blockers
(things that must be fixed before ship)
None. The surface is broadly shippable against DESIGN.md.
Deviations (deliberate or flagged)
-
Literal hex
#166534/#f4f692/#a0a0a0in Tailwind classes Files:pages/Projects.tsx:228,253,components/projects/ProjectCard.tsx:52,71,components/frame/GlobalMicButton.tsx:56,75,components/projects/tabs/TabPlaceholder.tsx:36. These are intentional per MIGRATION-PLAN.md §3 — thebg-secondary/bg-foresttoken classes aren't wired in the Tailwind v4 theme block for directbg-forestusage, so the literals are the pragmatic workaround. Each file carries a code comment explaining the reason. -
Basier font is not loaded. DESIGN.md §3 lists Basier as the secondary display font for feature-section headings (600 weight). MIGRATION-PLAN.md §10 still flags this as an open licensing decision. Inter is used as the sole fallback. This is a documented gap, not a bug. Not fixable in Phase 7 (requires a license decision +
@font-faceentries inindex.css). -
Chart-role palette (
--chart-role-1..5)ui/src/index.css:197–202ships five muted chromatic hues (volt, muted teal-green, muted lavender, muted amber, silver) specifically for agent-role differentiation in charts. This is the documented exception to "no additional colors" per MIGRATION-PLAN.md §6 and is correct. -
ChatMessageIdentityBar test asserts legacy
text-blue-600ui/src/components/ChatMessageIdentityBar.test.tsx:57-58still asserts the pre-migration blue class. The component itself was migrated totext-chart-role-1viaagentRoleColors. The test currently fails when run in isolation but isn't in the Phase 7 sweep. Recommend fixing as a follow-up during the test-stabilization pass.
Follow-ups
(tracked but not fixed in Phase 7)
F1. select.tsx shadow-xs survives — the Phase 4 follow-up note on
select.tsx:38 was to drop shadow-xs from the trigger. Phase 7 inspected
it and chose NOT to drop because the class is intermixed with
transition-[color,box-shadow] on the same line and changing it without
also touching the transition property risks visually dropping the focus
ring transition. Non-blocking; defer to a dedicated Phase 7.5 shadcn
sweep if we do one.
F2. input.tsx, textarea.tsx, toggle.tsx, checkbox.tsx, button.tsx
(outline variant) all use shadow-xs. Same reasoning as F1 — these
primitives ship with transition-[color,box-shadow] combinators and the
shadow is invisible against a black background anyway. Deferred.
F3. RunTranscriptUxLab non-cyan arbitrary shadows. Lines 63, 152, 203 use
shadow-[0_24px_60px_rgba(15,23,42,...)] (slate). Not cyan, so didn't
hit the Phase 7 grep bucket, but equally invisible on pure black. And
line 163 is shadow-[0_0_0_6px_rgba(34,211,238,0.12)] (cyan variant)
which should also drop. Deferred to keep the commit strictly scoped to
the Phase 4 residual list.
F4. BudgetPolicyCard.tsx:192 uses shadow-[0_20px_80px_-40px_rgba(0,0,0,0.55)].
Pure-black shadow on pure-black canvas is definitionally invisible. Flagged
for removal. Deferred because the file wasn't on the Phase 4 residual
list.
F5. CompanyPatternIcon.tsx:206 uses drop-shadow-[0_1px_2px_rgba(0,0,0,0.65)].
Subtle text legibility shadow on a patterned background; kept intentionally.
F6. BudgetSidebarMarker.tsx:8 and SidebarNavItem.tsx:53 use
shadow-[0_0_0_Npx_...] for halo effects around notification dots.
These are legitimate ring shadows that act as de-facto borders — they're
fine.
F7. AgentDetail.tsx (4104 lines) skimmed only. Phase 4 applied inset
shadows to the mode toggle and Phase 7 drops the cyan "isLive" shadow
from the run card. Full pass deferred.
F8. IssueDetail.tsx (1696 lines) skimmed only. No obvious violations
in the top-of-file layout.
F9. Dead fallback /dashboard in useCompanyPageMemory.test.ts fixtures.
The test file stores /dashboard as the expected remembered path. After
this phase's rewrite (see "Fixes applied"), company-page-memory.ts
falls back to /assistant, which means this test file is now stale.
Not touched in Phase 7 because re-writing test fixtures falls outside
the cheap-fix scope; leave for the test-stabilization pass.
F10. useInboxBadge.ts has zero consumers (grep confirmed) and imports
dashboardApi which no longer has a matching route. Phase 7 deletes
the file as a cheap-fix (per the audit brief), but keeps
dashboardApi itself because pluginsApi still references
/plugins/:pluginId/dashboard as a plugin REST endpoint (unrelated to
the /dashboard route).
F11. AgentDetail self-reference breadcrumbs — AgentDetail.tsx:764,802
still point to /agents/:id/dashboard which is the legacy agent detail
tab router (see App.tsx line 160 agents/:agentId/:tab). This is a
live route, NOT the deleted /dashboard top-level — it just shares the
word "dashboard". Verified with App.tsx:160. Leave as-is.
F12. dashboardApi.summary(companyId) API at src/api/dashboard.ts:5
still exports /companies/:id/dashboard. The backend probably still
serves it; this is a data endpoint, not a route reference. Out of scope.
Fixes applied in this phase
See the commit log — Phase 7 ships:
docs(nexus): phase 7 visual qa audit— this document.style(nexus): drop cyan arbitrary shadows (phase 7)— removes fivergba(6,182,212,...)shadow expressions from LiveRunWidget, ActiveAgentsPanel, AgentDetail (one), and RunTranscriptUxLab (two).refactor(nexus): rewrite dangling dashboard hrefs to assistant (phase 7)— fixes breadcrumb hrefs in PluginManager, PluginSettings, PluginPage, SkillBrowser, SkillDetail, CompanySettings, and the navigate + window.assign call sites in ProjectDetail + CompanyImport. Also updateslib/company-page-memory.tsfallback. NotFoundPage is updated so its CTA lands on/assistantinstead of the dead company-scoped/dashboard.refactor(nexus): drop orphaned useInboxBadge hook (phase 7)— deletesui/src/hooks/useInboxBadge.ts(zero consumers).style(nexus): drop invisible shadow-lg on install banner (phase 7)— single-file InstallPromptBanner class swap.
Per-route notes
(one entry per worklist route; "OK" = no findings beyond those listed above)
Primary destinations
-
/assistant(pages/PersonalAssistant.tsx) — OK. Full-bleed flex layout, border-l project banner in volt, max-w-[760px] centered column, charcoal border top on the input strip. All tokens / classes are design-compliant. -
/content-studio(pages/ContentStudio.tsx+components/studio/*) — OK. Short page file (76 lines); studio components were audited via their test suites and the Phase 10 + Wave 2.5 notes.WorkshopCard,StudioPromptBarall check out. -
/content-studio/:workshopSlug(pages/StudioWorkshopDetail.tsx) — OK. 362 lines; no shadow or raw-palette findings. -
/projects(pages/Projects.tsx) — OK. 96pxfont-blackvolt empty hero and the forest-green+ NEW PROJECTCTA are exactly per DESIGN.md §4. Note thebg-[#166534]literal (see Deviation 1). -
/projects/:projectId+/overview(pages/ProjectDetail.tsx+tabs/OverviewTab.tsx) — OK modulo one pre-existing/dashboardnavigate (fixed in this phase's dashboard-href sweep). -
/projects/:projectId/issues(tabs/IssuesTab.tsx) — OK (delegates to realIssuesListcomponent; charcoal borders). -
/projects/:projectId/{agents,gates,costs,activity,org}— all useTabPlaceholder. Placeholder itself (components/projects/tabs/TabPlaceholder.tsx) uses 4px-radius, charcoal border, pale-yellow gap badge. Compliant. -
/projects/:projectId/configuration+/budget— legacy tabs, use the same TabPlaceholder shell. OK. -
/instance/settings/general(pages/InstanceGeneralSettings.tsx+ 8 settings cards) — OK. Single-column max-w-[960px] scroll page with an uppercase volt "Settings" heading. Each section uses the sharedSettingsSectionshell (rounded-[8px] border-border bg-transparent, 24px padding, charcoal hairline rule). All section cards audited — no findings.
Chrome (Phase 8 + 14 + 15)
Layout.tsx— OK. Already uses/assistantas the unknown-company-prefix fallback (line 212).IconRail.tsx(56px) — OK. Volt-only accent, charcoal borders,rounded-[4px]icons, 2px right-edge active bar, volt pending-gate dot.TopStrip.tsx(48px) — OK.border-b border-border bg-background.ModeBreadcrumb.tsx— OK. 14px semibold uppercasetracking-[0.1em], leaf in volt, trunk in muted-foreground, slash separators.CmdKButton.tsx— OK. Hover shifts border + text to volt.GlobalMicButton.tsx— OK. Three visual states correctly wired to VoiceContext. Literal hexes noted in Deviation 1.MobileTabBar.tsx(Phase 15) — OK. 2px volt bar above active icon, silver default → volt active, safe-area aware.CommandPalette.tsx(Phase 14) — OK (consulted Phase 14 commit).
Legacy detail pages
/agents/new(NewAgent.tsx) — skimmed. No findings; uses tokens./agents/:agentId(AgentDetail.tsx, 4104 lines) — skim only per the Phase 7 directive. One cyan shadow on line 1107 dropped; twodashboardbreadcrumb hrefs retained (they're legacy agent-tab router paths, not dead top-level routes — see F11)./issues/:issueId(IssueDetail.tsx, 1696 lines) — skim only. No blockers in the visible layout header./company/settings(CompanySettings.tsx) — breadcrumb href fixed to/assistant./company/export/*(CompanyExport.tsx) — OK. References to/company/export/...are real routes, not dead dashboard links./company/import(CompanyImport.tsx) — post-importwindow.location.assignrewritten from/${prefix}/dashboard→/${prefix}/assistant. User-visible "company" vocab is already routed throughVOCAB.companywhich resolves to "Workspace"./skills/*(CompanySkills.tsx) — OK. SkillBrowser + SkillDetail breadcrumb hrefs fixed./execution-workspaces/:workspaceId(ExecutionWorkspaceDetail.tsx) — skimmed. No findings.
Auth + landing + empty states
/auth(Auth.tsx) — OK. Border-only inputs, foreground text, destructive error. Left half form, right half ASCII animation./invite/:token(InviteLanding.tsx) — not touched; out of scope scan./board-claim/:token(BoardClaim.tsx) — not touched./cli-auth/:id(CliAuth.tsx) — not touched./*(NotFound.tsx) — breadcrumb href was/${prefix}/dashboard. Rewritten to/${prefix}/assistantand the button label changed from "Open dashboard" to "Open assistant".- Onboarding wizard (
OnboardingWizard.tsx+onboarding/*) — not touched; previous phases already covered. /design-guide(DesignGuide.tsx, 1532 lines) — the canonical DESIGN.md showcase. Skimmed; not touched (any findings would be meta since the page IS the design system).
Plugin subsystem
/plugins/:pluginId(PluginPage.tsx) — back link href fixed./instance/settings/plugins(PluginManager.tsx) — breadcrumb href fixed./instance/settings/plugins/:pluginId(PluginSettings.tsx) — breadcrumb href fixed.
Top 3 recommended follow-ups (by visual impact)
-
Wire the forest-green and pale-yellow token classes — eliminates the
bg-[#166534]/bg-[#f4f692]literals in ProjectCard, Projects, GlobalMicButton, and TabPlaceholder. Low-riskindex.cssaddition plus a grep-and-replace. One commit of ~15 line touches. (MIGRATION-PLAN.md §3.) -
Drop the remaining
shadow-xssurvivors in shadcn primitives (F1 + F2) and collapse theirtransition-[color,box-shadow]totransition-colors. Five files, ten lines total. Visible improvement: removes the last "invisible on black" shadow artifacts. -
Resolve the Basier font decision (Deviation 2). Either license + load it, or formally accept Inter as the sole display font and update DESIGN.md §3 to match. This is the last open item from the visual repaint and blocks closing the MIGRATION-PLAN open-decisions list.