Su
Mo
Tu
We
Th
Fr
Sa
πŸ“…
Select a Date
Choose a date above to view NBA AI picks for that day.

⚠️ Model output only β€” not financial advice. Past performance does not guarantee future results.

function closeExplain() { document.getElementById('explainOverlay').style.display = 'none'; } function openNBAExplainModal(row, away, home) { const matchup = row['Matchup (Away @ Home)'] || `${away} @ ${home}`; const date = row['Date'] || ''; document.getElementById('explainMatchup').textContent = matchup; document.getElementById('explainSub').textContent = (date ? isoToDisplay(date) + ' Β· ' : '') + 'πŸ€ NBA Β· Moneyline'; buildNBAExplanation(row, away, home); // instant rule-based document.getElementById('explainOverlay').style.display = 'flex'; tryAIExplanation(row, 'nba', away, home); // async AI upgrade } async function tryAIExplanation(row, sport, away, home) { const gameKey = `${row['Date']||''}|${row['Matchup (Away @ Home)']||''}`; if (_explainCache[gameKey]) { renderAIBody(_explainCache[gameKey]); return; } if (_explainCount >= SESSION_LIMIT) return; const now = Date.now(); if (now - _lastCallTime < DEBOUNCE_MS) return; _lastCallTime = now; document.getElementById('explainBody').innerHTML = `
AI analysis loading…
`; try { const res = await fetch(EXPLAIN_API, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sport, game: row }), }); if (!res.ok) { buildNBAExplanation(row, away, home); return; } const data = await res.json(); if (data.explanation) { _explainCount++; sessionStorage.setItem('mlai_exp_count', _explainCount); _explainCache[gameKey] = data.explanation; renderAIBody(data.explanation); } } catch (_) { buildNBAExplanation(row, away, home); } } function renderAIBody(text) { document.getElementById('explainBody').innerHTML = `
${text}
🧠 AI Analysis
`; } function buildNBAExplanation(row, away, home) { const predRaw = row['Predicted Score (Away-Home)'] || '0-0'; const [pa, ph] = predRaw.split('-').map(x => parseFloat(x)||0); const picked = pa > ph ? away : home; const margin = Math.abs(pa-ph).toFixed(1); const predTotal = parseFloat(row['Predicted Total']||(pa+ph)).toFixed(1); const winProb = (() => { const candidates = [row['Cover Probability'], row['Home Win Probability']]; for (const c of candidates) { const pct = toProbPct(c); if (pct !== null) return pct; } return 0; })(); const vegasImpl = row['Vegas Implied Prob'] ? parseFloat(row['Vegas Implied Prob']) : null; const lineupH = row['Home Lineup Strength'] ? (parseFloat(row['Home Lineup Strength'])*100).toFixed(0) : null; const lineupA = row['Away Lineup Strength'] ? (parseFloat(row['Away Lineup Strength'])*100).toFixed(0) : null; const injH = row['Home Injury Notes'] && row['Home Injury Notes']!=='Full strength' ? row['Home Injury Notes'] : null; const injA = row['Away Injury Notes'] && row['Away Injury Notes']!=='Full strength' ? row['Away Injury Notes'] : null; const confColor = winProb>=65?'var(--green)':winProb>=60?'var(--amber)':'var(--muted)'; const confTier = winProb>=65?'HIGH':winProb>=60?'MEDIUM':'LOW'; document.getElementById('explainVerdict').innerHTML = `
Model Pick
${picked}
ML Β· predicted by ${margin} pts
Confidence
${winProb.toFixed(0)}%
${confTier} CONFIDENCE
`; let n = `Our ensemble model predicts ${picked} to win with a ${winProb.toFixed(0)}% win probability`; if (vegasImpl!==null && !isNaN(vegasImpl)) { const ev=winProb-vegasImpl; const ec=ev>0?'var(--green)':'var(--red)'; n += ` vs. Vegas's implied ${vegasImpl.toFixed(0)}% (EV: ${(ev>=0?'+':'')+ev.toFixed(1)}%)`; } n += `. Predicted score: ${Math.round(pa)} – ${Math.round(ph)}, total ${predTotal} pts. `; if (lineupA&&lineupH) { const diff=Math.abs(parseFloat(lineupA)-parseFloat(lineupH)); const s=parseFloat(lineupA)>parseFloat(lineupH)?away:home; n += diff>=5?`Lineup edge to ${s} (${lineupA}% vs ${lineupH}%). `:`Rosters evenly matched (${lineupA}% vs ${lineupH}%). `; } if (injA) n += `⚠️ ${away}: ${injA}. `; if (injH) n += `⚠️ ${home}: ${injH}. `; document.getElementById('explainBody').innerHTML = `
${n}
`; const factors = [ {label:`${away} Pred`,value:`${Math.round(pa)} pts`,color:pa>ph?'var(--green)':'var(--muted)'}, {label:`${home} Pred`,value:`${Math.round(ph)} pts`,color:ph>pa?'var(--green)':'var(--muted)'}, {label:'Pred Total', value:`${predTotal} pts`, color:'var(--text)'}, {label:'Win Prob', value:`${winProb.toFixed(0)}%`,color:confColor}, ]; if (lineupA) factors.push({label:`${away} Lineup`,value:`${lineupA}%`,color:'var(--text)'}); if (lineupH) factors.push({label:`${home} Lineup`,value:`${lineupH}%`,color:'var(--text)'}); if (vegasImpl) factors.push({label:'Vegas Implied',value:`${vegasImpl.toFixed(0)}%`,color:'var(--muted)'}); document.getElementById('explainFactors').innerHTML = `
Key Factors
${factors.map(f=>`
${f.label}
${f.value}
`).join('')}
`; }

⚠️ Model output only β€” not financial advice. Past performance does not guarantee future results. Picks are for informational and entertainment purposes only.

-->