ad9cc78f00
- F1: gate the card on rows-WITH-text (`thread.some(row => row.text.length > 0)`) instead of thread length. A text-less root whose only reply is also text-less would otherwise open an empty <Paper> (the render already filters empty rows). New test locks it (parent + reply both empty → no card). - F2: ESTIMATED_CARD_HEIGHT 200 -> 300 (= CARD_MAX_HEIGHT) so the flip-above decision reserves the real worst-case height and a tall thread near the viewport bottom flips up instead of overflowing off-screen. vitest 19/19, tsc 0, eslint 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>