fix(web): timeline follow listeners attach once the list exists

The opt-out listeners (wheel, keys, scrollbar, touch, chained scroll)
attached through a 12-frame requestAnimationFrame retry keyed on the
thread id. A thread that was still hydrating rendered the loading
placeholder with no LegendList, so the retry expired and the listeners
never attached once the list mounted. Scrolling up moved the viewport,
live follow stayed on, and the next tool boundary snapped back to the end.

MessagesTimeline now reports its scroll node through a ref callback and
the hook attaches to that node whenever it mounts or remounts. The
unpositioned-tail overflow fallback from the previous attempt is
reverted: LegendList positions appended rows synchronously on data
change, and the real cause was the missing listeners.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ca449ec80eJulius Marminge committed on 10/21/2026, 10:00:25 AMparente4e1b8c

Checks

22 successful · 6 skipped
All checks passed
6 files changedLine totals unavailable