Skip to content

fix(web): chat text no longer shows through a 1px gap under composer banners - #8551

Closed
vitalyiegorov wants to merge 1 commit into
pingdotgg:mainfrom
vitalyiegorov:fix/composer-banner-seam
Closed

fix(web): chat text no longer shows through a 1px gap under composer banners#8551
vitalyiegorov wants to merge 1 commit into
pingdotgg:mainfrom
vitalyiegorov:fix/composer-banner-seam

Conversation

@vitalyiegorov

@vitalyiegorov vitalyiegorov commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Closes #8546.

What Changed

On 125% and 150% displays, a crisp line of chat text shows through a one-pixel gap between any attached composer banner ("Monitoring", offline, "This thread is snoozed", "Resume with less context") and the composer. It looks like a rendering glitch every time the timeline scrolls under the banner.

One line in apps/web/src/components/chat/ComposerBanner.tsx: the banner's glass mask now ends one pixel below the seam instead of exactly on it, so the banner paints the row the composer never reaches. The composer's own glass sits over that pixel, so the overlap is invisible.

Why

Chromium drops the last device-pixel row of a backdrop-filter surface when its mask cut-off lands between device pixels, and the composer surface starts exactly at that cut-off, so nothing paints the row. A border or shadow on the composer cannot reach it; only the banner's own mask can. A fixed 1px (not scaled with the 1rem overlap) because this repairs a device-pixel rounding artefact, not a layout distance.

UI Changes

Dark theme, DPR 1.25, collapsed resting composer with the snoozed notice attached, chat text scrolled under the join. Before, then after:

Before: a crisp line of chat text leaks through the seam under the snoozed notice After: the seam is uniformly blurred, no text leak

Seam at 4×, before and after:

Seam magnified 4x: one crisp unblurred row of text at the cut-off Seam magnified 4x: the crisp row is gone, blur continuous across the join

No motion, so no video.

Verification

  • Measured in the running app with Playwright, 208 viewport/scroll configurations per DPR on main vs this commit: crisp-text leaks at DPR 1.25 / 1.5 / 2 go from 24 / 21 / 0 to 0 / 0 / 0. Rows above the seam are byte-identical before and after.
  • The production Tailwind build emits the arbitrary value with valid spacing, matching the sibling + 10px value on the same element.
  • At DPR 2 in a 1400-px window the banner bottom lands on a whole device pixel, which is why a Retina window of that size never shows the bug and why it went unreported for a while.
Measurement history and alternatives tried

Per-device-row luminance at the cut-off (Rec. 709), collapsed composer:

before after
cut-off row peak 75 30
neighbour mean 18.9 18.9
peak / neighbour ratio 3.97 1.59

Alternatives, 224 configurations (7 DPRs × 8 sub-pixel phases × ancestor transform × light/dark):

approach leaking configs
main 48
border-top or box-shadow: inset 0 1px 0 on the composer 48
a separate strip with the same tokens + backdrop-filter 30
mask bleed 1px 0

Original report (macOS desktop app, "Resume with less context" banner):

Resume with less context banner with chat text showing through the seam above the composer

Expanded composer with the offline banner, before and after:

Offline banner on the expanded composer with a crisp line of text leaking through the seam Same offline banner, seam now uniformly blurred

History: #8733 removed the masked overlap and #8734 restored it into ComposerBanner.tsx, which is where the fix now lives.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes (nothing moves)

Built with Claude Fable 5 in Claude Code.

Note

Fix 1px gap showing chat text under composer banner in Chromium

Adjusts the surface pseudo-element mask gradient in ComposerBanner.tsx so the opaque cutoff sits one pixel before the attachment overlap. This covers a Chromium backdrop-filter seam that let chat text bleed through.

  • Risk: changes the rendered boundary of attached and floating glass surfaces by extending the masked region one pixel toward the attachment seam

Macroscope summarized 4bcb1f0.

@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 6bb76dd5-308f-4ce0-a0b7-cd447a01d6ab

📥 Commits

Reviewing files that changed from the base of the PR and between 6abdf37 and 410f549bedfdfbe52f08b54f21fbea1f175b427d.

📒 Files selected for processing (1)
  • apps/web/src/components/chat/ComposerBanner.tsx

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The attached composer surface mask now ends one pixel before the seam. A comment documents the Chromium device-pixel bleed that caused the backdrop-filter row to disappear.

Changes

Composer seam rendering

Layer / File(s) Summary
Adjust attached-surface mask cutoff
apps/web/src/components/chat/ComposerBanner.tsx
The mask reaches opaque black at calc(var(--chat-composer-attachment-overlap)-1px). A comment documents the device-pixel bleed.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Merge Risk: ⚪ Minimal · up to 4bcb1

The attached composer banner mask now covers the device-pixel seam with the composer, preventing background chat text from appearing through the join. No current merge-blocking risk remains.

