# S04 Research — ToC Modernization

## Summary

Straightforward frontend slice. The TableOfContents component and its CSS exist, the page layout is already a 2-column grid with a sticky sidebar. The work is: relocate ToC from main column to sidebar, restyle it (remove counters, add left accent bar, rename heading), and add active-section tracking via IntersectionObserver.

## Recommendation

Single-pass implementation. No new libraries needed — IntersectionObserver is native browser API. No backend changes. The work divides into two natural tasks: (1) move + restyle ToC, (2) add active section tracking.

## Implementation Landscape

### Current State

**`frontend/src/components/TableOfContents.tsx`** — Stateless component. Takes `BodySectionV2[]` sections, renders nested `<ol>` with anchor links. Uses `slugify()` for IDs. No scroll tracking, no active state.

**`frontend/src/pages/TechniquePage.tsx`** — Two-column grid layout (`technique-columns`). ToC currently renders at line 424 inside `technique-columns__main`, inside the `technique-prose` section (before the actual section content). Sidebar (`technique-columns__sidebar`) contains: key moments, signal chains, related techniques.

**`frontend/src/App.css`** (lines 2034–2108) — ToC styles use CSS counters (`counter-reset: toc-section`, `counter-increment`) to generate numbered prefixes like "1. ", "1.2 ". Background card style with border-radius.

**Layout** (lines 1849–1878) — `technique-columns`: `grid-template-columns: 1fr 22rem`, sidebar is `position: sticky; top: 1.5rem`. At ≤768px, collapses to single column with static sidebar.

### What Changes

1. **Move ToC to sidebar** — In TechniquePage.tsx, move the `<TableOfContents>` render from inside `technique-columns__main` (line 424) to the top of `technique-columns__sidebar` (before key moments, line 471). Only render in sidebar for v2 format pages.

2. **Restyle ToC** — In App.css:
   - Remove `counter-reset`, `counter-increment`, and `::before` pseudo-elements (the numbered prefixes)
   - Remove background/border card styling, replace with `border-left: 2px solid var(--color-accent)` accent bar
   - Change title from "Contents" to "On this page" (in component)
   - Add `--toc-active` color variable or reuse `--color-accent` for active link highlighting

3. **Active section tracking** — In TableOfContents.tsx:
   - Accept section element IDs (already computed via `slugify()`)
   - Create an IntersectionObserver watching all `[id]` elements matching section/subsection slugs
   - Track which section is currently in view (topmost intersecting section with `rootMargin: '0px 0px -70% 0px'` to trigger when section enters top 30%)
   - Apply `.technique-toc__link--active` class to the matching link
   - CSS: active link gets `color: var(--color-accent)` + optionally a small left-border highlight or font-weight change

4. **Mobile behavior** — At ≤768px the sidebar is already `position: static`. ToC should still render but won't be sticky. This is fine — no special mobile handling needed beyond what exists.

### Key Files

| File | Role |
|------|------|
| `frontend/src/components/TableOfContents.tsx` | Component: restyle, add active tracking |
| `frontend/src/pages/TechniquePage.tsx` | Move ToC render location from main to sidebar |
| `frontend/src/App.css` | ToC CSS: remove counters, add accent bar, add active state |

### CSS Variables Available

- `--color-accent: #22d3ee` (cyan) — for active link and accent bar
- `--color-accent-subtle: rgba(34, 211, 238, 0.1)` — for active link background highlight
- `--color-text-secondary: #8b8b9a` — for inactive links
- `--color-text-muted: #828291` — for heading text
- `--color-border: #2a2a38` — for inactive accent bar segments

### Slug ID Convention

Section IDs use `slugify(heading)` for H2 and `${sectionSlug}--${slugify(sub.heading)}` for H3 (double-hyphen compound slug, per KNOWLEDGE.md). These same IDs are set on the `<div id={...}>` elements in TechniquePage.tsx's prose rendering. The IntersectionObserver targets these exact IDs.

### Risks

None. Standard browser API, existing layout supports it, no backend changes.

### Verification

- `cd frontend && npm run build` — zero TypeScript errors
- Visual: ToC appears in sidebar, no numbered counters, left accent bar visible
- Scroll test: active section highlights as user scrolls through prose sections
- Mobile (≤768px): ToC renders inline (not sticky), still functional

### Skills

No additional skills needed. Standard React + CSS work within established codebase patterns.
