From 89ee76dd7511ad8446e485110b04238031f0c7b2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 13 Jul 2026 07:38:39 +0000 Subject: [PATCH 1/2] fix(mobile): remove half-screen black void below short phone answers On phones the answer view left a large near-black empty band below short answers (e.g. the source-only fallback) down to the fixed "Ask a follow-up" dock. Three phone-only reservations stacked: a viewport-height min-height floor forced the answer section to ~full height even for short content (scrollable dead-space with a false scroll affordance), the
follow-up reserve (18rem) far exceeded the real ~6rem composer dock (painting a black band above it), and pb-32 added more. - Bottom-anchor the answer section on phones (flex + floor + justify-end) so a short answer sits just above the composer instead of top-hugging with a black void beneath it; long answers exceed the floor so justify-end is inert and they scroll normally from the top. - Right-size the follow-up composer reserve (18rem -> 7.5rem) to hug the measured dock height, removing the black band above the dock. - Trim the phone answer wrapper padding (pb-32 -> pb-4) so nothing scrolls into a black strip below the anchored content. sm+/desktop, the answer-home centering, other result kinds, and the answer pending state are unchanged. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01A1ekcXQZVFVKKzdoVpjyVQ --- src/components/ClinicalDashboard.tsx | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index 7190ebe88..19cf2210c 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -3547,11 +3547,16 @@ export function ClinicalDashboard({ // bottom, so
reserves room for it. When that dock hides on // scroll, reclaim the reserved strip too — otherwise the near-black // shell background shows through as an empty band. (sm+ is inert: - // bottomSearchScrollHidden only ever goes true on phones.) + // bottomSearchScrollHidden only ever goes true on phones.) The + // reserve hugs the real dock height (follow-up scroll row + composer + // pill ≈ 6rem measured); a larger reserve just paints extra shell + // background above the dock. The answer section fills the remaining + // space and bottom-anchors its content, so short answers sit against + // the dock instead of floating under a half-screen black void. bottomSearchScrollHidden ? "mb-0 sm:mb-24" : answerFollowUpSuggestions.length > 0 - ? "mb-[calc(18rem+env(safe-area-inset-bottom))] sm:mb-24" + ? "mb-[calc(7.5rem+env(safe-area-inset-bottom))] sm:mb-24" : "mb-[calc(5.25rem+env(safe-area-inset-bottom))] sm:mb-24" : hasMobileBottomSearch ? bottomSearchScrollHidden @@ -3584,7 +3589,10 @@ export function ClinicalDashboard({ searchMode === "answer" ? compactMobileModeHome ? "pb-4" - : "pb-32 sm:pb-36 lg:pb-40" + : // Phones bottom-anchor the answer against the dock (the
+ // reserve already clears it), so the large mobile bottom padding + // would only add a scrollable black strip under a short answer. + "pb-4 sm:pb-36 lg:pb-40" : hasMobileBottomSearch ? compactMobileModeHome ? "pb-4 sm:pb-10 lg:pb-12" @@ -3612,7 +3620,17 @@ export function ClinicalDashboard({ "max-sm:flex max-sm:min-h-[calc(100dvh-12.5rem)] max-sm:flex-col sm:min-h-[calc(100dvh-11rem)]", centeredModeHome && "max-sm:justify-center", ) - : "min-h-[calc(100dvh-12.5rem)] sm:min-h-[calc(100dvh-11rem)]", + : // A rendered answer bottom-anchors on phones: the section fills + // the space left above the fixed composer dock and pushes its + // content to the bottom, so a SHORT answer sits just above the + // dock instead of top-hugging with a half-screen black void + // below it. The floor subtracts the safe-area insets so it tracks + // the real header/dock height across notched devices. Long answers + // exceed the floor, so justify-end is inert and they scroll + // normally. sm+/desktop keeps the original block + floor. + activeModeResultKind === "answer" && answer + ? "flex min-h-[calc(100dvh-13rem-env(safe-area-inset-top)-env(safe-area-inset-bottom))] flex-col justify-end sm:block sm:min-h-[calc(100dvh-11rem)]" + : "min-h-[calc(100dvh-12.5rem)] sm:min-h-[calc(100dvh-11rem)]", centeredModeHome || showAnswerHome ? // Phones centre the home block mid-screen, matching the // standalone-route homes; the pop-up action surface picks From 8ea8cf9c3751a7144b4c4a4f92b651fa1e44c0a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 13 Jul 2026 07:51:36 +0000 Subject: [PATCH 2/2] fix(mobile): keep short phone answers top-aligned under the question Follow-up to the phone answer-view black-void fix: per product choice, short answers stay top-aligned (just under the question) rather than bottom-anchoring against the composer. The two cleanup fixes are kept: the answer section is content-sized (no viewport-height floor, so no phantom scroll into black) and the follow-up composer reserve stays right-sized to the real dock (no black band above it). Long answers remain top-aligned and scroll from the top; sm+/desktop unchanged. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01A1ekcXQZVFVKKzdoVpjyVQ --- src/components/ClinicalDashboard.tsx | 31 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index 19cf2210c..9ea9a8b36 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -3549,10 +3549,8 @@ export function ClinicalDashboard({ // shell background shows through as an empty band. (sm+ is inert: // bottomSearchScrollHidden only ever goes true on phones.) The // reserve hugs the real dock height (follow-up scroll row + composer - // pill ≈ 6rem measured); a larger reserve just paints extra shell - // background above the dock. The answer section fills the remaining - // space and bottom-anchors its content, so short answers sit against - // the dock instead of floating under a half-screen black void. + // pill ≈ 6rem measured); the old 18rem reserve just painted extra + // shell background as a black band above the dock. bottomSearchScrollHidden ? "mb-0 sm:mb-24" : answerFollowUpSuggestions.length > 0 @@ -3589,9 +3587,11 @@ export function ClinicalDashboard({ searchMode === "answer" ? compactMobileModeHome ? "pb-4" - : // Phones bottom-anchor the answer against the dock (the
- // reserve already clears it), so the large mobile bottom padding - // would only add a scrollable black strip under a short answer. + : // The
reserve already clears the fixed composer dock on + // phones, so the old large mobile bottom padding only floated a + // long answer's last line high above the dock (and padded a short + // answer's empty space further). Keep it small here; sm+/desktop + // keep the original generous padding. "pb-4 sm:pb-36 lg:pb-40" : hasMobileBottomSearch ? compactMobileModeHome @@ -3620,16 +3620,15 @@ export function ClinicalDashboard({ "max-sm:flex max-sm:min-h-[calc(100dvh-12.5rem)] max-sm:flex-col sm:min-h-[calc(100dvh-11rem)]", centeredModeHome && "max-sm:justify-center", ) - : // A rendered answer bottom-anchors on phones: the section fills - // the space left above the fixed composer dock and pushes its - // content to the bottom, so a SHORT answer sits just above the - // dock instead of top-hugging with a half-screen black void - // below it. The floor subtracts the safe-area insets so it tracks - // the real header/dock height across notched devices. Long answers - // exceed the floor, so justify-end is inert and they scroll - // normally. sm+/desktop keeps the original block + floor. + : // A rendered answer is content-sized and top-aligned on phones: + // it must NOT inherit the viewport-height floor (that floor exists + // to give the centred home block room). With the floor, a short + // answer stretches the section to ~full height and you can scroll + // down into a black void; content-sized keeps the answer under the + // question with calm space below and no phantom scroll. Other + // result kinds keep the floor; sm+/desktop is unchanged. activeModeResultKind === "answer" && answer - ? "flex min-h-[calc(100dvh-13rem-env(safe-area-inset-top)-env(safe-area-inset-bottom))] flex-col justify-end sm:block sm:min-h-[calc(100dvh-11rem)]" + ? "sm:min-h-[calc(100dvh-11rem)]" : "min-h-[calc(100dvh-12.5rem)] sm:min-h-[calc(100dvh-11rem)]", centeredModeHome || showAnswerHome ? // Phones centre the home block mid-screen, matching the