---
id: S05
parent: M016
milestone: M016
provides:
  - ReadingHeader component
  - Lifted activeId scroll-spy state in TechniquePage
requires:
  - slice: S04
    provides: ToC modernization with IntersectionObserver scroll-spy (the code that was lifted)
affects:
  - S06
key_files:
  - frontend/src/components/ReadingHeader.tsx
  - frontend/src/components/TableOfContents.tsx
  - frontend/src/pages/TechniquePage.tsx
  - frontend/src/App.css
key_decisions:
  - Hide section name on mobile (<600px) rather than truncating both — keeps title readable at 375px
  - pointer-events:none when hidden so invisible bar doesn't block clicks
  - z-index 150 for reading header — between overlays (100) and mobile menu (200)
patterns_established:
  - Lifted scroll-spy pattern: IntersectionObserver state in parent page, passed down to multiple consumer components (ToC + ReadingHeader)
observability_surfaces:
  - none
drill_down_paths:
  - .gsd/milestones/M016/slices/S05/tasks/T01-SUMMARY.md
duration: ""
verification_result: passed
completed_at: 2026-04-03T06:02:23.985Z
blocker_discovered: false
---

# S05: Sticky Reading Header

**Added a thin sticky reading header that slides in when the article H1 leaves the viewport, showing technique title + current section from lifted scroll-spy state.**

## What Happened

Single-task slice. The IntersectionObserver-based scroll-spy (activeId state + observer effect) was extracted from TableOfContents into TechniquePage, making it available to both the ToC sidebar and the new ReadingHeader component. A second IntersectionObserver watches the H1 element to control ReadingHeader visibility.

ReadingHeader is a stateless component receiving title, currentSection, and visible props. CSS handles the slide animation via transform translateY(-100%) → translateY(0) with a 0.25s ease transition. z-index 150 slots between overlays (100) and mobile menu (200). pointer-events:none when hidden prevents invisible click interception.

Mobile (< 600px): section name is hidden entirely rather than truncated, keeping the title readable at 375px. The reading header only renders on v2 format pages with sections (same gate as ToC).

## Verification

Frontend build passes clean (0 errors, 993ms). reading-header class present in App.css and ReadingHeader.tsx. activeId referenced 5 times in TechniquePage.tsx confirming state lift. V2 format gate guards ReadingHeader rendering.

## Requirements Advanced

- R041 — ReadingHeader component implemented with slide-in/out animation, title + section display, mobile support. Needs live browser verification for full validation.

## Requirements Validated

None.

## New Requirements Surfaced

None.

## Requirements Invalidated or Re-scoped

None.

## Deviations

None.

## Known Limitations

None.

## Follow-ups

None.

## Files Created/Modified

- `frontend/src/components/ReadingHeader.tsx` — New component — thin sticky bar showing article title + current section
- `frontend/src/components/TableOfContents.tsx` — Now receives activeId as prop instead of owning scroll-spy state
- `frontend/src/pages/TechniquePage.tsx` — Owns scroll-spy state (activeId + two IntersectionObservers), renders ReadingHeader
- `frontend/src/App.css` — Added .reading-header styles with slide animation and mobile breakpoint
