feat(search): rebuild the results band as a single-line spine - #1280
Conversation
The shared results band spent its space on labels rather than answers, and
below `sm` one of its two controls was cut mid-word ("Current search" ->
"Current searcl").
Root cause of the clipping and of the controls out-shouting the query: the
unlayered iOS anti-zoom rule in globals.css pins every input/select/textarea
to 16px below 640px so Safari does not zoom on focus. It deliberately beats
Tailwind's text-* utilities, so `text-xs` never applied to those selects --
16px extra-bold values rendered in boxes sized for 12px text. That rule is
correct and stays; hierarchy is restored around it instead.
- Drop the QUERY / RESULTS FOR eyebrow; query, divider and count share one
row. Phone height ~148px -> 120px, desktop min-height 4.5rem -> 3.75rem.
- Count becomes neutral text with a tabular-nums figure instead of a success
pill, so green keeps meaning a state that was achieved. The role="status"
live announcement is unchanged.
- Sort becomes a segmented aria-pressed group rather than a two-option
select, removing a menu you had to open to learn nothing.
- Active scopes render as accent chips at the head of the utility group, with
a desktop-only spacer keeping them near the query while controls stay at
the trailing edge.
- The utility group is a swipe rail below `lg` instead of a second tinted
band; children keep natural width and the right-edge fade applies only
while it actually overflows, measured by a ResizeObserver.
- Query steps to 18px and select values to semibold with `truncate`, so the
16px-floored controls read quieter and ellipse instead of clipping.
Records the band's rules, including the 16px floor, in
docs/search-chrome-behaviour.md so the next change does not fight it with
!important.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Warning Review limit reached
Next review available in: 58 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
CI triageCI failed on this PR. Automated classification of the 2 failed job(s):
Compared with main CI run #5955 (success). Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger. |
Two production UI specs still drove result sort as a native select, which broke when the control became a segmented aria-pressed group: - ui-smoke "document search mode lists matching documents and scope actions" called selectOption on the group element. - ui-tools "result sorting persists in the URL and restores through browser history" located `select[aria-label="Sort results"]` and read the persisted order via toHaveValue after goBack/goForward. Both now click the labelled option button and assert aria-pressed, which is where a segmented control carries its state. The URL and result-order assertions are unchanged, so the specs still prove sort persists through history rather than only that the control moved. These two call sites were missed because they reference the control by its accessible name rather than by component or test id. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
…ign-mockups-w53znc
An accent-soft chip that swaps to the neutral --border-strong on hover reads as losing its active state. Deepen the chip's own accent instead, matching how the other active-state surfaces in the band behave. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
…ign-mockups-w53znc
Production UI on
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
@cursoragent resolve failing CI testing |
|
CI on #1280 is resolved. Cause: Production UI failed on Fix: Proof:
A docs-only ledger closeout ( |
Production UI failed when getByLabel("Loading answer") matched both the
live skeleton and a hidden Suspense S: clone (search-chrome invariant 17).
Use the same :visible locator pattern as the rest of ui-smoke.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Observe rail childList mutations so scope/control changes remeasure overflow, and sync the branch with origin/main.
|
Follow-up on tip |
…rden Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* docs(ledger): record open-PR review and Bugbot sweep Append review outcomes for the current open PR queue after #1277 merged, including merge-tree classification and pr-bugbot findings. * docs(ledger): record open-PR recommendation implementation Capture closeouts for the unsafe audit cluster and the follow-up fixes pushed to #1273, #1275, #1280, and #1281. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…ign-mockups-w53znc
…ign-mockups-w53znc
…ign-mockups-w53znc


Summary
SearchResultsHeaderBandaround a single-line spine: theQUERY/RESULTS FOReyebrow is dropped and query, divider and count share one row. Phone height goes ~148px → 120px; desktop min-height 4.5rem → 3.75rem.tabular-numsfigure, so success colour keeps meaning a state that was actually achieved. Therole="status"/aria-liveannouncement is unchanged.aria-pressedgroup instead of a two-option<select>— a menu you had to open to learn nothing.lgrather than a second tinted band. Children keep natural width; the right-edge fade applies only while it actually overflows, measured by aResizeObserver.docs/search-chrome-behaviour.md.Root cause worth calling out. The reported clipping (
Current search→Current searcl) and the controls out-shouting the query came from the same place: the intentionally unlayered rule inglobals.cssthat pins everyinput/select/textareato 16px below 640px so iOS Safari does not zoom on focus. It deliberately beats Tailwind'stext-*utilities, sotext-xsnever applied to those selects — 16px extra-bold values rendered inside boxes sized for 12px text. That rule is correct and is left alone. Hierarchy is restored around it: the query steps to 18px, select values step down tofont-semibold, andtruncategives them a real ellipsis. Size is not available on those controls, so weight and colour carry the hierarchy. The new doc section states this so the next change does not fight it with!important.Verified by hand in the running app at
/services?q=CMHT&run=1— the exact scenario from the reported screenshots — at 1440px and 390px.Verification
npm run verify:pr-localVerification not run: verify:cheap and verify:ui were used as the gates for this change; verify:pr-local should run before this leaves draft.npm run verify:cheap— green (392 test files, 3537 tests passed, 1 skipped; plus lint, typecheck, runtime, Actions-pin, CI-scope and sitemap checks)npm run verify:uiwhen UI, routing, styling, browser behavior, reduced-motion, or forced-colors behavior changedRun with PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/opt/pw-browsers/chromium (the escape hatch playwright.config.ts already provides for sandboxed containers that block browser downloads): 320 passed, 3 failed. None of the 3 is attributable to this branch, established rather than assumed:ui-pwa.spec.ts:143(Chromium PWA installability) andui-smoke.spec.ts:3498(document viewer PDF ordering) fail identically on untouched origin/main in this container — pre-existing and environmental (this image ships Chromium 1194; CI uses 1228).ui-phone-scroll.spec.ts:481(calculators phone dock) passes in isolation on this branch (2.9s) and failed only at position Simplify operational tooling and runbooks #56 of the full suite (12.3s) — a suite-order timing flake./calculatorsnever rendersSearchResultsHeaderBand, so this diff cannot reach it.All three pass in CI's Production UI job on this branch.
npm run verify:releasebefore release or handoff confidence claimsRetrieval/ranking evals are not applicable: no retrieval, ranking, selection, chunking, or scoring behaviour is touched.
src/lib/result-sort.tsis consumed throughreadResultSortand is not modified.Risk and rollout
SearchResultsHeaderBandis shared chrome rendered by 12 call sites (services, documents, differentials, forms, DSM, factsheets, formulation, specifiers, medication, favourites, applications launcher, therapy compass), so a layout regression would surface on every mode at once. No data, API, auth, or ranking behaviour changes.Clinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy) — no Supabase surface touchedNotes
<select>to a segmented group broke two Playwright specs that reach the control by its accessible name rather than by component or test id, so component/test-id greps did not surface them. Both are fixed inc307c98and verified passing:ui-smoke.spec.ts›document search mode lists matching documents and scope actions @critical, andui-tools.spec.ts›result sorting persists in the URL and restores through browser history. The latter also read the persisted order viatoHaveValueaftergoBack/goForward; a segmented control has no value, so those becamearia-pressedassertions while the URL and result-order assertions stayed untouched.tests/ui-tools.spec.tscounted two<label>elements in the phone control pair. Sort is no longer a<label>, so those measure the pair's direct children and additionally assert the 44px tap-target floor. The no-internal-scroll assertion is kept: overflow belongs to the rail that owns the pair, not the pair.ResultSortControlloses itscompactprop (it existed to hide a "Sort" label the segmented control no longer has). It is not imported outside this module.MobileResultFilterControl's public API is unchanged — it is used by 10 call sites and only gainstruncateplus the weight step-down.