- per-row Cancel button in the scan-progress card; listeners are bound
after the TS island renders its rows (module scope has no inline
handlers), and the button is removed once its job turns terminal
- cancel-all icon button in the card header: resolves the server's
active job list first, so it also covers scans this page never
started (e.g. started before a refresh), then cancels each one
- polling treats cancelled as terminal, averages overall progress
only over jobs that can still advance (so the bar can reach 100%),
and the results panel reports cancelled scans instead of claiming
"Scan Complete!"
- sidebar spinner resets on the scan_cancelled websocket event (same
quiet handling as scan_error)
- setup wizard shows "Cancelled" as a terminal status in its poller
No new innerHTML assignment sites - rendering-ownership baseline
unchanged.