---
phase: 30
slug: hardware-detection-mode-selection
status: draft
shadcn_initialized: true
preset: new-york / neutral / css-variables
created: 2026-04-02
---

# Phase 30 — UI Design Contract

> Visual and interaction contract for Phase 30: Hardware Detection + Mode Selection.
> Generated by gsd-ui-researcher. Verified by gsd-ui-checker.

---

## Design System

| Property | Value | Source |
|----------|-------|--------|
| Tool | shadcn/ui | components.json detected |
| Style | new-york | components.json |
| Base color | neutral | components.json |
| CSS variables | yes | components.json |
| Component library | radix-ui | package.json |
| Icon library | lucide-react (v0.574.0) | package.json |
| Font | system sans-serif (Tailwind default) | index.css — no custom font declared |

---

## Spacing Scale

Declared values (must be multiples of 4):

| Token | Value | Usage |
|-------|-------|-------|
| xs | 4px | Icon gaps, inline padding (`gap-1`) |
| sm | 8px | Compact element spacing (`gap-2`, `p-2`) |
| md | 16px | Default element spacing (`gap-4`, `p-4`) |
| lg | 24px | Section padding (`gap-6`, `p-6`) |
| xl | 32px | Card padding, layout gaps (`p-8`) |
| 2xl | 48px | Major section breaks |
| 3xl | 64px | Page-level spacing |

Exceptions:
- Mode selector cards: `p-4` (16px) internal padding — consistent with existing shadcn card pattern
- Hardware stat rows: `gap-2` (8px) between icon and value
- Wizard dialog: `p-8` (32px) outer padding — matches NexusOnboardingWizard.tsx

Source: NexusOnboardingWizard.tsx spacing patterns (`p-8`, `gap-6`, `gap-4`, `gap-2`)

---

## Typography

| Role | Size | Weight | Line Height | Usage |
|------|------|--------|-------------|-------|
| Body | 14px (`text-sm`) | 400 (regular) | 1.5 | Descriptions, form labels, mode card titles, stat labels, muted helper text |
| Heading | 24px (`text-2xl`) | 600 (semibold) | 1.2 | Step heading ("Choose your mode") |
| Caption | 12px (`text-xs`) | 400 (regular) | 1.4 | Mode card descriptions, hardware sub-labels |

Source: NexusOnboardingWizard.tsx uses `text-2xl font-semibold` for heading, `text-sm` for body, `text-xs text-muted-foreground` for captions. No 4th size needed beyond these three roles.

---

## Color

All values are CSS variable references to the project's dual-theme token set (Catppuccin Latte light / Catppuccin Mocha dark, Tokyo Night dark variant also present).

| Role | Light value | Dark value | Usage |
|------|-------------|------------|-------|
| Dominant (60%) | `--background` #eff1f5 | #1e1e2e | Dialog backdrop, page surface |
| Secondary (30%) | `--card` #e6e9ef | #181825 | Mode selector cards, hardware info card, stat rows |
| Accent (10%) | `--primary` #1e66f5 | #89b4fa | Selected mode card border + tint, active step indicator, spinner |
| Destructive | `--destructive` #d20f39 | #f38ba8 | Error messages only |

Accent reserved for:
1. Selected mode card: `border-primary bg-primary/5` (identical to RESEARCH.md Pattern 5)
2. Primary CTA button background
3. Spinner/loading indicator while probe is in-flight
4. Focus ring (`--ring` = same as `--primary`)

No second semantic color beyond destructive. Success states (hardware probe OK) use muted text color, not a success green — consistent with wizard's existing error pattern that uses `text-destructive` not a new semantic color.

Source: index.css CSS custom properties; NexusOnboardingWizard.tsx color class patterns

---

## Component Inventory

New components to build for this phase:

| Component | Path | Shadcn primitives used |
|-----------|------|------------------------|
| `ModeSelector` | `ui/src/components/onboarding/ModeSelector.tsx` | none (raw buttons + cn utility) |
| `HardwareSummaryStep` | `ui/src/components/onboarding/HardwareSummaryStep.tsx` | `Skeleton`, `Badge` (optional) |
| `NexusOnboardingWizard` | `ui/src/components/NexusOnboardingWizard.tsx` | `Dialog/DialogPortal`, `Button`, `Input` (already imported) |

Existing shadcn components already installed and usable without re-adding:
`button`, `input`, `dialog`, `skeleton`, `badge`, `card`, `separator`, `tabs`, `tooltip`

