'+esc(vT)+'

'+STATE.game.visitor.lineup.filter(function(s,i){var dh=getDHIdx(STATE.game.visitor.lineup),p=getPIdx(STATE.game.visitor.lineup);var g=STATE.game.visitor;if(i<9)return true;if(i===9)return g.use10th;if(i===dh)return g.showDH;if(i===p)return g.showP;return s.active!==false}).map(function(s,i){return''}).join('')+'
#JerseyPlayerPosNotes
'+(i+1)+''+esc(s.num)+''+esc(s.name)+''+esc(s.pos)+''+esc(s.notes||'')+'

'+esc(hT)+'

'+STATE.game.home.lineup.filter(function(s,i){var dh=getDHIdx(STATE.game.home.lineup),p=getPIdx(STATE.game.home.lineup);var g=STATE.game.home;if(i<9)return true;if(i===9)return g.use10th;if(i===dh)return g.showDH;if(i===p)return g.showP;return s.active!==false}).map(function(s,i){return''}).join('')+'
#JerseyPlayerPosNotes
'+(i+1)+''+esc(s.num)+''+esc(s.name)+''+esc(s.pos)+''+esc(s.notes||'')+'
');w.document.close();w.onload=function(){w.print()}} function confirmResetGame(){if(!confirm('Reset game?'))return;STATE.game.visitor.lineup=mkLineup();STATE.game.home.lineup=mkLineup();STATE.game.visitor.teamId='';STATE.game.home.teamId='';STATE.game.visitor.runs=0;STATE.game.home.runs=0;STATE.game.inning=1;STATE.game.visitor.battingIdx=-1;STATE.game.home.battingIdx=-1;STATE.game.visitor.use10th=false;STATE.game.home.use10th=false;STATE.game.visitor.showDH=true;STATE.game.home.showDH=true;STATE.game.visitor.showP=true;STATE.game.home.showP=true;document.getElementById('firstPitchDisplay').innerText='--:--';resetWx();renderLineup('visitor');renderLineup('home');renderDDs();saveGame();updateSB()} function setTheme(mode){STATE.settings.theme=mode;saveSettings();document.body.classList.toggle('dark-mode',mode==='dark');document.getElementById('lightModeBtn').classList.toggle('active',mode==='light');document.getElementById('darkModeBtn').classList.toggle('active',mode==='dark')} function clearCache(){if(confirm('Clear ALL cached data?')){if(confirm('FINAL WARNING: Are you sure?')){clearAllCache();alert('Cache cleared! Reloading...');window.location.reload(true)}}} function markPitch(){if(STATE.cdTimer){clearInterval(STATE.cdTimer);STATE.cdTimer=null}STATE.cdTarget=null;var d=new Date();var h=d.getHours()%12||12;document.getElementById("firstPitchDisplay").innerText=h+':'+String(d.getMinutes()).padStart(2,'0')} function setCountdown(){var inp=prompt("Countdown (HH:MM):");if(!inp)return;var parts=inp.split(':');var hh=parseInt(parts[0]),mm=parseInt(parts[1]);if(isNaN(hh)||isNaN(mm))return;var target=new Date();target.setHours(target.getHours()+hh,target.getMinutes()+mm,0,0);STATE.cdTarget=target;if(STATE.cdTimer)clearInterval(STATE.cdTimer);function tick(){var diff=STATE.cdTarget-new Date();var el=document.getElementById("firstPitchDisplay");if(diff<=0){el.innerText="00:00";clearInterval(STATE.cdTimer);STATE.cdTimer=null}else{var ts=Math.floor(diff/1000);el.innerText=String(Math.floor(ts/60)).padStart(2,'0')+':'+String(ts%60).padStart(2,'0')}}tick();STATE.cdTimer=setInterval(tick,500)} function startWx(){if(STATE.wxTimer)clearInterval(STATE.wxTimer);STATE.wxSeconds=1800;function tick(){if(STATE.wxSeconds<=0){document.getElementById("wxTimerDisplay").innerText="00:00";clearInterval(STATE.wxTimer);return}var m=Math.floor(STATE.wxSeconds/60),s=STATE.wxSeconds%60;document.getElementById("wxTimerDisplay").innerText=String(m).padStart(2,'0')+':'+String(s).padStart(2,'0');STATE.wxSeconds--}tick();STATE.wxTimer=setInterval(tick,1000)} function resetWx(){if(STATE.wxTimer)clearInterval(STATE.wxTimer);STATE.wxSeconds=0;document.getElementById("wxTimerDisplay").innerText="--:--"} function printScript(){var w=window.open('','_blank');w.document.write('
'+esc(document.getElementById('scriptTextarea').value)+'
');w.document.close();w.onload=function(){w.print()}} function clearScript(){document.getElementById('scriptTextarea').value='';STATE.script='';localStorage.removeItem('vdw_script')} function loadScriptFile(input){var f=input.files[0];if(!f)return;var r=new FileReader();r.onload=function(e){document.getElementById('scriptTextarea').value=e.target.result;STATE.script=e.target.result;localStorage.setItem('vdw_script',e.target.result)};r.readAsText(f)} function saveScript(){STATE.script=document.getElementById('scriptTextarea').value;localStorage.setItem('vdw_script',STATE.script)} function newTeam(){var id=Date.now().toString();STATE.teams[id]={id:id,name:"New Team",players:[]};addNAXPlayersToTeam(STATE.teams[id]);saveTeams();renderTeamList();renderDDs();editTeam(id)} function renderTeamList(){var c=document.getElementById('teamListContainer');c.innerHTML=Object.keys(STATE.teams).map(function(k){var cnt=STATE.teams[k].players?STATE.teams[k].players.filter(function(p){return p.name!=="NA"&&p.name!=="X"}).length:0;return'
'+esc(STATE.teams[k].name)+' ('+cnt+' players)
'}).join('')} function editTeam(id){var t=STATE.teams[id];if(!t)return;var ws=document.getElementById('rosterWorkspace');var posSelectOptions='';POSITIONS.forEach(function(pos){posSelectOptions+=''});ws.innerHTML='
#NamePositionPronNotesPhoto
';var g=document.getElementById('rosterEditGrid');t.players.forEach(function(p){addPRow(g,p,posSelectOptions)});document.getElementById('svBtn').onclick=function(){t.name=document.getElementById('editTeamName').value;t.players=collectP(g);addNAXPlayersToTeam(t);saveTeams();renderTeamList();renderDDs();renderLineup('visitor');renderLineup('home');alert('✅ Team saved!')};document.getElementById('adBtn').onclick=function(){addPRow(g,{number:'',name:'',position:'',pronunciation:'',college:'',photo:''},posSelectOptions)};document.getElementById('delBtn').onclick=function(){deleteTeam(id)};document.getElementById('blkBtn').onclick=function(){var c=document.getElementById('bulkAddContainer');c.style.display=c.style.display==='none'?'block':'none'};document.getElementById('bulkAddBtn').onclick=function(){var txt=document.getElementById('bulkAddText').value;var ls=txt.split(/\r?\n/);var added=0;ls.forEach(function(l){if(!l.trim())return;var num='',name='';var m=l.match(/^(\d+)\s+(.+)/);if(m){num=m[1];name=m[2].trim()}else{name=l.trim()}addPRow(g,{number:num,name:name,position:'',pronunciation:'',college:'',photo:''},posSelectOptions);added++});if(added>0){document.getElementById('bulkAddText').value='';alert('✅ Added '+added+' players! Click SAVE to keep them.')}}} function addPRow(g,p,posSelectOptions){var d=document.createElement('div');d.className='player-row';var sp=p.position||'';d.innerHTML='';g.appendChild(d)} function collectP(g){var a=[];g.querySelectorAll('.player-row').forEach(function(rw){var inp=rw.querySelectorAll('input,select');a.push({number:inp[0].value,name:inp[1].value,position:inp[2].value,pronunciation:inp[3].value,college:inp[4].value,photo:inp[5]?inp[5].value:''})});return a} function deleteTeam(id){if(!confirm('Delete team "'+STATE.teams[id].name+'"?'))return;delete STATE.teams[id];saveTeams();renderTeamList();renderDDs();document.getElementById('rosterWorkspace').innerHTML='';if(STATE.game.visitor.teamId===id){STATE.game.visitor.teamId='';STATE.game.visitor.lineup=mkLineup();renderLineup('visitor')}if(STATE.game.home.teamId===id){STATE.game.home.teamId='';STATE.game.home.lineup=mkLineup();renderLineup('home')}updateSB();saveGame()} function cloudSaveTeam(teamId){var team=STATE.teams[teamId];if(!team)return;if(!confirm('Save team "'+team.name+'" to cloud?'))return;fetch(CLOUD_API_BASE+'?id=team_'+encodeURIComponent(teamId),{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(team)}).then(function(r){if(!r.ok)throw new Error('HTTP '+r.status);alert('✅ Team saved.')}).catch(function(e){alert('❌ '+e.message)})} function cloudLoadTeam(){fetch(CLOUD_API_BASE+'?list=true').then(function(r){return r.json()}).then(function(data){var keys=(data.keys||[]).filter(function(k){return k.startsWith('team_')});if(!keys.length){alert('No teams found.');return}var key=prompt('Enter team key:\n'+keys.join(', '));if(!key)return;if(!key.startsWith('team_'))key='team_'+key;fetch(CLOUD_API_BASE+'?id='+encodeURIComponent(key)).then(function(r){return r.json()}).then(function(team){if(!team.id||!team.name)throw new Error('Invalid data');if(STATE.teams[team.id]&&!confirm('Team exists. Overwrite?'))return;addNAXPlayersToTeam(team);STATE.teams[team.id]=team;saveTeams();renderTeamList();renderDDs();editTeam(team.id);alert('✅ Team loaded.')}).catch(function(e){alert('❌ '+e.message)})}).catch(function(e){alert('❌ '+e.message)})} async function cloudDelete(id,li){if(!confirm('Delete "'+id+'"?'))return;var st=document.getElementById('cloud-status');st.textContent='Deleting...';try{var r=await fetch(CLOUD_API_BASE+'?id='+encodeURIComponent(id),{method:'DELETE'});if(!r.ok)throw new Error('HTTP '+r.status);if(li)li.remove();st.textContent='✅ Deleted.';setTimeout(cloudList,800)}catch(e){st.textContent='❌ '+e.message}} function renderAdmin(){var p=document.getElementById('adminPanel');p.innerHTML='