Suggested reviewers: maria-rcks, juliusmarminge, bil0000

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The CSS mask adjustment directly addresses issue #8546 by covering the previously unpainted device-pixel row and preventing crisp chat text from showing through the seam.
Out of Scope Changes check ✅ Passed The changes are limited to the focused ComposerBanner surface mask adjustment and related documentation. No unrelated code or behavior changes are present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files.
Title check ✅ Passed The title clearly and concisely describes the primary fix: preventing chat text from showing through a one-pixel gap under composer banners.
Description check ✅ Passed The description is complete and focused. It explains the change, the cause, the UI impact, verification results, screenshots, and checklist status. The unchecked video item is appropriate because the …
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 28, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 28, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: 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 42f87cd. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread apps/web/src/index.css Outdated
@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch from 69cbd4c to cb2663d Compare August 28, 2026 15:01
@macroscopeapp
macroscopeapp Bot dismissed their stale review August 28, 2026 15:01

Dismissing prior approval to re-evaluate cb2663d

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread apps/web/src/index.css Outdated
@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch from cb2663d to 36fe1b9 Compare August 28, 2026 15:07
@github-actions github-actions Bot added size:S 10-29 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 28, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread apps/web/src/index.css Outdated
@vitalyiegorov

vitalyiegorov commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Verified in the real app, not just the harness — same build, dark theme, DPR 2, with the actual ComposerBannerStack attached above the real composer and bright content behind it. The only difference between the two frames is the seal being disabled and enabled via an injected style; same page instance, same DOM, same clip box, no reload.

Per-row brightness across the clip (1448 device px wide), rows relative to the seam:

device row before mean / peak after mean / peak
0–5 identical identical
6 21.1 / 68 20.1 / 68
7 24.4 / 73 20.1 / 73
8 38.6 / 76 20.1 / 76
9 39.2 / 70 20.1 / 68
10 42.1 / 77 20.0 / 29
11 41.4 / 77 20.0 / 29
12–19 identical identical

Rows 10–11 are the leak: peak 77 against a ~60–68 surround, carrying crisp glyph tops. After the fix they read a flat 29. Exactly six device rows change — the 3 CSS px strip — and every row outside it is identical, so nothing else moved.

Real app before and after at 6x magnification: the leaking row at the seam disappears with the fix

Every attached banner hits this seam: .chat-composer-drawer-surface is what ComposerBannerStack renders, and externalComposerDrawerAttached is composerBannerItems.length > 0.

@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch from 36fe1b9 to b6a13d1 Compare August 28, 2026 17:10
@vitalyiegorov

Copy link
Copy Markdown
Contributor Author

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:

glass opacity worst-case per-channel delta in the seam strip
100 % 0 / 255
80 % (default) ≤ 4 / 255
40 % (minimum) ≤ 7 / 255

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).

@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch 2 times, most recently from 2497405 to 7a8c97e Compare August 30, 2026 17:13
@vitalyiegorov

Copy link
Copy Markdown
Contributor Author

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.

@vitalyiegorov vitalyiegorov reopened this Sep 3, 2026
@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch from 7a8c97e to 85cc716 Compare September 3, 2026 05:29
@github-actions github-actions Bot added size:XS 0-9 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 3, 2026
@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch 2 times, most recently from 99f5cf3 to b3333fd Compare September 5, 2026 03:31
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 5, 2026
@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch from b3333fd to c39eede Compare September 5, 2026 09:37
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Bugbot is paused — on-demand spend limit reached

Bugbot 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.

@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch 3 times, most recently from d168c4d to c184c4e Compare September 6, 2026 16:15
@cursor

cursor Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Bugbot is paused — on-demand spend limit reached

Bugbot 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.

@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch from c184c4e to 410f549 Compare September 7, 2026 05:16
@vitalyiegorov vitalyiegorov changed the title fix(web): seal the seam between attached banners and the composer fix(web): chat text no longer shows through a 1px gap under composer banners Sep 7, 2026
@vitalyiegorov
vitalyiegorov force-pushed the fix/composer-banner-seam branch 3 times, most recently from 42f87cd to b67b203 Compare September 7, 2026 17:28
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>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing as part of the open-PR backlog sweep (wave 2).

Reason: Author said closing; seam gone after later composer-banner rework.
Related: #8734

Reopen if this is still wanted and you’re willing to rebase onto current main.

@vitalyiegorov

Copy link
Copy Markdown
Contributor Author

Reopening, with apologies for the stale signal: the Aug 31 "closing" comment was mine, and it was wrong. On Sep 3 I re-measured on main after #8734 and reopened: #8733 had removed the masked overlap, but #8734 restored it into ComposerBanner.tsx, and the seam came back with it. Measured on the nightly with the collapsed resting composer (#7855): 80 / 78 / 0 leaking configurations at DPR 1.25 / 1.5 / 2 out of 208, and 24 / 21 / 0 crisp-text leaks, all 0 after this one-line change (numbers and 4× crops are in the PR body and on #8546, which is still open). The branch is on today's main (4bcb1f03e), CI green.

@vitalyiegorov

Copy link
Copy Markdown
Contributor Author

GitHub refuses to reopen this one (422 on reopen), so the same branch continues as #10635.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: A 1px line of chat text shows through under every attached composer banner on 125%/150% displays

2 participants