---
estimated_steps: 20
estimated_files: 2
skills_used: []
---

# T02: Add mobile hamburger menu with touch targets and auto-close behavior

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

## Inputs

- ``frontend/src/App.tsx` — app shell with nav search bar from T01`
- ``frontend/src/App.css` — global styles to extend with mobile nav rules`

## Expected Output

- ``frontend/src/App.tsx` — hamburger button, menuOpen state, auto-close behavior added`
- ``frontend/src/App.css` — mobile nav styles with hamburger, panel, touch targets, transitions`

## Verification

cd frontend && npm run build 2>&1 | tail -5
