From db341491b0d94cf11641eb98aa8726629580a652 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 30 Jul 2026 02:32:44 +0000 Subject: [PATCH 1/4] fix(ui): paint the phone top safe-area with the header surface The `chrome-safe-area-top` spacer painted `var(--background)` while the bar directly below it paints `var(--surface)`, so every collapse-strategy mode drew a page-coloured status-bar band above the white header on phones. Answer mode never showed the seam because it is the only mode on the overlay hide strategy: it renders no spacer and pads the inset inside the header itself, so the bar's surface paints straight through to the viewport top. Collapse-strategy modes need the separate spacer so the inset can be released on scroll, and that spacer simply had the wrong colour. Measured at 440x956 with the inset injected as tests/ui-phone-scroll.spec.ts does, top-edge pixel before -> after: /?mode=answer rgb(252,253,254) -> unchanged /?mode=documents rgb(241,244,248) -> rgb(252,253,254) /services rgb(241,244,248) -> rgb(252,253,254) /services?q=Community&run=1 rgb(241,244,248) -> rgb(252,253,254) Kept opaque so the sm+ pinned inset still hides scrolled content, and the release contract is unchanged: on scroll-hide the spacer still collapses to height 0 with data-scroll-hidden="true" and the top pixel returns to page content (light rgb(241,244,248), dark rgb(6,7,8)). Dark mode paints rgb(16,19,21), matching the dark `--surface`. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01MYeZh7qEEXc36AX4JuDjzF --- docs/search-chrome-behaviour.md | 2 +- .../clinical-dashboard/master-search-header.tsx | 10 +++++++++- tests/header-scroll-hide-contract.test.ts | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/search-chrome-behaviour.md b/docs/search-chrome-behaviour.md index 669bae9f17..610fe35e0d 100644 --- a/docs/search-chrome-behaviour.md +++ b/docs/search-chrome-behaviour.md @@ -21,7 +21,7 @@ This repo uses one shared search experience across the global shell, dashboard r 3. A visible fixed phone dock may include `var(--safe-area-bottom)` so the pill clears the home indicator. 4. A hidden phone dock must release the content-facing reserve to `0rem`; do not use `env(safe-area-inset-bottom)` or `var(--safe-area-bottom)` for hidden content padding. 5. Edge-to-edge phone dock mode is `left: 0; right: 0; bottom: 0; width: 100%`; inset the pill with padding, not with a non-zero bottom offset. Keep the dock form transparent and use its absolute `.answer-footer-search-backdrop` child for localized translucent gradient/blur around the pill. The gradient and every blur mask must return to fully transparent at the physical bottom edge. It must move and fade with the dock, then become `visibility: hidden` after the hide transition so WebKit cannot retain a safe-area compositor strip; it must never become a viewport-fixed or opaque slab. -6. Header and footer chrome that share the same scroll signal should hide/reveal symmetrically for the surfaces that actually hide: when the phone top bar is hidden, `chrome-safe-area-top` and the controls both release to `0rem` so underlying content paints to the physical viewport edge. The visible phone header still owns `var(--safe-area-top)`; tablet/desktop sticky chrome keeps its pinned inset. Top-bar hide/reveal is cross-breakpoint; the search field stays pinned on tablets, while desktop search belongs to page flow and scrolls away naturally; the bottom search dock is phone-only. Hidden bottom dock reserve stays `0rem` (invariant 4). Read "Scroll hide/reveal" below before changing either. +6. Header and footer chrome that share the same scroll signal should hide/reveal symmetrically for the surfaces that actually hide: when the phone top bar is hidden, `chrome-safe-area-top` and the controls both release to `0rem` so underlying content paints to the physical viewport edge. The visible phone header still owns `var(--safe-area-top)`; tablet/desktop sticky chrome keeps its pinned inset. While visible that spacer is the top of the header, so it paints `var(--surface)` — the bar's own opaque phone colour — never `var(--background)`: the page colour there reads as a status-bar band above the bar, the seam overlay-strategy answer mode never shows because its header pads the inset itself. Keep it opaque so the sm+ pinned inset still hides scrolled content. Top-bar hide/reveal is cross-breakpoint; the search field stays pinned on tablets, while desktop search belongs to page flow and scrolls away naturally; the bottom search dock is phone-only. Hidden bottom dock reserve stays `0rem` (invariant 4). Read "Scroll hide/reveal" below before changing either. 7. Do not add page-local dock-sized `pb-[calc(...safe-area...)]` under a shell-owned dock. Put clearance in the shared reserve or the page-owned composer, never both. 8. `GlobalSearchShell` uses an inner `mobile-composer-reserve-pad` so phone padding contributes to scroll height; do not move phone shell clearance back to scrollport padding without a browser proof. 9. Page-owned fixed phone composers follow the same release contract: calculators use the shared footer backdrop; DocumentViewer keeps its floating pill but synchronizes transform, opacity, pointer release, and its own zero-reserve content padding. In-flow hero composers remain free of fixed-footer glass. diff --git a/src/components/clinical-dashboard/master-search-header.tsx b/src/components/clinical-dashboard/master-search-header.tsx index 8d14879d38..4849152a7b 100644 --- a/src/components/clinical-dashboard/master-search-header.tsx +++ b/src/components/clinical-dashboard/master-search-header.tsx @@ -2169,7 +2169,15 @@ export function MasterSearchHeader({ // header row's timing to avoid a one-frame gap during hide/reveal. // sm+ keeps its pinned inset because the sticky [bar | search] stack // is a separate wide-layout contract. - "relative z-40 shrink-0 bg-[color:var(--background)] motion-reduce:transition-none sm:h-[var(--safe-area-top)]", + // + // Paint the header's own surface, not the page background. While the + // spacer is visible it is the top of the header, so `--background` + // drew a page-coloured status-bar band above a `--surface` bar on + // every collapse-strategy mode — the seam answer mode never had, + // because its overlay header pads the inset itself and paints + // straight through. Opaque on purpose: the spacer must keep hiding + // scrolled content at the sm+ pinned inset. + "relative z-40 shrink-0 bg-[color:var(--surface)] motion-reduce:transition-none sm:h-[var(--safe-area-top)]", phoneOverlayMotion ? "max-sm:h-[var(--safe-area-top)]" : cn( diff --git a/tests/header-scroll-hide-contract.test.ts b/tests/header-scroll-hide-contract.test.ts index 9896a9a27c..d204bc33f5 100644 --- a/tests/header-scroll-hide-contract.test.ts +++ b/tests/header-scroll-hide-contract.test.ts @@ -289,6 +289,21 @@ describe("shared header hide/reveal wiring", () => { expect(behaviourDocSource).toContain("`h-0` while hidden"); }); + it("paints the visible top safe-area with the header surface, not the page background", () => { + // While visible the spacer is the top of the header. `--background` there + // drew a page-coloured status-bar band above the `--surface` bar on every + // collapse-strategy mode, which answer mode (overlay, pads the inset in the + // header itself) never showed. + const spacerStart = headerSource.indexOf('data-testid="chrome-safe-area-top"'); + expect(spacerStart).toBeGreaterThan(-1); + // Bound the window to this element so a later call site cannot satisfy or + // break the assertion from outside the spacer. + const safeAreaSpacer = headerSource.slice(spacerStart, headerSource.indexOf("/>", spacerStart)); + expect(safeAreaSpacer).toContain("bg-[color:var(--surface)]"); + expect(safeAreaSpacer).not.toContain("bg-[color:var(--background)]"); + expect(behaviourDocSource).toContain("paints `var(--surface)`"); + }); + it("keeps the header out of sticky positioning wherever its row collapses", () => { // Sticky pins the bar inside the viewport and fights the 1fr -> 0fr grid. expect(headerSource).toMatch(/sticksAbovePhones \|\| collapsesAtEveryWidth\s*\?\s*"relative"/); From aa4a6cf70364832eddc5418d5786f31699629515 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 02:47:40 +0000 Subject: [PATCH 2/4] docs: record PR #1393 diff-review and bugbot triage Ledger append for claude/white-element-positioning-t607pk at db341491b0d94cf11641eb98aa8726629580a652 after local review and Bugbot triage (no hosted cursor[bot] findings; suite stuck queued). Co-authored-by: BigSimmo --- docs/branch-review-ledger.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 2740e31d48..0486fda88d 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -1305,3 +1305,6 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-29 | 1391 | ff4ddfabb8d8594da0c09e04dc37e9286745140b | PR #1391 merge | merged as 39f2bcea. Three review P2s fixed: both ui-smoke retries made idempotent (toPass re-runs after a late-landing click; the mode-menu one clicked a toggle and oscillated) plus a second guard so the <768px branch can recover at all, and #111 archived instead of left open-and-done. One Production UI red on ui-phone-scroll.spec.ts:574 was proven a flake before re-running: the delta from the passing head baecef05 was two ui-smoke guards and one docs row, neither reachable from that spec, and the PR touches no document-viewer phone-scroll surface. Re-run green | verify:cheap exit 0 (429 files / 4404 tests); design-token orphan guard proven red on a reintroduced class; PR required success with UI_RESULT success on re-run | | 2026-07-29 | 1391 | baecef05cac86c4d52af895d483a33ba3c40cd61 | PR #1391 review | reviewed clean — text-4xs retirement confirmed against globals.css (--text-3xs 0.625rem present, --text-4xs absent); orphan guard proven to fail on a reintroduced class; six Playwright retries all retry action-plus-effect so a genuine regression still fails. Resolved the outstanding-issues #108/#109 double-allocation (renumbered to #110/#111, marker to 112) and recorded #111 done | verify:cheap exit 0 (429 files / 4404 tests); design-token-contract 28 passed; check:branch-review-ledger passed | | 2026-07-29 | 1374 | c14edb9c6f0bdbbfb147752503e016f2543fd803 | PR #1374 review + merge | merged as 3704007c — DocumentViewer identity-bound state clear (P1) implemented and verified red without it; all 12 review threads resolved | verify:cheap exit 0 (429 files / 4403 tests); PR required success; Production UI success | +| 2026-07-30 | claude/white-element-positioning-t607pk | db341491b0d94cf11641eb98aa8726629580a652 | phone-chrome safe-area paint fix | APPROVED — no P0/P1. One P2 pre-existing residual (spacer/bar mismatch on notched tablet sm+ in PWA mode — worse before, slightly better after; no action needed). P3: contract test slice brittleness (indexOf '/>') and invariant-6 prose length. No defects introduced. | vitest header-scroll-hide-contract 27/27 green; source read: master-search-header.tsx, globals.css forced-colors block, tests/header-scroll-hide-contract.test.ts, docs/search-chrome-behaviour.md | +| 2026-07-30 | claude/white-element-positioning-t607pk | db341491b0d94cf11641eb98aa8726629580a652 | pr-diff-review | No P0/P1. Phone chrome-safe-area-top paint fix from --background to --surface is correct for collapse-strategy modes; overlay answer path unchanged (no spacer). Scroll-hide h-0 release untouched. Residual: sm+ translucent glass vs opaque spacer (pre-existing, improved); hosted Cursor Bugbot suite stuck queued with 0 runs. | vitest:header-scroll-hide-contract:27-pass; frontend-ui-reviewer; local-bug-hunt; gh-threads:0; no-provider-gates | +| 2026-07-30 | claude/white-element-positioning-t607pk | db341491b0d94cf11641eb98aa8726629580a652 | bugbot | pr-bugbot: no cursor[bot] Bugbot findings on PR #1393 head. Hosted Cursor check suite 82712209672 stuck queued (0 check-runs) since 2026-07-30T02:33:11Z; rerequest 403. Local Bugbot-equivalent: no P0/P1 confirmed. | gh-graphql-threads:empty; gh-review-comments:0; pr-bugbot-agent; rerequest:403; no-fixes | From 8f0c5bee05a3b2a2002e628e5f88006bc128d26f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 03:30:06 +0000 Subject: [PATCH 3/4] docs: record PR #1393 babysit closeout Hosted CI green on e7a27bbf (Production UI + PR required). Prior PR-required failures were Production UI cancelled by superseding main merges, not product defects. No Bugbot findings; no unresolved review threads. Local A/B confirmed Playwright env flakes unrelated to the spacer paint token. Co-authored-by: BigSimmo --- docs/branch-review-ledger.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 0486fda88d..551ff2313c 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -1308,3 +1308,4 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | claude/white-element-positioning-t607pk | db341491b0d94cf11641eb98aa8726629580a652 | phone-chrome safe-area paint fix | APPROVED — no P0/P1. One P2 pre-existing residual (spacer/bar mismatch on notched tablet sm+ in PWA mode — worse before, slightly better after; no action needed). P3: contract test slice brittleness (indexOf '/>') and invariant-6 prose length. No defects introduced. | vitest header-scroll-hide-contract 27/27 green; source read: master-search-header.tsx, globals.css forced-colors block, tests/header-scroll-hide-contract.test.ts, docs/search-chrome-behaviour.md | | 2026-07-30 | claude/white-element-positioning-t607pk | db341491b0d94cf11641eb98aa8726629580a652 | pr-diff-review | No P0/P1. Phone chrome-safe-area-top paint fix from --background to --surface is correct for collapse-strategy modes; overlay answer path unchanged (no spacer). Scroll-hide h-0 release untouched. Residual: sm+ translucent glass vs opaque spacer (pre-existing, improved); hosted Cursor Bugbot suite stuck queued with 0 runs. | vitest:header-scroll-hide-contract:27-pass; frontend-ui-reviewer; local-bug-hunt; gh-threads:0; no-provider-gates | | 2026-07-30 | claude/white-element-positioning-t607pk | db341491b0d94cf11641eb98aa8726629580a652 | bugbot | pr-bugbot: no cursor[bot] Bugbot findings on PR #1393 head. Hosted Cursor check suite 82712209672 stuck queued (0 check-runs) since 2026-07-30T02:33:11Z; rerequest 403. Local Bugbot-equivalent: no P0/P1 confirmed. | gh-graphql-threads:empty; gh-review-comments:0; pr-bugbot-agent; rerequest:403; no-fixes | +| 2026-07-30 | claude/white-element-positioning-t607pk | e7a27bbfb2fca907aa235c36f8966164e1ad9e27 | pr-babysit | No product fix needed. Prior PR-required failures were production-ui cancelled by repeated main merges superseding runs. Current head: merge-tree clean, 0 behind main, hosted CI success including Production UI + PR required. No unresolved review threads. Bugbot: no cursor[bot] findings; Cursor suite still queued. Local A/B proved 3 Playwright failures identical on --surface and --background (env flake). | verify:cheap:4451-pass; format:check:pass; phone-contracts:82-pass; hosted:PR-required:pass; hosted:Production-UI:pass; A/B-playwright:same-3-fail; bugbot:no-findings | From 2a1f2217cb23426a8b62c28ea0d70fabcbea3640 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 03:53:42 +0000 Subject: [PATCH 4/4] =?UTF-8?q?docs:=20record=20PR=20#1393=20babysit=20?= =?UTF-8?q?=E2=80=94=20CI=20churn=20blocker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Product change is sound (hosted green at e7a27bbf). Remaining merge blocker is repeated main merges cancelling Production UI before PR required can pass. No product code change in this commit. Co-authored-by: BigSimmo --- docs/branch-review-ledger.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index c7e54571ff..a0ef51e01d 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -1316,3 +1316,4 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | PR #1394 / `claude/top-search-design-mockups-w53znc` | `0d47141fc030684299dcb265e3d853c93b9e2a91` | CI/review closeout — merged | MERGED as squash `0d47141f`. Prior tip `4a001efa` had required CI green after prettier fix `61314887` (Static PR/CircleCI red on `#096` padding) and main sync. Layout/`/tools` false-positive fixed; `#115` deferred; review threads resolved. Post-merge ledger-only follow-up. | hosted Static/Unit/PR-required/CircleCI pass on pre-merge tip; vitest adoption 6/6; typecheck; Bugbot no open P0/P1; merge-tree clean | | 2026-07-30 | cursor/pr-1394-ledger-closeout-c2bf | f734dc4d4c8b19d5fec43bbd388c2a421e47668a | PR #1399 babysit / CI+Bugbot closeout | MERGE-READY. No failing CI, no unresolved review threads, merge-tree clean vs origin/main, Bugbot no bugs. Docs-only ledger append for merged #1394; no code fix required. | hosted PR required SUCCESS; Static PR SUCCESS (lint/typecheck/format/ledger); CircleCI verify SUCCESS; local check:branch-review-ledger PASS; prettier PASS; lint PASS; Bugbot pr-bugbot no findings | | 2026-07-30 | claude/test-coverage-analysis-2vcd8a | d5842e62238237ff5c47da0b32ef8d9f12819714 | PR #1398 babysit | COMPLETE for tip: cleared main conflict; fixed Codex P2 (reject refs/*→origin/* nesting); prior Codex P2 (destination check) already fixed in de594186 and resolved; 0 unresolved threads; merge-tree clean. Hosted CI re-running. | repo-hygiene 40/40; verify:cheap earlier PASS on pre-tip; format:changed PASS; Bugbot none; Codex P2 resolved | +| 2026-07-30 | claude/white-element-positioning-t607pk | b82ff088436cd936d219a4eb54a54d09a88fbd7c | pr-babysit | Product tip sound; no code fix. Hosted CI fully green once at e7a27bbf (Production UI+PR required). Recurring blocker: repeated Merge main into PR cancels Production UI mid-run so PR required fails with production-ui=cancelled. merge-tree clean / MERGEABLE when left alone. No review threads. Bugbot: no cursor[bot] findings; suite stays queued. Local A/B: 3 Playwright fails identical on --surface/--background. | verify:cheap:pass; hosted:e7a27bbf:PR-required+Production-UI:pass; A/B-playwright:env-flake; bugbot:no-findings; churn:main-merges-cancel-ui |