ADMIN SUITE

Branding

Team Colors

HUD Colors

At-Bat

Cloud

'} function saveAdmin(){var f=document;STATE.settings.brand=f.getElementById('adminBrand').value;STATE.settings.subtext=f.getElementById('adminSubtext').value;STATE.settings.subtextColor=f.getElementById('subtextColor').value;STATE.settings.atbatBg=f.getElementById('atbatBg').value;STATE.settings.atbatText=f.getElementById('atbatText').value;STATE.settings.awayColor=f.getElementById('awayColor').value;STATE.settings.homeColor=f.getElementById('homeColor').value;STATE.settings.hudAwayBg=f.getElementById('hudAwayBg').value;STATE.settings.hudHomeBg=f.getElementById('hudHomeBg').value;applyAllStyles();saveSettings();alert('Applied!');renderLineup('visitor');renderLineup('home')} function applyAllStyles(){var r=document.documentElement.style;r.setProperty('--atbat-bg',STATE.settings.atbatBg||'#fff9c4');r.setProperty('--atbat-text',STATE.settings.atbatText||'#000');r.setProperty('--away-color',STATE.settings.awayColor||'#1d4ed8');r.setProperty('--home-color',STATE.settings.homeColor||'#c41e3a');r.setProperty('--hud-away-bg',STATE.settings.hudAwayBg||'#e8f0fe');r.setProperty('--hud-home-bg',STATE.settings.hudHomeBg||'#fce8e8');document.querySelector('.brand-text p').style.color=STATE.settings.subtextColor||'#e6b422'} function exportAll(){var d={teams:STATE.teams,game:STATE.game,settings:STATE.settings,script:STATE.script};var a=document.createElement('a');a.href=URL.createObjectURL(new Blob([JSON.stringify(d)],{type:'application/json'}));a.download='backup-'+new Date().toISOString().slice(0,10)+'.json';a.click()} function importAll(input){var f=input.files[0];if(!f)return;var r=new FileReader();r.onload=function(e){try{var d=JSON.parse(e.target.result);if(d.teams){STATE.teams=d.teams;for(var tid in STATE.teams)addNAXPlayersToTeam(STATE.teams[tid])}if(d.settings)STATE.settings=d.settings;if(d.script){STATE.script=d.script;document.getElementById('scriptTextarea').value=d.script}rebuildPositions();applyAllStyles();saveTeams();saveSettings();renderDDs();renderLineup('visitor');renderLineup('home');renderTeamList();renderAdmin();alert('Restored!')}catch(ex){alert('Invalid file.')}};r.readAsText(f)} function getSerializableState(){var c=JSON.parse(JSON.stringify(STATE));delete c.wxTimer;delete c.cdTimer;delete c.cdTarget;return c} async function cloudSave(){var id=document.getElementById('cloud-save-id').value.trim();if(!id)return;if(!confirm('Save as "'+id+'"?'))return;var st=document.getElementById('cloud-status');st.textContent='Saving...';try{var p=getSerializableState();var r=await fetch(CLOUD_API_BASE+'?id='+encodeURIComponent(id),{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(p)});if(!r.ok)throw new Error('HTTP '+r.status);st.textContent='Saved.'}catch(e){st.textContent='Error: '+e.message}} async function cloudLoad(){var id=document.getElementById('cloud-save-id').value.trim();if(!id)return;if(!confirm('Load "'+id+'"?'))return;var st=document.getElementById('cloud-status');st.textContent='Loading...';try{var r=await fetch(CLOUD_API_BASE+'?id='+encodeURIComponent(id));if(!r.ok)throw new Error('HTTP '+r.status);var d=await r.json();if(d.teams){STATE.teams=d.teams;for(var tid in STATE.teams)addNAXPlayersToTeam(STATE.teams[tid])}if(d.settings)STATE.settings=d.settings;if(d.script){STATE.script=d.script;document.getElementById('scriptTextarea').value=d.script}rebuildPositions();applyAllStyles();renderDDs();renderLineup('visitor');renderLineup('home');renderTeamList();renderAdmin();saveTeams();saveSettings();st.textContent='Loaded (teams only).'}catch(e){st.textContent='Error: '+e.message}} async function cloudList(){var st=document.getElementById('cloud-status'),le=document.getElementById('cloud-list');st.textContent='Listing...';try{var r=await fetch(CLOUD_API_BASE+'?list=true');var d=await r.json();le.innerHTML='';if(d.keys&&d.keys.length){d.keys.forEach(function(k){var li=document.createElement('li');li.textContent=k;li.style.cursor='pointer';li.onclick=function(){document.getElementById('cloud-save-id').value=k};var del=document.createElement('button');del.textContent='X';del.style.cssText='margin-left:8px;background:var(--accent-red);color:#fff;border:none;border-radius:4px;font-size:.7rem;';del.onclick=function(e){e.stopPropagation();cloudDelete(k,li)};li.appendChild(del);le.appendChild(li)});st.textContent=d.keys.length+' save(s).'}else{st.textContent='No saves.'}}catch(e){st.textContent='Error: '+e.message}} document.querySelectorAll('.nav-link').forEach(function(b){b.onclick=function(){document.querySelectorAll('.view-pane').forEach(function(p){p.classList.remove('active')});document.getElementById(this.dataset.view).classList.add('active');document.querySelectorAll('.nav-link').forEach(function(n){n.classList.remove('active')});this.classList.add('active');if(this.dataset.view==='roster')renderTeamList();if(this.dataset.view==='admin')renderAdmin()}}); (function updateClock(){document.getElementById('footerClock').innerText=new Date().toLocaleTimeString('en-US',{hour:'2-digit',minute:'2-digit',second:'2-digit'});setTimeout(updateClock,1000)})(); rebuildPositions();renderDDs();renderLineup('visitor');renderLineup('home');updateSB(); var savedScript=localStorage.getItem('vdw_script');if(savedScript){STATE.script=savedScript;document.getElementById('scriptTextarea').value=savedScript} window.markPitch=markPitch;window.setCountdown=setCountdown;window.startWx=startWx;window.resetWx=resetWx; window.chRuns=chRuns;window.chInning=chInning;window.printBothLineups=printBothLineups;window.confirmResetGame=confirmResetGame; window.setTheme=setTheme;window.markAB=markAB;window.updPlayerFromSelect=updPlayerFromSelect;window.updPos=updPos;window.updNotes=updNotes;window.updNum=updNum; window.clearSide=clearSide;window.printScript=printScript;window.clearScript=clearScript;window.loadScriptFile=loadScriptFile;window.saveScript=saveScript; window.newTeam=newTeam;window.editTeam=editTeam;window.exportAll=exportAll;window.importAll=importAll;window.saveAdmin=saveAdmin; window.cloudSave=cloudSave;window.cloudLoad=cloudLoad;window.cloudList=cloudList;window.deleteTeam=deleteTeam; window.cloudSaveTeam=cloudSaveTeam;window.cloudLoadTeam=cloudLoadTeam; window.toggleSlot=toggleSlot;window.toggleHeaderSlot=toggleHeaderSlot;window.clearCache=clearCache;window.cloudDelete=cloudDelete; window.addPlayerToLineup=addPlayerToLineup; })();