Skip to content

fix(search): stop the results bar clipping its own controls on phones - #1672

Merged
BigSimmo merged 6 commits into
mainfrom
claude/search-bar-mobile-regression-ober7w
Aug 7, 2026
Merged

fix(search): stop the results bar clipping its own controls on phones#1672
BigSimmo merged 6 commits into
mainfrom
claude/search-bar-mobile-regression-ober7w

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • The results bar clipped its own controls on phones. The one-line band (Results bar: one line, one filter, nothing unreachable #1615) left the inline utilities group shrink, so an over-subscribed line paid the shortfall out of the controls rather than out of the truncating query. The sort group was severed mid-glyph by the utility track's overflow-x-auto, and its trailing option was then washed out by the 28px overflow mask — which reads as a rendering fault, not as "swipe for more". Measured on the live app before the fix: clipped at 320/375/390/393/402 and 430/440px, and by 41.9px at 540px with a four-word query, so this was never bounded by phone width. The query truncated a 7-character word ("Lithiu…") alongside it.
  • Inline utilities are now shrink-0. The band's own contract is that the query is what gives way when the line runs out; truncate + min-w-[2rem] on the query heading already exist to absorb exactly this.
  • Below 414px the utilities take their own full-width row. One line provably cannot hold count + query + sort + filter there even with the query fully truncated, and the band is overflow-hidden, so overflowing would clip the pinned Filter instead.
  • Sort options drop to px-2.5 below sm, returning the 8px that clears the one-line widths. Tap height is untouched — min-h-tap is the floor that matters.
  • The Filter wordmark now hides only across 414–429px, the one genuinely single-line-and-short band, instead of everywhere below 430px. On the wrapped row below 414px, hiding it spent nothing and bought nothing.
  • The Filter trigger no longer reads as a different component from the sort group it sits flush against. It composed floatingControl plus an override string, and cn is a plain join, not tailwind-merge — so font-semibold (600 against the sort group's 470/560) and --border-lux (a visibly darker stroke than --border) both reached the DOM and stylesheet order, not intent, picked the winner. It now uses the band's own control recipe (the same one Save search and Retry use), with active and resting colours as mutually exclusive branches.
  • Docs corrected. docs/search-results-bar-decisions.md claimed the library button was "the sole reason the phone rail could overflow at all". That was measured wrong — with Library gone the rail still overflowed at every common phone width. The claim is amended in the doc and in the ui-smoke comment that repeated it.

Verification

  • npm run lint — exit 0, no findings
  • npm run typecheck — exit 0, no findings
  • npx prettier --check .All matched files use Prettier code style!
  • tests/search-results-header-band.dom.test.tsx + tests/document-search-scope-zero-results.dom.test.tsxTest Files 2 passed (2) / Tests 52 passed (52)
  • Phone-chrome contract set (the gate's contracts stage, 9 files) — Test Files 9 passed (9) / Tests 118 passed (118)
  • ui-smoke + ui-tools on Chromium against a production build — 185 passed, 1 failed
  • npm run verify:pr-local

UI verification not run in full: npm run verify:phone-chrome stops at its own lock-parity precondition in this container — playwright: installed 1.62.0 does not match locked 1.62.1 — which is pre-existing environment drift, not a property of this diff. Its remaining stages were run directly instead: the contract set above, and the changed-browser Playwright stage via PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH (the container ships Chromium 1194, not the pinned build).

The one ui-smoke failure is the known pre-existing PDF-canvas test (document viewer puts the PDF preview first with pinned evidence after it on mobile). Confirmed pre-existing by stashing this branch's changes and re-running it on the clean baseline: it fails identically, same test and same toBeVisible assertion. The same failure is recorded against PR #1555 in the branch review ledger with the same Chromium-build cause.

The new gate was proven to fail, not just to pass. ui-smoke now sweeps the utility rail across 320/375/390/402/414/430/440/540px and asserts fit as geometry. With shrink reinstated it fails at 414px with sortClipped: 16, masked: true; with the fix it passes. A single-width assertion at the test's existing 390px viewport passes against the broken code — at 390 the band wraps and the rail has width to spare — which is why the sweep has to cross 414px. expectNoPageHorizontalOverflow cannot see an internal scroller, which is how the original defect shipped green.

Risk and rollout

  • Risk: Low, and presentation-only. The change is layout and colour-token parity on a shared band rendered by twelve modes, so the blast radius is wide even though each change is small. The two behavioural levers are shrink-0 (which redirects flex shortfall to the query heading that already truncates) and the max-[413px] wrap (which restores the pre-Results bar: one line, one filter, nothing unreachable #1615 two-row geometry below 414px). No data, retrieval, auth, or API path is touched. The eleven modes that use mobileControlsPlacement="row" are untouched — both new rules are inside the inline branch, which only documents and therapy-compass opt into.
  • Rollback: git revert the single commit. No migration, no config, no stored state.
  • Provider or production effects: None.

Notes

  • RAG impact: no retrieval behaviour change — the diff is phone layout and control styling in the results band and its filter trigger. classifyPullRequestFiles returns clinicalRisk: false, operationalRisk: false, ragRanking: false, ui: true, so neither the Clinical Governance Preflight nor a mandatory RAG impact: line applies; the line is stated here for the record rather than because the gate requires it.
  • Follow-up worth tracking separately: the 28px overflow mask fades a fixed width regardless of how much is actually hidden, so a 2px overflow still washes out most of a control. This diff removes the overflow in the inline modes rather than changing the mask, which is still correct for genuine multi-control overflow.

Generated by Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved mobile search-results layouts to prevent clipping and horizontal overflow.
    • Preserved visibility of filter and sort controls across phone screen sizes.
    • Ensured search queries truncate appropriately while utility controls retain their usable size.
    • Improved responsive wrapping for utility controls on narrower screens.
  • Tests

    • Added regression coverage for responsive control layout and overflow behavior across multiple phone widths.

The one-line results band (#1615) left the inline utilities group `shrink`, so
an over-subscribed line paid the shortfall out of the *controls* instead of the
truncating query. The sort group was severed mid-glyph by the utility track's
`overflow-x-auto` and its trailing option was then washed out by the 28px
overflow mask, which reads as a rendering fault rather than as "swipe for more".

Measured on the live app before the fix: clipped at 320/375/390/393/402 and
430/440px, and by 41.9px at 540px with a four-word query — so this was never
bounded by phone width, and the query truncated a 7-character word alongside it.

- Inline utilities are `shrink-0`. The band's own contract is that the query is
  what gives way when the line runs out; `truncate` + `min-w-[2rem]` on the
  heading already exist to absorb exactly this.
- Below 414px one line cannot hold count + query + sort + filter even with the
  query fully truncated, so the utilities take their own full-width row rather
  than overflow a band that is `overflow-hidden` and would clip the pinned
  Filter.
- Sort options drop to `px-2.5` below `sm`, returning the 8px that clears the
  one-line widths. Tap height is untouched.
- The Filter wordmark now hides only across 414–429px, the one genuinely
  single-line-and-short band, instead of everywhere below 430px.

Also fixes the Filter trigger reading as a different component from the sort
group it sits flush against. It composed `floatingControl` plus an override
string, and `cn` is a plain join, not tailwind-merge — so `font-semibold` (600
against the sort group's 470/560) and `--border-lux` (a visibly darker stroke
than `--border`) both reached the DOM and stylesheet order picked the winner. It
now uses the band's own control recipe, with the active and resting colours as
mutually exclusive branches.

Gates: `ui-smoke` sweeps the rail across 320–540px as geometry, not as a class —
verified to fail (`sortClipped: 16, masked: true` at 414px) with `shrink`
reinstated, and to pass with the fix. A single-width check at the existing 390px
viewport passes against the broken code, which is why the sweep crosses 414px.
`expectNoPageHorizontalOverflow` cannot see an internal scroller, which is how
this shipped green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015BkKbgdhhAg8REq2wudR8V
@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, add credits to your account and enable them for code reviews in your settings.

@supabase

supabase Bot commented Aug 7, 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 Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 30 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

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

Run ID: 71e21e18-865c-4877-8a7a-cb52adf31d35

📥 Commits

Reviewing files that changed from the base of the PR and between 9e431dd and f7ee8a2.

📒 Files selected for processing (1)
  • docs/branch-review-ledger.md
📝 Walkthrough

Walkthrough

The document search header now prevents utility shrinking, wraps utilities below 414px, adjusts sort spacing, and applies explicit active or inactive filter styling. DOM and UI smoke tests cover responsive layout and overflow across phone widths.

Changes

Search-results responsive layout

Layer / File(s) Summary
Header layout and overflow validation
src/components/clinical-dashboard/search-results-header-band.tsx, tests/search-results-header-band.dom.test.tsx, tests/ui-smoke.spec.ts, docs/search-results-bar-decisions.md, docs/branch-review-ledger.md
Inline utilities no longer shrink. They move to a full-width row below 414px. Sort spacing is narrower on phones. Regression tests validate wrapping, clipping, overflow, and utility visibility from 320px to 540px.
Filter control styling
src/components/clinical-dashboard/document-search-results.tsx, docs/search-results-bar-decisions.md
The filter trigger uses explicit search-band classes with separate active and inactive styles. Its label is hidden only from 414px through 429px.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: codex

Suggested reviewers: claude, cursoragent

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary fix for mobile clipping in the search results bar.
Description check ✅ Passed The description covers the change, verification results, known limitations, risk, rollback, and production impact with clear evidence.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/search-bar-mobile-regression-ober7w

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

Copilot AI 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.

Pull request overview

Fixes a mobile layout regression in SearchResultsHeaderBand where the horizontally scrollable utility rail could clip/fade its own controls (notably the Sort group) instead of forcing the query to truncate, and aligns the document Filter trigger styling with the band’s established control recipe. The change is concentrated in the shared results header UI used across modes, with added DOM + Playwright coverage and supporting docs.

Changes:

  • Make inline utilities refuse to shrink (shrink-0) and wrap utilities to a dedicated row below 414px to prevent control clipping on phones.
  • Tighten Sort option horizontal padding below sm, and rework the document Filter trigger to avoid conflicting utility overrides (since cn does not merge Tailwind classes).
  • Add/extend tests (DOM + ui-smoke) to assert the “no clipped controls” geometry across multiple phone widths; update docs and ledger entry.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/ui-smoke.spec.ts Adds a multi-viewport geometry sweep ensuring the utility rail does not overflow/clip/mask its own controls.
tests/search-results-header-band.dom.test.tsx Pins the key class-level contracts for inline utilities (shrink-0 + <414px wrap) in jsdom.
src/components/clinical-dashboard/search-results-header-band.tsx Implements the layout fixes: inline utility group shrink-0, wrap behavior below 414px, and reduced Sort padding below sm.
src/components/clinical-dashboard/document-search-results.tsx Rebuilds the Filter trigger classes to match band control styling without relying on conflicting overrides; adjusts label hiding to a narrower width range.
docs/search-results-bar-decisions.md Updates the documented rationale/constraints to match the measured overflow behavior and new layout contract.
docs/branch-review-ledger.md Appends the review/verification record for this change set.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Behind-but-clean (merge-tree clean). Clears GitHub DIRTY/mergeability
blocker after required CI settled on the pre-sync tip.
The shrink-0 / max-[413px] child checks were green even if the parent lost
max-[413px]:flex-wrap, and the ui-smoke rail-fit sweep could not see wrap
failure when overflow-hidden clipped the utilities off-screen. Assert the
parent wrap class in DOM, and require the utilities group to stay in the
viewport below 414px.

@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: 1

🤖 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/clinical-dashboard/search-results-header-band.tsx`:
- Around line 294-302: Define semantic --breakpoint-* and --spacing-* `@theme`
tokens in src/app/globals.css for the search-band thresholds and padding, then
replace the raw utilities in search-results-header-band.tsx (294-302 and
435-454) and document-search-results.tsx (713-749) with the named utilities.
Update the related comments and DOM assertions in
tests/search-results-header-band.dom.test.tsx (273-307) to use those names,
preserving the 413px wrapping boundary and 414–429px label range.
🪄 Autofix

❌ Autofix failed (check again to retry)

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

Run ID: 7bf31595-83d3-4746-bd4f-9a17d666212d

📥 Commits

Reviewing files that changed from the base of the PR and between dfcbe20 and 9e431dd.

📒 Files selected for processing (6)
  • docs/branch-review-ledger.md
  • docs/search-results-bar-decisions.md
  • src/components/clinical-dashboard/document-search-results.tsx
  • src/components/clinical-dashboard/search-results-header-band.tsx
  • tests/search-results-header-band.dom.test.tsx
  • tests/ui-smoke.spec.ts

Comment thread src/components/clinical-dashboard/search-results-header-band.tsx
@BigSimmo

BigSimmo commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

Cursor review-and-fix summary — PR #1672

Tip: ab4ff6770c267ecd380534ebdb7d7ee1075168bc on claude/search-bar-mobile-regression-ober7w
Base: origin/main · ahead/behind: 6 / 0 · mergeable: MERGEABLE · merge-tree: clean
Auto-merge: not armed

Sync

  1. First tip 7ba35011 was GitHub DIRTY/CONFLICTING but git merge-tree was clean (behind-but-clean, 5 behind). Waited for required CI green on product tip 5fa1bedd (PR required + Production UI), then merged origin/main once → pushed with P2 test fixes as 9e431dd8.
  2. Tip then advanced by an operator merge of origin/main (#1674 Factsheets mode nav) to ab4ff677. Re-confirmed merge-tree clean / MERGEABLE. No further product conflict in the search-band files.

Review findings

  • P0/P1: none in the PR delta
  • P2 fixed (9e431dd8): DOM + ui-smoke could miss wrap failure if parent lost max-[413px]:flex-wrap while child basis-full stayed — track overflow metrics report zero when utilities are clipped off-screen. Assert parent wrap class; require utilities bounding box in-viewport below 414px.
  • CodeRabbit (resolved): suggested @theme tokens for the 413/414–429 thresholds and pr-[0.6875rem]. Dispositioned no change — measured layout thresholds / intentional asymmetric Filter padding, not shared DS breakpoints; repo already uses many arbitrary width utilities for the same pattern.
  • Copilot / Bugbot: Copilot completed with 0 findings. Codex usage-capped. No Cursor Bugbot inline findings.

Disposition table

Item Result
Main sync (behind-but-clean) Fixed / pushed (bcddde55, later operator merge ab4ff677)
P2 parent-wrap + on-screen utilities guards Fixed / pushed (9e431dd8)
CodeRabbit tokenisation suggestion Dispositioned / thread resolved
Actionable threads 0 unresolved

Required CI (this tip ab4ff677)

  • PR mergeability: PASS · PR policy: PASS
  • Full CI / Production UI: in progress on the post-operator-merge tip (prior tip 9e431dd8 had Build/Static/Unit/Safety/Production UI critical green; shards 1–3 were still running when tip moved)
  • Advisory ignored

Local gates (decisive lines)

  • Test Files 519 passed (519) / Tests 5494 passed | 1 skipped (5495) (verify:cheap on 9e431dd8)
  • All matched files use Prettier code style!
  • Offline RAG fixture and manifest validation passed (36 golden cases, 23 suites). (verify:pr-local)
  • Phone-chrome contracts: Test Files 9 passed (9) / Tests 118 passed (118)
  • Band DOM on current tip: Test Files 2 passed (2) / Tests 52 passed (52)
  • Not run locally: full Chromium verify:ui / phone-chrome browser stages (hosted Production UI covers). No provider/release gates.

Residual risk

  • Filter wordmark band (414–429px) and wrap threshold are intentional measured contracts.
  • 28px overflow mask still fades a fixed width on genuine multi-control overflow elsewhere (called out in PR notes; out of scope).
  • Review ledger row for ab4ff677 is local only (unpushed) to avoid a ledger-only tip.

Merge left to you.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Autofix skipped. No unresolved CodeRabbit review comments with fix instructions found.

@BigSimmo
BigSimmo enabled auto-merge (squash) August 7, 2026 10:58
@BigSimmo

BigSimmo commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

Unblock summary — PR #1672

Tip: f7ee8a295541285e72fe995f31febc1f257b45f7 on claude/search-bar-mobile-regression-ober7w
Base: origin/main @ 46002681 · ahead/behind: 6 / 0 · mergeable: MERGEABLE · merge-tree: clean
Auto-merge: armed (squash) · unresolved review threads: 0

Sync / merge-tree

  • Operator already synced main twice onto this branch (ab4ff677, then f7ee8a29 for #1675).
  • Re-confirmed git merge-tree --write-tree origin/main <tip> is clean; no further sync needed.
  • No product push from this pass (auto-merge armed + required CI in flight).

What blocked / what was done

Item Result
Merge-tree / behind-main Clean / current — left alone
CodeRabbit @theme breakpoint tokenisation Already dispositioned no-change + resolved (DS SPEC §4.13: no breakpoint tokens; measured 413/414–429 layout contracts stay literal)
Other review threads None open
Superseded CI on 9e431dd8 holding concurrency Cancelled so the current-tip CI could start
Product / CI code fixes None required on this tip

Required CI (this tip)

  • Green: Change scope, Safety and config, PR policy, PR mergeability, Gitleaks, Semgrep (+ ingestion gate)
  • In progress: Static PR checks, Build, Unit coverage, Production UI critical — CI run 31172197409
  • Advisory jobs ignored

Residual risks

  • Filter wordmark band (414–429px) and wrap threshold remain intentional measured contracts.
  • Ledger row for this tip is local only (not pushed) to avoid a ledger-only tip under armed auto-merge.

Merge left to you / auto-merge.

@BigSimmo
BigSimmo merged commit cd8f011 into main Aug 7, 2026
25 of 26 checks passed
@BigSimmo
BigSimmo deleted the claude/search-bar-mobile-regression-ober7w branch August 7, 2026 11:10
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.

4 participants