# S03: Global Search & Mobile Navigation

**Goal:** Compact search bar in nav on all non-home pages with Cmd+K focus. Mobile viewport (<768px) shows hamburger menu with stacked nav links and generous touch targets.
**Demo:** After this: Compact search bar in nav on all pages. Cmd+K focuses it. Mobile viewport shows hamburger menu.

## Tasks
- [x] **T01: Refactored SearchAutocomplete from heroSize boolean to variant string prop and wired compact nav search bar with Cmd+K shortcut into App.tsx header on all non-home routes** — Refactor SearchAutocomplete from heroSize boolean to variant string prop ('hero' | 'inline' | 'nav'), add nav-variant CSS (compact sizing, hidden submit button, high z-index dropdown), add globalShortcut prop for Cmd+K/Ctrl+K focus, wire nav search into App.tsx conditionally on non-home routes, update existing callers in Home.tsx and SearchResults.tsx.

This task delivers R020 (Global Search in Navigation).

## Steps

1. In `SearchAutocomplete.tsx`: replace `heroSize?: boolean` with `variant?: 'hero' | 'inline' | 'nav'` (default `'inline'`). Update the className logic: `search-form--hero` when variant=hero, `search-form--inline` when variant=inline, `search-form--nav` when variant=nav. Same pattern for `search-input--*`.
2. When `variant === 'nav'`: hide the submit button (don't render `<button>` — Enter submits the form). Add `search-container--nav` class to the container div for positioning context.
3. Add `globalShortcut?: boolean` prop. When true, register a `useEffect` with a `keydown` listener for Cmd+K (metaKey) / Ctrl+K (ctrlKey) that calls `e.preventDefault()` and focuses `inputRef.current`. Clean up on unmount.
4. In `App.css`: add `.search-form--nav` styles (max-width: 16rem, compact padding), `.search-input--nav` (smaller font, reduced padding), `.search-container--nav .typeahead-dropdown` (z-index: 200 to overlay page content). Add a Cmd+K hint badge (`.search-nav__shortcut`) styled as a subtle kbd element inside the input area.
5. In `App.tsx`: import `useLocation` and `useNavigate` from react-router-dom, import `SearchAutocomplete`. Render `<SearchAutocomplete variant="nav" globalShortcut onSearch={...} placeholder="Search… ⌘K" />` between brand and right section, conditionally when `location.pathname !== '/'`.
6. Update `Home.tsx` caller: change `heroSize` to `variant="hero"`.
7. Update `SearchResults.tsx` caller: remove heroSize (already falsy, so `variant="inline"` default works, but be explicit: add `variant="inline"`).
8. Verify: `cd frontend && npm run build` succeeds. Visually confirm in browser at desktop width.

## Must-Haves

- [ ] SearchAutocomplete accepts variant prop ('hero' | 'inline' | 'nav')
- [ ] Nav variant: compact input, no submit button, high z-index dropdown
- [ ] Cmd+K / Ctrl+K focuses nav search input (globalShortcut prop)
- [ ] Nav search bar appears on all pages except homepage
- [ ] Existing callers (Home.tsx, SearchResults.tsx) updated and unbroken
- [ ] Build succeeds with zero errors
  - Estimate: 45m
  - Files: frontend/src/components/SearchAutocomplete.tsx, frontend/src/App.tsx, frontend/src/App.css, frontend/src/pages/Home.tsx, frontend/src/pages/SearchResults.tsx
  - Verify: cd frontend && npm run build 2>&1 | tail -5
- [x] **T02: Added mobile hamburger menu with 44px touch targets, Escape/outside-click/route-change auto-close** — Add a hamburger menu button visible below 768px that toggles a mobile nav panel. Nav links stack vertically with 44×44px minimum touch targets. Menu closes on route change, Escape, and outside click. The nav search bar (from T01) repositions inside the mobile panel on small screens.

This task delivers R021 (Mobile Hamburger Menu).

## Steps

1. In `App.tsx`: add `menuOpen` state via `useState(false)`. Add a `<button className="hamburger-btn" onClick={() => setMenuOpen(v => !v)} aria-label="Toggle navigation" aria-expanded={menuOpen}>` inside `app-header__right`, before the nav element. Use a hamburger icon (three-line SVG or unicode ☰).
2. Add `className` toggle on `app-nav`: when `menuOpen` is true, add `app-nav--open` class.
3. Add `useEffect` watching `location.pathname` to close menu on navigation: `setMenuOpen(false)` when pathname changes.
4. Add `useEffect` for Escape key: listen for `keydown` event, close menu when key is 'Escape' and menuOpen is true.
5. Add outside-click close: `useRef` on the header element, check if click target is outside header when menuOpen, close if so.
6. In `App.css`: add `.hamburger-btn` styles — hidden above 768px (`display: none`), visible below as a 44×44px button with no border/background, color matching nav text. Add `@media (max-width: 768px)` block: hide `.app-nav` by default, show `.app-nav--open` as a full-width column below the header row (position: absolute or flex column, stacked links). Each nav link gets `min-height: 44px; display: flex; align-items: center; padding: 0.75rem 1.5rem` for touch targets. The `.search-container--nav` inside the mobile panel gets `max-width: 100%` and appropriate positioning.
7. Add open/close transition: `max-height` transition or `transform: scaleY` for smooth reveal.
8. Verify: `cd frontend && npm run build` succeeds. Test at mobile viewport in browser.

## Must-Haves

- [ ] Hamburger button visible only below 768px
- [ ] Tapping hamburger toggles nav panel with stacked links
- [ ] All mobile nav touch targets ≥ 44×44px
- [ ] Menu closes on route change
- [ ] Menu closes on Escape key
- [ ] Menu closes on outside click
- [ ] Nav search bar accessible in mobile menu
- [ ] Build succeeds with zero errors
  - Estimate: 45m
  - Files: frontend/src/App.tsx, frontend/src/App.css
  - Verify: cd frontend && npm run build 2>&1 | tail -5
