Skip to content

fix(ui): restore phone Safari and PWA edge chrome#1270

Merged
BigSimmo merged 11 commits into
mainfrom
codex/fix-phone-bottom-edge-20260727
Jul 27, 2026
Merged

fix(ui): restore phone Safari and PWA edge chrome#1270
BigSimmo merged 11 commits into
mainfrom
codex/fix-phone-bottom-edge-20260727

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • make document scrolling the browser-phone owner so iOS Safari can minimize its browser chrome and paint the header/footer to the viewport edges
  • keep installed standalone PWA scrolling bounded while portaling page-owned phone footers outside the inner scroller
  • synchronize header/footer hide/reveal, safe-area reserves, anchoring suppression, and focus behavior to eliminate white bands and scroll jumps across all modes
  • add static and production Chromium guards for shared, calculator, document, and differential phone footer ownership

Root cause

Browser Safari and installed standalone mode require different scroll ownership. Browser pages were trapped in a fixed inner scroller, preventing Safari toolbar collapse, while page-owned PWA footers were rendered inside that same inner scroller. Hidden chrome also retained paint/reserve paths that could leave an opaque band. The shared frame/portal contract now assigns each surface one scroll and footer owner.

Verification

  • npm run verify:cheap - all 25 gates; 393 files; 3,532 tests passed, 2 skipped
  • focused scroll contracts - 32/32
  • exact affected production Chromium journeys - 4/4, repeated twice
  • hosted /forms hydration failure reproduced and fixed - exact production journey 10/10
  • hosted required CI - PR required SUCCESS and Production UI 323/323
  • exact staging runtime source - deployment 8c84b87e-6345-490b-b20b-89d9c844ea4e SUCCESS; readiness and health HTTP 200
  • physical iPhone Home Screen PWA - accepted edge-to-edge hide/reveal behavior
  • physical Safari screenshot - app content reaches the web viewport edges; the remaining top status row and bottom Private address pill are native Safari controls outside the page viewport
  • npm run check:branch-review-ledger
  • git diff --check

npm run verify:pr-local previously passed runtime, formatting, lint, typecheck, the full unit suite, offline RAG fixtures, and its standalone production build; one aggregate wrapper invocation exited silently during Next's post-compile TypeScript phase. The identical build passed independently, and exact-head hosted Build plus Production UI are green.

Physical acceptance

The installed PWA now passes the requested edge-to-edge header/footer behavior with seamless hide/reveal and no retained app band. In normal Safari, the page also owns the full web viewport; iOS still renders its status row and floating Private address control outside that viewport. CSS cannot remove or paint through those system-owned controls, so they are recorded as the platform boundary rather than an unresolved app defect.

Risk and rollback

Risk is limited to phone chrome/scroll ownership and iOS safe-area compositing. Tablet and desktop retain inline ownership. Roll back by reverting the squash merge if physical or production smoke checks regress.

Merging this PR to main automatically deploys the Railway production app.

RAG impact: no retrieval behaviour change — UI-only phone chrome and scroll ownership changes.

Summary by CodeRabbit

  • Bug Fixes

    • Improved phone layouts across browser and standalone modes, including scrolling, header behavior, and bottom action areas.
    • Stabilized mobile search, composer, calculator, document, and comparison controls while scrolling.
    • Improved focused-control visibility and bottom clearance on phones.
    • Corrected desktop and mobile scroll ownership and hide/reveal behavior.
  • Documentation

    • Clarified phone scrolling, footer placement, and header behavior contracts.
  • Tests

    • Expanded automated coverage for phone and desktop scrolling, footer anchoring, focus clearance, and responsive layout behavior.

@supabase

supabase Bot commented Jul 27, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@BigSimmo, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 55 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8113c684-0f10-47cb-9771-66ce09e1b4aa

📥 Commits

Reviewing files that changed from the base of the PR and between 15358f2 and 4e8a378.

📒 Files selected for processing (5)
  • docs/branch-review-ledger.md
  • src/components/ClinicalDashboard.tsx
  • tests/ui-chrome-scroll.spec.ts
  • tests/ui-smoke.spec.ts
  • tests/ui-tools.spec.ts
