# Nexus Phase 15 — Mobile Parity

> Use `superpowers:test-driven-development`. Commit atomically.

**Goal:** Bring the new frame to mobile breakpoint `< 768px`. Replace the legacy `MobileBottomNav` with a 4-destination bottom tab bar matching the desktop IconRail destinations (Assistant, Studio, Projects, Settings). Collapse the desktop slide-overs (History, Memory) to full-screen sheets on mobile. Make the project tab strip scroll horizontally without shrinking. Adapt the promote-to-project transition to a full-screen takeover on mobile instead of the split layout.

**Source of truth:** spec §9 (Mobile).

**Branch:** `nexus/design-system-migration`.

---

## Ownership boundaries

**You may create or modify ONLY:**

| Path | Action |
|---|---|
| `ui/src/components/frame/MobileTabBar.tsx` | Create |
| `ui/src/components/frame/MobileTabBar.test.tsx` | Create |
| `ui/src/components/Layout.tsx` | Modify — swap `MobileBottomNav` for `MobileTabBar` |
| `ui/src/components/assistant/HistorySheet.tsx` | Modify — add mobile full-screen variant |
| `ui/src/components/assistant/MemorySheet.tsx` | Modify — add mobile full-screen variant |
| `ui/src/components/assistant/PromoteTransition.tsx` | Modify — mobile full-screen takeover variant |
| `ui/src/components/projects/BuilderTabStrip.tsx` | Modify — horizontal scroll on mobile |
| `ui/src/components/frame/TopStrip.tsx` | Modify if needed — mobile tweaks to cluster spacing |

**You MUST NOT touch:**

- Phase 8 icon rail semantics (desktop behavior stays)
- Phase 9 Assistant thread layout (desktop stays)
- Phase 10 Studio grid (mobile already collapses to 1-col)
- Phase 11 Project card layout (desktop stays)
- `ui/src/App.tsx`

---

## Scope

### 1. MobileTabBar component

Replacement for `MobileBottomNav`. Renders 4 tab links at the bottom of the viewport:
- Assistant (MessageCircle)
- Studio (Sparkles)
- Projects (FolderKanban)
- Settings (Settings)

Specs:
- `fixed bottom-0 left-0 right-0 h-14` (56px tall)
- `border-t border-border bg-background` — charcoal top border, pure black fill
- Each tab is a flex column: icon on top (20×20), label below (10px uppercase 1.4px tracking)
- Silver default, volt active with a 2px volt bar above the icon
- Focus-visible styles per DESIGN.md
- Safe-area aware: `pb-[env(safe-area-inset-bottom)]`
- Active state derivation: same regex patterns as IconRail's `isActive` functions — factor out if possible

Delete the existing `MobileBottomNav.tsx` after confirming the new bar covers its behavior. If `MobileBottomNav` has non-destination features (e.g., a "new issue" FAB), report them and the controller will decide whether to keep or drop.

### 2. Mobile slide-over → full-screen sheet

Phase 9's `HistorySheet` and `MemorySheet` are desktop slide-overs at 320px / 340px. On mobile:
- Take the full viewport width
- Full viewport height below the top strip (48px)
- Close button in the top-right of the sheet
- Swipe-down-to-close gesture (optional — acceptable if CSS-only)

Implementation: add a `useMediaQuery("(min-width: 768px)")` check; when mobile, render different class names that go full-screen. Do NOT duplicate the component — same file, conditional rendering.

### 3. Promote-to-project mobile takeover

Phase 12's `PromoteTransition` split-screen layout (30% chat ribbon / 70% brainstormer) doesn't fit on mobile. On mobile, the brainstormer **completely covers the chat** — slides up to 100% viewport height instead of 70%.

Implementation: same `PromoteTransition.tsx` file, conditional max-height and translate values based on `useMediaQuery`. Tests need a mobile case.

### 4. BuilderTabStrip horizontal scroll

Phase 11's Project tab strip has 7 tabs that don't fit on narrow mobile. Spec §9.1 says "Project sub-tabs become a horizontally-scrolling strip under the header, no shrinking."

Implementation: on mobile, wrap the tab list in a `flex overflow-x-auto` container with `scroll-snap-type: x mandatory` for tab-sized snapping. Add edge fades (`mask-image` or left/right gradient overlays) so users see there's more content. Tests need a mobile case.

### 5. TopStrip mobile polish

On mobile, the top strip should:
- Keep the 48px height
- Drop the `⌘K` text label and show only the kbd glyph (already minimal — verify)
- Keep the mic button
- Keep the mode breadcrumb but allow it to truncate if too long
- Consider whether to hide the breadcrumb entirely on very narrow screens

---

## Implementation notes

### `useMediaQuery("(min-width: 768px)")` already exists

`ui/src/hooks/useMediaQuery.ts` (or similar) is used throughout the codebase. Consume it rather than adding a new media-query hook.

### Mobile breakpoint is single — 768px

Per spec §9.2: "Single breakpoint: `>= 768px` is desktop frame, `< 768px` is mobile frame." Don't introduce intermediate breakpoints; everything is binary.

### Tailwind responsive classes vs runtime media query

For simple show/hide behavior, use Tailwind's `hidden md:block` / `md:hidden`. For layout variants that need JS logic (like the promote transition's translate values), use `useMediaQuery`. Prefer CSS when possible.

---

## Acceptance criteria

1. On a viewport `< 768px`, the new MobileTabBar renders with 4 destinations matching the IconRail; clicking each navigates correctly
2. The 56px desktop IconRail is hidden on mobile (already `hidden md:flex` from Phase 8 — verify)
3. HistorySheet and MemorySheet render full-screen on mobile
4. The promote-to-project transition completely covers the chat on mobile
5. BuilderTabStrip scrolls horizontally on mobile with no tabs cropped
6. TopStrip remains 48px and functional on mobile
7. Safe-area insets (notch, home indicator) respected
8. `MobileBottomNav` file deleted or clearly documented as dead
9. All existing frame + assistant + projects tests pass
10. Mobile-specific tests added

---

## Report format

- Status
- Commit SHAs
- Files created / modified / deleted
- Mobile tests added
- Features carried over from MobileBottomNav (if any)
- Gesture support (swipe-down-to-close etc.)
- Concerns, deviations, self-review
