# S02 Research: Topics, Creator Stats & Card Polish

## Summary

Straightforward frontend-only changes across 5–6 files. All patterns (CSS color system, catSlug utility, badge classes, expand/collapse state) already exist. No new dependencies, no backend changes, no unfamiliar technology.

## Targeted Requirements

| Req | Description | Status |
|-----|-------------|--------|
| R019 | Topics page default-collapsed with expand animation | Active — this slice |
| R026 | Creator stats topic-colored pills | Active — this slice |
| R027 | Tag overflow limit (4 + "+N more") | Active — this slice |
| R028 | Empty subtopic handling | Active — this slice |

## Implementation Landscape

### 1. Topics Default-Collapsed (R019)

**File:** `frontend/src/pages/TopicsBrowse.tsx`

- **Current:** Line ~42: `setExpanded(new Set(data.map((c) => c.name)))` — starts all-expanded.
- **Change:** `setExpanded(new Set())` — starts all-collapsed.
- **Animation:** The subtopics container (`div.topic-subtopics`) currently renders conditionally (`{isExpanded && ...}`). For smooth expand/collapse, replace the conditional render with CSS `max-height` + `overflow: hidden` + `transition`. Use a wrapper with `max-height: 0` when collapsed and `max-height: <computed>px` when expanded, or use CSS `grid-template-rows: 0fr / 1fr` technique (better, no fixed height needed).
- **CSS file:** `frontend/src/App.css` — `.topic-subtopics` starts at line 2318. Add transition properties.

**Recommendation:** Use the CSS `display: grid; grid-template-rows: 0fr → 1fr` pattern for the smoothest transition without needing to know content height. Wrap subtopics in a grid container that transitions `grid-template-rows`.

### 2. Creator Stats Colored Pills (R026)

**File:** `frontend/src/pages/CreatorDetail.tsx`

- **Current:** Lines ~97–110: Stats render as `<span className="creator-detail__topic-stat">Cat: N</span>` with dot separators.
- **Change:** Replace with `<span className="badge badge--cat-{slug}">{cat}: {count}</span>` using `catSlug()` from `../utils/catSlug`.
- **Existing CSS:** `.badge--cat-sound-design`, `.badge--cat-mixing`, etc. already defined in App.css with bg/text color pairs for all 7 categories.
- **Import needed:** `import { catSlug } from "../utils/catSlug";` (not currently imported in CreatorDetail.tsx).
- **Layout:** Replace the run-on text with a flex-wrap container holding pill badges.

### 3. Tag Overflow Limit (R027)

**Files affected (5 tag-rendering sites):**

| File | Line | Context |
|------|------|---------|
| `frontend/src/pages/Home.tsx` | ~201 | Featured technique tags |
| `frontend/src/pages/Home.tsx` | ~247 | Recent technique card tags |
| `frontend/src/pages/SearchResults.tsx` | ~143 | Search result card tags |
| `frontend/src/pages/SubTopicPage.tsx` | ~147 | Sub-topic technique card tags |
| `frontend/src/pages/CreatorDetail.tsx` | ~108 | Creator technique card tags |

**Pattern:** All 5 sites use the same idiom:
```tsx
{t.topic_tags.map(tag => <span className="pill">{tag}</span>)}
```

**Change:** Extract a shared helper or inline the pattern:
```tsx
{tags.slice(0, 4).map(tag => <span className="pill">{tag}</span>)}
{tags.length > 4 && <span className="pill pill--overflow">+{tags.length - 4} more</span>}
```

**Recommendation:** Create a small `TagList` component in `frontend/src/components/TagList.tsx` to DRY up the 5 sites. Props: `tags: string[]`, `max?: number` (default 4). The component renders pills with overflow. This avoids repeating the slice/overflow logic 5 times.

### 4. Empty Subtopic Handling (R028)

**File:** `frontend/src/pages/TopicsBrowse.tsx`

- **Current:** All subtopics render as clickable links regardless of `technique_count`.
- **Change:** When `st.technique_count === 0`, render as a non-clickable element with a "Coming soon" badge instead of a link. Keep it visible (don't hide) so users know the topic exists.
- **CSS:** Add a `.topic-subtopic--empty` modifier class with muted styling and a small "Coming soon" badge.

## Key Observations

1. **CSS color system is complete** — all 7 category color pairs exist as CSS custom properties and badge modifier classes. No new colors needed for creator stats pills.
2. **`catSlug()` utility exists** — converts category names to CSS-safe slugs (lowercase, spaces→hyphens). Already used in TopicsBrowse.tsx.
3. **S01 added `card-stagger` animation** — `@keyframes cardEnter` and `.card-stagger` class with `--stagger-index` CSS variable. Already applied to topic cards and creator technique cards.
4. **No existing expand/collapse animation** — subtopics use conditional rendering (`{isExpanded && ...}`), not CSS transitions. Needs refactoring for smooth animation.
5. **`grid-template-rows` transition** is well-supported (Chrome 57+, Firefox 66+, Safari 16+) and doesn't require knowing content height.

## Natural Task Seams

1. **Topics collapse + animation (R019)** — Self-contained in TopicsBrowse.tsx + App.css. Change default state, add CSS grid transition.
2. **Creator stats pills (R026)** — Self-contained in CreatorDetail.tsx + App.css. Import catSlug, replace text with badges.
3. **Tag overflow + empty subtopics (R027, R028)** — Create TagList component, update 5 files for tag overflow, update TopicsBrowse.tsx for empty subtopics. These can be one task since TagList is the shared piece.

**Risk ordering:** Topics collapse/animation is slightly riskier (CSS transition refactor), so do it first. The others are mechanical.

## Verification

- `cd frontend && npx tsc --noEmit` — TypeScript compiles clean
- `cd frontend && npm run build` — Vite production build succeeds
- Browser verification at http://ub01:8096:
  - Topics page loads collapsed, click expands with animation
  - Creator detail shows colored pills for topic stats
  - Cards with >4 tags show exactly 4 + "+N more"
  - Empty subtopics show "Coming soon" badge
