feat(theme): white chat canvas with grey shell in kiro-light - #8711
Conversation
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsAll candidate claims verified against source: the five test hook regexes match their real markup ( No findings. [OPUS-REVIEWED] 11903a4 Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
Design Review (Fable 5) — 🟡 CONCERNSDesign-level review of Design-Verdict: CONCERNS Collapsing Watch
Suggestions
[DESIGN-REVIEWED] 11903a4 |
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsFINDING -- website/src/apps/workflows/WorkflowsRuns.tsx:325 -- False positive or not applicable? A repository writer can comment: |
First Principles Review (Fable 5) — 🟡 CONCERNSPremise-level review of All claims verified: the per-theme scoped-rule mechanism pre-exists (index.css:1531,1543), First-Principles-Verdict: CONCERNS The whole change hangs on an inherited premise: "every mainstream chat product does the opposite" is analogy, and no user harm or recorded decision backs the inversion. What this change shipsIntent: make the chat transcript, not the shell, the visually primary surface in kiro-light. ADDITION (a changed default, not a fix).
Watch
[FIRST-PRINCIPLES-REVIEWED] 11903a4 |
UX Review (Fable 5) — ✅ PASSUX-level review of UX-Verdict: PASS The white-canvas swap ships with every vanishing-surface case hooked, screenshot-proven, and pinned by test plus contract doc; nothing a user hits regresses. [UX-REVIEWED] 11903a4 |
3ad635e to
93dbb19
Compare
Added |
Confirmed in the rendered build — and the status readout capsule next to it ( |
93dbb19 to
fab67ca
Compare
Sweep: a computed-style pass over nine non-chat routes in kiro-light on the built bundle (Settings ×4, Schedule, Artifacts, Knowledge, Apps library, Members), counting every element painted |
The edit box now carries the same |
Per candidate:
The heuristic gap the finding exposes — inline |
fab67ca to
8d91290
Compare
|
Rebased onto |
That element is |
Exactly that one-line change was applied locally on the head before this one and reverted: the wells render kiro-cli's spec-refusal output, and touching them pulled them under the blocking |
The frequency argument is fair and is why #8751 (a rendered computed-style gate over the routes) exists as the durable answer for both directions; the contract paragraph is what a reviewer applies until that gate lands. |
Invert kiro-light's surface hierarchy so the content is the primary surface and the app shell steps back, the layout every mainstream chat product uses. --bg moves from #fafafa to #ffffff, so the transcript and every page render on pure white; the nav rail and sessions list, which sat as white cards on the grey page, now take --panel (#fafafa) so they read as a quiet grey shell beside the white canvas. --chrome follows --bg so the translucent top bar does not band against it. The user bubble is a borderless bg-card fill and on a white canvas it disappeared entirely (white on white), so it carries a stable `user-bubble` hook and kiro-light tints it with --bg-hover (#f0f0f0), keeping it in the same grey family as the shell; the in-place edit box and the pinned-prompt banner (a pixel-for-pixel stand-in for the bubble while it is scrolled under the band) carry the same hook so editing and pinning do not flip the surface back to white. The steer variant is untouched. The two top-bar capsules (status readout, Request a Feature) share that failure mode -- borderless bg-card on --chrome, which now follows the white canvas -- so kiro-light gives them an inset 1px --border ring, the edge the neighbouring search field draws with a real border, without changing the box's size. Because --card now equals --bg in kiro-light, any borderless bg-card on the page is invisible there, and a hover that only swaps --bg for --card is no hover at all: the workflow-runs rows take --bg-hover, which reads in every theme. The theming contract states the convention (a card on --bg carries a border, ring or shadow, a bg-bg well inside a card does the same, hover states use --bg-hover; the deliberate exceptions are the kiro-light hooks), and a source-level guard pins every hook class the kiro-light rules select to the component that must render it, so a refactor that drops one fails a test instead of quietly returning the surface to white-on-white.
47aaace to
11903a4
Compare
|
|
|
|
|
|
|
|
|
|
Problem / Motivation
In
kiro-lightthe chat transcript sits on a grey page (--bg: #fafafa) while the nav rail and sessions list float above it as white cards. The content — long markdown answers, code blocks, the composer — is the thing a user reads for hours, yet it is the recessive surface; the shell is the one that reads as "lifted". Every mainstream chat product does the opposite: a white canvas for the conversation and a quiet grey shell beside it.Why it matters
Readability of long-form answers is the light theme's main job. A pure-white canvas gives markdown and code the highest-contrast surface available, and letting the shell step back makes the transcript unambiguously the primary surface instead of one more panel among the cards. This only touches
kiro-light; every other theme, includingkiro-dark, renders byte-identically.What changed (motivation → approach → change)
Goal: invert the surface hierarchy in
kiro-light— white canvas, grey shell.Approach. Three token-level options were rendered against the real built SPA before choosing: (a)
--bg→#ffffffalone, (b) the same plus a bordered user bubble, (c) the swap. (a) collapses every depth cue in the theme — the user bubble is a borderlessbg-cardfill and vanishes entirely (white on white), and the rail/sidebar/composer fall onto one flat plane. (b) fixes the bubble but adds an outline to every user turn. (c) is what shipped here: the canvas goes white and the two shell surfaces take the grey the page used to have.Moving the rail and sidebar onto a shared token was considered and rejected: in ~30 of the 50 built-in theme blocks
--panelis the page colour, not a shell colour, so a token-levelbg-panelwould have collapsed the rail and sidebar into the page background across most themes. Adding a new colour role instead would mean defining it in every built-in theme and both validator allowlists — the wrong scale for a one-theme change. The repo already scopes per-theme component rules with a[data-theme="kiro-light"]prefix (inline code, selected nav rows), so the change uses that mechanism.Change.
website/src/index.css,[data-theme="kiro-light"]:--bg#fafafa→#ffffff;--chromefollows torgba(255,255,255,.95)so the translucent top bar does not band against the canvas.--panelstays#fafafa.website/src/index.css, kiro-light-scoped rules:.focus-chrome-rail(nav rail) and.sidebar-inner(sessions list) takebackground-color: var(--panel);.user-bubbletakesvar(--bg-hover)(#f0f0f0) so the bubble stays visible on the white canvas, in the same grey family as the shell. Specificity(0,2,0)outranks the Tailwind utilities(0,1,0); the existing embed-mode[&_.sidebar-inner]:!bg-bgoverride still wins.website/src/pages/chat/UserMessage.tsx: the non-steer user bubble carries a stableuser-bubblehook class, and so does the in-place edit box that replaces it (its textarea is transparent), so editing does not flip the surface back to white under the caret. The steer variant (bg-accent-subtle) is untouched.website/src/pages/chat/PinnedPrompt.tsx: the pinned-prompt banner is documented as a pixel-for-pixel stand-in for the user bubble it replaces while that bubble is scrolled under the band; it carries the sameuser-bubblehook so the hand-off does not flip from#f0f0f0to white in kiro-light.website/src/index.css+website/src/components/FeedbackPill.tsx: the two top-bar capsules (status readout.tb-capsule, Request a Feature.feedback-pill) share the bubble's failure mode — borderlessbg-cardon--chrome, which now follows the white canvas — so kiro-light gives thembox-shadow: inset 0 0 0 1px var(--border), the edge the neighbouring search field draws with a real border, with no change to the box's size.website/docs/theming-contract.md: new paragraph "A card must carry its own edge" — since--cardequals--bgin kiro-light, abg-cardbox on the page draws a border, ring or shadow, abg-bgwell inside a card does the same, and hover states use--bg-hover; the deliberate borderless exceptions are the kiro-light hooks below, and a new one is a new hook, not an unmarked exception. Cross-referenced from theindex.csscomment.website/src/apps/workflows/WorkflowsRuns.tsx: the run rows'hover:bg-cardbecomeshover:bg-bg-hover— with--cardequal to--bg, swapping one for the other was no hover at all in kiro-light; the hover token reads in every theme.website/src/test/kiroLightShellHooks.test.ts: a source-level guard pins every hook class the kiro-light rules select (focus-chrome-rail,sidebar-inner,user-bubble,tb-capsule,feedback-pill) to the component that must render it, and pins the three rules themselves.Tests
kiroLightShellHooks.test.ts(12 cases) locks in: each hook class the kiro-light rules select is rendered by its component, the bubble tint stays on the non-steer branch only, and the three scoped rules exist as written — mutation-checked (droppinguser-bubblefromUserMessage.tsxturns two cases red). Existing coverage that pins the touched surfaces still passes —userBubbleMobileOverflow.test.tsx/UserMessage.bubbleHug.test.tsx(bubble width chain, tolerant of the added class),PhasedViewTheme.test.tsx(every referenced token exists),themeFillForeground.test.tsanddashboardTheme.test.ts(kiro-light resolution). Full frontend suite: 1854 files / 29168 tests green;tsc -b, eslint (--max-warnings 0), phantom-classes, i18n check + render, jscpd, focus-cue, bundle-size, brand, docs-lint and scrub-lint all green. The 434 backend cross-surface guard files were run; the 76 reds are host-environment failures (uid ownership of the checkout path, pytest tmp under the data home) and reproduce identically on the base commit.Manual verification
Rendered the real built
website/distagainst stubbed fixtures with the repo's transcript harness, before and after, and read the computed colours: kiro-light bodyrgb(250,250,250)→rgb(255,255,255); rail and sessions list#ffffff→#fafafa; user bubble#ffffff→#f0f0f0. kiro-dark body/rail/sidebar/bubble are identical before and after. Settings and the chat page were checked visually. A computed-style sweep of nine non-chat routes in kiro-light (Settings ×4, Schedule, Artifacts, Knowledge, Apps library, Members) found zero card-coloured boxes without a border, ring, shadow or contrasting parent — the only hit isbodyitself — so no further borderlessbg-cardsurface is affected by--cardnow equalling--bg.Screenshots / video
Static change, no motion — stills are the right evidence.
Chat, kiro-light — before / after

Bubble + composer, after (crop)

Top-bar capsules — first head vs now (crop, 2x)

Settings page before / after, and kiro-dark parity
Related Issues
no linked issue: design decision taken directly with the maintainer from rendered variants; no tracked issue exists for it.
Checklist
feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)