arena: takeover model for same-handle multi-tab
Matches field.mjs's mental model: when a second tab joins under the
same handle, the older tab becomes a spectator instead of both tabs
fighting over one avatar.
Server (arena-manager.mjs):
- On rejoin with same handle but different wsId, detect takeover:
emit "arena:takeover" to the old wsId, then register that old ws
as a spectator probe so it keeps receiving snapshots (tab stays
alive, the user can watch the other tab drive their avatar).
- playerLeave cleans up any "<handle>#spec<wsId>" probe entries
bound to the closing socket.
Client (arena.mjs):
- New netSpectator flag set on receiving arena:takeover.
- Suppress enqueueCmd / flushCmds while spectating (no cmd traffic).
- Suppress reconcileLocal while spectating (cam would be yanked toward
the other tab's position otherwise).
- HUD: "SPECTATE" row + center-screen banner explaining why.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>