# Extrudex — Homepage (Main Hub) UI/UX Specification

> **Author:** Sketch (Design Lead)  
> **Date:** April 20, 2026  
> **Version:** 1.0  
> **Status:** Ready for Review → Implementation Handoff

---

## 1. Objective

**Who is it for?**  
Workshop operators and print managers who interact with Extrudex primarily on a Raspberry Pi 5 kiosk touchscreen (arm's length, greasy hands, ambient workshop lighting) and secondarily via a mobile PWA browser for remote monitoring.

**What task are they completing?**  
The Homepage serves as the **command center** — the single screen where a user can, at a glance:

1. **Assess the fleet** — See the real-time status of every printer (printing, idle, paused, error, offline).
2. **Spot problems fast** — Instantly identify which machines need attention (errors, paused jobs, low filament).
3. **Take action** — Navigate to a specific printer, spool, or print job with minimal taps.
4. **Monitor inventory** — Get a quick read on filament stock levels and recent consumption.
5. **Recent activity** — See the last few completed or failed prints for situational awareness.

**Success metric:** A user walking past the kiosk can determine fleet health in under 2 seconds without touching the screen.

---

## 2. Screen Inventory

The Homepage/Main Hub is a **single screen** that serves as the root of the navigation tree. It does not itself contain sub-screens, but it is the gateway to:

| Destination Screen | Triggered By | Priority |
|---|---|---|
| **Printer Detail** | Tapping any printer card | Primary |
| **Spool Inventory** | Nav tab "Spools" | Primary |
| **Print Jobs** | Nav tab "Prints" | Primary |
| **Materials DB** | Nav tab "Materials" | Secondary |
| **Settings** | Nav tab "Settings" | Secondary |
| **Quick Scan** | Floating action button (FAB) | Primary |

The Homepage itself contains these **in-page sections** (not separate screens):

1. **Status Summary Bar** — Fleet-wide health at a glance
2. **Printer Fleet Grid** — Live status cards for each printer
3. **Filament Stock Snapshot** — Inventory overview with low-stock alerts
4. **Recent Activity Feed** — Last 5 print events

---

## 3. Layout Specification

### Page Title
**"Extrudex"** — Always visible in the top app bar. No subtitle needed; this is the root screen.

### Navigation Structure

**Primary Navigation: Bottom Navigation Bar (Mobile/Kiosk)**  
Material Design 3 bottom navigation with 5 destinations:

| Tab | Icon (Material Symbols) | Label | Badge? |
|---|---|---|---|
| **Hub** | `dashboard` | Hub | — (active by default) |
| **Printers** | `print` | Printers | Error count badge |
| **Spools** | `inventory_2` | Spools | Low-stock badge |
| **Prints** | `receipt_long` | Prints | — |
| **Settings** | `settings` | Settings | — |

**Rationale for bottom nav:**  
- Touch-first: bottom nav is the easiest reach zone on a touchscreen kiosk or phone.
- 5 tabs is the MD3 maximum — keeps things scannable.
- "Hub" is the homepage; the other four are top-level destinations.
- Badges on Printers/Spools draw attention to problems without requiring navigation.

**Desktop/Navigation Rail (Future)**  
On wider screens (browser dashboard), the bottom nav converts to a Material 3 Navigation Rail on the left edge with the same 5 destinations. This is a responsive transformation, not a separate navigation system.

### Main Sections (Top to Bottom)

#### A. Top App Bar
- **Leading:** Extrudex logo mark (gear icon + "EXTRUDEX" in Inter Bold)
- **Trailing:** 
  - Connection status indicator (green dot = SignalR connected, red dot = disconnected)
  - Clock (kiosk mode — always visible so users know the time without looking at their phone)
- **Style:** MD3 medium top app bar, `surface` color background, no elevation (flat)
- **Height:** 64px kiosk / 56px mobile

#### B. Status Summary Bar
A horizontal strip below the app bar showing fleet-wide metrics in a single row:

| Metric | Format | Color Logic |
|---|---|---|
| Printers Active | `4 / 7` | Text only, neutral |
| Printers in Error | `1` | Red if > 0, hidden if 0 |
| Low Filament Spools | `2` | Yellow if > 0, hidden if 0 |
| Prints Today | `12` | Neutral |

- **Layout:** Horizontal flex row, evenly spaced, each metric in a compact chip/badge
- **Kiosk override:** Larger font (20px), more spacing between metrics
- **Mobile:** Compact chips with icons, horizontally scrollable if overflow
- **Tap behavior:** Tapping "Printers in Error" navigates to Printers tab filtered to errors. Tapping "Low Filament" navigates to Spools tab filtered to low stock.

#### C. Printer Fleet Grid
The **heart of the homepage**. A responsive grid of printer status cards.

**Card Layout (each printer):**

```
┌─────────────────────────────┐
│  [Status Dot]  Printer Name  │  ← Header row
│─────────────────────────────│
│  Current Job: Benchy #3     │  ← Job name or "Idle"
│  [████████░░] 72%           │  ← Progress bar + percentage
│  Filament: PLA Silk         │  ← Active material
│  Remaining: ~142g           │  ← Spool remaining
│  ETA: 0h 23m               │  ← Time remaining
│─────────────────────────────│
│  [View Detail →]            │  ← Tap target / CTA
└─────────────────────────────┘
```

**Status Dot Colors:**
- 🟢 Green (`#4ADE70` kiosk / `#16A34A` light) — Printing / Active
- 🟡 Yellow (`#FACC15` kiosk / `#CA8A04` light) — Paused
- 🔴 Red (`#F87171` kiosk / `#DC2626` light) — Error / Failed
- ⚪ Gray (`#64748B`) — Idle / Offline

**Grid Behavior:**
- Kiosk (800×480 Pi 5): 2 columns, 3–4 rows (scrollable)
- Tablet (768px+): 3 columns
- Mobile (< 480px): 1 column, list view

**Card Dimensions:**
- Kiosk: Full-width within column, min-height 180px
- Mobile: Full-width, min-height 140px, slightly denser

**Important States:**
- **Printing (active):** Progress bar animates, card has subtle left-border accent in green
- **Paused:** Yellow left border, progress bar frozen, "PAUSED" badge overlaid
- **Error:** Red left border, card background shifts to `error-container` token, error message shown
- **Idle:** Gray left border, dimmed progress area, "Ready" label
- **Offline:** Fully dimmed card, "OFFLINE" badge, no real-time data

#### D. Filament Stock Snapshot
A compact section showing inventory health:

**Layout:** Horizontal scrolling row of small cards or a mini-list

```
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│  PLA             │ │  PETG            │ │  TPU             │
│  ████████░░ 80%  │ │  ████░░░░░ 40%  │ │  ██░░░░░░░ 20%   │
│  23 spools       │ │  8 spools        │ │  3 spools ⚠️     │
└──────────────────┘ └──────────────────┘ └──────────────────┘
```

- Each card shows: Material base name, stock percentage bar, spool count
- Cards with < 25% stock get a `⚠️` warning indicator and yellow-tinted background
- **Kiosk:** 2–3 cards visible, swipe to see more
- **Mobile:** Horizontal scroll carousel
- **Tap:** Navigates to Spools tab filtered by that material

#### E. Recent Activity Feed
The last 5 print events in a compact list:

```
┌────────────────────────────────────────────────────┐
│ ✓  Benchy #3      · PLA Silk    · 23g   · 0h45m    │
│ ✓  Gear Set v2    · PETG Basic  · 87g   · 2h12m    │
│ ✗  Phone Case     · TPU Basic   · —      · Failed   │
│ ✓  Calibration    · PLA Basic   · 4g    · 0h05m    │
│ ✓  Bracket x4     · ASA Matte   · 156g  · 4h30m    │
└────────────────────────────────────────────────────┘
```

- Each row: Status icon, job name, material, weight used, duration
- Failed prints show `✗` in red with "Failed" label
- **Kiosk:** Larger text, comfortable row height (56px)
- **Mobile:** Standard list density (48px rows)
- **Tap a row:** Navigates to that print's detail view
- **"View All" link:** At bottom, navigates to Prints tab

### Primary CTA
**Floating Action Button (FAB):** "Quick Scan" — a prominent FAB in the bottom-right corner with a `qr_code_scanner` icon. This triggers the barcode/USB scanner workflow for spool check-in/check-out.

- Kiosk: Extended FAB with label "Scan" + icon, 56×56px minimum
- Mobile: Standard FAB, icon only, 56×56px
- Positioned above the bottom nav, with 16px margin from edges

### Secondary Actions
- Tap any printer card → Printer Detail
- Tap any stock card → Spools filtered
- Tap any activity row → Print detail
- Tap error/low badges in summary bar → Filtered navigation

### Key Components (MD3)

| Component | Usage | Notes |
|---|---|---|
| Bottom Navigation | Primary nav | 5 destinations |
| Top App Bar (Medium) | App header | Logo + status + clock |
| Cards (Elevated) | Printer status | Real-time content |
| Cards (Filled/outlined) | Filament stock | Compact, scrollable |
| List | Activity feed | 3-line items |
| FAB (Extended/Regular) | Quick Scan | Always accessible |
| Badge | Nav tabs, status | Error count, low stock |
| Linear Progress Indicator | Print progress | On printer cards |
| Chip | Status summary | Compact metrics |

### Important States

| State | Visual Treatment |
|---|---|
| Loading (initial) | Skeleton screens for printer cards, shimmer animation |
| SignalR disconnected | Red dot in app bar, banner: "Live updates paused — reconnecting..." |
| No printers registered | Empty state illustration + "Add your first printer" CTA |
| No spools registered | Stock section shows "No inventory — add spools to start tracking" |
| All printers idle | Fleet grid shows all gray cards, summary bar shows "0 active" |
| Critical error (printer) | Card pulses red border once, then steady red left border |

---

## 4. UX Rationale

### Why This Layout Supports the Task

1. **Fleet health at a glance:** The Status Summary Bar + Printer Fleet Grid are visible immediately on load. No scrolling required on kiosk to see if something is wrong. Color-coded status dots and left-border accents make the visual scan instantaneous.

2. **Progressive detail:** The homepage gives you "enough" — status, progress, material. You only tap into a printer card when you need details (temps, G-code, history). This avoids information overload while keeping critical data surface-level.

3. **Inventory awareness without navigation:** The Filament Stock Snapshot means operators don't need to leave the homepage to know if they're running low. The warning state (yellow + ⚠️) is visible without interpreting numbers.

4. **Activity context:** The Recent Activity Feed gives "what just happened" situational awareness — useful when returning to the kiosk after being away. It answers "did that print finish?" without requiring navigation.

5. **Scan-first workflow:** The FAB for Quick Scan is always accessible from the homepage, which is the most common action for spool check-in during workshop operations. Placed bottom-right — the natural resting thumb zone.

### Hierarchy (What matters most → least)

1. **Printer errors** (red, draws the eye immediately)
2. **Active printers with progress** (green accent, animated progress bars)
3. **Paused printers** (yellow accent, needs attention)
4. **Low filament warnings** (yellow indicators in stock section)
5. **Idle printers** (gray, calm, no action needed)
6. **Recent activity** (informational, below the fold on mobile)

### Tradeoffs

| Decision | Benefit | Cost | Mitigation |
|---|---|---|---|
| Bottom nav over side nav | Touch-friendly, MD3 standard, always visible | Takes screen space at bottom | Acceptable on touch-first device |
| Cards over table | Glanceable, status-colorable, touch-friendly | Less dense (can't see 7 printers at once) | Grid layout maximizes visible count; scroll for 6+ printers |
| Summary bar metrics | Fleet health without scrolling | Adds cognitive load if too many metrics | Keep to 4 max, hide zero-value metrics |
| Horizontal scroll for stock cards | Saves vertical space, works well for 3–6 materials | Hidden cards require swipe | First 3 most-used materials visible; swipe for rest |
| FAB for scan | Always accessible, one-tap | Covers content behind it | Standard FAB behavior; scrolls away on mobile |
| No sidebar on kiosk | Maximizes kiosk screen real estate | No persistent deep-nav | Bottom nav is sufficient for 5 top-level destinations |

---

## 5. Visual Direction

### Tone
**Modern Industrial/Maker** — Dark mode by default on kiosk. Professional workshop vibe. High contrast. Think: a CNC control panel, not a social media app. The aesthetic should feel like a tool you trust, not an app you browse.

### Dark Mode Palette (Kiosk Default)

| Token | Value | Usage |
|---|---|---|
| `md.sys.color.background` | `#0F172A` | Page background |
| `md.sys.color.surface` | `#1E293B` | Card backgrounds, nav bar |
| `md.sys.color.surface-container` | `#334155` | Elevated cards, containers |
| `md.sys.color.surface-container-high` | `#475569` | Hover/pressed states |
| `md.sys.color.primary` | `#60A5FA` | Primary actions, links, active tab |
| `md.sys.color.on-primary` | `#0F172A` | Text on primary |
| `md.sys.color.primary-container` | `#1E3A5F` | Subtle primary tinted containers |
| `md.sys.color.error` | `#F87171` | Error states, failed prints |
| `md.sys.color.error-container` | `#450A0A` | Error card backgrounds |
| `md.sys.color.on-error` | `#FFFFFF` | Text on error |
| `md.sys.color.on-surface` | `#F1F5F9` | Primary text |
| `md.sys.color.on-surface-variant` | `#94A3B8` | Secondary text |
| `md.sys.color.outline` | `#334155` | Borders, dividers |
| `md.sys.color.outline-variant` | `#1E293B` | Subtle borders |

### Light Mode Palette (Dashboard/Future)

| Token | Value | Usage |
|---|---|---|
| `md.sys.color.background` | `#F8FAFC` | Page background |
| `md.sys.color.surface` | `#FFFFFF` | Card backgrounds |
| `md.sys.color.primary` | `#2563EB` | Primary actions |
| `md.sys.color.on-surface` | `#0F172A` | Primary text |
| `md.sys.color.on-surface-variant` | `#475569` | Secondary text |

### Typography

| Role | Font | Weight | Size (Kiosk) | Size (Mobile) |
|---|---|---|---|---|
| App Title | Inter | Bold | 22px | 20px |
| Card Title (Printer Name) | Inter | SemiBold | 20px | 18px |
| Section Heading | Inter | SemiBold | 18px | 16px |
| Body Text | Inter | Regular | 18px | 16px |
| Metric Value | Inter | Bold | 28px | 24px |
| Metric Label | Inter | Medium | 14px | 12px |
| Mono Values (weight, time, %) | JetBrains Mono | Medium | 18px | 16px |
| Caption / Timestamp | Inter | Regular | 14px | 12px |

**Rationale for oversized metrics:** The kiosk is viewed at arm's length or further. A 28px bold metric is legible from 3–4 feet away. Monospace for numeric values ensures columns align and feels "instrument-like."

### Spacing / Density

| Token | Kiosk | Mobile |
|---|---|---|
| Page padding | 24px | 16px |
| Card padding | 20px | 16px |
| Grid gap | 16px | 12px |
| Section gap | 32px | 24px |
| Row height (lists) | 56px | 48px |
| FAB margin from edge | 16px | 16px |
| Touch target minimum | 48px | 44px |

### Component Behavior

- **Printer cards:** Update in real-time via SignalR. Progress bar animates smoothly (CSS transition 300ms). Status changes trigger a brief highlight flash (200ms background shift) to draw attention.
- **Bottom nav:** Active tab has `primary` color icon + label. Inactive tabs use `on-surface-variant`. Badges are small circles positioned at the icon's top-right.
- **FAB:** Elevated with shadow-3. On tap, ripple effect. Extended label appears on kiosk (wider screen), icon-only on mobile.
- **Status summary bar:** Metric chips are non-scrolling on kiosk (fits in one row at 800px width), horizontally scrolling on mobile if needed.
- **Activity feed:** List items have subtle divider lines (`outline-variant`). Failed items have `error-container` background tint.
- **Skeleton loading:** Cards show shimmer placeholder during initial load (1.5s max before content appears).

### Color Usage Guidelines

1. **Color is information, not decoration.** Every colored element must communicate state.
2. **Red = immediate attention.** Only use for errors, failures, disconnections. Never for decoration.
3. **Yellow = needs attention soon.** Paused printers, low filament, warnings.
4. **Green = operating normally.** Active printing, completed, connected.
5. **Blue = interactive.** Links, buttons, active navigation, primary CTAs.
6. **Gray = neutral/idle.** Offline printers, inactive states, secondary info.
7. **Never use color alone to convey meaning.** Always pair with icon + text label (accessibility).

---

## 6. Responsiveness

### Breakpoints

| Breakpoint | Width | Layout |
|---|---|---|
| Kiosk | 480–800px (Pi 5 typical: 800×480) | 2-col grid, bottom nav, extended FAB |
| Mobile (compact) | < 480px | 1-col list, bottom nav, standard FAB |
| Tablet | 768–1024px | 3-col grid, bottom nav, extended FAB |
| Desktop | 1024px+ | 3-col grid, nav rail, extended FAB |

### Layout Changes by Device

#### Pi 5 Kiosk (800×480, Landscape)
- **Top app bar:** 64px height, clock always visible
- **Status summary:** 4 metrics in a single row (fits 800px)
- **Printer grid:** 2 columns × N rows, scrollable vertically
- **Stock snapshot:** 3 cards visible, no scroll needed (most common materials first)
- **Activity feed:** 3 rows visible, "View All" link
- **Bottom nav:** Full 5 tabs
- **FAB:** Extended with "Scan" label

#### Mobile PWA (< 480px, Portrait)
- **Top app bar:** 56px height, no clock (use phone clock)
- **Status summary:** 2–3 metrics visible, horizontal scroll for more
- **Printer grid:** 1 column list view (cards become horizontal list items)
- **Stock snapshot:** Horizontal carousel, 2 cards visible
- **Activity feed:** 3–5 rows, compact density
- **Bottom nav:** 5 tabs (may collapse labels on very narrow screens)
- **FAB:** Icon only, standard 56px

#### Tablet / Desktop Browser
- **Bottom nav → Navigation Rail** (left side, 80px wide)
- **Printer grid:** 3 columns
- **Stock snapshot:** 4–5 cards visible in row
- **Activity feed:** 5 rows
- **Additional whitespace** — dashboard mode can breathe more

### Kiosk-Specific Considerations

- **No hover states** — all interactions are tap/click only
- **No tooltips** — information must be visible inline
- **Larger touch targets** — 48px minimum (4px above MD3 default)
- **No right-click context menus** — all actions are explicit buttons/links
- **Screen wake** — kiosk should not sleep; CSS `animation` on a subtle element to prevent screen burn-in (shift a 1px element every 60s)
- **Overshoot scroll** — prevent pull-to-refresh or browser gestures (PWA `overscroll-behavior: none`)

---

## 7. Developer Handoff Notes

### Reusable Components to Build

| Component | Type | Props/Inputs | Notes |
|---|---|---|---|
| `<ex-printer-card>` | Standalone | `printer: Printer`, `status: PrinterStatus`, `job?: PrintJob` | Left-border color computed from status. SignalR drives re-renders. |
| `<ex-status-dot>` | Atom | `status: 'active' \| 'paused' \| 'error' \| 'idle' \| 'offline'` | Small colored circle (12px) with aria-label for accessibility |
| `<ex-metric-chip>` | Atom | `label: string`, `value: string \| number`, `variant: 'default' \| 'error' \| 'warning'` | Used in Status Summary Bar |
| `<ex-stock-card>` | Standalone | `material: string`, `percentage: number`, `spoolCount: number`, `lowStock: boolean` | Horizontal scroll child |
| `<ex-activity-item>` | List Item | `job: PrintEvent` | 3-line list item with status icon |
| `<ex-progress-bar>` | Atom | `value: number`, `status: PrinterStatus` | MD3 linear progress, color matches status |
| `<ex-fleet-summary>` | Composite | `printers: Printer[]`, `spools: Spool[]` | Renders metric chips row |
| `<ex-connection-indicator>` | Atom | `connected: boolean` | Green/red dot in app bar |

### Angular Material Components Used

- `MatBottomNavigation` (or custom bottom nav — MD3 bottom nav is not yet in Angular Material; implement with `MatTabNav` + custom styling)
- `MatCard` → Styled with custom dark tokens
- `MatProgressBar` → Custom color per status
- `MatFabButton` / `MatMiniFabButton`
- `MatBadge` → For nav tab badges
- `MatList` → Activity feed
- `MatChip` → Status summary metrics
- `MatIcon` → Material Symbols throughout
- `MatToolbar` → Top app bar

### Interaction Notes

1. **SignalR subscriptions:** The homepage must subscribe to `PrinterHub` on mount. Each printer card re-renders on status/progress push events. Unsubscribe on navigate-away.
2. **Optimistic updates:** Progress bars should animate smoothly — use CSS transitions, not discrete jumps. If SignalR sends a progress update every 5s, interpolate between values.
3. **FAB scan action:** On tap, immediately focus a hidden text input that captures USB HID barcode scanner output ( scanners type characters + Enter). This is a capture-only input — no keyboard should appear on mobile. Use `<input readonly>` or intercept `keydown` globally.
4. **Pull-to-refresh:** Disabled on kiosk. On mobile PWA, consider enabling for manual data refresh.
5. **Navigation:** Use Angular Router with bottom nav tabs bound to routerLinkActive. Highlight active tab. Preserve scroll position when returning to Hub.
6. **Skeleton screens:** On initial load, show 6 skeleton printer cards (matching grid layout). Use `@angular/material` skeleton patterns or custom shimmer CSS.

### Accessibility

| Requirement | Implementation |
|---|---|
| Screen reader | All status indicators have `aria-label` (e.g., "Printer Elegoo-1: Printing, 72% complete") |
| Color blindness | Never color-only — always icon + text + color. Status dots have aria-labels |
| Keyboard nav | Tab order: top bar → summary metrics → printer cards (grid order) → stock → activity → FAB → bottom nav |
| Focus management | After navigation, focus lands on the page title. After FAB tap, focus returns to FAB |
| Touch target | 48px minimum on kiosk, 44px minimum on mobile — all interactive elements |
| Contrast | All text on dark background meets WCAG AA (4.5:1 for body, 3:1 for large text) |
| Motion | Respect `prefers-reduced-motion` — disable progress bar animation and shimmer if set |
| Live regions | Printer status changes announced via `aria-live="polite"` on the card region |

### Performance Notes

- **OnPush change detection** for all components receiving SignalR data
- **TrackBy** on printer grid `*ngFor` to avoid re-rendering unchanged cards
- **Virtual scrolling** for activity feed if it grows beyond 20 items (use `@angular/cdk ScrollingModule`)
- **Lazy load** Spools, Prints, Materials, Settings tabs — only Hub is eager-loaded
- **Image optimization:** Use inline SVG for status icons, not raster images. Logo should be SVG.

### File Structure Suggestion

```
src/app/
├── pages/
│   └── hub/
│       ├── hub.component.ts
│       ├── hub.component.html
│       ├── hub.component.scss
│       └── hub.component.spec.ts
├── components/
│   ├── printer-card/
│   ├── status-dot/
│   ├── metric-chip/
│   ├── stock-card/
│   ├── activity-item/
│   ├── progress-bar/
│   ├── fleet-summary/
│   └── connection-indicator/
├── layout/
│   ├── bottom-nav/
│   ├── top-app-bar/
│   └── nav-rail/
└── shared/
    └── tokens/
        └── _extrudex-tokens.scss
```

---

## Appendix: Navigation Map

```
┌──────────────────────────────────────────────────────────────┐
│                        EXTRUDEX                              │
│                                                              │
│  ┌─ Hub (Home) ──────────────────────────────────────────┐   │
│  │  • Fleet Status Grid                                   │   │
│  │  • Filament Snapshot                                    │   │
│  │  • Recent Activity                                      │   │
│  │  • [FAB: Quick Scan]                                   │   │
│  └────────────────────────────────────────────────────────┘   │
│                                                              │
│  ┌─ Printers ────────┐  ┌─ Spools ─────────────────────┐     │
│  │  Printer List      │  │  Spool Inventory             │     │
│  │  → Printer Detail  │  │  → Spool Detail              │     │
│  │    → Job History   │  │  → Check-in/Check-out        │     │
│  │    → Controls      │  │  → Link to Printer           │     │
│  └────────────────────┘  └─────────────────────────────┘     │
│                                                              │
│  ┌─ Prints ──────────┐  ┌─ Settings ───────────────────┐    │
│  │  Print Job List    │  │  System Configuration          │    │
│  │  → Print Detail   │  │  Printer Management           │    │
│  │  → COGS Report    │  │  User Preferences              │    │
│  └────────────────────┘  └──────────────────────────────┘    │
│                                                              │
│  ══════════════════════════════════════════════════════════   │
│  [Hub]  [Printers]  [Spools]  [Prints]  [Settings]           │
│  ══════════════════════════════════════════════════════════   │
└──────────────────────────────────────────────────────────────┘
```

---

*End of Specification — Ready for Stuart (mockup generation) and Rex (implementation handoff)*