${escapeHtml(title)}
+${escapeHtml(meta)}
+diff --git a/README.md b/README.md
index a444fdc..2afa7f2 100644
--- a/README.md
+++ b/README.md
@@ -86,12 +86,12 @@ Vehicle icon PNGs are served statically at `/vehicle-icons` from `VEHICLE_ICONS_
The proxy blocks cross-origin/API-navigation requests, strips CORS headers from
the upstream response, rate limits callers, and caches successful GET responses.
-Public TSS reads are written to a bounded JSON snapshot cache and served at both
-their `/api/tss/*` route and matching `/data/*` path. The frontend uses `/data/*`
-by default for public pages. Fresh snapshots return without touching the backend;
-stale snapshots are served immediately while the server refreshes them in the
-background. Missing `/data/*` snapshots are filled from the matching upstream API
-with a short timeout, then written atomically for future requests. All responses
+Public TSS reads are written to a bounded JSON snapshot cache and served through
+their normal `/api/tss/*` route. Fresh snapshots return without touching the
+backend; stale snapshots are served immediately while the server refreshes them
+in the background. Matching `/data/*` paths are also available for diagnostics or
+static-first experiments, but the frontend uses `/api/tss/*` by default so the
+site stays dynamic. All responses
ship `X-Content-Type-Options`, `X-Frame-Options: DENY`, `Referrer-Policy`,
`Permissions-Policy`, `Cross-Origin-Opener-Policy`, `Cross-Origin-Resource-Policy`,
HSTS (over HTTPS), and HTML responses include a Content Security Policy that
@@ -119,7 +119,7 @@ PUBLIC_DATA_CACHE_FRESH_MS=300000
PUBLIC_DATA_CACHE_STALE_MS=86400000
PUBLIC_DATA_PREWARM_INTERVAL_MS=300000
PUBLIC_DATA_COLD_TIMEOUT_MS=8000
-VITE_STATIC_DATA=true
+VITE_STATIC_DATA=false
VITE_SITE_GATE=false
API_RATE_LIMIT_WINDOW_MS=60000
API_RATE_LIMIT_MAX=120
diff --git a/example.env b/example.env
index e7b0dad..6a9e844 100644
--- a/example.env
+++ b/example.env
@@ -63,4 +63,4 @@ DISCORD_INCLUDE_PATCH=true
VITE_TURNSTILE_SITE_KEY=
TURNSTILE_SECRET_KEY=
VITE_SITE_GATE=false
-VITE_STATIC_DATA=true
+VITE_STATIC_DATA=false
diff --git a/frontend/index.html b/frontend/index.html
index 0a9860d..eefd45b 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -38,7 +38,6 @@
} catch {}
window.__TSS_BOOT_PREFERENCES__ = { analyticsPreferences, theme }
- window.__TSS_BOOT_DATA__ = __TSS_BOOT_DATA__
document.documentElement.dataset.theme = theme
document.documentElement.style.colorScheme = theme
document.querySelector('meta[name="theme-color"]')?.setAttribute(
diff --git a/frontend/public/data/README.md b/frontend/public/data/README.md
index a750291..237255a 100644
--- a/frontend/public/data/README.md
+++ b/frontend/public/data/README.md
@@ -1,8 +1,9 @@
# Static Public Data
-The frontend tries these JSON snapshots before falling back to the live API by
-default. The web server serves `/data/*` from the public data cache and fills
-missing snapshots from the matching `/api/tss/*` route with a short timeout.
+The web server serves `/data/*` from the same public data cache used by
+`/api/tss/*`, and fills missing snapshots from the matching API route with a
+short timeout. The frontend uses `/api/tss/*` by default; set
+`VITE_STATIC_DATA=true` only for static-first experiments.
- `/data/leaderboard-teams.json`
- `/data/leaderboard-players.json`
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index aabfb49..8801076 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -52,7 +52,7 @@ const siteVersion = '1.0.1'
const turnstileSiteKey = import.meta.env.VITE_TURNSTILE_SITE_KEY || ''
const siteGateEnabled = String(import.meta.env.VITE_SITE_GATE || 'false').toLowerCase() === 'true'
const staticDataBase = (import.meta.env.VITE_STATIC_DATA_BASE || '/data').replace(/\/+$/, '')
-const staticDataEnabled = String(import.meta.env.VITE_STATIC_DATA || 'true').toLowerCase() !== 'false'
+const staticDataEnabled = String(import.meta.env.VITE_STATIC_DATA || 'false').toLowerCase() === 'true'
const missingStaticDataPaths = new Set()
const defaultAnalyticsPreferences = {
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
index 5671800..f4199eb 100644
--- a/frontend/src/main.jsx
+++ b/frontend/src/main.jsx
@@ -2,4 +2,53 @@ import { createRoot } from 'react-dom/client'
import './styles.css'
import App from './App.jsx'
-createRoot(document.getElementById('root')).render( ${escapeHtml(meta)} #${index + 1} ${escapeHtml(player.nick || player.uid)} ${escapeHtml(player.uid)} · last seen ${escapeHtml(fallbackDate(player.last_seen))} ${fallbackNumber(player.score)} ${fallbackNumber(player.total_battles)} ${fallbackNumber(player.total_kills)} ${fallbackNumber(player.assists)} ${Number(player.win_rate || 0).toFixed(1)}% ${Number(player.kdr || 0).toFixed(2)} ${fallbackNumber(player.teams_seen)}${escapeHtml(title)}
+
Rank
Player
Score
Battles
Kills
Assists
WR
KDR
Teams
+${escapeHtml(match.map_name || 'Unknown map')}
+${escapeHtml(fallbackDate(match.timestamp))} · ${escapeHtml(match.session_id)}
+${fallbackNumber(match.player_count)}v${fallbackNumber(match.player_count)}
+ + ` + }).join('') + + return fallbackShell( + 'Battle Logs', + `${matches.length} battles returned`, + `BorisBot got nothin on THIS
+Powered by Spectra. TSS analytics.
+ +Cached now
+${fallbackNumber(teams.length)} featured teams · ${fallbackNumber(matches.length)} recent games
+ ${teams.slice(0, 4).map((team) => `${escapeHtml(team.name || '')}`).join('')} +