- server.js disambiguateHops() now delegates to server-helpers.js
(was a full copy of the same algorithm, ~70 lines removed)
- live.js resolveHopPositions() now delegates to shared HopResolver
(was a standalone reimplementation, ~50 lines removed)
- HopResolver.init() called when live page loads/updates node data
- Net -106 lines, same behavior, single source of truth
All unit tests pass (241). E2E 13/16 (3 pre-existing Chromium crashes).