The conversation column that owns the scrolling
Turns stack inside a scrollable column with consistent gutters, a fade at either end, and a scrollbar that only appears while scrolling is happening. When a new turn is appended it floats to the top of the viewport, pushing the conversation upward and leaving the response room to stream in below.
Send anchoring
Sending appends a turn and scrolls it to the top. A trailing spacer grows so even a short newest exchange can reach the top, and reduced motion makes the glide instant.
Edge fades
A pure CSS mask fades the first and last lines as they scroll out, hinting there is more in either direction. No scroll listeners are involved.
A quiet scrollbar
The content gutters live on an inner wrapper, so the thin scrollbar rides the far edge of the component instead of sitting inside the conversation. It stays invisible until the thread is actually scrolling, then fades back out.