Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions src/components/ClinicalDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5373,6 +5373,12 @@ export function ClinicalDashboard({
// stay top-aligned so their lists start in a stable position.
const centeredModeHome =
showDesktopHomeComposer && activeModeResultKind !== "tools" && activeModeResultKind !== "favourites";
// Short mode homes (centred homes plus the services/forms registry homes)
// drop the large mobile bottom padding so phones don't get a scrollbar for
// content that already fits. Result views keep the full clearance.
const compactMobileModeHome =
centeredModeHome ||
((searchMode === "services" || searchMode === "forms") && !modeSearchSubmitted && !query.trim() && !loading);
// Submitted (non-answer) searches are result views, not mode homes: on phones
// the bottom composer drops its chip row and hugs the screen edge so results
// keep maximum vertical space. Mode homes keep the default chip-row layout.
Expand Down Expand Up @@ -5576,12 +5582,20 @@ export function ClinicalDashboard({
<div
className={cn(
"mx-auto max-w-7xl space-y-4 overflow-x-hidden px-3 py-4 sm:space-y-5 sm:px-4 sm:py-5 lg:px-8",
// Centred mode homes carry little content, so drop the large
// mobile bottom padding (the fixed composer already has its own
// reserved margin on <main>) to avoid a needless scrollbar.
// sm+/lg values stay identical to the result-view treatment.
searchMode === "answer"
? "pb-32 sm:pb-36 lg:pb-40"
? compactMobileModeHome
? "pb-4 sm:pb-36 lg:pb-40"
: "pb-32 sm:pb-36 lg:pb-40"
: hasMobileBottomSearch
? compactMobileBottomSearch
? "pb-8 sm:pb-10 lg:pb-12"
: "pb-32 sm:pb-10 lg:pb-12"
? compactMobileModeHome
? "pb-4 sm:pb-10 lg:pb-12"
: compactMobileBottomSearch
? "pb-8 sm:pb-10 lg:pb-12"
: "pb-32 sm:pb-10 lg:pb-12"
: "pb-8 sm:pb-10 lg:pb-12",
)}
>
Expand Down Expand Up @@ -5610,9 +5624,12 @@ export function ClinicalDashboard({

<section
className={cn(
"min-h-[calc(100dvh-11rem)]",
"min-h-[calc(100dvh-12.5rem)] sm:min-h-[calc(100dvh-11rem)]",
centeredModeHome || (activeModeResultKind === "answer" && !answer && !loading)
? "grid w-full place-items-center"
? // On tall phones the centred home leans slightly toward the
// bottom composer (matches the committed vertical-weighting
// guard); short phones skip the bias so content still fits.
"grid w-full place-items-center max-sm:[@media(min-height:800px)]:pt-[5vh]"
: activeModeResultKind === "tools" ||
activeModeResultKind === "favourites" ||
activeModeResultKind === "differentials"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,10 @@ function GlobalMockupSearchShellClient({
id="main-content"
tabIndex={-1}
className={cn(
"min-h-[calc(100dvh-4rem)] min-w-0 overflow-x-hidden focus:outline-none",
// Phone: fill the space under the header exactly (the header is
// taller than the 4rem the calc assumed, which forced a phantom
// scrollbar on every standalone page). sm+ keeps the original calc.
"min-w-0 overflow-x-hidden focus:outline-none max-sm:flex-1 sm:min-h-[calc(100dvh-4rem)]",
!shouldShowSearchComposer
? "pb-8"
: searchMode === "answer"
Expand Down
58 changes: 42 additions & 16 deletions src/components/mode-home-template.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,28 +59,51 @@ export function ModeHomeHero({
subtitle,
icon: Icon,
headingLevel = 1,
compact = false,
}: {
testId?: string;
title: string;
subtitle: string;
icon: LucideIcon;
headingLevel?: 1 | 2;
/**
* Mobile-only tightening used by ModeHomeTemplate so short mode homes fit a
* phone viewport without scrolling. All sm+/lg values are identical to the
* default treatment, so tablet and desktop render exactly the same.
*/
compact?: boolean;
}) {
const Heading = headingLevel === 1 ? "h1" : "h2";

return (
<section className="grid justify-items-center gap-3 sm:gap-4" aria-labelledby={`${testId ?? "mode-home"}-title`}>
<span className="mode-home-icon grid h-14 w-14 place-items-center rounded-2xl border border-[color:var(--clinical-accent-border)] bg-[color:var(--clinical-accent-soft)] text-[color:var(--clinical-accent)] shadow-[var(--shadow-inset)] sm:h-16 sm:w-16 lg:h-[4.75rem] lg:w-[4.75rem] lg:rounded-[1.35rem]">
<Icon className="h-7 w-7 sm:h-8 sm:w-8 lg:h-10 lg:w-10" aria-hidden="true" />
<section
className={cn("grid justify-items-center sm:gap-4", compact ? "gap-2" : "gap-3")}
aria-labelledby={`${testId ?? "mode-home"}-title`}
>
<span
className={cn(
"mode-home-icon grid place-items-center rounded-2xl border border-[color:var(--clinical-accent-border)] bg-[color:var(--clinical-accent-soft)] text-[color:var(--clinical-accent)] shadow-[var(--shadow-inset)] sm:h-16 sm:w-16 lg:h-[4.75rem] lg:w-[4.75rem] lg:rounded-[1.35rem]",
compact ? "h-12 w-12" : "h-14 w-14",
)}
>
<Icon className={cn("sm:h-8 sm:w-8 lg:h-10 lg:w-10", compact ? "h-6 w-6" : "h-7 w-7")} aria-hidden="true" />
</span>
<div className="grid gap-2">
<div className={cn("grid", compact ? "gap-1.5 sm:gap-2" : "gap-2")}>
<Heading
id={`${testId ?? "mode-home"}-title`}
className="text-balance text-[1.85rem] font-extrabold leading-[1.05] tracking-normal text-[color:var(--text-heading)] sm:text-[2.45rem] lg:text-[2.9rem]"
className={cn(
"text-balance font-extrabold leading-[1.05] tracking-normal text-[color:var(--text-heading)] sm:text-[2.45rem] lg:text-[2.9rem]",
compact ? "text-[1.6rem]" : "text-[1.85rem]",
)}
>
{title}
</Heading>
<p className="mx-auto max-w-2xl text-pretty text-sm font-medium leading-6 text-[color:var(--text-muted)] sm:text-base lg:text-[1.0625rem]">
<p
className={cn(
"mx-auto max-w-2xl text-pretty text-sm font-medium text-[color:var(--text-muted)] sm:text-base sm:leading-6 lg:text-[1.0625rem]",
compact ? "leading-5" : "leading-6",
)}
>
{subtitle}
</p>
</div>
Expand All @@ -107,10 +130,13 @@ export function ModeHomeMain({
data-testid={testId}
className={cn(
// Phone: content is vertically centred (not bottom-anchored) so the page
// no longer collapses all its slack into a void above the hero. Bottom
// padding still reserves room for the fixed mobile composer. From sm up
// the composer moves into the hero, so the reserved space drops away.
"grid min-h-[calc(100dvh-4rem)] items-center justify-items-center bg-[color:var(--background)] px-4 pb-[calc(9rem+env(safe-area-inset-bottom))] pt-[clamp(1.25rem,4vh,2.25rem)] text-[color:var(--text)] sm:px-6 sm:pb-[clamp(1.75rem,5vh,3.25rem)] sm:pt-[clamp(1.75rem,5vh,3.25rem)] lg:px-8",
// no longer collapses all its slack into a void above the hero. The
// standalone shell (#main-content) already reserves 9rem of bottom
// padding for the fixed mobile composer, so this main only subtracts
// that space from its min-height instead of re-adding the padding —
// otherwise short homes scroll by exactly the duplicated reservation.
// From sm up the composer moves into the hero, so the reserve drops away.
"grid min-h-[calc(100dvh-13.75rem-env(safe-area-inset-bottom))] items-center justify-items-center bg-[color:var(--background)] px-4 pb-4 pt-[clamp(1.25rem,4vh,2.25rem)] text-[color:var(--text)] sm:min-h-[calc(100dvh-4rem)] sm:px-6 sm:pb-[clamp(1.75rem,5vh,3.25rem)] sm:pt-[clamp(1.75rem,5vh,3.25rem)] lg:px-8",
className,
)}
>
Expand All @@ -133,7 +159,7 @@ export function ModeHomeVerificationFooter({
totalCount?: number;
}) {
return (
<p className="flex flex-wrap items-center justify-center gap-x-3 gap-y-2 pt-1 text-xs font-medium leading-5 text-[color:var(--text-muted)] sm:text-sm">
<p className="flex flex-wrap items-center justify-center gap-x-3 gap-y-2 pt-0.5 text-xs font-medium leading-5 text-[color:var(--text-muted)] sm:pt-1 sm:text-sm">
<span className="inline-flex items-center gap-2 font-semibold text-[color:var(--clinical-accent)]">
<Icon className="h-4 w-4" aria-hidden="true" />
{label}
Expand Down Expand Up @@ -202,11 +228,11 @@ export function ModeHomeTemplate({
<div
data-testid={testId}
className={cn(
"mode-home-template mx-auto box-border flex w-full max-w-[64rem] flex-col items-center justify-center gap-5 px-0 text-center sm:gap-6 lg:gap-7",
"mode-home-template mx-auto box-border flex w-full max-w-[64rem] flex-col items-center justify-center gap-3.5 px-0 text-center sm:gap-6 lg:gap-7",
className,
)}
>
<ModeHomeHero testId={testId} title={title} subtitle={subtitle} icon={icon} headingLevel={headingLevel} />
<ModeHomeHero testId={testId} title={title} subtitle={subtitle} icon={icon} headingLevel={headingLevel} compact />

{desktopComposerSlotId ? (
<div id={desktopComposerSlotId} className="mode-home-composer-slot hidden w-full sm:[&:not(:empty)]:block" />
Expand All @@ -228,7 +254,7 @@ export function ModeHomeTemplate({
<span className="block text-balance text-[0.98rem] font-bold leading-5 text-[color:var(--text-heading)] [overflow-wrap:anywhere] lg:text-[1.05rem]">
{action.title}
</span>
<span className="mt-1 block text-xs font-medium leading-5 text-[color:var(--text-muted)] lg:text-[0.9rem] lg:leading-6">
<span className="mt-0.5 block text-xs font-medium leading-5 text-[color:var(--text-muted)] sm:mt-1 lg:text-[0.9rem] lg:leading-6">
{action.description}
</span>
</span>
Expand All @@ -239,7 +265,7 @@ export function ModeHomeTemplate({
</>
);
const actionClassName = cn(
"mode-home-action group grid min-h-[4.8rem] w-full grid-cols-[2.5rem_minmax(0,1fr)_1.25rem] items-center gap-3 bg-[color:var(--surface)] px-4 py-3 text-left transition hover:bg-[color:var(--surface-subtle)] focus-visible:relative focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[color:var(--focus)] disabled:cursor-wait disabled:opacity-60 lg:min-h-[8.4rem] lg:grid-cols-[3.5rem_minmax(0,1fr)_1.5rem] lg:gap-4 lg:rounded-lg lg:border lg:border-[color:var(--border)] lg:px-6 lg:py-5 lg:shadow-[var(--shadow-card)]",
"mode-home-action group grid min-h-[4rem] w-full grid-cols-[2.5rem_minmax(0,1fr)_1.25rem] items-center gap-3 bg-[color:var(--surface)] px-4 py-2.5 text-left transition sm:min-h-[4.8rem] sm:py-3 hover:bg-[color:var(--surface-subtle)] focus-visible:relative focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-[color:var(--focus)] disabled:cursor-wait disabled:opacity-60 lg:min-h-[8.4rem] lg:grid-cols-[3.5rem_minmax(0,1fr)_1.5rem] lg:gap-4 lg:rounded-lg lg:border lg:border-[color:var(--border)] lg:px-6 lg:py-5 lg:shadow-[var(--shadow-card)]",
index > 0 && "border-t border-[color:var(--border)] lg:border-t-[color:var(--border)]",
);

Expand Down Expand Up @@ -268,7 +294,7 @@ export function ModeHomeTemplate({
) : null}

{pills?.length ? (
<section className="grid w-full max-w-none self-stretch gap-4 border-t border-[color:var(--border)] pt-5 sm:pt-6">
<section className="grid w-full max-w-none self-stretch gap-3 border-t border-[color:var(--border)] pt-3 sm:gap-4 sm:pt-6">
{pillsTitle || pillsAction ? (
<div
className={cn(
Expand Down