# Presentation Discussion Modal Composition Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Make discussion routes look like intentional defense overlays instead of plain document cards by giving Q&A and context-only branches a stage-aware composition. **Architecture:** Keep discussion navigation, branch data, and focus-trap behavior unchanged. Add a small presentation shell around `DiscussionPanel` content: the panel remains the only dialog component, but it gets an inner layout with header, content, and action zones. CSS chooses a Q&A layout or context layout from `data-discussion-layout`; no new state, routes, or component library. **Tech Stack:** React, TypeScript, Vitest, Testing Library, existing presentation CSS, Playwright CLI screenshots, `npx -y impeccable detect` rendered-route scan. ## Global Constraints - Do not change branch ids, route hashes, or Q&A answer copy. - Do not change focus trap semantics: return button focuses on open, Escape closes, Tab stays inside dialog. - Do not introduce a modal library or component library. - Do not touch demo workflow scenes, graph layout, evidence inspector, or replay state. - Avoid slop patterns: centered generic card, huge empty context page, side-stripe callout, wide diffuse shadow, all-caps body text. - At `1280x720`, both Q&A and context discussion routes must fit without page scroll. --- ## Current Findings The previous discussion craft pass improved semantics and hierarchy, but screenshots still show: - Q&A route reads as a document card spanning the top of the slide. - Context-only route leaves the bottom two-thirds empty, which looks unfinished. - Return action is functionally correct but visually disconnected from the content hierarchy. This slice should make discussion feel like a stage overlay: left side for the question/claim, right side for answer/provenance/actions, and a compact context layout for non-Q&A branches. --- ## File Structure - Modify `web/apps/console/src/presentation/DiscussionPanel.tsx` - Add structural wrappers: `.discussion-panel__shell`, `.discussion-panel__header`, `.discussion-panel__body`, `.discussion-panel__aside`, `.discussion-panel__actions`. - Keep current branch fields and focus trap. - Modify `web/apps/console/src/presentation/DiscussionPanel.test.tsx` - Pin shell/body/aside/actions semantics for Q&A and context layouts. - Modify `web/apps/console/src/presentation/presentation.css` - Add stage-sized discussion layout. - Make context layout intentionally compact instead of top-heavy. - Preserve existing editorial tokens and avoid shadows/side stripes. - Modify `docs/current_roadmap.md` - Mark this modal composition pass complete after implementation. - Move this plan to `docs/historical/superpowers/plans/2026-07-09-presentation-discussion-modal-composition.md` after implementation. --- ### Task 1: Add Discussion Panel Composition Structure **Files:** - Modify: `web/apps/console/src/presentation/DiscussionPanel.tsx` - Modify: `web/apps/console/src/presentation/DiscussionPanel.test.tsx` **Interfaces:** - Consumes: existing `DiscussionPanelProps` and `DiscussionBranchDefinition` fields. - Produces: stable DOM sections with labels: - `discussion shell` - `discussion body` - `discussion support` - `discussion actions` - [ ] **Step 1: Add failing structure tests** In `web/apps/console/src/presentation/DiscussionPanel.test.tsx`, add: ```tsx it("renders Q&A discussion as shell, body, support, and actions regions", () => { render(); expect(screen.getByRole("dialog")).toHaveAttribute("data-discussion-layout", "qna"); expect(screen.getByLabelText("discussion shell")).toBeInTheDocument(); expect(screen.getByLabelText("discussion body")).toHaveTextContent("Where is the AI agent in this thesis?"); expect(screen.getByLabelText("discussion support")).toHaveTextContent("Evidence"); expect(screen.getByLabelText("discussion actions")).toContainElement( screen.getByRole("button", { name: /return to thesis/i }), ); }); it("renders context-only discussion with a compact support column", () => { render(); expect(screen.getByRole("dialog")).toHaveAttribute("data-discussion-layout", "context"); expect(screen.getByLabelText("discussion body")).toHaveTextContent(/Hosted triggers/i); expect(screen.getByLabelText("discussion support")).toHaveTextContent(/Workflow Automation Platforms/i); expect(screen.queryByLabelText("defense question")).not.toBeInTheDocument(); }); ``` - [ ] **Step 2: Run tests and verify they fail** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DiscussionPanel.test.tsx ``` Expected: fail because the labelled shell/body/support/actions regions do not exist. - [ ] **Step 3: Refactor JSX into shell regions** In `web/apps/console/src/presentation/DiscussionPanel.tsx`, keep imports, props, focus effect, `trapKeyboardWithinDialog`, and `hasQuestion` logic. Replace the dialog contents inside the root `
` with this structure: ```tsx
{branch.claimClass}