📝 Walkthrough

Walkthrough

Phone browser and standalone layouts now use different scroll owners, shared scroll utilities, and frame/portal-based phone footer layers. Chrome hide/reveal wiring, responsive shell CSS, focus clearance, and extensive contract and Playwright coverage were updated.

Changes

Phone scroll and chrome behavior

Layer / File(s) Summary
Scroll ownership and hide/reveal contracts
docs/search-chrome-behaviour.md, src/components/clinical-dashboard/scroll-surface.ts, src/components/clinical-dashboard/use-hide-on-scroll.ts, src/components/clinical-dashboard/use-document-viewer-chrome-scroll.ts
Scroll utilities and hide/reveal hooks distinguish document and inner scroll owners, measure collapse roots, blur phone inputs during document scrolling, and extend transition settling.
Shell scroll wiring and footer hosts
src/components/ClinicalDashboard.tsx, src/components/clinical-dashboard/global-search-shell.tsx, src/components/clinical-dashboard/phone-footer-layer-portal.tsx, src/components/clinical-dashboard/master-search-header.tsx
Dashboard and shell scrolling now use shared ownership-aware behavior, while phone chrome is hosted in a frame and footer content can render through a portal.
Phone footer consumers and responsive layout
src/components/DocumentViewer.tsx, src/components/calculators/search-page.tsx, src/components/differentials/*, src/app/globals.css, src/components/therapy-compass/therapy-compass.css, src/components/ui-primitives.tsx
Phone composers and differential actions use the footer portal, and browser versus standalone positioning, overflow, sizing, and focus-clearance rules are updated.
Scroll geometry and layout regression coverage
tests/*, docs/branch-review-ledger.md
Tests now detect the active scroll owner and validate footer anchoring, CSS contracts, focus clearance, chrome transitions, and scroll-end behavior across phone and desktop scenarios; the review ledger records the related approvals.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested labels: codex

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main phone Safari/PWA edge-chrome fix.
Description check ✅ Passed The description covers summary, verification, risk, and rollback details, with only optional template sections omitted.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-phone-bottom-edge-20260727

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@BigSimmo BigSimmo added the skip-branch-sync Opt out of hosted pr-branch-sync / update-branch on this PR label Jul 27, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
tests/dashboard-scroll-padding.test.ts (1)

44-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

These regexes can match across rule boundaries.

\.phone-scroll-surface\s*\{[\s\S]*?overflow-y:\s*visible; is unbounded by the closing brace, so a overflow-y: visible declared in any later rule satisfies it — the guard would keep passing after the contract is broken. tests/ui-overlay-css-contract.test.ts already solves this with brace-depth block extraction (cssBlock); extracting the block first (or restricting the gap with [^}]*?) makes this assertion actually load-bearing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/dashboard-scroll-padding.test.ts` around lines 44 - 47, The regex
assertions in the dashboard scroll-padding test are not scoped to the
`.phone-scroll-surface` rule and can match declarations in later rules. Update
the assertions near `globalStyles` to extract or constrain the rule block,
reusing the existing `cssBlock` approach from `ui-overlay-css-contract.test.ts`
or limiting matches to characters before `}`, while preserving the desktop
`visible` and standalone mobile `auto` expectations.
src/components/clinical-dashboard/phone-footer-layer-portal.tsx (1)

38-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the exported phone breakpoint constant before reusing it.

use-hide-on-scroll.ts has the matching 639px query, but it is currently private. Export phoneMediaQuery and import it here so the footer portal is gated the same way the scroll-hide paths use the shared phone seam.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/clinical-dashboard/phone-footer-layer-portal.tsx` around lines
38 - 45, Export the existing phone breakpoint constant phoneMediaQuery from
use-hide-on-scroll.ts, then import and use it in the phone-footer portal’s
useLayoutEffect instead of the duplicated "(max-width: 639px)" query. Preserve
the existing matchMedia synchronization and cleanup behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ClinicalDashboard.tsx`:
- Around line 372-375: Move the reportChromeScrollHideRef.current assignment out
of the render body and into a useEffect keyed by chromeScrollHide.reportScroll,
matching the latest-report ref pattern used by the sibling implementation. Keep
useDocumentScrollHideReporter unchanged.

In `@tests/ui-chrome-scroll.spec.ts`:
- Around line 176-189: Update the test around “desktop document scrolling does
not blur the focused page search” so it verifies the actual scroll owner using
readPrimaryScrollGeometry(page).owner before and after scrolling, or move the
assertion into the phone-sized document-scroll coverage where the phone-gated
focus behavior applies. Ensure the test no longer labels bounded `#main-content`
scrolling as document scrolling.

In `@tests/ui-smoke.spec.ts`:
- Around line 2004-2022: Update the geometry assertions around
readPrimaryScrollGeometry and the paired page.evaluate calls so both scroll and
DOM measurements are captured in one sequential snapshot rather than
Promise.all. Apply the same change to the corresponding blocks near the other
referenced assertions, preserving the existing geometry values and expectations
while eliminating split DOM moments.

---

Nitpick comments:
In `@src/components/clinical-dashboard/phone-footer-layer-portal.tsx`:
- Around line 38-45: Export the existing phone breakpoint constant
phoneMediaQuery from use-hide-on-scroll.ts, then import and use it in the
phone-footer portal’s useLayoutEffect instead of the duplicated "(max-width:
639px)" query. Preserve the existing matchMedia synchronization and cleanup
behavior.

In `@tests/dashboard-scroll-padding.test.ts`:
- Around line 44-47: The regex assertions in the dashboard scroll-padding test
are not scoped to the `.phone-scroll-surface` rule and can match declarations in
later rules. Update the assertions near `globalStyles` to extract or constrain
the rule block, reusing the existing `cssBlock` approach from
`ui-overlay-css-contract.test.ts` or limiting matches to characters before `}`,
while preserving the desktop `visible` and standalone mobile `auto`
expectations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4c66ae16-b07c-4e8b-80f7-44e05799b907

📥 Commits

Reviewing files that changed from the base of the PR and between a3420d0 and 13410da.

📒 Files selected for processing (27)
  • docs/branch-review-ledger.md
  • docs/search-chrome-behaviour.md
  • src/app/globals.css
  • src/components/ClinicalDashboard.tsx
  • src/components/DocumentViewer.tsx
  • src/components/calculators/search-page.tsx
  • src/components/clinical-dashboard/global-search-shell.tsx
  • src/components/clinical-dashboard/master-search-header.tsx
  • src/components/clinical-dashboard/phone-footer-layer-portal.tsx
  • src/components/clinical-dashboard/scroll-surface.ts
  • src/components/clinical-dashboard/use-document-viewer-chrome-scroll.ts
  • src/components/clinical-dashboard/use-hide-on-scroll.ts
  • src/components/differentials/differential-presentation-workflow-page.tsx
  • src/components/therapy-compass/therapy-compass.css
  • src/components/ui-primitives.tsx
  • tests/clinical-dashboard-merge-artifacts.test.ts
  • tests/dashboard-scroll-padding.test.ts
  • tests/header-scroll-hide-contract.test.ts
  • tests/playwright-scroll.ts
  • tests/ui-chrome-scroll.spec.ts
  • tests/ui-formulation.spec.ts
  • tests/ui-overlay-css-contract.test.ts
  • tests/ui-phone-scroll.spec.ts
  • tests/ui-smoke.spec.ts
  • tests/ui-stress.spec.ts
  • tests/ui-therapy-nav-scroll.spec.ts
  • tests/ui-tools.spec.ts

Comment thread src/components/ClinicalDashboard.tsx
Comment thread tests/ui-chrome-scroll.spec.ts Outdated
Comment thread tests/ui-smoke.spec.ts Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@github-actions

Copy link
Copy Markdown
Contributor

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Production UIneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #5913 (success).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

@BigSimmo BigSimmo removed the skip-branch-sync Opt out of hosted pr-branch-sync / update-branch on this PR label Jul 27, 2026
@BigSimmo
BigSimmo merged commit b6513f1 into main Jul 27, 2026
18 checks passed
@BigSimmo
BigSimmo deleted the codex/fix-phone-bottom-edge-20260727 branch July 27, 2026 04:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant