diff --git a/docs/branch-review-records/6651300a557416232b1653304a7e175fb005cc557190f316fe8c221a57c2e2bf.record.md b/docs/branch-review-records/6651300a557416232b1653304a7e175fb005cc557190f316fe8c221a57c2e2bf.record.md new file mode 100644 index 0000000000..3c5ace62e3 --- /dev/null +++ b/docs/branch-review-records/6651300a557416232b1653304a7e175fb005cc557190f316fe8c221a57c2e2bf.record.md @@ -0,0 +1 @@ +| 2026-08-18 | claude/search-recovery-rail | 7510216c672f293d26b8fdfe04a9ed3fd286b7f6 | SearchResultsEmptyState rail restyle + desktop tap floor restore (PR #2147) | approved — presentation-only; no copy, testid, heading-level, live-region or handler change; band untouched | typecheck 0 errors; eslint+prettier+format:changed clean; 10 DOM files/168 tests passed; chromium ui-accessibility 16 passed; full verify:ui not completed (lock contention + host exit) | diff --git a/docs/outstanding-issues-inbox/714e714b-dd1d-4a10-8f95-8552fa2c5296.json b/docs/outstanding-issues-inbox/714e714b-dd1d-4a10-8f95-8552fa2c5296.json new file mode 100644 index 0000000000..e3ab0a8193 --- /dev/null +++ b/docs/outstanding-issues-inbox/714e714b-dd1d-4a10-8f95-8552fa2c5296.json @@ -0,0 +1,14 @@ +{ + "version": 2, + "id": "714e714b-dd1d-4a10-8f95-8552fa2c5296", + "createdOn": "2026-08-18", + "action": "add", + "payload": { + "pri": "P2", + "type": "task", + "summary": "Hoist the filtered-zero empty state out of the documents results grid so it can sit flush under the results band", + "detail": "SearchResultsEmptyState renders the filtered-to-zero case nested two divs inside the results grid in document-search-results.tsx (grid gap-3 wrapper, with a conditional 'N results after filters' pill above it), not adjacent to SearchResultsHeaderBand. That nesting blocks the inline treatment evaluated for PR #2147: recovery cannot share the band's bottom edge, the band's data-tone lead is not adjacent so the panel has no state mark, and the filter chips are not near enough for the panel to point at them instead of duplicating them. PR #2147 therefore shipped the self-contained rail panel, which does not depend on adjacency. Hoisting the state to a sibling of the band would let the panel drop its own rail, its named-removal row and its eyebrow — roughly a third less height on phones. Only the documents nesting was verified; the other five consumers (favourites, calculators, forms, services, therapy-compass) were not checked and may nest the same way.", + "source": "PR #2147 design review; document-search-results.tsx:1558", + "issueUlid": "01M0B36TGQGBBYTAN7G28RJHWW" + } +} diff --git a/src/components/clinical-dashboard/search-results-header-band.tsx b/src/components/clinical-dashboard/search-results-header-band.tsx index 91150ecaf3..9c815dd33a 100644 --- a/src/components/clinical-dashboard/search-results-header-band.tsx +++ b/src/components/clinical-dashboard/search-results-header-band.tsx @@ -962,24 +962,65 @@ export function SearchResultsEmptyState({ ].filter(Boolean); return ( -
+
+ {/* The state mark, carrying the same vocabulary as the band's own lead: + the stroke *count* — not the hue — is what separates a degraded search + from a healthy one, because `--clinical-accent` resolves to LinkText + under forced colors while `--warning` resolves to CanvasText, and hue + alone would render "filtered" and "could not complete" identically. + Utilities rather than an unlayered class: `.search-band-lead` is + unlayered precisely so it can beat Tailwind's utilities layer, and this + mark has no utility to beat — adding a class here would enlarge the + inventory `style-contract-registry` polices for nothing. `box-content` + + `w-0` makes the border the entire width. Exactly one width class per + branch: two would both emit `border-left-width` and the winner would be + stylesheet order rather than the branch. */} + {/* Visible copy is never inside the live region: a region that mounts already populated is silent in most screen readers, and wrapping the visible tree would flash empty for a frame. The sr-only live region below is populated after mount (query-only) or omitted (filtered). NOT `role="status"`: the band already owns that role on every search route and a second one makes singular `getByRole("status")` ambiguous. */} - - {degraded ? ( - - ) : filtered ? ( - - ) : ( - - )} - - {emptyTitle} -

{emptyBody}

+ {/* The glyph sits beside the heading rather than inside it: a 48px tinted + disc above centred copy is a container the icon vocabulary does not + have, and putting the SVG inside `Title` would put a node inside the + accessible name that every heading assertion resolves. */} +
+ + {degraded ? ( + + ) : filtered ? ( + + ) : ( + + )} + +
+ {emptyTitle} +

{emptyBody}

+
+
{!filtered ? (
{liveMessage} @@ -991,7 +1032,7 @@ export function SearchResultsEmptyState({ own action, which is also the fix for the single button that said "Clear filters" and called `clearSearch`. */} {filtered ? ( -
+
{lastFilter ? (