## Task List T1: Add heading extraction utility [S] — T2: Add slug IDs to Heading component [S] — T3: Create MemoOutline sidebar component [M] — T4: Integrate outline into MemoDetailSidebar [S] ### T1: Add heading extraction utility [S] **Objective**: Provide a function to extract h1–h4 headings from markdown content with slugified IDs, reusing the existing MDAST parsing pattern from `markdown-manipulation.ts`. **Files**: `web/src/utils/markdown-manipulation.ts` **Implementation**: Add `HeadingItem` interface (text, level, slug) and `extractHeadings(markdown: string): HeadingItem[]` function. Use existing `fromMarkdown()` + `visit()` pattern. Visit `"heading"` nodes with depth 1–4, extract text from children, generate slug via `slugify()` helper (lowercase, replace non-alphanumeric with hyphens, deduplicate). Export both. **Validation**: `cd web && pnpm lint` — no new errors ### T2: Add slug IDs to Heading component [S] **Objective**: Generate deterministic `id` attributes on h1–h6 elements so outline links can scroll to them via `#hash`. **Files**: `web/src/components/MemoContent/markdown/Heading.tsx` **Implementation**: In `Heading` (~line 13), extract text from `children` using a `getTextContent(children)` helper that recursively extracts string content from React children. Generate slug with the same `slugify` logic. Apply `id={slug}` to the rendered ``. **Validation**: `cd web && pnpm lint` — no new errors ### T3: Create MemoOutline sidebar component [M] **Objective**: Create a modern, Claude/Linear-style outline component that renders h1–h4 headings as anchor links with indentation by level. **Size**: M (new component file, modern styling) **Files**: - Create: `web/src/components/MemoDetailSidebar/MemoOutline.tsx` **Implementation**: 1. Props: `{ headings: HeadingItem[] }` from `markdown-manipulation.ts` 2. Render a `