fix(web): time-grid pinned panes occlude scrolled content (opaque backdrop) - #341
Conversation
…hours In the week and interval time-grid (#339), the three pinned panes (the day-header row, the "DIA INTEIRO" all-day band, and the left hour gutter) were backed by --bg-card, which is translucent on dark (alpha 0.04). As the hourly body scrolled underneath, the gutter hour labels and day-column content bled through the all-day band (the 8:00 label rendered behind it) and through the gutter. The z-index layering (z-3 header, z-2 band, z-1 gutter) was already correct; only the backdrop was see-through. Back the pinned panes with an opaque equivalent of the card surface (opaque --bg canvas plus the --bg-card tint layered on top) so they fully occlude the scrolling content while matching the card's appearance. The all-day band now reads as its own zone with the hourly grid cleanly below it, and the horizontal scroll plus pinned gutter still work. Mobile already isolates the zones with separate clipped scroll regions and a reserved all-day band height, so it never had the overlap and needs no change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
There was a problem hiding this comment.
Code Review: PR #341
Scope: PR #341 — fix(web): time-grid pinned panes occlude scrolled content (opaque backdrop)
Recommendation: APPROVE
Summary
PR #341 fixes a visual bleed-through bug in the web calendar time-grid where semi-transparent pinned panes (day header, all-day band, hour gutter) let scrolling body content show through. The fix replaces background: var(--bg-card) with a two-layer CSS backdrop (backgroundColor: var(--bg) + backgroundImage: linear-gradient(var(--bg-card), var(--bg-card))), making the panes opaque while preserving the visual card tint. The change is web-only by design — mobile uses separate clipped ScrollViews that naturally prevent the bleed-through. No Critical or High findings.
Findings
Critical
None
High
None
Medium
None
Low / Info
None
Subagents
| Agent | Verdict |
|---|---|
| parity-checker | PAIRED — mobile uses separate clipped ScrollViews that naturally prevent bleed-through; bug never existed on mobile; no mobile change required |
| i18n-syncer | IN SYNC — no new user-facing strings; existing allDayLabel/nowLabel keys present in both locales |
| contract-aligner | N/A — no packages/shared types or API endpoint changes |
| security-reviewer | N/A — no orbit-api code changed |
Validation
| Check | Result |
|---|---|
| Lint | N/A (author reports 0 errors; sandbox blocked re-run) |
| Type check | N/A (author reports 3/3 pass; sandbox blocked re-run) |
| Tests | N/A (author reports web 1752 pass; sandbox blocked re-run) |
| Build (api) | N/A — no API changes |
Deferred — N/A dimensions & files not verdicted
- Dimension 5 (No-workaround): N/A — the two-layer CSS backdrop is the correct CSS technique for stacking an opaque base with a translucent tint, not a workaround.
- Dimension 6 (Type safety): N/A — no new types;
as constonpinnedPaneBackgroundis appropriate. - Dimension 7 (console.log): N/A — none introduced.
- Dimension 11 (Contract drift + backward-compat): N/A — no shared types or API changes.
- Dimension 12 (Security): N/A — no auth, data, or API surface touched.
- Dimension 13 (Backend hard rules): N/A — no orbit-api changes.
apps/web/__tests__/components/calendar/calendar-time-grid.test.tsx: PASS — new test assertstime-grid-all-day-bandcarriesvar(--bg)in its inline style; checking the CSS token name is the correct approach in JSDOM where CSS variables do not resolve.
What's good
- The two-layer CSS backdrop (
backgroundColoropaque base +backgroundImagetranslucent tint) is the idiomatic technique for this pattern. It preserves the visual card tint while making the pane fully opaque. CARD_BGis correctly retained for the outer card wrapper (line 250), which stays intentionally translucent. No dead code created.pinnedPaneBackgroundis used at five call sites — extraction is well past the three-use threshold.- Token compliance throughout:
var(--bg)andvar(--bg-card)are canonical semantic tokens; no raw slate values or hardcoded rgba. - Parity judgment is architecturally sound — mobile and web have genuinely different scroll mechanisms; the bug never existed on mobile.
Recommendation
Clean, targeted fix with correct technique and a good regression test. Ready to merge.
🤖 Generated with Claude Code
The four components are built and rewired. Eleven screens are read, four are corrected with Thomas, and the rest carry their findings here with the file and line each was traced to, so the next session does not re-derive them. Three API tickets came out of the review. #341 is the one that matters: Wrapped has no endpoint at all. The retrospective is Pro-gated, every window is rolling and ends today, and "month" is 30 rolling days rather than a calendar month. A Pro-gated viral loop is not a viral loop. Also records the traps that cost time: the model picker's silent confirm dialog, the real paste-to-attachment threshold, and the iframe scroller. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>



Fix the all-day band overlapping the hour labels on scroll
The week/interval time-grid's pinned panes (day-header, all-day "DIA INTEIRO" band, left hour gutter) were backed by the translucent
var(--bg-card)(rgba(...,0.04)on dark), so when the hourly body scrolled underneath, the8:00+ gutter labels and column tops bled straight through the all-day band — it looked like overlap. (z-ordering was already correct; the panes were just see-through.)Fix
The pinned panes now use an opaque backdrop —
var(--bg)canvas with the card tint layered on top (linear-gradient(var(--bg-card), var(--bg-card))) — the exact same color but fully occluding scrolled content. Applied to all five pinned sub-elements; the outer card stays intentionally translucent; #339's horizontal scroll + pinned gutter untouched.Mobile was already correct (separate clipped ScrollViews with a reserved all-day-band height) — no change.
Validation
type-check 3/3; lint 0 errors; web 1752, mobile 725 pass; new regression test asserts the all-day band carries an opaque backdrop.
🤖 Generated with Claude Code