5ae8b1fdd1
The attempts box's content is replaced on every render (the batch panel is static markup; the render fills the dynamic bits) and replacing a scrollable element's content resets its scroll. That was harmless while the render ran once per attempt, but v3.28.7 made it run on every 2 s poll, so scrolling back through the attempts during a run snapped to the top each poll. The render now captures the box's scrollTop before refilling it and restores it afterwards. Test: the stub box resets its scroll on an innerHTML write (like a browser) and the render must keep the reader's position - verified to fail without the restore. 920 frontend + 928 Python; sw cache simple-v446.