// in the ), OR by editing the fallback string on the next line.
// If left as-is with no backend reachable, the game safely falls back to a per-device board.
const LB_API = (typeof window!=='undefined' && window.TANKMAN_LB_API)
? window.TANKMAN_LB_API
: ('__PORT_8000__'.startsWith('__') ? 'http://localhost:8000' : '__PORT_8000__');
// In a standalone / offline build there is no backend, so use a local
// (this-browser-only) leaderboard stored in localStorage.
let LB_LOCAL = !!window.__STANDALONE;
let lbRange = 'week';
let lbLastId = null; // row id of the score this player just submitted (to highlight)
function esc(s){ return String(s==null?'':s).replace(/[&<>"']/g, c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); }
/* ---- local (offline) leaderboard store ---- */
const LB_KEY = 'tankman_leaderboard_v1';
function lbLocalAll(){ try{ return JSON.parse(localStorage.getItem(LB_KEY)||'[]'); }catch(e){ return []; } }
function lbLocalSave(rows){ try{ localStorage.setItem(LB_KEY, JSON.stringify(rows)); }catch(e){} }
// Most recent Sunday 00:00 America/Los_Angeles, as an epoch-ms cutoff.
function weekStartPacificMs(){
const now = new Date();
// Current time expressed in Pacific wall-clock parts
const parts = new Intl.DateTimeFormat('en-US', {
timeZone:'America/Los_Angeles', weekday:'short',
year:'numeric', month:'2-digit', day:'2-digit',
hour:'2-digit', minute:'2-digit', second:'2-digit', hour12:false
}).formatToParts(now).reduce((o,p)=>{o[p.type]=p.value;return o;},{});
const dayMap = {Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6};
const dow = dayMap[parts.weekday];
// Seconds elapsed since Pacific midnight today
const secToday = (+parts.hour)*3600 + (+parts.minute)*60 + (+parts.second);
// ms since the most recent Sunday 00:00 Pacific
const elapsed = (dow*86400 + secToday) * 1000;
return now.getTime() - elapsed;
}
function lbLocalTop(range){
let rows = lbLocalAll();
if(range === 'week'){
const wk = weekStartPacificMs(); // most recent Sunday 00:00 Pacific
rows = rows.filter(r => (r.ts||0) >= wk);
}
// best score per username
const best = {};
for(const r of rows){
if(!best[r.username] || r.score > best[r.username].score) best[r.username] = r;
}
return Object.values(best).sort((a,b)=> b.score - a.score).slice(0,20);
}
function lbLocalInsert(rec){
const rows = lbLocalAll();
rec.id = 'l' + Date.now() + '_' + Math.floor(Math.random()*1e4);
rec.ts = Date.now();
rows.push(rec);
lbLocalSave(rows);
return rec.id;
}
function lbRender(rows){
const list = document.getElementById('lbList');
if(!rows.length){ list.innerHTML = '