{branch.title}

{branch.summary}

{hasQuestion ? (

{branch.question}

{branch.shortAnswer && (
Short answer

{branch.shortAnswer}

)} {branch.expandedAnswer && (
Expanded answer

{branch.expandedAnswer}

)}
) : (

{branch.summary}

{branch.detail && (

{branch.detail.links?.map((link, index) => ( {index > 0 && " · "} {link.label} ))} {branch.detail.links && branch.detail.links.length > 0 ? " — " : ""} {branch.detail.text}

)}
)}
``` Important: - Remove the old top-level `

` outside the shell. - Remove the old duplicate `branch.detail` block after the Q&A section. - Keep `returnButtonRef` attached to the return button. - Keep `role="dialog"`, `aria-modal`, `aria-label`, and `onKeyDown` on the root `.discussion-panel` element. - [ ] **Step 4: Run tests and verify they pass** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DiscussionPanel.test.tsx ``` Expected: pass. - [ ] **Step 5: Commit Task 1** ```powershell git add web/apps/console/src/presentation/DiscussionPanel.tsx web/apps/console/src/presentation/DiscussionPanel.test.tsx git commit -m "fix: structure discussion modal regions" ``` --- ### Task 2: Compose Q&A And Context Layouts Visually **Files:** - Modify: `web/apps/console/src/presentation/presentation.css` - Modify: `web/apps/console/src/presentation/DiscussionPanel.test.tsx` **Interfaces:** - Consumes: `.discussion-panel[data-discussion-layout="qna" | "context"]` and shell regions from Task 1. - Produces: stage-aware modal composition with no document-like top-heavy layout. - [ ] **Step 1: Add class-contract tests** In `web/apps/console/src/presentation/DiscussionPanel.test.tsx`, add: ```tsx it("marks the modal shell with the active layout for styling", () => { const { rerender } = render(); expect(screen.getByLabelText("discussion shell")).toHaveClass("discussion-panel__shell"); expect(screen.getByRole("dialog")).toHaveAttribute("data-discussion-layout", "qna"); rerender(); expect(screen.getByRole("dialog")).toHaveAttribute("data-discussion-layout", "context"); }); ``` - [ ] **Step 2: Run tests** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DiscussionPanel.test.tsx ``` Expected: pass after Task 1. This test pins styling hooks before CSS work. - [ ] **Step 3: Replace discussion panel base CSS** In `web/apps/console/src/presentation/presentation.css`, replace the current `.discussion-panel[data-presentation-surface="editorial"]` block and its direct `h2`/badge rules with: ```css .discussion-panel[data-presentation-surface="editorial"] { min-height: min(34rem, calc(100cqh - 2rem)); padding: 0; border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 34%, transparent); border-radius: 0.9rem; overflow: hidden; background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 94%, white); color: var(--color-editorial-ink, oklch(0.19 0.015 65)); } .discussion-panel__shell { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(17rem, 0.65fr); grid-template-rows: auto minmax(0, 1fr) auto; gap: 0; min-height: inherit; } .discussion-panel__header { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(0, 1fr) minmax(18rem, 0.55fr); gap: 1rem; align-items: end; border-bottom: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 28%, transparent); padding: 1rem 1.1rem 0.85rem; } .discussion-panel__header h2 { margin: 0.35rem 0 0; color: var(--color-editorial-ink, oklch(0.19 0.015 65)); font-size: clamp(1.25rem, 2.6vw, 2rem); line-height: 1; } .discussion-panel__header p { margin: 0; color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 74%, var(--color-editorial-muted, oklch(0.48 0.025 65))); font-size: 0.9rem; line-height: 1.35; } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__badge { display: inline-block; border-radius: 0.35rem; background: color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 16%, transparent); color: var(--color-editorial-ink, oklch(0.19 0.015 65)); padding: 0.18rem 0.45rem; font: 700 0.7rem/1 var(--font-interface); } ``` - [ ] **Step 4: Add body/support/action CSS** Still in `presentation.css`, replace the current `.discussion-panel__qna`, `.discussion-panel__question`, `.discussion-panel__answer-card`, `.discussion-panel__presenter-note`, `.discussion-panel__detail`, and `.discussion-panel__return` rules with: ```css .discussion-panel__body { min-width: 0; padding: 1rem 1.1rem; } .discussion-panel__aside { display: grid; align-content: start; gap: 0.75rem; border-left: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 22%, transparent); padding: 1rem; background: color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 7%, transparent); } .discussion-panel__actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; border-top: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 22%, transparent); padding: 0.75rem 1rem; } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__qna { display: grid; gap: 0.75rem; margin: 0; } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__question { margin: 0; color: var(--color-editorial-ink, oklch(0.19 0.015 65)); font-size: clamp(1.35rem, 2.4vw, 2rem); font-weight: 760; line-height: 1.08; text-wrap: balance; } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__answer-card { display: grid; gap: 0.4rem; border: 1px solid color-mix(in oklch, var(--color-intent, oklch(0.53 0.17 250)) 28%, transparent); border-radius: 0.75rem; padding: 0.8rem 0.85rem; background: color-mix(in oklch, var(--color-intent, oklch(0.53 0.17 250)) 5%, var(--color-editorial-paper, oklch(0.975 0.012 82))); } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__answer-card--expanded { border-color: color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 28%, transparent); background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 90%, white); } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__answer-card span, .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__provenance span, .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note span { color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 68%, var(--color-editorial-muted, oklch(0.48 0.025 65))); font: 700 0.68rem/1 var(--font-interface); } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__answer-card p { margin: 0; color: var(--color-editorial-ink, oklch(0.19 0.015 65)); line-height: 1.42; } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__provenance, .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note, .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__detail { display: grid; gap: 0.35rem; border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 24%, transparent); border-radius: 0.7rem; padding: 0.65rem; background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 74%, white); } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__provenance p, .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note p, .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__detail p { margin: 0; color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 84%, var(--color-editorial-muted, oklch(0.48 0.025 65))); font-size: 0.85rem; line-height: 1.38; } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note { border-style: dashed; background: color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 8%, var(--color-editorial-paper, oklch(0.975 0.012 82))); } .discussion-panel[data-presentation-surface="editorial"] .discussion-panel__return { border: 1px solid var(--color-editorial-ink, oklch(0.19 0.015 65)); border-radius: 0.45rem; padding: 0.48rem 0.8rem; background: var(--color-editorial-ink, oklch(0.19 0.015 65)); color: var(--color-editorial-paper, oklch(0.975 0.012 82)); font-weight: 650; } ``` - [ ] **Step 5: Add context layout CSS** Add these rules after the block above: ```css .discussion-panel[data-discussion-layout="context"] .discussion-panel__shell { grid-template-columns: minmax(0, 1fr) minmax(18rem, 0.42fr); min-height: min(24rem, calc(100cqh - 2rem)); } .discussion-panel[data-discussion-layout="context"] .discussion-panel__body { display: grid; align-content: start; gap: 0.75rem; } .discussion-panel__context { display: grid; gap: 0.75rem; } .discussion-panel__context > p { margin: 0; max-width: 68ch; color: var(--color-editorial-ink, oklch(0.19 0.015 65)); font-size: 1.12rem; line-height: 1.35; } @media (max-height: 760px) { .discussion-panel__shell, .discussion-panel[data-discussion-layout="context"] .discussion-panel__shell { grid-template-columns: minmax(0, 1fr); min-height: auto; } .discussion-panel__header { grid-template-columns: minmax(0, 1fr); } .discussion-panel__aside { border-left: 0; border-top: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 22%, transparent); } } ``` - [ ] **Step 6: Run tests and verify they pass** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DiscussionPanel.test.tsx ``` Expected: pass. - [ ] **Step 7: Commit Task 2** ```powershell git add web/apps/console/src/presentation/DiscussionPanel.test.tsx web/apps/console/src/presentation/presentation.css git commit -m "fix: compose discussion modal stage layout" ``` --- ### Task 3: Browser Smoke, Detector, And Roadmap **Files:** - Modify: `docs/current_roadmap.md` - Move: `docs/superpowers/plans/2026-07-09-presentation-discussion-modal-composition.md` to `docs/historical/superpowers/plans/2026-07-09-presentation-discussion-modal-composition.md` **Interfaces:** - Consumes: rendered `/present#discuss/...` routes. - Produces: screenshots, detector output, roadmap completion. - [ ] **Step 1: Run focused tests** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DiscussionPanel.test.tsx src/presentation/PresentationRoute.test.tsx ``` Expected: pass. - [ ] **Step 2: Run broad presentation checks** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation pnpm --dir web --filter @lda/console typecheck pnpm --dir web --filter @lda/console build git diff --check ``` Expected: presentation tests pass, typecheck clean, build passes with only known chunk-size warning, diff check clean. - [ ] **Step 3: Run detector smoke** Run: ```powershell npx -y impeccable detect --json --gpt --gemini http://127.0.0.1:5173/present#discuss/where-is-ai-agent npx -y impeccable detect --json --gpt --gemini http://127.0.0.1:5173/present#discuss/hosted-automation ``` Expected: - No `gpt-thin-border-wide-shadow` findings. - No `side-stripe` style finding. - No new `all-caps-body` findings from modal content. - `line-length` or `flat-type-hierarchy` findings may still appear; report them if present and do not expand scope. - [ ] **Step 4: Capture screenshots** Run: ```powershell pnpx --package @playwright/cli playwright-cli -s=discussion-modal open "http://127.0.0.1:5173/present#discuss/where-is-ai-agent" pnpx --package @playwright/cli playwright-cli -s=discussion-modal resize 1280 720 pnpx --package @playwright/cli playwright-cli -s=discussion-modal screenshot --filename web/apps/console/.visual-smoke/discussion-modal-qna.png pnpx --package @playwright/cli playwright-cli -s=discussion-modal open "http://127.0.0.1:5173/present#discuss/hosted-automation" pnpx --package @playwright/cli playwright-cli -s=discussion-modal screenshot --filename web/apps/console/.visual-smoke/discussion-modal-context.png ``` Acceptance criteria: - Q&A modal uses the slide area intentionally with header/body/support/actions regions. - Context-only modal no longer leaves a huge empty lower stage. - Return button remains visible at `1280x720`. - No visible page scrollbar. - [ ] **Step 5: Update roadmap** In `docs/current_roadmap.md`, under `Next presentation visual slices`, insert this completed item after the discussion craft item: ```md 9. Completed: discussion modal composition pass made Q&A and context-only routes stage-aware, with body/support/action regions instead of plain document cards. Implementation: [`presentation discussion modal composition`](historical/superpowers/plans/2026-07-09-presentation-discussion-modal-composition.md). 10. Presentation craft pass: tune remaining motion, evidence receipt placement, route-level caption contrast, and graph visual language after the discussion modal is stable. ``` Renumber the existing open craft-pass item if needed. - [ ] **Step 6: Archive the plan** Run: ```powershell Move-Item docs/superpowers/plans/2026-07-09-presentation-discussion-modal-composition.md docs/historical/superpowers/plans/2026-07-09-presentation-discussion-modal-composition.md ``` Verify: ```powershell rg -n "presentation discussion modal composition|2026-07-09-presentation-discussion-modal-composition" docs/current_roadmap.md docs/superpowers/plans docs/historical/superpowers/plans ``` Expected: - Roadmap points to the historical plan path. - No active copy remains under `docs/superpowers/plans/`. - [ ] **Step 7: Commit Task 3** ```powershell git add docs/current_roadmap.md docs/historical/superpowers/plans/2026-07-09-presentation-discussion-modal-composition.md git add -u docs/superpowers/plans/2026-07-09-presentation-discussion-modal-composition.md git commit -m "docs: record presentation discussion modal composition" ``` --- ## Final Verification Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation pnpm --dir web --filter @lda/console typecheck pnpm --dir web --filter @lda/console build npx -y impeccable detect --json --gpt --gemini http://127.0.0.1:5173/present#discuss/where-is-ai-agent npx -y impeccable detect --json --gpt --gemini http://127.0.0.1:5173/present#discuss/hosted-automation git diff --check git status --short ``` Expected: - Presentation tests pass. - Typecheck passes. - Build passes with only known chunk warning if present. - Detector shows no ghost-card, side-stripe, or all-caps-body findings from the discussion modal. - `git diff --check` is clean. - `git status --short` is clean. ## Self-Review - Spec coverage: plan covers structure, visual composition, context-only route, detector smoke, screenshots, roadmap, and archival. - Placeholder scan: no placeholder markers or vague implementation instructions are present. - Type consistency: uses existing `DiscussionPanelProps`, existing branch fields, and current test utilities. - Scope check: no demo workflow, graph, evidence inspector, route hash, or Q&A copy changes.