function fmtSize(b) { if (!b) return '0 B'; const k = 1024, s = ['B','KB','MB','GB']; const i = Math.floor(Math.log(b) / Math.log(k)); return parseFloat((b / Math.pow(k, i)).toFixed(1)) + ' ' + s[i]; } function fmtDate(d) { if (!d) return ''; const dt = new Date(d); return dt.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) + ' ' + dt.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } function fmtThickness(t) { if (t == null) return '\u2014'; return `${t.toFixed(4)}"`; } function esc(s) { return s ? s.replace(//g,'>').replace(/"/g,'"').replace(/'/g,''') : ''; } function setPage(title, tag = '') { document.getElementById('page-title').textContent = title; document.getElementById('page-tag').textContent = tag; document.getElementById('page-tag').style.display = tag ? '' : 'none'; } const api = { async get(url) { const r = await fetch(url); if (!r.ok) throw new Error(`${r.status} ${r.statusText}`); return r.json(); } };