fix(web): seal the seam between attached banners and the composer - #8551
fix(web): seal the seam between attached banners and the composer#8551vitalyiegorov wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Warning Your free Security trial is over. An organization admin can activate Security or dismiss this notice. Comment |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This is a small, localized CSS visual fix for a one-pixel Chromium seam in attached composer banners. An unresolved finding identifies a plausible visible mismatch under configurable glass opacity and banner tint states, so the rendering behavior should receive human verification. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
One finding on the new attachment-seal strip: its fill does not follow the same surface composition as the drawer it seals, so the sealed row can read as a band rather than a continuation of the drawer. Geometry, the shoulder-tab exclusion, and the --chat-composer-drawer-inset inheritance (via [data-chat-composer-form="true"]) all check out.
Posted via Macroscope — UI Consistency
| background: | ||
| linear-gradient( | ||
| var(--chat-composer-attachment-seal-shade), | ||
| var(--chat-composer-attachment-seal-shade) | ||
| ), | ||
| var(--chat-composer-glass-surface); |
There was a problem hiding this comment.
The strip paints the glass surface fully opaque and untinted, but the surface it is sealing is color-mix(in srgb, <surface> var(--glass-opacity), transparent) plus --chat-composer-attached-tint. Since bottom: calc(100% - 1px) puts 2 of the 3px on top of the drawer's own surface, the mismatch is visible there:
--glass-opacityis a runtime user setting (40-100%, default 80;routes/__root.tsx:171). Every other composer/drawer surface derives from it, and the only other opaque paints of--chat-composer-glass-surfaceare inside@supports not (backdrop-filter)fallbacks. Below 100% the seal reads as a solid strip over translucent glass.- The tint is dropped: the internal top drawer always sets
data-variant="info"|"warning"(ChatComposer.tsx:2979) and banner-stack alerts set error/warning/success, each of which layers--chat-composer-attached-tintonto the drawer surface.
Consider composing the strip from the same tokens - the glass-opacity mix plus the drawer tint - and giving it its own backdrop-filter, so any row it loses at its own top edge lands on the drawer's already-blurred surface, keeping the opaque paint only for the @supports not fallback. The tint currently lives on the drawer element, so it needs hoisting to the shell (next to --chat-composer-attachment-seal-shade) for the strip to read it.
- var(--chat-composer-glass-surface);
+ color-mix(in srgb, var(--chat-composer-glass-surface) var(--glass-opacity), transparent);
+ -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation));
+ backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation));Posted via Macroscope — UI Consistency
69cbd4c to
cb2663d
Compare
Dismissing prior approval to re-evaluate cb2663d
There was a problem hiding this comment.
One finding on the attachment seal: the repainted strip does not reproduce the glass composition of the surfaces it covers, so it becomes visible as an opaque band under non-default glass opacity and on tinted banner variants.
Posted via Macroscope — UI Consistency
cb2663d to
36fe1b9
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 36fe1b92229d214b56d0624f479409c7e2f677c6. Configure here.
36fe1b9 to
b6a13d1
Compare
|
On the open visual-consistency question — configurable glass opacity and the alert tint variants across the overlap. The bleed does not introduce a new surface. It extends the drawer's own masked surface one CSS px further down, into a strip the composer's surface already covers, so the two overlap there instead of leaving a row painted by neither. That means the only thing that can differ is a double composite of two semi-transparent surfaces over one CSS px. Measured every state that can vary across the overlap — glass opacity 100 / 80 (default) / 40 %, light and dark, and the default / info / warning / error banner tints:
Rows above the seam are bit-identical in every combination. Only the two device rows at the seam change, and there they go from showing chat text through the gap to the surface colour. The residual at 40 % is the expected double composite, and it lands strictly closer to the intended surface colour than the leak it replaces. Worth stating plainly: this gives back 1 px of the 17 px the overlap lost in #8083. That is the cost of the fix, and I did not find a way to seal the seam without it — a border, an inset shadow, and a token-matched strip all still leaked, and an outset shadow sealed it but broke surface parity far worse (178–222 / 255). |
2497405 to
7a8c97e
Compare
|
Closing — no longer reproducible on recent nightlies. If the seam leak resurfaces, the root-cause analysis and per-DPR measurements in this thread should spare the next person the diagnosis. |
7a8c97e to
85cc716
Compare
99f5cf3 to
b3333fd
Compare
At the join between an attached banner and the composer, a row one device pixel tall was painted by neither surface, so the chat behind it showed through crisp and unblurred. The drawer's mask cut-off now bleeds one pixel past the seam, so the drawer paints that row itself. Built with Claude Fable 5 in Claude Code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
b3333fd to
c39eede
Compare
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |


