From 3b4e98976cfdb31530add691a9a358861750a9e7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 18 Jul 2026 07:16:36 +0000 Subject: [PATCH] Polish and harden the global search composer across breakpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Idle send button now reads as a calm neutral control and turns accent only when a query makes it actionable, replacing the muddy faded-teal (a 50%-opacity accent fill with a bleeding colour glow). - Restore hover and open-state feedback on the "+" compose trigger — an unlayered `background: transparent` was suppressing both the hover utility and the open-state background. - Scale the clear ("x") button to 48px at >=640px so it matches the "+" and send buttons instead of sitting a size smaller in the pill row. - Unify the send/spinner glyph at 20px (size-icon-lg) with the mode and search affordances it swaps between. - Soften the field/send divider into a hairline that fades at both ends. - Fix the workflow-header mode button's dead responsive variant: size utilities were duplicated in the shared base, so the smaller workflow override never applied (Tailwind v4 canonical order let the base win). - Keep the "+"->"x" open affordance under reduced motion by dropping the motion-safe gate (the global reduced-motion rule already makes it instant, so gating removed the state entirely for those users). - Extend forced-colors coverage to the pill, divider, and chip; drop a wasted backdrop blur on the opaque phone dock pill; consolidate the two duplicate max-width:430px blocks; and remove a dark-mode no-op that was overriding the new hover colours. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CkbwfoKvheoJPp3pYf3PAs --- src/app/globals.css | 87 ++++++++++++++----- .../master-search-header.tsx | 17 ++-- .../clinical-dashboard/mode-action-popup.tsx | 6 +- 3 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index a9fb9afe6..291c00f73 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1066,13 +1066,18 @@ summary::-webkit-details-marker { color: var(--clinical-accent); } -/* The mode-action popover only renders ≥1024px (smaller viewports get the Sheet), - so this block holds no .mode-action-* overrides. */ +/* Small-phone pin for the composer icon buttons: hold the 44px tap target and a + 1.1rem glyph below 431px (the ≥640px block grows them to 48px/3rem). Single + source of truth — do not re-add a second max-width:430px block for these. + The mode-action popover only renders ≥1024px, so this holds no .mode-action-* + overrides. */ @media (max-width: 430px) { .answer-footer-search-action, .answer-footer-search-send { - height: 2.75rem; - width: 2.75rem; + height: 2.75rem !important; + width: 2.75rem !important; + min-height: 2.75rem; + min-width: 2.75rem; } .answer-footer-search-action svg, @@ -1099,6 +1104,20 @@ summary::-webkit-details-marker { background: transparent; color: var(--text-muted); box-shadow: none; + transition: + background-color 150ms ease, + color 150ms ease; +} + +/* The unlayered `background: transparent` above beats the layered hover/open + utilities on the chatComposerIconButton trigger, so the "+" had NO tactile + feedback on hover and stayed flat even while its menu was open. Restore both + as unlayered rules so the primary compose action responds like every other + icon control. `[aria-expanded="true"]` is the trigger's open state. */ +.answer-footer-search-action:hover, +.answer-footer-search-action[aria-expanded="true"] { + background: var(--surface-subtle); + color: var(--text); } .answer-footer-search-input { @@ -1128,7 +1147,15 @@ summary::-webkit-details-marker { height: 2rem; width: 1px; flex: 0 0 auto; - background: color-mix(in srgb, var(--border-strong) 58%, transparent); + /* Hairline that fades at both ends rather than a hard bar — reads as a + premium separator between the field and the send action. */ + background: linear-gradient( + to bottom, + transparent, + color-mix(in srgb, var(--border-strong) 58%, transparent) 22%, + color-mix(in srgb, var(--border-strong) 58%, transparent) 78%, + transparent + ); } .answer-footer-search-send { @@ -1148,20 +1175,16 @@ summary::-webkit-details-marker { box-shadow: 0 5px 14px color-mix(in srgb, var(--clinical-accent) 38%, transparent); } -@media (max-width: 430px) { - .answer-footer-search-action, - .answer-footer-search-send { - height: 2.75rem !important; - width: 2.75rem !important; - min-height: 2.75rem; - min-width: 2.75rem; - } - - .answer-footer-search-action svg, - .answer-footer-search-send svg { - height: 1.1rem; - width: 1.1rem; - } +/* Idle/inactive send: a calm neutral chip, not a faded-teal button. The + chatComposerIconButton `disabled:opacity-50` utility over the accent fill + + colour glow read as muddy/half-broken on the empty hero. Unlayered so it + beats that layered utility; the button turns accent the moment a query makes + it actionable. */ +.answer-footer-search-send:disabled { + opacity: 1; + background: var(--surface-subtle); + color: var(--text-soft); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-strong) 42%, transparent); } .answer-footer-search-send:active { @@ -1521,11 +1544,6 @@ summary::-webkit-details-marker { } } -.dark .answer-footer-search-action, -.dark .answer-footer-search-chip { - color: var(--text-muted); -} - .dashboard-composer-edge { left: max(0.75rem, var(--safe-area-left)); right: max(0.75rem, var(--safe-area-right)); @@ -1719,6 +1737,10 @@ summary::-webkit-details-marker { .answer-footer-search-dock .answer-footer-search-pill { border-color: var(--border-strong); background: var(--surface); + /* The dock repaints the pill opaque, so the inherited blur has nothing + translucent to sample — drop it to save a compositing layer per scroll + frame (matches the chip override just below). */ + backdrop-filter: none; box-shadow: 0 -1px 0 color-mix(in srgb, var(--border) 60%, transparent), 0 1px 3px rgb(16 24 40 / 5%); @@ -2268,6 +2290,23 @@ summary::-webkit-details-marker { mask-image: none; -webkit-mask-image: none; } + + /* Composer pill/divider/chip use color-mix(...transparent) for their border, + fill, and separator, which thins system-color contrast exactly like the + glass header — force them opaque too (unlayered, matching the header + treatment above) so the composer boundary reads at full strength and its + divider stays visible next to the header chrome right above it. */ + .answer-footer-search-pill, + .answer-footer-search-chip { + border: 1px solid ButtonBorder; + background: Canvas; + backdrop-filter: none; + box-shadow: none; + } + + .answer-footer-search-divider { + background: ButtonBorder; + } } @media print { diff --git a/src/components/clinical-dashboard/master-search-header.tsx b/src/components/clinical-dashboard/master-search-header.tsx index 04ef4a475..fb9a980bd 100644 --- a/src/components/clinical-dashboard/master-search-header.tsx +++ b/src/components/clinical-dashboard/master-search-header.tsx @@ -1362,7 +1362,7 @@ export function MasterSearchHeader({