---

## States and Interactions

### ModeSelector

| State | Visual |
|-------|--------|
| Unselected | `border-border hover:border-muted-foreground/50` — subtle hover |
| Selected | `border-primary bg-primary/5` — primary accent border + tinted fill |
| Default selection | "Both (recommended)" pre-selected on mount |

### HardwareSummaryStep

| State | Visual |
|-------|--------|
| Probing (in-flight) | Three `Skeleton` rows (GPU/RAM/Tier), each `h-4 w-full rounded` — matches shadcn Skeleton usage |
| Probe success — GPU tier | GPU name + VRAM GB labeled "GPU VRAM", tier badge "GPU-accelerated" |
| Probe success — Apple Silicon | Unified memory GB labeled "Unified memory" (never "VRAM"), tier badge "Apple Silicon" |
| Probe success — CPU-only | RAM labeled "System RAM", muted warning "Slower than GPU-accelerated models — cloud AI recommended" |
| Probe error / timeout | Inline error row: "Could not detect hardware. You can still continue." — uses `text-muted-foreground`, not `text-destructive` (non-blocking) |

Privacy frame (ONBD-07 — shown when local AI tier is viable, i.e. gpu or apple_silicon):
```
Local AI  (recommended for privacy)
Runs entirely on your machine.
No accounts. No tracking. Works offline.
```
Rendered as: heading `text-sm font-medium` + two-line body `text-xs text-muted-foreground`. No icon required — copy is the signal.

### Onboarding Wizard Step Flow

Steps added to the existing `NexusOnboardingWizard`:
1. Hardware detection (auto-runs, no user input) — `HardwareSummaryStep`
2. Mode selection — `ModeSelector`
3. Root directory (existing step — moved to step 3)

Step indicator: simple numbered dots or text "Step N of 3" using `text-xs text-muted-foreground`. No progress bar component needed at this phase.

Probe timeout: 5 seconds maximum (ONBD-02 success criterion). If probe does not resolve within 5s, show error state and continue.

---

## Copywriting Contract

| Element | Copy | Source |
|---------|------|--------|
| Wizard heading (step 1) | "Detecting your hardware…" | Default (probe in-flight) |
| Wizard heading (step 1 resolved) | "Your hardware" | Default |
| Wizard heading (step 2) | "Choose your mode" | RESEARCH.md mode labels |
| Mode: Personal AI | "Personal AI Assistant" / "Always available, persistent memory, private." | RESEARCH.md Pattern 5 verbatim |
| Mode: Project Builder | "Project Builder" / "Brainstorm → PM → Engineer → shipped product." | RESEARCH.md Pattern 5 verbatim |
| Mode: Both | "Both (recommended)" / "A conversation becomes a project with one click." | RESEARCH.md Pattern 5 verbatim |
| Local AI privacy frame | "Local AI (recommended for privacy) — Runs entirely on your machine. No accounts. No tracking. Works offline." | ONBD-07 PRD copy verbatim |
| CPU-only warning | "Slower than GPU-accelerated models — cloud AI recommended" | RESEARCH.md Pattern 6 display rules |
| Hardware probe error | "Could not detect hardware. You can still continue." | Default — non-blocking |
| Primary CTA (step 2 → step 3) | "Continue" | Default |
| Primary CTA (step 3 — final) | "Get Started" | Existing wizard copy preserved |
| Empty state heading | not applicable — hardware probe always returns a result (even degraded) | — |
| Error state | "Setup failed. Please try again." | Existing wizard pattern preserved |

Destructive actions in this phase: none. Mode selection is reversible; no confirmation dialogs required.

No "company", "CEO", or "mission" language. VOCAB.appName is the only brand token allowed.

---

## Registry Safety

| Registry | Blocks Used | Safety Gate |
|----------|-------------|-------------|
| shadcn official | button, input, dialog, skeleton, badge | not required |
| third-party | none | not applicable |

No third-party registries declared for this phase.

---

## Checker Sign-Off

- [ ] Dimension 1 Copywriting: PASS
- [ ] Dimension 2 Visuals: PASS
- [ ] Dimension 3 Color: PASS
- [ ] Dimension 4 Typography: PASS
- [ ] Dimension 5 Spacing: PASS
- [ ] Dimension 6 Registry Safety: PASS

**Approval:** pending
