4437a1aaf9
Symmetric to the prev-rows commit. Adds 2 about-to-apply move
rows below the active row so the panel now shows a full 5-row
window: prev offset 2 → prev offset 1 → active → next offset 1
→ next offset 2. Panel grows from 84 → 112 px to fit the
additional rows.
Format helper `format_kth_next_row(state, k)` returns the kth
about-to-apply move's text:
- k=1 → moves[cursor], displayed as "{cursor + 1} │ {body}"
- k=2 → moves[cursor + 1], displayed as "{cursor + 2} │ ..."
- Returns empty when cursor + k - 1 >= moves.len() (under-fill
late in the replay) or k=0 (degenerate).
Symmetric implementation:
- New `ReplayOverlayMoveLogNextRow { offset: u8 }` component
- Spawn loop iterates 1..=MOVE_LOG_NEXT_ROWS in order so offset
1 sits directly below active, offset 2 below that
- Per-frame `update_move_log_next_rows` system mirrors the
prev-rows updater
- TEXT_SECONDARY (matching prev rows) keeps the active row's
highlight as the focal point
For post-game replays the next rows aren't spoilers (the game
is already won). If a future use case reuses the panel during
live play, the preview-shape would need rethinking.
4 new tests:
- format_kth_next_row: k=1, 2 in-range cases + k beyond
moves.len() out-of-range + k=0 degenerate.
- move_log_next_rows_spawn_with_panel: cardinality matches
MOVE_LOG_NEXT_ROWS.
- move_log_next_rows_paint_helper_strings_at_spawn: text
matches helper output per offset.
- move_log_next_rows_underfill_at_replay_end: offset 1
populates at cursor=9/10, offset 2 stays empty.
Tests: 1269 → 1273. Clippy clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>