From 4936b776ab6bc0d9da6215585db39f3158e174c9 Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Thu, 24 Sep 2026 19:13:22 +0300 Subject: [PATCH] Scroll-down disc rides the dock: anchored above the composer, never over it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The scroll-to-bottom disc (ConversationScrollButton) was the scroller's last child — DOM order painted it ABOVE the dock overlay, so it floated at the scroller's bottom edge, partly covering the composer (owner refinement round 3, 2026-09-24: it must ALWAYS sit above the composer, never over any element, and stay positioned with respect to the composer — which grows a lot taller when a question owns the band). The fix is a DOM move, not a coordinate: the button now renders INSIDE the DockOverlay, as a sibling of the DOCK container within the dock block — `absolute bottom-full mb-2`, anchored to the BLOCK's top edge. Because the anchor is the block itself (not the scroller's bottom): - it sits above the composer shell AND the stats row, in the gradient's transparent band; - it rides every height change LIVE: typing growth, a pending question expanding the band (verified: the disc moves with the 393px question form, 9px clear), the 180ms fold morph to the slim bar (8px clear of the folded bar — no overlap mid-morph either, height animations reflow per frame); - pointer-events-auto (the overlay is none by default); the isAtBottom/scrollToBottom context still reaches it — DockOverlay is a Conversation child. The use-stick-to-bottom pattern comment updated; the shared ConversationScrollButton component itself is untouched (positioning arrives via className, twMerge swaps bottom-4 → bottom-full). Live-verified on :3001 with a tall transcript, all three states: chat mode (15px clear of the composer textarea), expanded question (9px clear of the form top), folded slim bar (8px clear). 902/902. --- components/chat.tsx | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/components/chat.tsx b/components/chat.tsx index f40bac1..00ee7d1 100644 --- a/components/chat.tsx +++ b/components/chat.tsx @@ -1070,9 +1070,11 @@ export function Chat({
{/* The dock: an overlay sibling of the scroller (the - use-stick-to-bottom pattern — like the scroll button). Before - the button in DOM order so the button keeps painting above - the dock, as it always has. */} + use-stick-to-bottom pattern). The scroll-down button lives + INSIDE the overlay now (owner refinement round, 2026-09-24): + anchored to the dock block's top edge, so it rides every + height morph (typing, a question growing the band, the + fold) and NEVER overlaps the composer. */} - {/* The session-scoped focuses (chrome-melt wave, 2026-09-19): mounted @@ -1504,6 +1505,18 @@ function DockOverlay({ turns={turns} dictationSlot={dictationSlot} /> + {/* The scroll-down disc (moved here from the Conversation, + owner refinement round 2026-09-24): anchored to the BLOCK's + top edge — above the composer shell AND the stats row, in + the gradient's transparent band — so it never overlaps + any dock element. Because the anchor is the block itself + (not the scroller's bottom), it rides every height change + LIVE: typing growth, a pending question expanding the + band, the 180ms fold morph. pointer-events-auto: the + overlay is none by default. The isAtBottom/scrollToBottom + context still reaches it — DockOverlay is a Conversation + child. */} +
{/* The plan marginalia (owner, plan-placement round): the bare diagram in the band's right flank — boundaless, meet-fitted, part