${escapeHtml(g.statusText||String(g.status||"").toUpperCase())}
${escapeHtml(g.away.abbr||initials(g.away.school))}
${escapeHtml(g.away.school)}${g.away.team?" "+escapeHtml(g.away.team):""}
Away
${escapeHtml(String(g.away.score ?? "—"))}
${escapeHtml(g.home.abbr||initials(g.home.school))}
${escapeHtml(g.home.school)}${g.home.team?" "+escapeHtml(g.home.team):""}
Home
${escapeHtml(String(g.home.score ?? "—"))}
`; } function render(){ const sf=sportFilter.value, sch=schoolFilter.value, st=statusFilter.value; const f=gamesData.filter(g=> (sf==="all"||g.sport===sf) && (sch==="all"||g.away.school===sch||g.home.school===sch) && (st==="all"||g.status===st) ); $("games").innerHTML=f.length?f.map(gameCard).join(""):'
No games match these filters.
'; $("totalGames").textContent=f.length; $("liveGames").textContent=f.filter(g=>g.status==="live").length; $("finalGames").textContent=f.filter(g=>g.status==="final").length; $("upcomingGames").textContent=f.filter(g=>g.status==="upcoming").length; $("tickerContent").textContent=f.map(g=>g.status==="upcoming" ?`${icon(g.sport)} ${g.away.school} vs ${g.home.school} — ${g.date||""} ${g.time||""}` :`${icon(g.sport)} ${g.away.school} ${g.away.score} • ${g.home.school} ${g.home.score} — ${g.statusText||g.status}` ).join(" • ") || "No games currently selected."; } function initials(s=""){return s.split(/\s+/).map(x=>x[0]).join("").slice(0,3).toUpperCase()} function escapeHtml(v){return String(v).replace(/[&<>"']/g,c=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]))} function escapeAttr(v){return escapeHtml(v)} [sportFilter,schoolFilter,statusFilter].forEach(x=>x.addEventListener("change",render)); $("resetBtn").addEventListener("click",()=>{sportFilter.value="all";schoolFilter.value="all";statusFilter.value="all";render()}); $("refreshBtn").addEventListener("click",()=>loadScores(true)); loadScores(); setInterval(()=>loadScores(false),REFRESH_MS);