---
estimated_steps: 34
estimated_files: 3
skills_used: []
---

# T01: Add popular searches API client, homepage section, and CSS

Wire the existing GET /api/v1/search/popular endpoint into the homepage as a Trending Searches section.

## Steps

1. In `frontend/src/api/public-client.ts`, add `PopularSearchItem` and `PopularSearchesResponse` interfaces mirroring the backend schemas (query: string, count: number; items array + cached boolean). Add `fetchPopularSearches()` async function following the `fetchStats()` pattern.

2. In `frontend/src/pages/Home.tsx`:
   - Import `fetchPopularSearches` and `PopularSearchItem` from public-client
   - Add `const [trending, setTrending] = useState<PopularSearchItem[] | null>(null)`
   - Add a useEffect (with cancellation flag) that calls `fetchPopularSearches()` and sets `trending` to `data.items` when non-empty, or null on error/empty. Can share the existing stats useEffect or add a parallel one.
   - After the stats scorecard section and before the random technique button, add a conditional render: `{trending && trending.length > 0 && (<section className="home-trending">...</section>)}`
   - Section contains an H2 heading (e.g., "Trending Searches") and a flex-wrap container of `<Link>` elements, each navigating to `/search?q=${encodeURIComponent(item.query)}` with class `pill pill--trending`
   - Apply stagger animation via `card-stagger` class with appropriate `--stagger-index`

3. In `frontend/src/App.css`, add `.home-trending` styles:
   - Match scorecard aesthetic: `var(--color-bg-surface)` background, `var(--color-border)` border, centered with max-width, border-radius
   - `.pill--trending` variant: subtle accent border (`var(--color-accent)` at ~0.3 opacity), hover brightens border. Use existing pill sizing/spacing.
   - Heading styled with `var(--color-text-muted)`, small caps or uppercase letter-spacing to match section label patterns

4. Build: `cd frontend && npm run build` — must succeed with zero TS errors

5. Deploy to ub01: push changes, rebuild web container, verify at http://ub01:8096 that trending section appears with real search terms

## Must-Haves

- [ ] PopularSearchItem and PopularSearchesResponse types in public-client.ts
- [ ] fetchPopularSearches() function in public-client.ts
- [ ] Trending section renders on homepage between stats scorecard and random technique button
- [ ] Each term is a clickable Link to /search?q={term}
- [ ] Section hidden when API returns empty items or errors
- [ ] CSS matches existing dark/cyan design system
- [ ] npm run build passes

## Verification

- `cd frontend && npx tsc --noEmit` — zero errors
- `cd frontend && npm run build` — succeeds
- `grep -q 'fetchPopularSearches' frontend/src/api/public-client.ts` — function exists
- `grep -q 'home-trending' frontend/src/pages/Home.tsx` — section wired
- `grep -q 'home-trending' frontend/src/App.css` — styles exist
- Deploy and verify at http://ub01:8096 — trending section visible with real terms

## Negative Tests

- Empty items array: section must not render (verified by conditional `trending.length > 0`)
- API error/timeout: caught in useEffect, trending stays null, section hidden

## Inputs

- `frontend/src/api/public-client.ts`
- `frontend/src/pages/Home.tsx`
- `frontend/src/App.css`

## Expected Output

- `frontend/src/api/public-client.ts`
- `frontend/src/pages/Home.tsx`
- `frontend/src/App.css`

## Verification

cd frontend && npm run build && npx tsc --noEmit && grep -q 'fetchPopularSearches' src/api/public-client.ts && grep -q 'home-trending' src/pages/Home.tsx && grep -q 'home-trending' src/App.css