Closes #8546.
What Changed
At the join between an attached composer banner and the composer, one device-pixel row was painted by neither surface, so chat text behind it showed through crisp. The drawer's mask cut-off now bleeds one pixel past the seam so the drawer paints that row itself. One line in
apps/web/src/components/chat/ComposerBanner.tsx(Surface, attached placement):transparent 0 calc(var(--chat-composer-attachment-overlap) - 1px),black calc(... - 1px). Reopened because #8733 removed this mask construction and #8734 restored it intoComposerBanner.tsx; the branch is rebased ontomain@ 5b8445b (#7855, collapsed resting composer).Why
Chromium drops the final device-pixel row of a filtered backdrop when the mask cut-off lands off the device-pixel grid, and the composer's surface begins exactly at that cut-off, so nothing covers the row. Anything painted at offset ≥ 0 (a border-top or inset shadow on the composer, or a separate strip) cannot reach it; the drawer's own mask can. The
- 1pxis absolute, not scaled with the1removerlap, because it repairs a device-pixel rounding artefact, not a layout distance; 2px is no better. Cost: the composer's glass covers the extra row, so the overlap is invisible (surface parity ≤7/255 worst case at 40% glass opacity, ≤4 at the 80% default, 0 at 100%).UI Changes
Captured in the running web app with Playwright on
main@ 5b8445b vs this commit, dark theme, DPR 1.25, viewport 1400×902, timeline scrolled so a bright line of chat text sits behind the join, the collapsed resting composer with a real attached notice ("This thread is snoozed"); only the commit differs.Before vs after:
Seam magnified 4x, before vs after:
Per-device-row luminance at the cut-off (Rec. 709):
Earlier captures (the original report, an intermediate before shot, and the full 224-configuration approach comparison) are in the details block below. At DPR 2 in a 1400-px window the banner bottom lands on an integral device pixel, so a Retina window of that size shows nothing either way — the leak needs an off-grid phase, which 125%/150% scaling hits constantly.
Verification
vp build, apps/web) emits the arbitrary value with valid spacing:mask-image: linear-gradient(to top, transparent 0 calc(var(--chat-composer-attachment-overlap) - 1px), black calc(var(--chat-composer-attachment-overlap) - 1px)), matching the sibling+ 10pxvalue on the same element.main@ 5b8445b, 208 configurations per DPR (viewport heights 900–907 × scroll offsets 100–200), cut-off derived from the DOM per configuration, leak = cut-off row peak ≥ 1.8× its neighbours' mean peak. Expanded composer with the offline banner: leaking configurations 80 / 78 / 0 at DPR 1.25 / 1.5 / 2 before; 0 genuine after (10 / 11 / 0 residuals at ratio 1.8–2.1, the band the never-leaking DPR-2 baseline also reaches). Collapsed resting composer with the snoozed notice: 101 / 163 / 1 before; crisp-text leaks (row at least 20/255 brighter than its brightest neighbour) 24 / 21 / 0 before and 0 / 0 / 0 after; a faint edge of about 28/255 can remain at some sub-pixel phases in the collapsed layout, five times dimmer than before, and the worst before-configurations drop from 3.9× to 1.3–1.7×.Earlier captures and the full measurement history
Original report (macOS desktop app, "Resume with less context" banner):
Before, recaptured on
mainafter #8734 moved this seam intoComposerBanner.tsx(dark theme, Retina, the unified activity banner reading "Monitoring"):Expanded composer with the offline banner, before/after:
Magnified 4x, before and after:
Original 224-configuration approach comparison (7 device pixel ratios × 8 sub-pixel phases × ancestor transform × light/dark):
maintodayborder-top, orbox-shadow: inset 0 1px 0, on the composerbackdrop-filterChecklist
Built with Claude Fable 5 in Claude Code.
Note
Low Risk
Single CSS mask tweak on chat banner styling with no auth, data, or API impact; only slightly shifts the rendered glass boundary at the attachment seam.
Overview
Fixes a one-pixel leak at the join between attached composer banners (e.g. snoozed/offline notices) and the composer glass, where chat text could show through unblurred on Chromium at non-integer DPR.
In
ComposerBanner’sSurfacepseudo-element, the mask gradient cutoff moves from--chat-composer-attachment-overlaptocalc(... - 1px)so the banner’s backdrop-filter paints one device row past the seam; inline comments document the Chromium rounding behavior. Layout overlap and the dark-mode overlay gradient are unchanged—the extra row is covered by the composer’s own glass.Reviewed by Cursor Bugbot for commit b3333fd. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix
ComposerBannerbackdrop-filter seam at attachment boundaryAdjusts the surface pseudo-element's mask gradient in ComposerBanner.tsx so the opaque cutoff sits one pixel before the configured attachment overlap. This closes a Chromium backdrop-filter seam between the attached banner and the composer glass surface.
Macroscope summarized c39eede.