14 KiB
Presentation Contrast Readability 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: Fix the immediate /present readability regressions from the visual pass: dark-on-dark Scene 7 authoring loop text, dark-on-dark Scene 10 chat rail text, and generated screenshot hygiene.
Architecture: Treat this as a bugfix, not a redesign. Add explicit foreground colors and small DOM/test hooks where the contrast contract matters, keep the existing presentation layout, and verify with focused tests plus screenshots. Do not change scene composition, chat framework, or storyboard content.
Tech Stack: React, TypeScript, CSS, Vitest, Testing Library, Playwright CLI screenshot smoke.
Global Constraints
- Do not change
/console. - Do not add dependencies.
- Do not rewrite chat UI in this slice.
- Do not alter storyboard scene order or branch content.
- Keep visual fixes scoped to
web/apps/console/src/presentation. - Explicitly set foreground colors where dark surfaces are used.
- Generated screenshot directories must not remain untracked after the slice.
File Structure
- Modify
web/apps/console/src/presentation/SceneBody.tsx- Add stable readability data hooks to Scene 7 authoring nodes.
- Modify
web/apps/console/src/presentation/SceneBody.test.tsx- Pin Scene 7 authoring node readability hook.
- Modify
web/apps/console/src/presentation/OperatorChat.tsx- Restore or add chat theme/readability attributes.
- Modify
web/apps/console/src/presentation/OperatorChat.test.tsx- Pin chat surface readability attributes.
- Modify
web/apps/console/src/presentation/presentation.css- Set explicit authoring-loop and chat-rail foreground colors.
- Modify
.gitignore- Ignore generated visual smoke screenshot folder.
- Modify
docs/current_roadmap.md- Mark contrast/readability pass completed after implementation.
- Move this plan to
docs/historical/superpowers/plans/2026-07-08-presentation-contrast-readability.mdafter implementation.
Task 1: Scene 7 Authoring Loop Contrast
Files:
- Modify:
web/apps/console/src/presentation/SceneBody.tsx - Modify:
web/apps/console/src/presentation/SceneBody.test.tsx - Modify:
web/apps/console/src/presentation/presentation.css
Interfaces:
-
Consumes: existing Scene 7 authoring loop DOM:
aria-label="agent authoring loop".scene-body__authoring-nodedata-authoring-activedata-authoring-past
-
Produces:
data-readable-surface="dark"- explicit foreground colors for label/detail/number on authoring nodes.
-
Step 1: Add a failing readability-hook test
In web/apps/console/src/presentation/SceneBody.test.tsx, inside the existing test "renders Scene 7 as an agent authoring loop with beat-specific emphasis", add this assertion after const loop = ...:
expect(loop).toHaveAttribute("data-readable-surface", "dark");
Also add this assertion after the active-stage assertion:
expect(screen.getByText("Validate and diagnose").closest(".scene-body__authoring-node"))
.toHaveAttribute("data-readable-surface", "dark");
- Step 2: Run failing test
Run:
pnpm --dir web --filter @lda/console test -- src/presentation/SceneBody.test.tsx
Expected: FAIL because the authoring loop does not expose the readability hook yet.
- Step 3: Add readability data hooks
In web/apps/console/src/presentation/SceneBody.tsx, change:
<div className="scene-body__authoring-loop" aria-label="agent authoring loop" data-active-stage={beat.id}>
to:
<div
className="scene-body__authoring-loop"
aria-label="agent authoring loop"
data-active-stage={beat.id}
data-readable-surface="dark"
>
Change the authoring node element:
<div
key={step.id}
className="scene-body__authoring-node"
data-authoring-active={isActive}
data-authoring-past={isPast}
>
to:
<div
key={step.id}
className="scene-body__authoring-node"
data-authoring-active={isActive}
data-authoring-past={isPast}
data-readable-surface="dark"
>
- Step 4: Fix authoring foreground CSS
In web/apps/console/src/presentation/presentation.css, update .scene-body__authoring-node to set explicit text color:
.scene-body__authoring-node {
position: relative;
z-index: 1;
display: grid;
align-content: start;
gap: 0.35rem;
min-height: 8.6rem;
border: 1px solid color-mix(in oklch, var(--stage-line) 72%, transparent);
border-radius: 0.75rem;
padding: 0.75rem;
background: color-mix(in oklch, var(--stage-surface) 88%, transparent);
color: var(--text-primary);
transition: opacity 180ms ease, transform 180ms ease, border-color 180ms ease, background 180ms ease;
}
Add:
.scene-body__authoring-node strong {
color: var(--text-primary);
}
Replace:
.scene-body__authoring-node small {
color: var(--text-muted);
font: 0.72rem/1.35 var(--font-interface);
}
with:
.scene-body__authoring-node small {
color: color-mix(in oklch, var(--text-primary) 72%, var(--text-muted));
font: 0.72rem/1.35 var(--font-interface);
}
If --text-primary or --text-muted are not available in this scope during browser review, use the existing stage tokens already present in nearby CSS. Do not introduce new global tokens.
- Step 5: Run focused test
Run:
pnpm --dir web --filter @lda/console test -- src/presentation/SceneBody.test.tsx
Expected: PASS.
- Step 6: Commit Task 1
git add web/apps/console/src/presentation/SceneBody.tsx web/apps/console/src/presentation/SceneBody.test.tsx web/apps/console/src/presentation/presentation.css
git commit -m "fix: restore authoring loop contrast"
Task 2: Scene 10 Chat Rail Contrast
Files:
- Modify:
web/apps/console/src/presentation/OperatorChat.tsx - Modify:
web/apps/console/src/presentation/OperatorChat.test.tsx - Modify:
web/apps/console/src/presentation/presentation.css
Interfaces:
-
Consumes:
compositionForState(state)result withchatModeandchatTheme.- Existing
.operator-chatand.chat-messageCSS classes.
-
Produces:
data-chat-theme={composition.chatTheme}data-readable-surface="dark"or"light"on the chat root.- explicit chat message foreground colors.
-
Step 1: Add failing chat theme/readability test
In web/apps/console/src/presentation/OperatorChat.test.tsx, add:
it("exposes chat theme and readable surface attributes", () => {
render(<OperatorChat state={initialPresentationState} />);
const chat = screen.getByLabelText("scripted operator chat");
expect(chat).toHaveAttribute("data-chat-theme");
expect(chat).toHaveAttribute("data-readable-surface");
});
- Step 2: Run failing test
Run:
pnpm --dir web --filter @lda/console test -- src/presentation/OperatorChat.test.tsx
Expected: FAIL because OperatorChat currently emits data-mode only.
- Step 3: Restore chat attributes
In web/apps/console/src/presentation/OperatorChat.tsx, replace:
<aside className="operator-chat" data-mode={composition.chatMode} aria-label="scripted operator chat">
with:
<aside
className="operator-chat"
data-mode={composition.chatMode}
data-chat-theme={composition.chatTheme}
data-readable-surface={composition.chatTheme === "light" ? "light" : "dark"}
aria-label="scripted operator chat"
>
If composition.chatTheme can be undefined in the current type, use:
data-chat-theme={composition.chatTheme ?? "dark"}
data-readable-surface={(composition.chatTheme ?? "dark") === "light" ? "light" : "dark"}
Prefer the typed version if the compiler accepts it.
- Step 4: Fix chat foreground CSS
In web/apps/console/src/presentation/presentation.css, replace the current .chat-message rule with explicit foreground:
.chat-message {
border: 1px solid oklch(0.34 0.035 250);
border-radius: 0.65rem;
padding: 0.65rem 0.75rem;
background: oklch(0.18 0.025 250);
color: var(--text-primary);
font-size: 0.85rem;
}
Add:
.chat-message strong {
display: block;
margin-bottom: 0.35rem;
color: var(--text-primary);
}
.chat-message p,
.chat-message span,
.chat-message code {
color: inherit;
}
.operator-chat[data-readable-surface="light"] .chat-message {
border-color: color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 35%, transparent);
background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 92%, white);
color: var(--color-editorial-ink, oklch(0.19 0.015 65));
}
.operator-chat[data-readable-surface="light"] .chat-message strong {
color: var(--color-editorial-ink, oklch(0.19 0.015 65));
}
Then inspect the existing .chat-tool-part rules around presentation.css:604. If they set dark text implicitly, add:
.chat-tool-part {
color: var(--text-primary);
}
.operator-chat[data-readable-surface="light"] .chat-tool-part {
color: var(--color-editorial-ink, oklch(0.19 0.015 65));
}
Do not restyle the chat layout beyond foreground/readability.
- Step 5: Run focused test
Run:
pnpm --dir web --filter @lda/console test -- src/presentation/OperatorChat.test.tsx
Expected: PASS.
- Step 6: Commit Task 2
git add web/apps/console/src/presentation/OperatorChat.tsx web/apps/console/src/presentation/OperatorChat.test.tsx web/apps/console/src/presentation/presentation.css
git commit -m "fix: restore presentation chat contrast"
Task 3: Visual Smoke Hygiene And Roadmap
Files:
- Modify:
.gitignore - Modify:
docs/current_roadmap.md - Move:
docs/superpowers/plans/2026-07-08-presentation-contrast-readability.mdtodocs/historical/superpowers/plans/2026-07-08-presentation-contrast-readability.md
Interfaces:
-
Consumes: Task 1 and Task 2 fixes.
-
Produces: clean worktree with generated screenshots ignored or removed.
-
Step 1: Ignore generated screenshot folder
Add this near the testing/coverage ignores in root .gitignore:
# Local presentation screenshots
web/apps/console/.visual-smoke/
- Step 2: Remove existing generated folder if present
Run:
$target = Resolve-Path -LiteralPath 'web/apps/console/.visual-smoke' -ErrorAction SilentlyContinue
if ($target -and $target.Path -like (Resolve-Path '.').Path + '*') {
Remove-Item -LiteralPath $target.Path -Recurse -Force
}
Expected: no web/apps/console/.visual-smoke/ entry in git status --short.
- Step 3: Re-capture two screenshots for review only
Start dev server if needed:
pnpm --dir web dev
Capture:
New-Item -ItemType Directory -Force web/apps/console/.visual-smoke | Out-Null
pnpx playwright screenshot --viewport-size=1280,720 "http://127.0.0.1:5173/present#scene/authoring/discover" web/apps/console/.visual-smoke/scene-07-authoring-contrast-1280x720.png
pnpx playwright screenshot --viewport-size=1280,720 "http://127.0.0.1:5173/present#scene/interrupt-evidence/approval" web/apps/console/.visual-smoke/scene-10-approval-contrast-1280x720.png
Manual acceptance:
-
Scene 7 authoring node labels and details are readable.
-
Scene 10 chat rail labels and message text are readable.
-
Screenshot folder remains ignored by git.
-
Step 4: Update roadmap
In docs/current_roadmap.md, under Next presentation visual slices, replace:
1. Contrast and readability fix pass: repair dark-on-dark text in the Scene 7
authoring loop and the Scene 10 chat rail, then ignore or remove generated
`.visual-smoke/` screenshots.
with:
1. Completed: contrast and readability fix pass repaired dark-on-dark text in
the Scene 7 authoring loop and the Scene 10 chat rail, and ignored local
`.visual-smoke/` screenshots. Implementation:
[`presentation contrast readability`](historical/superpowers/plans/2026-07-08-presentation-contrast-readability.md).
- Step 5: Archive plan
Run:
git mv docs/superpowers/plans/2026-07-08-presentation-contrast-readability.md docs/historical/superpowers/plans/2026-07-08-presentation-contrast-readability.md
If the plan is not tracked yet, use PowerShell:
Move-Item docs/superpowers/plans/2026-07-08-presentation-contrast-readability.md docs/historical/superpowers/plans/2026-07-08-presentation-contrast-readability.md
- Step 6: Commit Task 3
git add .gitignore docs/current_roadmap.md docs/historical/superpowers/plans/2026-07-08-presentation-contrast-readability.md
git commit -m "docs: record presentation contrast readability pass"
Final Verification
- Run focused tests:
pnpm --dir web --filter @lda/console test -- src/presentation/SceneBody.test.tsx src/presentation/OperatorChat.test.tsx
Expected: PASS.
- Run console typecheck:
pnpm --dir web --filter @lda/console typecheck
Expected: PASS.
- Run full web tests:
pnpm --dir web test
Expected: PASS.
- Run whitespace/status checks:
git diff --check
git status --short
Expected:
- No whitespace errors.
- No untracked
.visual-smoke/files. - Only intentional files remain if not yet committed.
Review Checklist
- Scene 7 screenshot has readable authoring labels and details.
- Scene 10 screenshot has readable chat rail labels and message text.
/consoleunaffected.- No layout/composition changes beyond contrast/readability.
.visual-smoke/ignored or removed.- Roadmap still lists scene composition pass and craft pass as follow-ups.