The FRLG level-up stat window opened and the sequence kept pumping, so the
box outlived its own step: it stopped taking input (routing is phase-gated),
never closed, and drew over the win/money text.
- exp_seq: update() now waits while the window is open (mirroring the
already-correct busy()), and finish()/reset() tear the window down silently
so a stale onDone cannot advance a sequence that no longer owns it.
- stat_growth: close(opts) gains opts.silent for teardown callers.
- init: the input-routing phase list moves into STAT_WINDOW_PHASES behind
Battle.statWindowPhase(), and Battle.update() tears down a window whose
phase can no longer dismiss it.
- ui: the stat-window draw keys off the same predicate, so input and drawing
can never disagree.
Tests: the "In-Battle Level Up Stat Growth Window" block in
tests/game3_battle_switch_and_faint_test.lua now pumps ExpSeq.update() while
the box is open, and a new CI-covered tests/engine suite pins the same
regression.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>