Replays are bundled into the Pages deploy as gzipped static assets (B2 stays
the private cold archive). Repoint all replay/card/thumbnail/live.json fetches
off the empty R2 cache and the non-resolving b2.aicodebattle.com onto
same-origin /data/, via a shared fetchReplayFromUrl helper that gunzips
.json.gz with DecompressionStream.
- new web/src/lib/replay-data.ts (REPLAY_BASE, replayUrl, fetchReplayFromUrl)
- replay.ts / embed.ts / pages/embed.ts / playlist-carousel.ts use the helper
- og-tags, bot-card, home, matches, bot-profile, playlists, feedback, ambient,
api-types: /r2/ -> /data/
- pages.json data_paths updated; friendlier 404 message preserved
- 21 web tests pass; npm run build OK
Closes: bf-5cwi
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>