Files
waggle-os/docs/product-analysis/design-audit.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

433 lines
28 KiB
Markdown

# Waggle OS -- Design System Audit
**Date:** April 2026
**Scope:** `apps/web/` (primary frontend), `app/` (Tauri app), shared CSS and design tokens
**Method:** Automated deep scan of all CSS files, component source, and design token definitions
---
## Summary
**Overall Score: 6.3 / 10**
Waggle OS has a distinctive and intentional design identity ("Honey on Dark Steel") that is rare among AI products. The Hive DS token system is well-defined at the CSS variable level. However, there is a significant gap between the *defined* design system and its *applied* usage. Arbitrary Tailwind values are rampant (433 instances of `text-[Npx]` across the web app), two separate CSS systems exist for the two app targets with divergent token definitions, and accessibility is weak at the fundamentals level (tiny text, no responsive design, inconsistent focus states). The product looks good in screenshots but would not survive a WCAG audit.
---
## Dimension Scores
### 1. Color Consistency -- 7/10
**What exists:**
The Hive DS defines a comprehensive palette in `app/src/styles/globals.css`:
- Hive gray scale: 12 stops (`--hive-950` through `--hive-50`)
- Honey scale: 8 stops (`--honey-600` through `--honey-50`) plus `--honey-glow` and `--honey-pulse`
- Status colors: 5 named (`--status-healthy`, `--status-warning`, `--status-error`, `--status-info`, `--status-ai`)
- Semantic surfaces: 5 (`--surface-card`, `--surface-panel`, `--surface-overlay`, `--surface-hover`, `--surface-selected`)
- Shadows: 4 (`--shadow-card`, `--shadow-elevated`, `--shadow-overlay`, `--shadow-honey`)
- Knowledge graph node colors: 5 (`--kg-person`, `--kg-project`, `--kg-concept`, `--kg-org`, `--kg-default`)
**What is actually used:**
Components mostly use the semantic Tailwind tokens (`text-foreground`, `bg-card`, `text-primary`, etc.) which is correct. However, there are systemic leaks:
- **Direct Tailwind color classes bypass the design system.** Status colors are applied via `text-emerald-400`, `text-amber-400`, `text-violet-400`, `text-cyan-400`, `text-orange-400`, `text-sky-400`, `text-destructive` rather than through the defined `--status-*` tokens. This means status colors are hardcoded in 50+ locations across OS component files.
- `CockpitApp.tsx:66` -- `text-emerald-400` / `text-amber-400` inline instead of referencing status tokens
- `Desktop.tsx:63-75` -- Each app icon uses a different Tailwind color (`text-amber-300`, `text-cyan-400`, `text-emerald-400`, `text-violet-400`, `text-orange-400`)
- `VaultApp.tsx:66-71` -- TYPE_BADGES use `bg-sky-500/20 text-sky-400`, `bg-emerald-500/20 text-emerald-400`, etc.
- `CapabilitiesApp.tsx:7-16` -- Trust levels and category colors hardcoded as Tailwind classes
- **Two divergent CSS systems exist.** `app/src/styles/globals.css` defines HSL values one way (`--background: 222 20% 4%`), while `apps/web/src/index.css` defines them differently (`--background: 30 6% 8%`). The hue families are completely different (222 cold blue vs 30 warm amber). This means the Tauri app and web app render different colors from the "same" design system.
- **Inline hex values in SVG.** `MemoryApp.tsx:62,73` uses `stroke="hsl(38, 92%, 50%)"` and `fill="hsl(38, 92%, 50%)"` directly instead of referencing a CSS variable.
- **UserProfileApp.tsx:59-61** -- Default brand colors hardcoded as hex (`#D4A84B`, `#1a1a1a`, `#3b82f6`). The accent `#3b82f6` (Tailwind blue-500) is not part of the Hive DS palette at all.
**Fix recommendations:**
1. Create Tailwind theme extensions for status colors: `text-status-healthy`, `bg-status-warning/20`, etc., mapped to the existing `--status-*` CSS variables.
2. Reconcile the two CSS systems. The `apps/web/src/index.css` warm-amber base and `app/src/styles/globals.css` cold-blue base need to converge on one.
3. Replace all inline `hsl()` and hex values in TSX files with CSS variable references.
---
### 2. Typography Hierarchy -- 4/10
**What exists:**
- Display font: Space Grotesk (headings, labels) via `.font-display` utility
- Body font: DM Sans (web app) / Inter (Tauri app) -- another divergence
- Mono font: JetBrains Mono / Cascadia Code / Fira Code
- Body font size set to `13px` in `app/src/styles/globals.css`
- Chat prose styles are well-defined: h1=18px, h2=16px, h3=14px, p=14px, code=13px
**What is actually used -- the font size disaster:**
Arbitrary `text-[Npx]` values across `apps/web/src/**/*.tsx`: **433 total instances**.
Breakdown by size:
| Size | Count | WCAG Status |
|------|-------|-------------|
| `text-[7px]` | ~2 | FAIL -- unreadable |
| `text-[8px]` | ~8 | FAIL -- nearly unreadable |
| `text-[9px]` | ~25 | FAIL -- below minimum |
| `text-[10px]` | ~45 | FAIL -- below WCAG 12px minimum for body text |
| `text-[11px]` | ~10 | BORDERLINE |
| `text-[12px]` | ~7 | PASS (barely) |
Plus standard Tailwind classes in OS components: **460 instances** of `text-xs` (12px), `text-sm` (14px), `text-base`, `text-lg`, `text-xl`, `text-2xl`, `text-3xl`.
The worst offenders:
- `StatusBar.tsx` -- Almost all content is `text-[10px]`: workspace name, model name, token count, cost. This is the bar users see constantly.
- `ModelPilotCard.tsx` -- 16 instances of arbitrary sizes from `text-[8px]` to `text-[10px]`. The 3-lane model selector is a wall of microscopic text.
- `Dock.tsx:121,144` -- Hover labels are `text-[10px]`.
- `WorkspaceBriefing.tsx:70` -- Memory stats at `text-[11px]`.
- `SpawnAgentDialog.tsx` -- 11 instances of `text-[10px]`.
**The core problem:** There is no defined type scale. Developers pick whatever pixel value feels right at the time. The result is at least **10 distinct font sizes** (`7px, 8px, 9px, 10px, 11px, 12px, 13px, 14px, 16px, 18px`) used across the app, with no documented hierarchy.
**Fix recommendations:**
1. Define a type scale in the design tokens: `--text-micro: 11px`, `--text-caption: 12px`, `--text-body-sm: 13px`, `--text-body: 14px`, `--text-title: 16px`, `--text-heading: 20px`, `--text-display: 24px`.
2. Map these to Tailwind utilities and ban arbitrary `text-[Npx]` values via ESLint.
3. **Eliminate all text below 11px.** The `text-[7px]`, `text-[8px]`, and `text-[9px]` instances need to be bumped to at minimum 11px. Nothing in a productivity app needs to be 8 pixels tall.
4. The StatusBar and ModelPilotCard need a redesign to work at readable sizes.
---
### 3. Spacing Rhythm -- 7/10
**What exists:**
The Tailwind 4px grid is used consistently in most places. Components use standard Tailwind spacing: `p-2`, `p-3`, `p-4`, `gap-1.5`, `gap-2`, `gap-3`, `mb-4`, etc.
**What is used well:**
- Very few arbitrary spacing values. The grep for `p-[`, `m-[`, `gap-[`, `space-[` found almost no custom component instances (only shadcn UI library internals like `p-[1px]` in scroll-area).
- Border radius is consistent at `--radius: 0.75rem` (12px) with `rounded-xl`, `rounded-lg` variations.
- Cards use consistent padding patterns: `p-3` for compact, `p-4` for standard.
**Minor issues:**
- Window sizes are hardcoded pixel values in `Desktop.tsx:58-76`: `"520px"`, `"560px"`, `"640px"`, `"480px"`, etc. These should be tokens or at minimum constants.
- `EventsApp.tsx:176` uses `paddingLeft: ${depth * 20 + 8}px` for tree indentation -- calculated inline.
**Fix recommendations:**
1. Extract window dimensions to a constant map or config.
2. Replace calculated inline padding with Tailwind `pl-*` classes using data attributes or CSS custom properties for depth.
---
### 4. Component Consistency -- 6/10
**What exists:**
Two separate shadcn/ui component libraries:
- `app/src/components/ui/` -- 21 components (Tauri app). Uses `@base-ui/react` primitives, newer shadcn patterns with `data-slot` attributes and `class-variance-authority`.
- `apps/web/src/components/ui/` -- 49 components (web app). Uses `@radix-ui/react-*` primitives, standard shadcn patterns with `forwardRef`.
These are **two completely different component libraries** with different underlying primitives, different APIs, and different styling approaches. The `app/` Button uses `@base-ui/react/button` with CVA variants including `xs`, `sm`, `default`, `lg`, `icon`, `icon-xs`, `icon-sm`, `icon-lg`. The `apps/web/` Button uses `@radix-ui` with `default`, `sm`, `lg`, `icon` sizes.
**Custom components in `apps/web/src/components/os/`:**
- **Buttons are inconsistent.** Some views use the shadcn `<Button>` component, but many views construct buttons inline:
- `AgentsApp.tsx:237` -- `<input ... className="w-full text-xs bg-secondary/30 border border-border/30 rounded-lg pl-8 pr-3 py-2">` (hand-rolled input, not shadcn Input)
- `CreateAgentForm.tsx:68,85,88,91` -- All inputs are hand-rolled `<input>` elements with bespoke classes
- `CreateGroupForm.tsx:66,68` -- Same pattern: hand-rolled inputs
- `SettingsApp.tsx:166,269` -- `<input>` with custom `bg-muted/50 border border-border/50 rounded-lg`
- `GroupDetail.tsx:201` -- Another hand-rolled input
- **Cards are mostly consistent.** Most views use `bg-card`, `border border-border/30`, `rounded-xl` patterns consistently, though not all use the shadcn `<Card>` component.
- **Focus styles diverge.** Hand-rolled inputs use `focus:outline-none focus:border-primary/50` while shadcn components use `focus-visible:ring-2 focus-visible:ring-ring`. These are visually different focus indicators.
**Fix recommendations:**
1. Pick ONE component library. The web app (`apps/web/`) is the primary frontend per project memory. Standardize on its shadcn/ui library.
2. Replace all hand-rolled `<input>` elements with the shadcn `<Input>` component. There are at least 10-15 instances of bespoke inputs.
3. Create an `<IconButton>` wrapper if the shadcn Button icon variant doesn't cover all use cases.
4. Standardize focus styles project-wide: `focus-visible:ring-2 focus-visible:ring-ring` (the shadcn pattern).
---
### 5. Responsive Behavior -- 2/10
**This is intentionally desktop-only**, which is acknowledged in the UX analysis. However, even for a desktop-only app, there are problems.
**Evidence:**
- Responsive breakpoint utilities (`sm:`, `md:`, `lg:`, `xl:`) appear in the web app, but **only inside shadcn/ui library components** (alert-dialog, dialog, sheet, sidebar, calendar, breadcrumb). Zero custom OS components use responsive utilities.
- Root container: `w-screen h-screen overflow-hidden` -- no flexibility.
- Window sizes are hardcoded pixels.
- The 5-column template grid in `OnboardingWizard.tsx` and the 4-column persona grid have no responsive fallbacks.
- No `min-width` media query or warning for narrow viewports.
**Fix recommendations:**
1. Add a minimum viewport warning: "Waggle requires a screen width of at least 1024px."
2. Make the OnboardingWizard grids responsive: 5 columns on wide screens, 3 on narrower, 2 on smallest.
3. Add `min-w-[1024px]` to the root container to prevent layout breakage.
---
### 6. Dark Mode -- 8/10
**Strengths:**
- The dark theme is the primary and well-defined theme. Every token has a dark value.
- **A full light theme exists** in `app/src/styles/globals.css` under `:root[data-theme="light"]`, with warm beeswax/ivory palette. This includes inverted hive scale, adjusted honey values for contrast, light shadows, and light semantic surfaces. The scrollbar and honeycomb background also have light variants.
- Bee image variants for light mode exist (`bee-orchestrator-light.png`, etc.).
- The `apps/web/src/index.css` does NOT define a light theme, meaning the web app is dark-only.
**Weaknesses:**
- Light theme exists in CSS but there appears to be no UI toggle to activate it (per UX analysis: "No dark/light mode toggle -- only dark theme exists").
- The light theme only exists in the Tauri app's CSS, not the web app's. This is a gap.
**Fix recommendations:**
1. Add a theme toggle to Settings (General tab).
2. Port the light theme from `app/src/styles/globals.css` to `apps/web/src/index.css`.
3. Test all components in light mode -- the status colors (`emerald-400`, `amber-400`, etc.) will likely have contrast issues on a light background.
---
### 7. Animation -- 8/10
**Strengths:**
The animations are purposeful, restrained, and on-brand:
- **Boot sequence:** Spring-based logo entrance, sequential phase text with fade transitions, progress bar animation, phase dot scaling. All using framer-motion. Duration is proportional (600ms per phase). (`BootScreen.tsx`)
- **Window management:** `window-open` animation (scale 0.9 + translateY to normal), minimize shrinks to dock. (`AppWindow.tsx`, `tailwind.config.ts`)
- **Dock:** Spring-based hover animation (scale 1.2, y: -8) with `dock-bounce` keyframe. Playful without being distracting. (`Dock.tsx`)
- **Overlays:** Consistent pattern -- backdrop fade + panel scale from 0.95 to 1. (`GlobalSearch.tsx`, `PersonaSwitcher.tsx`, etc.)
- **Custom Hive animations in CSS:** `honey-pulse` (memory save), `heartbeat` (health dot), `float` (bee mascot), `hex-cursor` (streaming), `token-fade` (token streaming), `send-flash` (input border), `hex-spin` (loading), `card-enter` (card entrance). All defined in `globals.css`.
- **Loading states:** Consistent use of `Loader2` from Lucide with `animate-spin`, found in 25+ components.
- **Streaming indicator:** Three bouncing dots with staggered `animationDelay` (`TextBlock.tsx:17-19`) plus a pulsing cursor bar.
**Minor issues:**
- `FilesApp.tsx:450` uses `animate-bounce` on the upload icon, which feels more playful than necessary for a file upload zone.
- The `fade-up` animation (0.4s) is defined but usage is limited.
**Fix recommendations:**
1. Consider reducing the boot screen total duration for returning users (currently ~4.8s).
2. The `animate-bounce` on file upload could be toned down to `animate-pulse`.
---
### 8. Accessibility -- 3/10
**This is the weakest dimension.**
**Text size failures:**
- 97 instances of text below 10px (`text-[7px]`, `text-[8px]`, `text-[9px]`) across the web app.
- The StatusBar, ModelPilotCard, and ModelSelector are built almost entirely at 9-10px sizes.
- WCAG SC 1.4.4 requires text to be resizable to 200% without loss of content. At 8-9px base, 200% zoom is still only 16-18px -- barely readable.
**Contrast concerns:**
- `text-muted-foreground` (`#5a6380` / HSL 225 12% 50%) on `--background` (`#08090c`): contrast ratio is approximately 3.5:1. WCAG AA requires 4.5:1 for normal text. This fails.
- `honey-500` (`#e5a000`) on dark background (`#08090c`): approximately 7.5:1 -- passes AA.
- `text-emerald-400` on dark: approximately 8:1 -- passes.
- `text-amber-400` on dark: approximately 7:1 -- passes.
- The muted foreground color is used extensively across all apps for secondary text, labels, and helper text. This is a systematic contrast failure.
**ARIA attributes:**
- **Good:** `AppWindow.tsx` has `role="dialog"` and `aria-label={title}`. Window control buttons have `aria-label` ("Minimize window", "Toggle fullscreen", "Close window"). StatusBar buttons have `aria-label`. Dock items have `aria-label`. The shadcn components include proper ARIA attributes from Radix primitives.
- **Bad:** Most custom interactive elements (cards that act as buttons, clickable divs, tab-like interfaces built with `<button>` arrays) lack ARIA roles and states. The tab interfaces in `AgentsApp.tsx`, `VaultApp.tsx`, `SettingsApp.tsx`, and `CapabilitiesApp.tsx` are all built with `<button>` elements styled as tabs but without `role="tablist"`, `role="tab"`, or `aria-selected`.
**Focus management:**
- shadcn components use `focus-visible:ring-2 focus-visible:ring-ring` consistently.
- Hand-rolled inputs use `focus:outline-none focus:border-primary/50` -- visible but less prominent.
- Many interactive divs (clickable cards, persona grid items, template selections in onboarding) have no visible focus indicator at all.
- No skip-to-content link.
- No focus trap in overlays (though click-outside-to-close exists).
**Keyboard navigation:**
- Global keyboard shortcuts are comprehensive (Ctrl+K, Ctrl+Tab, Ctrl+Shift+P, etc.).
- Within individual apps, keyboard navigation is limited. Tab order follows DOM order but many interactive elements are not focusable.
**Fix recommendations (priority order):**
1. **Increase `--muted-foreground` contrast.** Change from `#5a6380` to at minimum `#7d869e` (`--hive-300`) for AA compliance.
2. **Eliminate all text below 11px.** This is a hard accessibility requirement.
3. **Add `role="tablist"` / `role="tab"` / `aria-selected`** to all custom tab interfaces (at least 5 views).
4. **Add focus-visible indicators** to all interactive elements (clickable cards, persona items, template selections).
5. **Add focus trap** to overlay components (or verify framer-motion handles it).
6. **Add skip link** for keyboard users.
---
### 9. Information Density -- 6/10
**Well-balanced views:**
- `DashboardApp.tsx` -- Clean 2-column grid with cards. Good use of whitespace.
- `ChatApp.tsx` -- The chat area itself is clean. The block-based rendering prevents wall-of-text.
- `BootScreen.tsx` -- Minimal and focused.
- `Desktop.tsx` (empty state) -- Beautiful: centered logo, subtle animation, dock hint.
**Overly dense views:**
- **StatusBar** -- Packs workspace name, model, token count, cost, search, notifications, wifi status, decorative volume/battery, date, and clock into a 32px bar. At `text-[10px]`, this is a pixel-packed nightmare.
- **ModelPilotCard** -- The 3-lane model selector crams lane title, description, model name, cost indicator, provider, current badge, and switch buttons into tiny cards. Text ranges from 8px to 10px. Users will need a magnifying glass.
- **OnboardingWizard Step 4** -- 15 templates in a 5-column grid. Each card has icon, name, and description. On screens narrower than 1400px, this will be unreadable.
- **SettingsApp.tsx** -- 7 tabs with dense content in each. The Permissions tab alone has auto-approve toggle, always-require list, and explanatory text in a small window.
- **FilesApp.tsx** -- At 1,176 lines, the file manager tries to be a full IDE: tree view, preview, upload, rename, delete, context menu, syntax highlighting, drag-drop. The split-pane layout works but the metadata badges use `text-[9px]`.
**Fix recommendations:**
1. StatusBar: Remove decorative Volume/Battery icons. Move token count and cost to a hover tooltip or the Cockpit view.
2. ModelPilotCard: Increase minimum text to 11px. Consider a different layout (vertical stack instead of 3-column).
3. OnboardingWizard: Use 3 columns max for templates, with a category filter or search.
---
### 10. Polish -- 7/10
**Loading states -- GOOD:**
Loading states are consistently handled across the app. Every data-fetching view has a loading spinner:
- `Loader2 className="animate-spin"` pattern used in 25+ components
- `CockpitApp.tsx` shows `RefreshCw` icon spinning during refresh
- `CreateWorkspaceDialog.tsx` shows loading spinners during folder creation, AI generation, and saving
- Consistent pattern: centered spinner with optional text
**Empty states -- MODERATE:**
- `MemoryApp.tsx:211` -- "No memories found" with muted text
- `AgentsApp.tsx:253` -- "No agents found" with muted text
- `CapabilitiesApp.tsx:222` -- "No {tab} packs found"
- `FilesApp.tsx:648` -- "Empty directory"
- `MarketplaceApp.tsx:171` -- Context-aware empty state ("No packages installed yet" vs "No results for...")
- `KGViewer` (MemoryApp) -- Network icon + "No knowledge graph data"
- **Missing:** No empty state for DashboardApp when there are no workspaces. No empty state for EventsApp when there are no events.
**Error states -- GOOD:**
- `CockpitApp.tsx:77-80` -- Offline banner with AlertTriangle icon and destructive styling
- `ErrorBoundary.tsx` -- App-level error catch
- `VaultApp.tsx` -- Toast notifications for validation errors
- Network offline detection throughout (`useOfflineStatus` hook)
**Hover states -- EXCELLENT:**
- 272 `hover:` utility uses across OS components
- 298 `transition` uses across OS components
- Consistent hover patterns: `hover:bg-muted`, `hover:text-foreground`, `hover:border-primary/50`
- The `waggle-interactive`, `waggle-card-lift`, `waggle-nav-hover`, and `waggle-press` utility classes in `waggle-theme.css` provide standardized hover/active behaviors
- Chat messages show copy and pin buttons on hover
**Micro-interactions:**
- `send-flash` animation on chat send
- `honey-pulse` animation on memory save
- `heartbeat` animation on health dots
- `hex-cursor` blinking for streaming state
- Dock items bounce on hover (spring animation)
- Window snap preview shows before drop
**Fix recommendations:**
1. Add empty state illustrations for DashboardApp (no workspaces) and EventsApp (no events).
2. Consider skeleton loading states instead of spinner-only for content-heavy views (DashboardApp, AgentsApp).
---
## AI Slop Detection
**Score: 2/10 sloppiness (meaning: mostly clean)**
**Gratuitous gradients:**
- Only one gradient found: `Desktop.tsx:203` uses `linear-gradient(90deg, transparent, hsl(var(--primary) / 0.3), transparent)` for a decorative divider line on the empty desktop. This is tasteful, not gratuitous.
- `Desktop.tsx:189-190` uses a radial gradient mask on the logo. Functional, not decorative.
- No purple-to-blue gradient defaults anywhere. The accent purple (`#a78bfa`) is used sparingly and intentionally for AI activity indicators.
**Glass morphism:**
- Used extensively: `glass` and `glass-strong` utility classes. Found in 17 components (`backdrop-blur-sm` or `backdrop-blur`).
- The glass morphism is part of the intentional OS metaphor (Dock, StatusBar, window snap preview, overlays). It is consistent and purposeful, not slapped on randomly.
- Overlay backdrops consistently use `bg-background/60 backdrop-blur-sm` -- a unified pattern.
- **Verdict:** Intentional design choice, not AI slop.
**Generic patterns:**
- `App.css` in the web app (`apps/web/src/App.css`) is **pure Vite scaffold CSS** that was never cleaned up. It contains `.logo`, `.card`, `.read-the-docs`, and `logo-spin` animation from the default Vite React template. This is dead code.
- No "inspired by Vercel" black-and-white defaults. The Hive DS color palette is distinctive.
- No gratuitous purple-to-blue gradients.
- No generic "glassmorphism card with gradient border" patterns that scream AI-generated.
**Verdict:** The design is authentically crafted, not AI-generated slop. The honey/dark theme is distinctive and consistent. The one flag is the dead `App.css` scaffold that should be deleted.
---
## Design Token Inventory
### What Exists (Defined)
| Category | Count | Location |
|----------|-------|----------|
| Hive gray scale | 12 stops | `app/src/styles/globals.css` |
| Honey scale | 8 stops + 2 special | `app/src/styles/globals.css` |
| shadcn semantic colors | 16 vars | `app/src/styles/globals.css` |
| Status colors | 5 | `app/src/styles/globals.css` |
| Semantic surfaces | 5 | `app/src/styles/globals.css` |
| Shadows | 4 | `app/src/styles/globals.css` |
| KG node colors | 5 | `app/src/styles/waggle-theme.css` |
| Step/event stream colors | 10 | `app/src/styles/waggle-theme.css` |
| Chat bubble colors | 2 | `app/src/styles/waggle-theme.css` |
| Legacy component tokens | 8 | `app/src/styles/waggle-theme.css` |
| Glass utility | 2 classes | `apps/web/src/index.css` |
| Interaction utilities | 4 classes | `app/src/styles/waggle-theme.css` |
| Animations | 9 keyframes | `app/src/styles/globals.css` |
| Light theme | Full set | `app/src/styles/globals.css` |
| Tailwind custom keyframes | 4 | `apps/web/tailwind.config.ts` |
### What Is Needed But Missing
| Token | Why |
|-------|-----|
| **Type scale** | No defined set of font sizes. Currently 10+ arbitrary sizes used. Need 6-7 named stops. |
| **Status color Tailwind mappings** | `--status-healthy` exists but no `text-status-healthy` Tailwind utility. Devs use `text-emerald-400` instead. |
| **Tier colors** | Solo/Basic/Teams/Enterprise tiers have no defined color tokens. Templates and personas also lack color tokens. |
| **Icon size scale** | Icons range from `w-2.5` to `w-10` with no defined scale. Need `--icon-xs`, `--icon-sm`, `--icon-md`, `--icon-lg`. |
| **Spacing tokens for layout** | Window dimensions, dock height, status bar height, sidebar width -- all hardcoded. Should be design tokens. |
| **Z-index scale** | Z-indexes range from 1 to 9999 with no defined layers. Need named layers: `--z-dock`, `--z-window`, `--z-overlay`, `--z-boot`. |
| **Breakpoint tokens** | No responsive breakpoints defined. Need at minimum a `--min-viewport` token. |
| **Focus ring token** | Already exists via shadcn `--ring` but not used consistently in hand-rolled components. |
---
## Critical Finding: Two Divergent CSS Systems
The most significant structural problem is that `app/` (Tauri) and `apps/web/` (web) have completely different CSS foundations:
| Property | `app/src/styles/globals.css` | `apps/web/src/index.css` |
|----------|------------------------------|--------------------------|
| Tailwind version | v4 (`@import "tailwindcss"`) | v3 (`@tailwind base/components/utilities`) |
| Background hue | `222` (cold blue) | `30` (warm amber) |
| Card hue | `222` (cold blue) | `30` (warm amber) |
| Primary | `40 100% 45%` | `38 92% 50%` |
| Accent | `270 60% 68%` (purple) | `38 92% 50%` (same as primary!) |
| Body font | Inter (bundled) | DM Sans (Google CDN) |
| Display font | (not explicitly set) | Space Grotesk (Google CDN) |
| Glass utility | Not defined in CSS | Defined in `@layer utilities` |
| Extended palette | Full hive/honey/status/semantic | None |
| Light theme | Full definition | None |
| Chat prose | Full definition | None |
| Animations | 9 custom keyframes | None |
| Interaction utilities | 4 utility classes | None |
**The web app is missing the entire extended Hive DS palette, light theme, animations, and interaction utilities.** It relies on inline `style={{ color: 'var(--hive-400)' }}` references to CSS variables that are not defined in its own stylesheet (they would only work if the `app/` CSS were also loaded, which it is not in the web build).
**This means:** Every `style={{ color: 'var(--hive-XXX)' }}` in the web app components is referencing **undefined variables**. These will render as black or the initial value. There are 35 such references across 13 files in `apps/web/src/`.
**Fix recommendations:**
1. **Port the extended Hive DS palette** from `app/src/styles/globals.css` to `apps/web/src/index.css`.
2. **Reconcile the base HSL values** -- pick either warm-amber or cold-blue, not both.
3. **Fix the accent divergence** -- in the web app, `--accent` equals `--primary` (both honey). In the Tauri app, `--accent` is purple. This breaks any component that differentiates between primary and accent colors.
4. Consider a shared `packages/ui/styles/tokens.css` that both apps import.
---
## Summary and Priority Matrix
| Dimension | Score | Priority |
|-----------|-------|----------|
| 1. Color consistency | 7/10 | P1 -- Status color tokens needed |
| 2. Typography hierarchy | 4/10 | **P0 -- Type scale is absent, accessibility failure** |
| 3. Spacing rhythm | 7/10 | P2 -- Minor cleanup |
| 4. Component consistency | 6/10 | P1 -- Hand-rolled inputs, dual libraries |
| 5. Responsive behavior | 2/10 | P2 -- Intentional but needs minimum safeguards |
| 6. Dark mode | 8/10 | P2 -- Light theme exists but is inaccessible |
| 7. Animation | 8/10 | P3 -- Minor polish |
| 8. Accessibility | 3/10 | **P0 -- Contrast failure, tiny text, missing ARIA** |
| 9. Information density | 6/10 | P1 -- StatusBar and ModelPilot too dense |
| 10. Polish | 7/10 | P2 -- Missing some empty states |
| **AI Slop** | **Clean** | P3 -- Delete dead `App.css` |
| **CSS divergence** | **Critical** | **P0 -- Two incompatible CSS systems** |
**Overall: 6.3 / 10**
### Top 5 Actions (In Order)
1. **Unify the CSS systems.** Port the Hive DS extended palette, light theme, animations, and interaction utilities from `app/src/styles/globals.css` into a shared location that `apps/web/src/index.css` imports. Fix the 35 undefined CSS variable references in web app components.
2. **Define and enforce a type scale.** Create 6-7 named size tokens, add Tailwind utilities, ban arbitrary `text-[Npx]`. Eliminate all text below 11px (97 instances).
3. **Fix muted-foreground contrast.** Increase from `#5a6380` (3.5:1) to at minimum `#7d869e` (5:1) for WCAG AA. This affects every component in the app.
4. **Create status color Tailwind utilities.** Map `--status-healthy`, `--status-warning`, `--status-error`, `--status-info`, `--status-ai` to Tailwind classes so developers stop using raw `text-emerald-400` (50+ instances to replace).
5. **Replace hand-rolled form inputs with shadcn components.** At least 15 `<input>` elements across AgentsApp, SettingsApp, CreateAgentForm, CreateGroupForm, and GroupDetail are styled inconsistently and have different focus behaviors than the shadcn Input component.
---
*Audit conducted via automated source scan of all CSS files, Tailwind configs, and 45+ component files in `apps/web/src/components/os/`. All line references are from the current HEAD.*