Files
headquarter/ui-audit-spacing-typography.md

315 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Headquarter Web UI — Spacing, Typography & Visual Rhythm Audit
**Scope:** `apps/web/src/components/**/*`, `apps/web/src/pages/**/*`, `apps/web/src/components/app-shell.tsx`, `apps/web/src/styles/*.css`, `apps/web/src/styles/pages/*.css`, and mobile-specific components under `apps/web/src/components/features/mobile`.
**Date:** 2026-06-16
**Method:** Static source review; no runtime screenshots. Line numbers reference the current state of the repository.
---
## 1. Critical Issues
These are problems that break layouts, make the UI unusable on mobile, or create accessibility failures.
### 1.1 Missing CSS for heavily-used component classes
A large number of class names are referenced in JSX/TSX but have **no rules** in any stylesheet. Browsers will render them as unstyled inline elements, causing broken spacing, unreadable text, and invisible interactive states.
| Class(es) | Used in (examples) | Impact |
|---|---|---|
| `.mobile-detail-view`, `.mobile-detail-header`, `.mobile-detail-field`, `.mobile-detail-field-label`, `.mobile-detail-field-value`, `.mobile-detail-code` | `components/features/mobile/mobile-detail-view.tsx` (lines 3091), `pages/WorkspacesPage.tsx` (detail view), `ToolWorkshopMobileView.tsx`, `ConfigProfilesMobileView.tsx` | The entire mobile detail view has **no layout styling**; fields stack without gaps, labels/values are indistinguishable, code blocks overflow. |
| `.mobile-list-search`, `.mobile-list-search-input` | `components/features/mobile/mobile-list-view.tsx` (lines 3742) | Search input is unstyled on mobile list views. |
| `.btn`, `.btn-primary`, `.btn-secondary`, `.btn-sm` | `pages/WorkspacesPage.tsx:150,157,183`, `components/features/workspace/workspace-tools-panel.tsx:26,56`, `components/features/workspace/workspace-card.tsx:74`, `components/features/project/ProjectCard.tsx:131` | Buttons fall back to native browser styling; spacing and sizing are inconsistent with `.primary-button`/`.secondary-button`. |
| `.link-button` | `components/features/session/session-card.tsx:187` | Session URL button has no styling. |
| `.checkbox-label` | `components/features/tool/tool-starter.tsx:280`, `components/features/session/create-session-form.tsx:368`, `components/features/tool/instance-list.tsx:345,490`, `components/features/config-profiles/ConfigProfileEditorPanel.tsx:170` | Checkbox pills rely only on inline styles; base class is undefined. |
| `.hint` | `components/features/tool/tool-starter.tsx:312`, `components/features/session/create-session-form.tsx:398` | Helper text is unstyled and hard to read. |
| `.form-error`, `.error-message` | `components/features/tool/tool-starter.tsx:318`, `components/features/tool/start-tool-modal.tsx:92`, `components/features/workspace/workspace-create-form.tsx:296`, `pages/ProfilePage.tsx:177`, `pages/ProjectSettingsPage.tsx:51,122`, `components/features/project/repositories-settings-tab.tsx:62`, `components/features/project/repository-create-dialog.tsx:384`, `components/features/tool/instance-list.tsx:249` | Error states have no visual treatment (color, padding, background). |
| `.alert`, `.alert-error` | `pages/WorkspacesPage.tsx:97,165` | Alert banners are unstyled. |
| `.loading-state` | `pages/WorkspacesPage.tsx:100,178`, `pages/WorkspaceDetailPage.tsx:27` | Loading states are unstyled plain text. |
| `.text-muted` | `components/features/mobile/mobile-detail-view.tsx:30` | Undefined; should be `.muted`. |
| `.badge`, `.badge-success`, `.badge-secondary` | `components/features/mobile/mobile-detail-view.tsx:3336` | Badge classes used but never defined. |
| `.key-signing`, `.key-verification`, `.signature-result`, `.verify-result` | `components/features/ssh-keys/SSHKeyList.tsx` (lines 79161) | Signing/verification sections have no spacing or typography rules; the SSH key page is visually broken below the public-key copy area. |
| `.form-input` | `components/features/config-profiles/ConfigProfileEditorPanel.tsx` (multiple lines) | Inputs in config profile editor use `.form-input`, which is not defined. |
**Recommendation:** Add a single “missing primitives” pass to `global.css` or `utilities.css` defining `.btn`, `.btn-primary`, `.btn-secondary`, `.btn-sm`, `.link-button`, `.checkbox-label`, `.hint`, `.form-error`/`.error-message`, `.alert`/`.alert-error`, `.loading-state`, `.badge*`, `.form-input`, and the entire `.mobile-detail-*` block. Then remove the duplicated inline `style={{...}}` blocks from components.
### 1.2 Mobile detail view is completely unstyled
- **File:** `components/features/mobile/mobile-detail-view.tsx` (lines 5391)
- **Issue:** The component defines `.mobile-detail-view`, `.mobile-detail-header`, `.mobile-detail-fields`, `.mobile-detail-field`, `.mobile-detail-field-label`, `.mobile-detail-field-value`, and `.mobile-detail-code`, but no stylesheet contains these selectors. The result is a raw HTML-like stack with no padding, no separators, no label/value hierarchy, and unbounded `<pre>` blocks.
- **Recommendation:** Add to `utilities.css`:
```css
.mobile-detail-view { display:flex; flex-direction:column; min-height:100%; background:var(--bg); }
.mobile-detail-header { position:sticky; top:0; z-index:10; display:flex; align-items:center; gap:var(--space-3); padding:var(--space-3); background:var(--panel); border-bottom:1px solid var(--border); }
.mobile-detail-header-content { flex:1; min-width:0; }
.mobile-detail-title { margin:0; font-size:var(--font-size-lg); }
.mobile-detail-subtitle { margin:var(--space-1) 0 0; color:var(--muted); font-size:var(--font-size-sm); }
.mobile-detail-actions { display:flex; gap:var(--space-2); }
.mobile-detail-action { … }
.mobile-detail-fields { display:flex; flex-direction:column; gap:var(--space-3); padding:var(--space-3); }
.mobile-detail-field { display:flex; flex-direction:column; gap:var(--space-1); padding:var(--space-3); background:var(--panel); border:1px solid var(--border); border-radius:10px; }
.mobile-detail-field-label { font-size:var(--font-size-xs); text-transform:uppercase; letter-spacing:0.05em; color:var(--muted); }
.mobile-detail-field-value { font-size:var(--font-size-base); color:var(--ink); word-break:break-word; }
.mobile-detail-code { overflow:auto; max-width:100%; font-size:var(--font-size-sm); }
```
### 1.3 Mobile navigation and FAB collision
- **File:** `styles/utilities.css` (lines 24482474) and `styles/global.css` (lines 11531205)
- **Issue:**
- `.mobile-nav` is fixed `bottom:0`, `height:64px`, with `padding-bottom: env(safe-area-inset-bottom, 0)`.
- `.start-tool-fab` on mobile is positioned `bottom: 5rem; right: 1rem` (`global.css:1201`).
- `.mobile-edit-actions` is `position: fixed; bottom: 64px` (`utilities.css:2272`).
- `.shell-content.mobile` adds `padding-bottom: calc(1.25rem + 64px)` (`utilities.css:2412`).
- **Impact:** The FAB, bottom sheets, edit actions, and mobile tab bar can overlap depending on safe-area insets. The `5rem` magic number does not account for `env(safe-area-inset-bottom)` and may collide with the nav on devices with home indicators.
- **Recommendation:** Replace magic numbers with a CSS custom property: `--mobile-nav-height: calc(64px + env(safe-area-inset-bottom, 0px))`. Then set `.start-tool-fab { bottom: calc(var(--mobile-nav-height) + var(--space-3)); }`, `.mobile-edit-actions { bottom: var(--mobile-nav-height); }`, and `.shell-content.mobile { padding-bottom: var(--mobile-nav-height); }`.
### 1.4 Unreadable type scale and cramped touch targets
- **Files:** `styles/tokens.css` (lines 4045), `styles/utilities.css` (lines 25012526), multiple component inline styles
- **Issue:**
- The token scale defines only six font sizes (`--font-size-xs` through `--font-size-2xl`) and **no line-height tokens**.
- Many inline styles use `fontSize: "0.7rem"` (e.g. `ConfigProfileListSidebar.tsx:82,95`), which is below the 11 px effective minimum recommended for mobile legibility.
- Several buttons use `min-height` derived only from `padding`, not the design-system touch target. The global rule `button, a, input, select, textarea, [role="button"] { min-height: 44px; min-width: 44px; }` (`utilities.css:2501`) is too broad and can distort form elements.
- **Recommendation:** Add `--line-height-*` tokens and a `--touch-target: 44px` token. Replace inline `fontSize: "0.7rem"` with `var(--font-size-xs)` (or larger). Narrow the broad `min-height/min-width` selector to interactive controls only, not every `input`/`select`/`textarea`.
### 1.5 Sidebars use fixed pixel widths and inline styles
- **Files:**
- `components/features/config-profiles/ConfigProfileListSidebar.tsx` (lines 2223): `style={{ width: "280px", minWidth: "280px" }}`
- `components/features/tool-workshop/ToolTypeListSidebar.tsx` (lines 2223): `style={{ width: "280px", minWidth: "280px" }}`
- `styles/global.css` (line 35): `.shell-body { grid-template-columns: 230px 1fr; }`
- **Issue:** These values are hardcoded in pixels/rem strings inside components and CSS. They do not respond to breakpoints and are inconsistent with the shell sidebar width.
- **Recommendation:** Define `--sidebar-width: 280px` in tokens and use it consistently. On small desktop/large tablets (≤860 px) the shell collapses to a top nav, but the config-profiles/tool-workshop pages keep their 280 px sidebars, causing horizontal overflow.
---
## 2. Major Inconsistencies
### 2.1 Mixed px/rem/em units and magic numbers
The codebase uses `px`, `rem`, `em`, and string literals in inline styles interchangeably.
| Location | Value | Problem |
|---|---|---|
| `styles/syntax-highlight.css:46,87,125` | `font-size: 14px` | Hardcoded px in code areas; should use `--font-size-sm`. |
| `styles/syntax-highlight.css:21,29,55,69,104,110,115` | `px`-based paddings | Should be `--space-*` tokens. |
| `styles/global.css:36` | `height: calc(100vh - 57px)` | Magic number 57 px assumes header height; fragile if header wraps. |
| `styles/global.css:12` | `padding: 0.85rem 1.25rem` | Non-token values; closest tokens are `--space-3`/`--space-4`. |
| `styles/global.css:50` | `padding: 0.65rem 0.75rem` | Non-token; should be `--space-2`/`--space-3`. |
| `styles/global.css:187` | `min-height: 38px` | Below `--touch-target`; should be 44 px. |
| `styles/global.css:269` | `font-size: 1.6rem` | One-off size; should map to a token or be removed. |
| `styles/global.css:623628` | `min-width: 400px`, `max-width: 600px`, `max-height: 80vh`, `border-radius: 8px` | Modal sizing inconsistent with `.dialog` rules above. |
| `styles/pages/git-history.css:69` | `padding: 0.15rem 0.4rem` | Should be `--space-1`/`--space-2`. |
| `styles/pages/sessions.css:64` | `bottom: calc(100% + 0.25rem)` | Should be `--space-1`. |
| `styles/pages/sessions.css:67` | `min-width: 12rem` | Should be a token or `--space-*` composition. |
| `styles/utilities.css:2448` | `height: 64px` | Should be a token. |
| `styles/utilities.css:2459` | `padding: 8px 12px` | Should be `--space-2`/`--space-3`. |
| `styles/utilities.css:2461` | `font-size: 11px` | Hardcoded px; should be `--font-size-xs`. |
| `styles/utilities.css:2465` | `min-width: 64px` | Should be a touch-target token. |
| Inline styles in `manifest-editor.tsx`, `ConfigProfileEditorPanel.tsx`, `ToolTypeEditorPanel.tsx`, `ToolTypeListSidebar.tsx`, `ConfigProfileListSidebar.tsx`, `git-mount-editor.tsx` | Dozens of `style={{ gap:"0.5rem", padding:"1rem", borderRadius:"0.375rem" }}` | Bypass tokens entirely. |
**Recommendation:** Run a pass to replace ad-hoc `px`/`rem` values with `--space-*` and `--font-size-*` tokens. Create additional tokens where the current scale is insufficient (`--space-7: 2.5rem`, `--space-12: 6rem`, `--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-full`).
### 2.2 Duplicated and overlapping responsive breakpoints
- **Files:** `styles/global.css` (lines 198, 330, 517), `styles/utilities.css` (many `@media (max-width: 767px)`), `styles/pages/workspaces.css` (`@media (max-width: 767px)`), `styles/pages/sessions.css` (`@media (max-width: 767px)`), `styles/pages/workspace-detail.css` (`@media (max-width: 767px)`)
- **Issue:** The codebase mixes `767px`, `768px`, `860px`, and `1024px` breakpoints with no clear mobile/desktop boundary. For example:
- `.shell-body` collapses at `860px` (`global.css:517`) and again at `767px` (`global.css:198`).
- `.settings-layout` collapses at `768px` (`global.css:742`) and is overridden again at `767px` (`utilities.css`).
- `.card-grid` goes 1-column at `<768px` but `.workspaces-grid` stays multi-column until `<767px`, causing a 1 px gap in behavior.
- **Recommendation:** Standardize on the token breakpoints (`--bp-sm: 480px`, `--bp-md: 768px`, `--bp-lg: 1024px`, `--bp-xl: 1280px`) and use `min-width` mobile-first queries. Remove the `860px` one-off breakpoint.
### 2.3 Token scale is incomplete
- **File:** `styles/tokens.css` (lines 2431, 4045)
- **Issue:**
- Spacing jumps from `--space-6: 2rem` to `--space-8: 3rem` to `--space-10: 4rem`; no `--space-7`, `--space-9`, `--space-12`.
- No border-radius tokens (`--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-full`).
- No line-height tokens.
- No shadow/elevation tokens; shadows are copy-pasted (`box-shadow: 0 1px 0 rgba(0,0,0,0.02)`, `0 6px 18px rgba(0,0,0,0.08)`, `0 4px 14px rgba(0,0,0,0.25)`, etc.).
- No touch-target or nav-height tokens.
- **Recommendation:** Expand `tokens.css` to include these primitives and refactor existing rules to consume them.
### 2.4 Two competing modal/dialog systems
- **File:** `styles/global.css` (lines 394451 and 619643)
- **Issue:** There are two separate modal implementations:
- `.dialog-overlay` + `.dialog` / `.dialog-lg` (rounded, centered, responsive)
- `.modal-overlay` + `.modal-content` (older, square, fixed `min-width: 400px`)
- **Impact:** Different paddings, border radii, widths, and mobile behaviors. Components use both (`SessionCard` uses `.modal-overlay`, `instance-list.tsx` uses `.dialog-overlay`).
- **Recommendation:** Deprecate `.modal-*` and migrate all modals to `.dialog*` tokens. Add a single `.modal-content → .dialog` mapping for backward compatibility, then refactor callers.
### 2.5 Inline styles bypass the design system
Dozens of components embed `style={{...}}` objects that duplicate layout primitives.
- **High-volume offenders:**
- `components/features/tool/manifest-editor.tsx` — ~70 inline style props (cards, rows, gaps, padding, font sizes).
- `components/features/config-profiles/ConfigProfileEditorPanel.tsx` — ~40 inline style props.
- `components/features/tool-workshop/ToolTypeEditorPanel.tsx` — ~20 inline style props.
- `components/features/tool-workshop/ToolTypeListSidebar.tsx` — sidebar dimensions and list item spacing inline.
- `components/features/config-profiles/ConfigProfileListSidebar.tsx` — same pattern.
- `components/features/git/git-mount-editor.tsx` — many inline flex/gap/padding rules.
- **Impact:** Prevents theming, makes responsive overrides impossible, and scatters magic numbers across the codebase.
- **Recommendation:** Replace inline styles with utility classes (`.stack`, `.stack-sm`, `.row`, `.card`, `.form-group`, `.form-row`, `.p-3`, `.rounded-lg`, etc.) and add missing utilities as needed.
### 2.6 Page-specific CSS files repeat global patterns
- **Files:** `styles/pages/projects.css`, `styles/pages/sessions.css`, `styles/pages/ssh-keys.css`, `styles/pages/workspace-detail.css`, `styles/pages/workspaces.css`, `styles/pages/git-history.css`
- **Issue:** Each page file redeclares card spacing, grid gaps, responsive overrides, and form field patterns that already exist (or should exist) in `global.css`/`utilities.css`. For example:
- `.repo-block`, `.workspace-chip`, `.instance-card`, `.settings-section` all duplicate `background: var(--panel); border: 1px solid var(--border); border-radius: 10/12/14px;`.
- **Recommendation:** Consolidate card variants into `global.css` using `.card`, `.card-sm`, `.card-lg`, and `.card-elevated` modifiers. Reserve page files for truly page-specific layout (e.g., `.history-container` two-column grid).
---
## 3. Minor Polish
### 3.1 Misaligned icons and nav density
- **File:** `components/app-shell.tsx` (lines 1468) and `styles/global.css` (lines 1277)
- **Issue:**
- `.shell-header` uses `padding: 0.85rem 1.25rem` while `.shell-content` uses `padding: 1.25rem`. The header baseline does not visually align with the content grid.
- `.nav-item` uses `gap` inherited from `.shell-nav` (`gap: 0.4rem`) plus `border-radius: 10px`; active and hover states have inconsistent text colors (`#f7fff7` vs `var(--primary-fg)`).
- `.nav-section-title` has `margin-top: 0.5rem` and `padding: 0.25rem 0.75rem` while `utilities.css` redeclares it with `padding: var(--space-2) var(--space-4)` and `font-size: var(--text-xs)` (an undefined variable; should be `--font-size-xs`).
- **Recommendation:** Use `--space-3`/`--space-4` consistently for header and content padding. Unify nav active/hover colors to token values. Fix `--text-xs` typo in `utilities.css`.
### 3.2 Page header spacing
- **File:** `styles/global.css` (lines 320337)
- **Issue:** `.page-header` uses `gap: var(--space-3)` and wraps to column on mobile, but the bottom margin/rhythm is inconsistent across pages. Dashboard home sections use `.page-header` inside `.card`, while other pages use it at the section root.
- **Recommendation:** Add `.page-header { margin-bottom: var(--space-4); }` and a nested variant `.card .page-header { margin-bottom: var(--space-3); }`.
### 3.3 Card gaps and grid inconsistencies
- **File:** `styles/global.css` (lines 230261) and `styles/pages/workspaces.css` (lines 1236)
- **Issue:**
- `.home-summary-grid`, `.home-project-grid`, `.home-session-grid` use `gap: var(--space-4)`.
- `.card-grid` uses `gap: var(--space-4)` and breakpoint-driven columns.
- `.workspaces-grid` uses `gap: var(--space-4)` on desktop and `var(--space-3)` on mobile.
- `.sessions-grid` uses `gap: var(--space-4)`.
- **Impact:** Mostly consistent, but the workspace card internal gap (`workspace-card { gap: var(--space-4); }`) combined with the grid gap creates double spacing relative to project/session cards.
- **Recommendation:** Standardize all list/grids on `--space-3` mobile and `--space-4` desktop. Reduce workspace card internal gap to `--space-3`.
### 3.4 Form spacing
- **File:** `styles/global.css` (lines 428451)
- **Issue:** `.form-field` and `.form-group` both exist with nearly identical rules (`display:flex; flex-direction:column; gap: 0.35rem`). `.form-field` is newer and used in Settings; `.form-group` is legacy and used in SSH keys, dialogs, and many inline forms.
- **Recommendation:** Merge into a single `.form-field` class. Provide `.form-row` for horizontal groups (already partially defined) and `.form-actions` for button rows. Add `margin-bottom: var(--space-4)` to each field for vertical rhythm.
### 3.5 Status badges use arbitrary colors
- **File:** `styles/utilities.css` (lines 23562396) and `styles/global.css` (lines 10921131)
- **Issue:** Status badges are defined in both files with overlapping status names but different background rules. `.instance-chip` also duplicates status colors.
- **Recommendation:** Consolidate status colors into a single `.status-badge` component with `.status-badge--running`, `.status-badge--error`, etc., and reuse it for chips.
### 3.6 Notification center positioning
- **File:** `components/features/notification/notification-center.tsx` (lines 4259)
- **Issue:** Dropdown position is computed in JavaScript and applied via `style={dropdownStyle}`. On mobile, `left/right: 1rem` is hardcoded in JS; on desktop, it uses `window.innerWidth - rect.right`.
- **Recommendation:** Use CSS anchoring or simpler absolute positioning relative to `.notification-center` so the dropdown responds to tokens and does not need resize listeners.
### 3.7 Profile page desktop card lacks profile-specific CSS
- **File:** `pages/ProfilePage.tsx` (lines 134180)
- **Issue:** Uses `.profile-avatar-section`, `.avatar-preview`, `.avatar-image`, `.avatar-placeholder` which are not defined in any stylesheet. The desktop profile form will render unstyled.
- **Recommendation:** Add profile avatar styles or reuse a generic `.avatar` component.
### 3.8 Terminal page uses hardcoded dark-theme values
- **File:** `styles/utilities.css` (terminal section, lines ~12001900)
- **Issue:** Terminal colors (`#1e1e1e`, `#2d2d2d`, `#3e3e3e`, `#d4d4d4`) are hardcoded and do not adapt to the light/dark theme tokens. This is acceptable for a terminal surface, but many spacing values (`8px`, `4px`, `2px`, `16px`) are also hardcoded.
- **Recommendation:** Keep terminal colors as exceptions, but convert spacing to tokens for consistency.
---
## 4. Priority-Ranked Action List
### P0 — Fix before any further mobile work
1. **Add missing primitive styles** (`global.css`/`utilities.css`)
- `.mobile-detail-*` full block
- `.btn`, `.btn-primary`, `.btn-secondary`, `.btn-sm`
- `.link-button`
- `.checkbox-label`
- `.hint`
- `.form-error`/`.error-message`
- `.alert`, `.alert-error`
- `.loading-state`
- `.badge`, `.badge-success`, `.badge-secondary`
- `.form-input`
- `.mobile-list-search`, `.mobile-list-search-input`
- `.key-signing`, `.key-verification`, `.signature-result`, `.verify-result`
- Profile avatar classes (`.profile-avatar-section`, `.avatar-preview`, etc.)
2. **Unify mobile nav / FAB / bottom-sheet spacing**
- Introduce `--mobile-nav-height: calc(64px + env(safe-area-inset-bottom, 0px))`.
- Update `.start-tool-fab`, `.mobile-edit-actions`, `.shell-content.mobile`, `.mobile-bottom-sheet`, and `.mobile-action-sheet` to use it.
3. **Fix critical accessibility issues**
- Ensure all interactive controls meet `min-height: 44px; min-width: 44px` without distorting text inputs.
- Add visible `:focus` states to `.nav-item`, `.mobile-nav-item`, `.tab`, `.tree-entry`, `.button`, and `.form-field input`.
- Replace `font-size: 0.7rem` inline styles with `--font-size-xs` (or larger).
### P1 — Tokenize and consolidate
4. **Expand `tokens.css`**
- Add `--space-7`, `--space-9`, `--space-12`.
- Add `--radius-sm: 6px`, `--radius-md: 10px`, `--radius-lg: 14px`, `--radius-xl: 16px`, `--radius-full: 999px`.
- Add `--line-height-tight`, `--line-height-normal`, `--line-height-relaxed`.
- Add `--shadow-sm`, `--shadow-md`, `--shadow-lg`, `--shadow-xl`.
- Add `--touch-target: 44px` and `--sidebar-width: 280px`.
5. **Standardize breakpoints**
- Replace `767px`, `768px`, `860px` with `--bp-sm`, `--bp-md`, `--bp-lg`, `--bp-xl`.
- Prefer mobile-first `min-width` queries.
- Remove the redundant `.shell-body` collapse at `860px`.
6. **Refactor inline styles into utility classes**
- Start with the highest-volume offenders: `manifest-editor.tsx`, `ConfigProfileEditorPanel.tsx`, `ToolTypeEditorPanel.tsx`, `ToolTypeListSidebar.tsx`, `ConfigProfileListSidebar.tsx`, `git-mount-editor.tsx`.
- Replace `style={{ display:"flex", gap:"0.5rem" }}` with `.row.row-sm` or `.row.gap-sm` utilities.
### P2 — Merge duplicated systems
7. **Merge `.form-field` and `.form-group`** into one component class with consistent vertical rhythm.
8. **Deprecate `.modal-overlay`/`.modal-content`** in favor of `.dialog-overlay`/`.dialog` and migrate callers.
9. **Consolidate status badges/chips** into a single `.status-badge` family and reuse across sessions, instances, and workspaces.
10. **Consolidate card patterns** across page CSS files into `global.css` modifiers (`.card-sm`, `.card-lg`, `.card-elevated`).
### P3 — Polish and documentation
11. **Add design-system documentation comments** at the top of `tokens.css` listing the spacing/type/radius/shadow scales and naming rules.
12. **Add a lint rule or code-review checklist** to prevent new inline `style={{...}}` layout declarations and undefined class names.
---
## Summary of Files Most Likely to Need Changes
| File | Lines to review | Why |
|---|---|---|
| `apps/web/src/styles/tokens.css` | 192 | Incomplete token scale; needs spacing, radius, line-height, shadow, touch-target, and nav tokens. |
| `apps/web/src/styles/global.css` | 11206 | Many magic numbers, duplicate modal/dialog systems, missing primitive classes, inconsistent breakpoints. |
| `apps/web/src/styles/utilities.css` | 13270 | Overly broad touch-target rules, undefined `--text-xs`, missing `.mobile-detail-*`, duplicated badge/status styles. |
| `apps/web/src/styles/pages/*.css` | all | Heavy duplication of card/grid patterns; should use shared utilities. |
| `apps/web/src/components/app-shell.tsx` | 1150 | Header/nav padding misalignment, mobile nav/FAB collision. |
| `apps/web/src/components/features/mobile/mobile-detail-view.tsx` | 195 | Component references unstyled classes. |
| `apps/web/src/components/features/mobile/mobile-list-view.tsx` | 1115 | Search input unstyled. |
| `apps/web/src/components/features/tool/manifest-editor.tsx` | ~70 inline styles | Highest-volume inline-style offender. |
| `apps/web/src/components/features/config-profiles/ConfigProfileEditorPanel.tsx` | ~40 inline styles | Second-highest inline-style offender. |
| `apps/web/src/components/features/tool-workshop/ToolTypeEditorPanel.tsx` | ~20 inline styles | Third-highest offender. |
| `apps/web/src/components/features/tool-workshop/ToolTypeListSidebar.tsx` | 1150 | Hardcoded 280 px sidebar; inline styles. |
| `apps/web/src/components/features/config-profiles/ConfigProfileListSidebar.tsx` | 1160 | Hardcoded 280 px sidebar; inline styles. |
| `apps/web/src/components/features/git/git-mount-editor.tsx` | Many inline styles | Complex mount editor with inline flex/gap/padding. |
| `apps/web/src/components/features/ssh-keys/SSHKeyList.tsx` | 1180 | Signing/verification sections have no CSS. |
| `apps/web/src/pages/ProfilePage.tsx` | 130180 | Desktop profile card uses unstyled avatar classes. |
| `apps/web/src/pages/WorkspacesPage.tsx` | 90110 | Uses `.alert alert-error` and `.loading-state` without styles. |
---
*End of audit. No code changes were made; this is an analysis-only report.*