Root cause (dual bugs):
1. SCOPE BUG: snapStart/snapEnd/snapElement/snapRange were local vars inside
runAction() but showModal() is a sibling function — those snap vars were
never in scope inside the Replace button handler. The condition always
silently fell through, doing nothing.
2. TIMING BUG: Selection was only captured on document mouseup, which could
race against focus changes when clicking the toolbar.
Fix:
- showModal() now accepts snapStart/snapEnd/snapElement/snapRange as explicit
parameters — guaranteed in-scope, no closure ambiguity
- Each toolbar button mousedown calls captureForButton() BEFORE any focus
shift can occur (belt-and-suspenders, works even if e.preventDefault fails)
- Added console.log debug lines to Replace handler and runAction snapshot
- selectionLocked reset on Escape and overlay click (was missing)