---
estimated_steps: 8
estimated_files: 4
skills_used: []
---

# T01: Lift activeId state, create ReadingHeader component, wire into TechniquePage

Extract IntersectionObserver scroll-spy from TableOfContents into the parent TechniquePage, create a ReadingHeader component that shows article title + current section in a thin fixed bar, and add CSS with slide animation. The bar appears when the H1 title scrolls out of view and hides when it reappears.

**Context for executor:**
- `TableOfContents.tsx` currently owns `activeId` state and the IntersectionObserver effect. These must move up to `TechniquePage.tsx` so both ToC and ReadingHeader can read activeId.
- `TableOfContents` currently takes `sections: BodySectionV2[]` as its only prop. After the lift, it should also accept `activeId: string`.
- The H1 element has class `technique-header__title` — use a ref or querySelector to observe it.
- z-index landscape: modals=1000, mobile menu=200, overlays/dropdowns=100. Use z-index 150 for reading header.
- v2 format gate: only render ReadingHeader when `displayFormat === 'v2'` and sections exist (same condition as ToC).
- Mobile: reading header should still appear at 375px. Truncate title with text-overflow: ellipsis.

## Inputs

- ``frontend/src/components/TableOfContents.tsx` — current IntersectionObserver + activeId logic to extract`
- ``frontend/src/pages/TechniquePage.tsx` — parent page; will own activeId state and render ReadingHeader`
- ``frontend/src/App.css` — add .reading-header CSS block`

## Expected Output

- ``frontend/src/components/ReadingHeader.tsx` — new component: fixed bar with title + current section, controlled by visible prop`
- ``frontend/src/components/TableOfContents.tsx` — modified: accepts activeId as prop, no longer owns observer state`
- ``frontend/src/pages/TechniquePage.tsx` — modified: owns activeId state via IntersectionObserver useEffect, owns H1 visibility observer, renders ReadingHeader for v2 pages`
- ``frontend/src/App.css` — modified: .reading-header block with position:fixed, transform:translateY transition, z-index:150, mobile truncation`

## Verification

cd frontend && npm run build 2>&1 | tail -5 && echo '---' && grep -l 'reading-header' src/App.css src/components/ReadingHeader.tsx && echo '---' && grep -c 'activeId' src/pages/TechniquePage.tsx
