let csrfToken="", thinkingCount=0, thinkingTimer=null;
    function setGlobalThinking(on){const el=document.getElementById("thinkingToast");if(el)el.classList.toggle("hide",!on)}
    function clearGlobalThinking(){thinkingCount=0;if(thinkingTimer){clearTimeout(thinkingTimer);thinkingTimer=null}setGlobalThinking(false)}
    function beginGlobalThinking(options={}){if(options?.quiet)return()=>{};let active=true;thinkingCount++;if(!thinkingTimer)thinkingTimer=setTimeout(()=>{thinkingTimer=null;if(thinkingCount>0)setGlobalThinking(true)},180);return()=>{if(!active)return;active=false;thinkingCount=Math.max(0,thinkingCount-1);if(thinkingCount===0){if(thinkingTimer){clearTimeout(thinkingTimer);thinkingTimer=null}setGlobalThinking(false)}}}
    const APP_VERSION=window.YSP_APP_VERSION||"__APP_VERSION__", API_BASE=window.YSP_API_BASE||"api.php", apiUrl=action=>API_BASE+"?action="+encodeURIComponent(action)+"&_="+Date.now(), $=id=>document.getElementById(id), delay=ms=>new Promise(resolve=>setTimeout(resolve,ms)), screens=["loading","loginStart","auth","teamPick","menu","managerSavesPage","optionsPage","admin","manager","match"].map($).filter(Boolean), api=(action,data={},options={})=>{const done=beginGlobalThinking(options),h={"Content-Type":"application/json","Cache-Control":"no-cache"};if(csrfToken)h["X-CSRF-Token"]=csrfToken;return fetch(apiUrl(action),{method:"POST",cache:"no-store",headers:h,body:JSON.stringify(data)}).then(r=>r.json()).then(r=>{if(r?.csrfToken)csrfToken=r.csrfToken;if(shouldForceClientLogout(action,r))forceClientLogout(r?.loggedOut?"Logged out":"");return r}).finally(done)};
    const POLL_MS=260, MANAGER_POLL_MS=2000, MANAGER_FULL_REFRESH_MS=15000, MENU_INVITE_POLL_MS=1500, VERSION_CHECK_MS=15000, INTERP_MIN=150, INTERP_MAX=380, INTRO_MS=4300, LINEUP_MS=10000, FINAL_SCORERS_MS=10000, MANAGER_SIM_PLAYBACK_MS=60000, MANAGER_SIM_LOAD_SETTLE_MS=260, MANAGER_BUSY_STALE_MS=10000, MAX_MATCH_SUBS=5, MAX_BENCH_TRAINING=5;
    let me=null, match=null, poll=null, pollBusy=false, managerPoll=null, managerPollBusy=false, menuInvitePoll=null, menuInvitePollBusy=false, lastMatchAt=0, W=1,H=1,p={}, view=emptyView(), goalFx=null, goalBanner=null, refView=null, introMatchId=null, introUntil=0, crowdMatchId=null, crowdWanted=false, crowdActive=0, crowdFading=false, lineupMatchId=null, lineupUntil=0, finalTimer=null, finalMatchId=null, matchReturnBusy=false, audio=null;
    let trainingMode=false, trainingData=null, trainingSelection=[], trainingRace=null, trainingShot=null, trainingScenario="speed", trainingLast=0, trainingDivisionId="", trainingTeamId="";
    let managerUsers=[], managerPicked=[], managerDraftTeams={}, managerInviteDraftTeams={}, managerCreateMode="", managerTeamMenuOpen="", managerSeason=null, managerSeasonServerAt=0, managerSeasonReceivedAt=0, managerLastRevision="", managerLastFullRefreshAt=0, managerFinance=null, managerSquad=null, managerMarket=[], managerTransferOffers={incoming:[],outgoing:[],notices:[]}, managerTurnAlerts=[], managerPrivateChatAlerts=[], managerPrivateChatTarget="", managerPrivateChatMessages=[], managerInvites=[], managerDivisions=[], managerSaveUsers=[], managerViewDivision=null, managerAbortConfirm=false, managerMarketNotice="", managerScoutNotice="", managerScoutResults=[], managerMarketRoleFilter="", managerSquadSellRoleFilter="", managerBrowseLevel=5, managerBrowseTeam="", managerBrowseNotice="", managerBrowseRoleFilter="", managerBrowseTeamDetails=null, managerScorersScope="league", managerScorersContext=null, managerBusy=false, managerBusySince=0, managerHasSeason=false, managerCanContinue=false, managerHasAnySave=false, managerAutoStartFixture=null, managerAutoContinueBusy=false, managerAutoContinueLastAt=0, squadSwapFirst=null, squadSwapSecond=null, squadSwapBusy=false, squadPlacementMode=false, squadSwapFirstSource="", squadBenchActionPlayer=null, squadRoleFilter="", squadRosterOpen={start:false,bench:false}, currentTeamDetailsUser="", currentTeamDetails=null, managerTeamBackTarget="", managerTeamInfoOpen=false, managerSaves=[], teamChoices=[], transferOffer=null, adminUsers=[], managerMsgTimer=null, managerSimTimer=null, managerSimRunning=false, managerSimWhistledGoals=new Set(), touchlinesView=null, managerDealReturnSection="", managerDealReturnView=null, managerDealReturnFixture=null;
    let managerTeamMenuScrollTop={}, managerTeamMenuTouchY=0;
    let currentScreen="", appHistoryReady=false, appRestoringHistory=false, appHistoryDepth=0;
    let clientDebugQueue=[], clientDebugTimer=null, clientDebugSending=false;
    function clientDebugData(data){
      try{return JSON.parse(JSON.stringify(data??{}))}catch(e){return{unserializable:String(e?.message||e)}}
    }
    function clientDebugLog(type,message,data={},scope="app",immediate=false){
      clientDebugQueue.push({at:new Date().toISOString(),type:String(type||"debug"),scope,message:String(message||""),data:clientDebugData(data)});
      if(clientDebugQueue.length>240)clientDebugQueue=clientDebugQueue.slice(-240);
      if(immediate)return clientDebugFlush();
      if(!clientDebugTimer)clientDebugTimer=setTimeout(clientDebugFlush,1600);
    }
    function clientDebugFlush(){
      if(clientDebugSending||!clientDebugQueue.length)return;
      if(clientDebugTimer){clearTimeout(clientDebugTimer);clientDebugTimer=null}
      const events=clientDebugQueue.splice(0,80),headers={"Content-Type":"application/json","Cache-Control":"no-cache"};
      if(csrfToken)headers["X-CSRF-Token"]=csrfToken;
      clientDebugSending=true;
      fetch(apiUrl("clientDebugLog"),{method:"POST",cache:"no-store",headers,body:JSON.stringify({events})}).catch(()=>{clientDebugQueue=events.concat(clientDebugQueue).slice(-240)}).finally(()=>{clientDebugSending=false;if(clientDebugQueue.length&&!clientDebugTimer)clientDebugTimer=setTimeout(clientDebugFlush,2200)});
    }
    addEventListener("error",e=>clientDebugLog("window_error",e.message||"window error",{file:e.filename,line:e.lineno,col:e.colno,error:e.error?.stack||String(e.error||"")},"app",true));
    addEventListener("unhandledrejection",e=>clientDebugLog("unhandled_rejection",e.reason?.message||String(e.reason||"rejection"),{reason:e.reason?.stack||String(e.reason||"")},"app",true));
    addEventListener("pagehide",()=>clientDebugFlush());
    const ROUTE_KEY="yspRoute", SOUND_KEY="yspSound", SOUND_FILE_KEY="yspSoundFiles", SOUND_FILES=[
      {id:"menuMusic",label:"MENU MUSIC",file:"menu.mp3"},
      {id:"crowdSound",label:"CROWD",file:"crowd.mp3"},
      {id:"crowdSoundB",label:"CROWD 2",file:"crowd2.mp3"},
      {id:"crowdGoalSound",label:"GOAL CHEER",file:"crowd_score.mp3"},
      {id:"critSound",label:"CRIT PLAYER",file:"crit_player.mp3"},
      {id:"whistleAudio",label:"WHISTLE",file:"whistle.ogg"},
      {id:"shotSound",label:"KICK / SHOT",file:"kick.ogg"},
    ];
    let soundSettings={};
    try{soundSettings=JSON.parse(localStorage.getItem(SOUND_FILE_KEY)||"{}")||{}}catch(e){soundSettings={}}
    let soundEnabled=true;
    const APP_PLACEHOLDER="__"+"APP_VERSION__";
    let appReloading=false, pendingAppVersion="", lastVersionCheckAt=0;
    function realAppVersion(v=APP_VERSION){return v&&v!==APP_PLACEHOLDER?String(v):""}
    function cacheBustedUrl(version){const u=new URL(location.href);u.searchParams.set("v",version);u.searchParams.set("_",Date.now());return u.toString()}
    function forceAppReload(version=realAppVersion()){if(appReloading||!version)return true;appReloading=true;if($("loading"))show("loading");try{sessionStorage.setItem("yspReloadVersion",version)}catch(e){}location.replace(cacheBustedUrl(version));return true}
    function appVersionReloadAllowed(){
      const screen=visibleScreen(),serverMatchActive=!!(match&&["waiting","ready","active"].includes(String(match.status||""))),managerMatchActive=!!(managerSimRunning||(touchlinesView&&!touchlinesView.finished));
      if(serverMatchActive||managerMatchActive||managerBusy)return false;
      return ["loading","loginStart","auth","teamPick","menu","manager","managerSavesPage","optionsPage","admin","match"].includes(screen);
    }
    function maybeApplyPendingVersion(){return pendingAppVersion&&appVersionReloadAllowed()?forceAppReload(pendingAppVersion):false}
    function checkLoadedVersion(version,force=false){version=realAppVersion(version);const loaded=realAppVersion();if(!version||!loaded)return false;if(version===loaded){pendingAppVersion="";return false}pendingAppVersion=version;return force||appVersionReloadAllowed()?forceAppReload(version):false}
    async function checkRemoteVersion(force=false){const now=Date.now();if(!force&&now-lastVersionCheckAt<VERSION_CHECK_MS)return;lastVersionCheckAt=now;try{const r=await fetch(apiUrl("version"),{cache:"no-store",headers:{"Cache-Control":"no-cache"}}).then(x=>x.json());if(r?.ok)checkLoadedVersion(r.appVersion,force&&appVersionReloadAllowed())}catch(e){}}
    addEventListener("pageshow",e=>{if(e.persisted)location.reload();else checkRemoteVersion(true)});
    addEventListener("focus",()=>{checkRemoteVersion();refreshMenuInvite();refreshManager()});
    document.addEventListener("visibilitychange",()=>{if(!document.hidden){checkRemoteVersion();refreshMenuInvite();refreshManager()}});
    setInterval(checkRemoteVersion,VERSION_CHECK_MS);
    function show(id){if(!$(id))id=me?"menu":"auth";currentScreen=id;screens.forEach(s=>s.classList.toggle("hide",s.id!==id));syncScreenPolls();syncManagerMenuMusic();maybeApplyPendingVersion()}
    function syncScreenPolls(){if(currentScreen==="menu"&&me)startMenuInvitePoll();else stopMenuInvitePoll()}
    function visibleScreen(){return currentScreen||screens.find(s=>s&&!s.classList.contains("hide"))?.id||""}
    function appHistoryState(screen=visibleScreen()){return{ysp:true,screen,managerSection:screen==="manager"?currentManagerSection():""}}
    function sameAppState(a,b){return !!a&&!!b&&a.ysp&&b.ysp&&a.screen===b.screen&&(a.managerSection||"")===(b.managerSection||"")}
    function replaceAppHistory(){if(!history.replaceState)return;const s=appHistoryState();try{history.replaceState(s,"",location.href)}catch(e){}}
    function pushAppHistory(){if(appRestoringHistory||!appHistoryReady||!history.pushState)return;const s=appHistoryState();if(s.screen==="menu"||sameAppState(history.state,s))return;try{history.pushState(s,"",location.href);appHistoryDepth++}catch(e){}}
    function syncHistoryFromState(){
      if(appRestoringHistory)return;
      if(!appHistoryReady){
        appHistoryReady=true;
        const screen=visibleScreen(),needsMenuBase=!!(me&&me.team&&screen&&screen!=="menu"&&screen!=="loginStart"&&screen!=="teamPick");
        if(needsMenuBase&&history.replaceState&&history.pushState){
          const current=appHistoryState(screen);
          try{history.replaceState({ysp:true,screen:"menu",managerSection:""},"",location.href);history.pushState(current,"",location.href);appHistoryDepth=1}catch(e){replaceAppHistory()}
          return
        }
        replaceAppHistory();return
      }
      replaceAppHistory()
    }
    function goBackOrMenu(){if(appHistoryDepth>0)history.back();else goMainMenu(true)}
    function resetTrainingView(){trainingMode=false;trainingRace=null;trainingShot=null;$("trainingPanel").classList.add("hide");$("toMenu").textContent="MENU"}
    function goMainMenu(replace=false){stopPoll();stopManagerPoll();stopCrowd();setMatch(null);resetTrainingView();setRoute("");renderUserTop();syncMenuControls();show("menu");renderMenuInvite();if(replace)replaceAppHistory()}
    async function restoreAppHistoryState(s){if(!s?.ysp)return;appRestoringHistory=true;try{if(!me&&s.screen!=="loginStart"&&s.screen!=="auth"){setRoute("");show("auth");replaceAppHistory();return}const leavingMatch=visibleScreen()==="match"&&match;if(leavingMatch){await api("leave");setMatch(null);stopPoll()}resetTrainingView();if(s.screen!=="manager")stopManagerPoll();if(s.screen==="manager"){setRoute("manager");if(!managerSeason)clearManagerView("Loading manager mode");show("manager");if(!managerSeason)await loadManager(false);else{renderUserTop();renderManagerInviteUi();renderManagerSeason()}if(s.managerSection)showManagerSection(s.managerSection,false);else showManagerSection("managerHome",false);return}if(s.screen==="managerSavesPage"){await openManagerSaves(false);return}if(s.screen==="menu"||!$(s.screen)){goMainMenu(false);return}if(s.screen==="optionsPage"){setRoute("");renderUserTop();updateSoundButton();updateSiteLightButton();show("optionsPage");return}if(s.screen==="admin"){setRoute("");renderUserTop();show("admin");return}show(s.screen||"menu")}finally{appRestoringHistory=false}}
    addEventListener("popstate",e=>{if(e.state?.ysp){if(appHistoryDepth>0)appHistoryDepth--;restoreAppHistoryState(e.state)}})
    function setManagerMessage(text="",thinking=false){const el=$("managerMsg");if(!el)return;if(managerMsgTimer){clearTimeout(managerMsgTimer);managerMsgTimer=null}const hasText=!!String(text||"");el.classList.toggle("thinking",hasText&&!!thinking);el.textContent=text||"";el.classList.toggle("show",hasText);if(hasText&&!thinking)managerMsgTimer=setTimeout(()=>setManagerMessage("",false),20000)}
    function msg(id,text){const el=$(id);if(!el)return;if(id==="managerMsg"){setManagerMessage(text||"",false);return}el.textContent=text||""}
    function askConfirm(title,text,yes="YES",no="NO",danger=true){return new Promise(resolve=>{const modal=$("confirmModal"),yesBtn=$("confirmYes"),noBtn=$("confirmNo");$("confirmTitle").textContent=title;$("confirmText").textContent=text||"";yesBtn.textContent=yes;noBtn.textContent=no;yesBtn.classList.toggle("orange",danger);yesBtn.classList.toggle("green",!danger);modal.classList.remove("hide");const close=v=>{modal.classList.add("hide");yesBtn.onclick=null;noBtn.onclick=null;modal.onclick=null;removeEventListener("keydown",key);resolve(v)},key=e=>{if(e.key==="Escape")close(false);if(e.key==="Enter")close(true)};yesBtn.onclick=()=>close(true);noBtn.onclick=()=>close(false);modal.onclick=e=>{if(e.target===modal)close(false)};addEventListener("keydown",key)})}
    function closeLogoModal(){const modal=$("logoModal"),img=$("logoModalImage");if(!modal)return;modal.classList.add("hide");if(img)img.src=""}
    function openLogoModal(src){const modal=$("logoModal"),img=$("logoModalImage");src=String(src||"");if(!modal||!img||!src)return;img.src=src;modal.classList.remove("hide")}
    function logoModalSrcFromTarget(target){if(!(target instanceof Element))return "";const img=target.closest("img");if(!img)return "";if(!img.classList.contains("team-logo")&&!img.closest(".team-logo-line"))return "";return img.getAttribute("src")||""}
    document.addEventListener("click",e=>{const src=logoModalSrcFromTarget(e.target);if(!src)return;e.preventDefault();e.stopPropagation();openLogoModal(src)},true)
    document.addEventListener("keydown",e=>{if(e.key==="Escape")closeLogoModal()})
    $("logoModal")?.addEventListener("click",e=>{if(e.target===$("logoModal"))closeLogoModal()})
    $("logoModalClose")?.addEventListener("click",closeLogoModal)
    function managerStatus(text,thinking=false){setManagerMessage(text||"",!!thinking)}
    function setRoute(route){try{route?localStorage.setItem(ROUTE_KEY,route):localStorage.removeItem(ROUTE_KEY)}catch(e){}}
    function getRoute(){try{return localStorage.getItem(ROUTE_KEY)||""}catch(e){return ""}}
    function clamp(v,a,b){return Math.max(a,Math.min(b,v))}
    const SITE_LIGHT_KEY="yspSiteLightLevel";
    function normalizeSiteLightLevel(value){const n=Number(value);return Number.isFinite(n)?clamp(Math.round(n),1,10):10}
    function loadSiteLightLevel(){try{return normalizeSiteLightLevel(localStorage.getItem(SITE_LIGHT_KEY)||10)}catch(e){return 10}}
    let siteLightLevel=loadSiteLightLevel();
    function updateSiteLightButton(){const b=$("siteLightButton");if(!b)return;b.textContent=`LIGHT: ${siteLightLevel*10}%`;b.title="Click to lower site brightness in 10 steps"}
    function applySiteLightLevel(level=siteLightLevel,save=false){siteLightLevel=normalizeSiteLightLevel(level);document.documentElement.style.setProperty("--site-dim-opacity",String(((10-siteLightLevel)*.075).toFixed(3)));if(save){try{localStorage.setItem(SITE_LIGHT_KEY,String(siteLightLevel))}catch(e){}}updateSiteLightButton()}
    function cycleSiteLightLevel(){applySiteLightLevel(siteLightLevel<=1?10:siteLightLevel-1,true)}
    applySiteLightLevel(siteLightLevel,false);
    const MATCH_SPEED_KEY="yspMatchSpeedPct", MATCH_SPEED_STEPS=[25,50,75,100,125,150,175,200,225,250,275,300,325,350,375,400];
    function normalizeManagerMatchSpeedPct(value){const n=Number(value);return MATCH_SPEED_STEPS.includes(n)?n:100}
    function loadManagerMatchSpeedPct(){try{return normalizeManagerMatchSpeedPct(localStorage.getItem(MATCH_SPEED_KEY)||100)}catch(e){return 100}}
    let managerLocalMatchSpeedPct=loadManagerMatchSpeedPct(),managerMatchSpeedPct=managerLocalMatchSpeedPct;
    function managerMatchSpeedFactor(){return normalizeManagerMatchSpeedPct(managerMatchSpeedPct)/100}
    function managerMatchSpeedLabel(){return `${normalizeManagerMatchSpeedPct(managerMatchSpeedPct)}%`}
    function managerMatchSpeedCanControl(fixture=null){const f=fixture||touchlinesView?.fixture||{},user=String(me?.name||"");return !!user&&(String(f.home||"")===user||String(f.away||"")===user)}
    function setManagerMatchSpeedPct(value,saveLocal=false){managerMatchSpeedPct=normalizeManagerMatchSpeedPct(value);if(saveLocal){managerLocalMatchSpeedPct=managerMatchSpeedPct;try{localStorage.setItem(MATCH_SPEED_KEY,String(managerLocalMatchSpeedPct))}catch(e){}}renderManagerMatchSpeedControls()}
    function applyManagerMatchSpeedFromFixture(fixture=null){const speed=normalizeManagerMatchSpeedPct(fixture?.playbackSpeedPct||managerLocalMatchSpeedPct);setManagerMatchSpeedPct(speed,false);return speed}
    function noteManagerSeasonClock(){const serverAt=Number(managerSeason?.serverAt||0);if(serverAt>0&&serverAt!==managerSeasonServerAt){managerSeasonServerAt=serverAt;managerSeasonReceivedAt=Date.now()/1000}}
    function managerServerNow(){noteManagerSeasonClock();return managerSeasonServerAt>0&&managerSeasonReceivedAt>0?managerSeasonServerAt+(Date.now()/1000-managerSeasonReceivedAt):Date.now()/1000}
    function managerPlaybackFixturePayload(fixture=null){const f=fixture||touchlinesView?.fixture||{},roundIndex=Number(f.roundIndex),fixtureIndex=Number(f.fixtureIndex);return Number.isInteger(roundIndex)&&roundIndex>=0&&Number.isInteger(fixtureIndex)&&fixtureIndex>=0?{roundIndex,fixtureIndex}:null}
    async function syncManagerPlaybackSpeed(fixture=null){const payload=managerPlaybackFixturePayload(fixture);if(!payload||!managerMatchSpeedCanControl(fixture))return;try{const r=await api("managerLivePlaybackSpeed",{...payload,speedPct:managerMatchSpeedPct},{quiet:true});if(r?.ok!==false){if(r.managerSeason)managerSeason=r.managerSeason;if(touchlinesView?.fixture)touchlinesView.fixture.playbackSpeedPct=normalizeManagerMatchSpeedPct(r.speedPct||managerMatchSpeedPct);syncManagerActions()}}catch(e){clientDebugLog("manager_speed_sync_error",e?.message||String(e||"speed sync failed"),{stack:e?.stack||""},"manager",true)}}
    function saveManagerMatchSpeedPct(value){setManagerMatchSpeedPct(value,true);syncManagerPlaybackSpeed()}
    function renderManagerMatchSpeedControls(){const value=$("touchlinesSpeedValue"),slow=$("touchlinesSlowDown"),fast=$("touchlinesFastForward"),idx=MATCH_SPEED_STEPS.indexOf(normalizeManagerMatchSpeedPct(managerMatchSpeedPct)),can=managerMatchSpeedCanControl();if(value)value.textContent=managerMatchSpeedLabel();if(slow)slow.disabled=!can||idx<=0;if(fast)fast.disabled=!can||idx>=MATCH_SPEED_STEPS.length-1}
    function changeManagerMatchSpeed(step){if(!managerMatchSpeedCanControl())return;const idx=MATCH_SPEED_STEPS.indexOf(normalizeManagerMatchSpeedPct(managerMatchSpeedPct)),next=MATCH_SPEED_STEPS[clamp((idx<0?MATCH_SPEED_STEPS.indexOf(100):idx)+step,0,MATCH_SPEED_STEPS.length-1)];saveManagerMatchSpeedPct(next)}
    function bindManagerMatchSpeedControls(){const slow=$("touchlinesSlowDown"),fast=$("touchlinesFastForward"),bind=(btn,step)=>{if(!btn)return;btn.onclick=e=>{e?.preventDefault?.();if(btn.disabled)return;changeManagerMatchSpeed(step);btn.blur&&btn.blur()}};bind(slow,-1);bind(fast,1);renderManagerMatchSpeedControls()}
    function lerp(a,b,t){return a+(b-a)*t}
    function safe(s){return String(s??"").replace(/[&<>"']/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]))}
    function flagPatternClass(pattern){pattern=String(pattern||"plain").toLowerCase();return["plain","vertical","horizontal","stripes-v","stripes-h","hoops","halves","quarters","sash","cross","check"].includes(pattern)?`flag-${pattern}`:"flag-plain"}
    function flagSpec(t){const accent=t?.flagAccent||t?.trim||"#111";return{cls:flagPatternClass(t?.flagPattern),style:`--shirt:${safe(t?.shirt||"#fff")};--trim:${safe(t?.trim||"#111")};--accent:${safe(accent)}`}}
    function teamLogoSrc(t){return t?.logo?String(t.logo):""}
    function teamFlag(t){const logo=teamLogoSrc(t);if(logo)return `<img class="team-flag team-logo" src="${safe(logo)}" alt="" loading="lazy" decoding="async">`;const f=flagSpec(t);return `<i class="team-flag ${f.cls}" style="${f.style}"></i>`}
    function lineFlag(t){const logo=teamLogoSrc(t);if(logo)return `<span class="line-flag team-logo-line"><img src="${safe(logo)}" alt="" loading="lazy" decoding="async"></span>`;const f=flagSpec(t);return `<span class="line-flag ${f.cls}" style="${f.style}"></span>`}
    function teamLabel(t,r,away=false){let name=`<span>${safe(t?.name||"TEAM")}${r?" "+safe(r):""}</span>`;return away?name+teamFlag(t):teamFlag(t)+name}
    function soundFileEnabled(id){return soundSettings[id]!==false}
    function soundAnyEnabled(){return SOUND_FILES.some(f=>soundFileEnabled(f.id))}
    function soundAllEnabled(){return SOUND_FILES.length>0&&SOUND_FILES.every(f=>soundFileEnabled(f.id))}
    function saveSoundSettings(){soundEnabled=soundAnyEnabled();try{localStorage.setItem(SOUND_FILE_KEY,JSON.stringify(soundSettings));localStorage.setItem(SOUND_KEY,soundEnabled?"on":"off")}catch(e){}}
    function stopAudioId(id,reset=true){const a=$(id);if(!a)return;try{a.pause();if(reset)a.currentTime=0}catch(e){}}
    function stopAllSounds(){stopMenuMusic(true);stopCrowd();SOUND_FILES.forEach(f=>stopAudioId(f.id,true));if(audio?.state==="running")audio.suspend&&audio.suspend()}
    function renderSoundOptions(){const box=$("soundOptions");if(!box)return;box.innerHTML=SOUND_FILES.map(f=>{const on=soundFileEnabled(f.id);return `<div class="sound-option"><span><b>${safe(f.label)}</b><small>${safe(f.file)}</small></span><button class="${on?"green":"orange"}" data-sound-file="${safe(f.id)}" type="button">${on?"ON":"OFF"}</button></div>`}).join("");box.querySelectorAll("[data-sound-file]").forEach(b=>b.onclick=()=>setSoundFileEnabled(b.dataset.soundFile,!soundFileEnabled(b.dataset.soundFile)))}
    function updateSoundButton(){soundEnabled=soundAnyEnabled();const b=$("soundToggle");if(b){const all=soundAllEnabled();b.textContent=all?"ALL SOUND: ON":soundEnabled?"SOUND: CUSTOM":"ALL SOUND: OFF";b.classList.toggle("green",soundEnabled);b.classList.toggle("orange",!soundEnabled)}renderSoundOptions()}
    function setSoundEnabled(on){SOUND_FILES.forEach(f=>{soundSettings[f.id]=!!on});saveSoundSettings();if(!on)stopAllSounds();else{if(match&&["ready","active"].includes(match.status))playCrowd();syncManagerMenuMusic()}updateSoundButton()}
    function setSoundFileEnabled(id,on){if(!SOUND_FILES.some(f=>f.id===id))return;soundSettings[id]=!!on;saveSoundSettings();if(!on){stopAudioId(id,true);if(id==="crowdSound"||id==="crowdSoundB")stopCrowd();if(id==="menuMusic")stopMenuMusic(true)}else{if(match&&["ready","active"].includes(match.status)&&/^crowdSound/.test(id))playCrowd();syncManagerMenuMusic()}updateSoundButton()}
    function ensureAudio(){if(!soundAnyEnabled())return false;const C=window.AudioContext||window.webkitAudioContext;if(!C)return false;audio=audio||new C();if(audio.state==="suspended")audio.resume();return true}
    function tone(freq,dur,type="square",gain=.03,delay=0){if(!soundAnyEnabled()||!audio)return;const now=audio.currentTime+delay,o=audio.createOscillator(),g=audio.createGain();o.type=type;o.frequency.setValueAtTime(freq,now);g.gain.setValueAtTime(0,now);g.gain.linearRampToValueAtTime(gain,now+.01);g.gain.exponentialRampToValueAtTime(.0001,now+dur);o.connect(g);g.connect(audio.destination);o.start(now);o.stop(now+dur+.02)}
    function playAudio(id,vol=.6,overlap=false){if(!soundFileEnabled(id))return false;const a=$(id);if(!a)return false;try{const n=overlap?a.cloneNode(true):a;n.loop=false;n.volume=vol;n.currentTime=0;const p=n.play();if(p&&p.catch)p.catch(()=>{});if(overlap)n.addEventListener("ended",()=>n.remove&&n.remove(),{once:true});return true}catch(e){return false}}
    function kickSound(){if(!soundFileEnabled("shotSound"))return;tone(120,.045,"triangle",.035);tone(78,.035,"sine",.025,.025)}
    function shotSound(){if(!playAudio("shotSound",.95,true))kickSound()}
    function whistleSound(){if(!soundFileEnabled("whistleAudio"))return;if(!playAudio("whistleAudio",.75)){tone(1320,.12,"square",.024);tone(1660,.12,"square",.018,.10)}}
    function critSound(){if(!soundFileEnabled("critSound"))return;if(!playAudio("critSound",.78)){tone(440,.08,"sawtooth",.035);tone(660,.12,"square",.025,.07)}}
    function goalCheerSound(){playAudio("crowdGoalSound",.86,true)}
    function allCrowdTracks(){return[$("crowdSound"),$("crowdSoundB")].filter(Boolean)}
    function crowdTracks(){return allCrowdTracks().filter(a=>soundFileEnabled(a.id))}
    function playMenuMusic(){if(!soundFileEnabled("menuMusic"))return false;const a=$("menuMusic");if(!a)return false;try{a.loop=true;a.volume=.34;if(a.paused){const p=a.play();if(p&&p.catch)p.catch(()=>{})}return true}catch(e){return false}}
    function stopMenuMusic(reset=false){const a=$("menuMusic");if(!a)return;try{a.pause();if(reset)a.currentTime=0}catch(e){}}
    function menuMusicShouldPause(){const matchEl=$("match"),matchVisible=visibleScreen()==="match"||!!(matchEl&&!matchEl.classList.contains("hide")),liveMatch=matchVisible&&!!match&&!trainingMode&&["waiting","ready","active","finished"].includes(match.status||"");return liveMatch||managerSimRunning}
    function syncManagerMenuMusic(){if(menuMusicShouldPause())stopMenuMusic();else playMenuMusic()}
    ["pointerdown","touchstart","keydown"].forEach(type=>document.addEventListener(type,()=>syncManagerMenuMusic(),{passive:true}))
    function fadeAudio(a,from,to,ms,done){const start=performance.now();function step(){let t=clamp((performance.now()-start)/ms,0,1);a.volume=from+(to-from)*t;if(t<1)requestAnimationFrame(step);else if(done)done()}step()}
    function playCrowd(){stopMenuMusic();const tracks=crowdTracks();crowdWanted=tracks.length>0;const a=tracks[crowdActive]||tracks[0];if(!a)return false;try{tracks.forEach(x=>x.loop=false);a.volume=a.volume||.55;if(a.paused){if(Number.isFinite(a.duration)&&a.currentTime>=a.duration-.12)a.currentTime=0;const p=a.play();if(p&&p.catch)p.catch(()=>{})}return true}catch(e){return false}}
    function maintainCrowd(){if(!crowdWanted||!match||!["ready","active"].includes(match.status))return;playCrowd();const tracks=crowdTracks(),a=tracks[crowdActive],b=tracks[1-crowdActive];if(!a||!b||crowdFading||!Number.isFinite(a.duration))return;if(a.duration-a.currentTime<.55){crowdFading=true;try{b.pause();b.currentTime=0;b.volume=0;const p=b.play();if(p&&p.catch)p.catch(()=>{});fadeAudio(b,0,.55,420);fadeAudio(a,a.volume,0,520,()=>{a.pause();a.currentTime=0;crowdActive=1-crowdActive;crowdFading=false})}catch(e){crowdFading=false}}}
    function stopCrowd(){crowdWanted=false;crowdFading=false;allCrowdTracks().forEach(a=>{try{a.pause();a.currentTime=0;a.volume=.55}catch(e){}});crowdActive=0}
    allCrowdTracks().forEach(a=>a.addEventListener("ended",()=>{if(crowdWanted){crowdActive=1-crowdActive;playCrowd()}}));
    function emptyFrame(){return{ball:null,units:{home:{},away:{}}}}
    function emptyView(){return{id:null,prev:emptyFrame(),next:emptyFrame(),from:0,duration:1,lastAt:0}}
    function unitMap(units){const out={};(units||[]).forEach(u=>out[u.id]={x:u.x,y:u.y,weightClass:u.weightClass||"medium"});return out}
    function frameFromMatch(m){return m?{ball:m.ball?{...m.ball}:null,units:{home:unitMap(m.units?.home),away:unitMap(m.units?.away)}}:emptyFrame()}
    function interpAmount(now=performance.now()){return view.duration<=1?1:clamp((now-view.from)/view.duration,0,1)}
    function sampleBall(a,b,t,now){if(!b)return a;if(!a)return b;if(match?.engine?.owner)return{...b,z:0};if(match?.engine?.restart?.type)return{...b,x:lerp(a.x,b.x,t),y:lerp(a.y,b.y,t),z:Math.max(0,lerp(a.z||0,b.z||0,t))};let airPass=match?.engine?.passTarget?.type==="long",ground=!match?.engine?.shot&&!airPass,dx=b.x-a.x,dy=b.y-a.y;if(dx*dx+dy*dy>.09)return ground?{...b,z:0}:b;let over=t>=1&&match?.status==="active"?Math.min(.18,(now-view.from-view.duration)/1000):0;return{...b,x:clamp(lerp(a.x,b.x,t)+(b.vx||0)*over,.02,.98),y:clamp(lerp(a.y,b.y,t)+(b.vy||0)*over,-.16,1.16),z:ground?0:Math.max(0,lerp(a.z||0,b.z||0,t))}}
    function sampleFrame(now=performance.now()){if(!match||view.id!==match.id)return frameFromMatch(match);let t=interpAmount(now),out=emptyFrame();["home","away"].forEach(side=>{let ids=new Set([...Object.keys(view.prev.units[side]||{}),...Object.keys(view.next.units[side]||{})]);ids.forEach(id=>{let a=view.prev.units[side][id],b=view.next.units[side][id]||a;if(!a||!b)return;let dx=b.x-a.x,dy=b.y-a.y;out.units[side][id]=dx*dx+dy*dy>.03?{x:b.x,y:b.y}:{x:lerp(a.x,b.x,t),y:lerp(a.y,b.y,t)}})});out.ball=sampleBall(view.prev.ball,view.next.ball,t,now);return out}
    function showGoalBanner(goal,now){goalBanner={until:now+3300,name:goal?.scorer||"GOAL",team:goal?.team||"",assist:goal?.assist||""}}
    function showFinalScorers(goals,id,managerMatch=false){if(finalMatchId===id&&goalBanner?.final)return;finalMatchId=id;if(finalTimer)clearTimeout(finalTimer);goalBanner={final:true,goals:goals||[],until:performance.now()+FINAL_SCORERS_MS};finalTimer=setTimeout(()=>{if(match?.id===id&&match.status==="finished"){goalBanner=null;renderGoalBanner();returnFromMatch(managerMatch)}},FINAL_SCORERS_MS)}
    function goalAssistLine(g){return g?.assist?`A: ${g.assist}`:""}
    function goalScorerHtml(goals){return (goals||[]).map(g=>`<span class="score-goal"><b>${safe(Math.max(0,Math.round(g.at||0))+"' "+(g.scorer||"Unknown"))}</b>${g.assist?`<small>A: ${safe(g.assist)}</small>`:""}</span>`).join("")}
    function eventLineHtml(e){const text=String(e?.text||""),parts=text.split(" | ASSIST: "),main=parts[0]||text,assist=parts[1]||"";return `<div>${String(e?.t??"").padStart(2,"0")} ${safe(main)}${assist?`<br><small>ASSIST: ${safe(assist)}</small>`:""}</div>`}
    function renderGoalBanner(now=performance.now()){const el=$("goalBanner");if(!el)return;if(!goalBanner||now>goalBanner.until){el.classList.add("hide");el.classList.remove("final");return}el.classList.remove("hide");el.classList.toggle("final",!!goalBanner.final);if(goalBanner.final){let rows=(goalBanner.goals||[]).length?(goalBanner.goals||[]).map(g=>{const assist=goalAssistLine(g);return `<div class="goal-row"><b>${String(Math.max(0,Math.round(g.at||0))).padStart(2,"0")}</b><div>${safe(g.scorer||"Unknown")}${assist?`<br><span class="goal-assist">${safe(assist)}</span>`:""}<br><span>${safe(g.team||"")}</span></div></div>`}).join(""):`<div class="goal-row"><b>FT</b><div>No goals</div></div>`;el.innerHTML=`<div class="goal-word">FULL TIME</div><div class="goal-name">SCORERS</div><div class="goal-list">${rows}</div>`;return}el.innerHTML=`<div class="goal-word">GOAL</div><div class="goal-name">${safe(goalBanner.name)}</div><div class="goal-team">${safe(goalBanner.team)}${goalBanner.assist?`<br><span>A: ${safe(goalBanner.assist)}</span>`:""}</div>`}
    function goalScorerSummary(goals){return (goals||[]).map(g=>`${Math.max(0,Math.round(g.at||0))}' ${g.scorer||"Unknown"}${g.assist?` (A: ${g.assist})`:""}`).join("  |  ")}
    function isManagerMatch(m=match){return !!m?.managerFixture}
    async function returnFromMatch(managerMatch=false){if(matchReturnBusy)return;matchReturnBusy=true;try{setMatch(null);stopPoll();if(managerMatch){setRoute("manager");show("manager");await loadManager(false);replaceAppHistory();return}goMainMenu(true)}finally{matchReturnBusy=false}}
    function setMatch(next){
      const now=performance.now();
      if(!next){stopCrowd();if(finalTimer)clearTimeout(finalTimer);finalTimer=null;finalMatchId=null;match=null;view=emptyView();lastMatchAt=0;goalFx=null;goalBanner=null;renderGoalBanner(now);refView=null;introMatchId=null;introUntil=0;crowdMatchId=null;lineupMatchId=null;lineupUntil=0;return}
      const same=match&&view.id===next.id,old=match,oldScore=same&&old.score?old.score:null;
      let goalChanged=false;
      if(oldScore&&next.score){
        if(next.score[0]>oldScore[0]){goalFx={net:"top",at:now};goalChanged=true}
        else if(next.score[1]>oldScore[1]){goalFx={net:"bottom",at:now};goalChanged=true}
        if(goalChanged){showGoalBanner(next.engine?.lastGoal,now);goalCheerSound();whistleSound()}
      }
      if(same&&next.status==="active"){
        let os=(old?.engine?.shots?.home||0)+(old?.engine?.shots?.away||0),ns=(next?.engine?.shots?.home||0)+(next?.engine?.shots?.away||0),oldShot=old?.engine?.lastShotSeq||0,newShot=next?.engine?.lastShotSeq||0,ot=old?.engine?.lastTouchAt,nt=next?.engine?.lastTouchAt;
        if((next?.engine?.kickoff?.seq||0)>(old?.engine?.kickoff?.seq||0))whistleSound();
        if((next?.engine?.restart?.seq||0)>(old?.engine?.restart?.seq||0))whistleSound();
        if(ns>os||newShot>oldShot)shotSound();
        else if(nt!==null&&nt!==undefined&&nt!==ot)kickSound();
      }
      let ne=(next.events||[]).slice(-1)[0],oe=same?(old.events||[]).slice(-1)[0]:null;
      if(same&&ne&&(!oe||ne.t!==oe.t||ne.text!==oe.text)){
        if(!goalChanged&&/FREE KICK|PENALTY|YELLOW CARD|GOAL/.test(ne.text||""))whistleSound();
        if(/CRIT SHOT/.test(ne.text||""))critSound();
      }
      if(next.status==="finished"){stopPoll();stopCrowd();showFinalScorers(next.engine?.goalScorers||[],next.id,isManagerMatch(next))}
      if(!same){refView=null;introMatchId=null;introUntil=0;crowdMatchId=null;lineupMatchId=null;lineupUntil=0}
      const prev=same?sampleFrame(now):frameFromMatch(next),target=frameFromMatch(next),since=same&&view.lastAt?now-view.lastAt:POLL_MS,duration=next.status==="active"?clamp(since+45,INTERP_MIN,INTERP_MAX):1;
      view={id:next.id,prev,next:target,from:now,duration,lastAt:now};match=next;lastMatchAt=now;
    }
    function teamChoiceSkill(team){const n=Number(team?.baseRating??team?.skill??team?.rating);return Number.isFinite(n)?Math.round(n):""}
    function teamChoiceSkillHtml(team){const skill=teamChoiceSkill(team);return skill===""?"":`<span class="team-choice-skill">S ${safe(skill)}</span>`}
    function selectedTeamHtml(team){return `<span class="team-choice">${teamChoiceSkillHtml(team)}${teamFlag(team)}<span>${safe(team?.name||"CHOOSE NATIONAL LEAGUE TEAM")}</span></span>`}
    function chooseTeam(id){const t=teamChoices.find(x=>x.id===id);if(!t||t.taken)return;$("teamId").value=t.id;$("teamDropdown").innerHTML=selectedTeamHtml(t);$("teamDropdownList").classList.add("hide");msg("teamMsg","")}
    function fillTeams(teams){
      teamChoices=teams||[];
      const input=$("teamId"),button=$("teamDropdown"),list=$("teamDropdownList");
      if(!input||!button||!list)return;
      const selected=teamChoices.find(t=>t.id===input.value&&!t.taken);
      if(selected)button.innerHTML=selectedTeamHtml(selected);
      else{input.value="";button.innerHTML='<span class="team-choice"><span>CHOOSE NATIONAL LEAGUE TEAM</span></span>'}
      list.innerHTML=teamChoices.map(t=>`<button class="team-option ${t.taken?"taken":""}" data-team="${safe(t.id)}" type="button" ${t.taken?"disabled":""}>${teamChoiceSkillHtml(t)}${teamFlag(t)}<b>${safe(t.name)}</b>${t.taken?" TAKEN":""}</button>`).join("");
      list.querySelectorAll("[data-team]").forEach(b=>b.onclick=()=>chooseTeam(b.dataset.team));
    }
    function setMenuOptionVisible(id,on){const o=$(id);if(!o)return;o.hidden=!on;o.classList.toggle("hide",!on);o.disabled=!on||managerInteractionBusy()}
    function syncAdminControls(){const isAdmin=!!me?.admin,seasonDone=managerSeason?.status==="finished";if($("adminMenu"))$("adminMenu").classList.toggle("hide",!isAdmin);setMenuOptionVisible("managerAdminOption",isAdmin);if($("adminSimSeason")){$("adminSimSeason").classList.toggle("hide",!isAdmin);$("adminSimSeason").disabled=!isAdmin||seasonDone||managerInteractionBusy()}if($("resetGameData"))$("resetGameData").classList.add("hide")}
    function normalizeManagerSaveUsers(users=[]){const seen=new Set(),out=[];(Array.isArray(users)?users:[]).forEach(u=>{u=String(u||"").trim();const key=u.toLowerCase();if(u&&!seen.has(key)){seen.add(key);out.push(u)}});return out}
    function updateManagerSaveUsersFromResponse(r={}){if(Array.isArray(r.managerSaveUsers))managerSaveUsers=normalizeManagerSaveUsers(r.managerSaveUsers);else if(Array.isArray(r.managerSeason?.saveUsers))managerSaveUsers=normalizeManagerSaveUsers(r.managerSeason.saveUsers);else if(Array.isArray(managerSeason?.saveUsers))managerSaveUsers=normalizeManagerSaveUsers(managerSeason.saveUsers);else if(!r.managerHasSeason&&!managerSeason&&("managerHasSeason"in r))managerSaveUsers=[]}
    function setManagerStateFlags(r={}){managerHasSeason=!!r.managerHasSeason;managerCanContinue=!!(r.managerCanContinue??r.managerHasSeason);managerHasAnySave=!!(r.managerHasAnySave??managerHasAnySave);updateManagerSaveUsersFromResponse(r);if("managerPrivateChatAlerts"in r)setManagerPrivateChatAlerts(r.managerPrivateChatAlerts)}
    function syncMenuControls(){const hasSave=!!managerHasAnySave;$("managerMode")?.classList.toggle("hide",hasSave);$("managerSaveButton")?.classList.toggle("hide",!hasSave);$("startNewManagerMode")?.classList.toggle("hide",!hasSave)}
    function setManagerTurnAlerts(alerts){managerTurnAlerts=Array.isArray(alerts)?alerts.filter(a=>a&&(a.saveId||a.seasonId||a.managerGameId)):[]}
    function setManagerPrivateChatAlerts(alerts){managerPrivateChatAlerts=Array.isArray(alerts)?alerts.filter(a=>a&&a.user&&Number(a.count||0)>0):[]}
    function applyManagerStatusResponse(r={}){if(Array.isArray(r.managerUsers))managerUsers=r.managerUsers;if(Array.isArray(r.managerInvites))managerInvites=r.managerInvites;if("managerTurnAlerts"in r)setManagerTurnAlerts(r.managerTurnAlerts);setManagerStateFlags(r)}
    function managerPrivateChatAlertFor(user){user=String(user||"").toLowerCase();return managerPrivateChatAlerts.find(a=>String(a?.user||"").toLowerCase()===user)||null}
    function hasPrivateChatAlerts(){return managerPrivateChatAlerts.length>0}
    function managerTurnAlertText(a){return `YOUR TURN: ${String(a?.label||a?.saveName||a?.managerGameId||"MANAGER SAVE").toUpperCase()}`}
    function renderManagerTurnAlerts(){const box=$("managerTurnAlerts");if(!box)return;const has=managerTurnAlerts.length>0;box.hidden=!has;box.classList.toggle("hide",!has);box.innerHTML=has?managerTurnAlerts.map((a,i)=>`<button class="manager-turn-alert manager-deal-alert" data-manager-turn-index="${safe(i)}" data-manager-turn-save="${safe(a.saveId||"")}" data-manager-turn-season="${safe(a.seasonId||"")}" data-manager-turn-game="${safe(a.managerGameId||"")}" type="button">${safe(managerTurnAlertText(a))}</button>`).join(""):""}
    function hasManagerTurnAlerts(){return managerTurnAlerts.length>0}
    function currentManagerDivision(){return managerSeason?.divisionName||managerFinance?.divisionName||me?.managerDivisionName||""}
    function currentManagerSaveUsersText(){const users=normalizeManagerSaveUsers(managerSaveUsers.length?managerSaveUsers:(managerSeason?.saveUsers||managerSeason?.humanManagers||[]));return users.length?`USERS: ${users.map(u=>u.toUpperCase()).join(", ")}`:""}
    function currentManagerSeasonText(){const year=Number(managerSeason?.seasonYear||0);return year?`SEASON ${year}`:""}
    function stopAppTopMarquee(host=$("appTopWho")){if(!host)return;if(host._marqRaf){cancelAnimationFrame(host._marqRaf);host._marqRaf=0}}
    function setAppTopMarquee(text){const host=$("appTopWho");if(!host)return;text=String(text||"");if(host._marqText===text&&host.querySelector(".app-top-marquee-item"))return;stopAppTopMarquee(host);host._marqText=text;host.textContent="";host.title=text;if(!text)return;const tape=document.createElement("span"),item=document.createElement("span");tape.className="app-top-marquee-track";item.className="app-top-marquee-item";item.textContent=text;tape.append(item);host.appendChild(tape);requestAnimationFrame(()=>{if(!host.isConnected||!host.contains(tape))return;let x=0,last=0;const speed=28,measure=()=>({hostW:Math.max(1,host.getBoundingClientRect?.().width||host.clientWidth||0),textW:Math.max(1,item.getBoundingClientRect?.().width||item.scrollWidth||0)}),render=()=>{item.style.transform=`translate3d(${x}px,-50%,0)`};const loop=ts=>{if(!host.isConnected||!host.contains(tape)||host._marqText!==text){host._marqRaf=0;return}const {hostW,textW}=measure();if(!last){last=ts;render();host._marqRaf=requestAnimationFrame(loop);return}const dt=Math.max(0,Math.min(80,ts-last));last=ts;x-=speed*dt/1000;if(x<=-textW)x=hostW;render();host._marqRaf=requestAnimationFrame(loop)};render();host._marqRaf=requestAnimationFrame(loop)})}
    function renderUserTop(){const division=currentManagerDivision(),text=me?.team?`${me.name.toUpperCase()} - ${me.team.name}${division?` - ${division}`:""}`:(me?.name||"").toUpperCase(),saveUsers=currentManagerSaveUsersText(),seasonText=currentManagerSeasonText(),marqueeText=[text,seasonText,saveUsers].filter(Boolean).join(" - ");["whoFlag","managerWhoFlag","adminWhoFlag","optionsWhoFlag","trainingWhoFlag","savesWhoFlag","appTopFlag"].forEach(id=>{if($(id))$(id).innerHTML=me?.team?teamFlag(me.team):""});[["who",text],["managerWho",text],["adminWho",text],["optionsWho",text],["trainingWho",text],["savesWho",text]].forEach(([id,val])=>{if($(id))$(id).textContent=val});setAppTopMarquee(marqueeText);$("appTopBar")?.classList.toggle("hide",!me)}
    function shouldForceClientLogout(action,r){
      if(!r||!me)return false;
      if(r.loggedOut||r.error==="not_logged_in")return true;
      return action==="state"&&r.ok&&Object.prototype.hasOwnProperty.call(r,"user")&&!r.user
    }
    function forceClientLogout(message=""){
      if(!me&&visibleScreen()==="auth")return;
      stopPoll();stopManagerPoll();stopMenuInvitePoll();stopCrowd();setMatch(null);clearClientManagerState();csrfToken="";me=null;adminUsers=[];managerUsers=[];teamChoices=[];managerInvites=[];managerSaves=[];renderUserTop();syncMenuControls();syncAdminControls();appHistoryDepth=0;show("auth");replaceAppHistory();if(message)msg("authMsg",message)
    }
    async function state(quiet=false){
      const r=await api("state",{},quiet?{quiet:true}:{});if(!r.ok){if(quiet)return;throw new Error(r.error||"state failed")}if(checkLoadedVersion(r.appVersion))return;
      if(!r.match&&match?.status==="finished"&&goalBanner?.final)return;
      if(Array.isArray(r.teams))fillTeams(r.teams);me=r.user;managerUsers=r.managerUsers||managerUsers;setManagerStateFlags(r);setManagerTurnAlerts(r.managerTurnAlerts);syncAdminControls();syncMenuControls();managerInvites=r.managerInvites||[];setMatch(r.match);
      if(me){
        renderUserTop();
        if(!me.team){$("pickWho").textContent=me.name.toUpperCase();show("teamPick");syncHistoryFromState();return}
        if(match){show("match");renderMatch();syncHistoryFromState();return}
        if(getRoute()==="manager"){clearManagerView("Loading manager mode");show("manager");try{await loadManager(false)}catch(e){console.error(e);setRoute("");goMainMenu(true);msg("menuMsg","Manager mode could not load. Try again.")}syncHistoryFromState();return}
        show("menu");renderMenuInvite();renderMatch();syncHistoryFromState();return
      }
      setRoute("");renderUserTop();show("auth");syncHistoryFromState()
    }
    function startupError(e){console.error(e);clearGlobalThinking();setRoute("");show("auth");msg("authMsg","Could not load page. Try login again.")}
    function speedKmh(p){return Math.round(Number(p?.speedKmh??((p?.stats?.speed??p?.rating??0)*.45))*10)/10}
    function shotKmh(p){return Math.round(Number(p?.shotKmh??((p?.stats?.shooting??p?.rating??0)*1.5))*10)/10}
    function trainingDivisions(){return trainingData?.divisions?.length?trainingData.divisions:[{id:"all",name:"Teams",teams:trainingData?.teams||[]}]}
    function currentTrainingDivision(){const divisions=trainingDivisions();return divisions.find(d=>d.id===trainingDivisionId)||divisions[0]}
    function currentTrainingTeam(){const d=currentTrainingDivision();return (d?.teams||[]).find(t=>t.id===trainingTeamId)||(d?.teams||[])[0]}
    function closeTrainingDropdowns(except=""){if(except!=="division")$("trainingDivisionList")?.classList.add("hide");if(except!=="team")$("trainingTeamList")?.classList.add("hide")}
    function renderTrainingDivisionDropdown(){const divisions=trainingDivisions();if(!divisions.length)return;if(!trainingDivisionId||!divisions.some(d=>d.id===trainingDivisionId))trainingDivisionId=divisions[0].id;const current=currentTrainingDivision(),button=$("trainingDivisionButton"),list=$("trainingDivisionList");if(button)button.innerHTML=`<span class="team-choice"><span>${safe(current?.name||"DIVISION")}</span></span>`;if(list){list.innerHTML=divisions.map(d=>`<button class="team-option ${d.id===trainingDivisionId?"green":""}" data-training-division="${safe(d.id)}" type="button"><b>${safe(d.name)}</b></button>`).join("");list.querySelectorAll("[data-training-division]").forEach(b=>b.onclick=()=>{trainingDivisionId=b.dataset.trainingDivision||"";trainingTeamId="";closeTrainingDropdowns();renderTrainingDivisionDropdown();renderTrainingTeams()})}}
    async function loadTrainingData(){return null}
    function renderTrainingTeams(){const division=currentTrainingDivision(),teams=division?.teams||[],button=$("trainingTeamButton"),list=$("trainingTeamList");if(!division)return;if(!trainingTeamId||!teams.some(t=>t.id===trainingTeamId))trainingTeamId=teams[0]?.id||"";const current=currentTrainingTeam();if(button)button.innerHTML=`<span class="team-choice">${current?teamFlag(current):""}<span>${safe(current?.name||"TEAM")}</span></span>`;if(list){list.innerHTML=teams.map(t=>`<button class="team-option ${t.id===trainingTeamId?"green":""}" data-training-team="${safe(t.id)}" type="button">${teamFlag(t)} <b>${safe(t.name)}</b></button>`).join("");list.querySelectorAll("[data-training-team]").forEach(b=>b.onclick=()=>{trainingTeamId=b.dataset.trainingTeam||"";closeTrainingDropdowns();renderTrainingTeams();renderTrainingPlayers()})}renderTrainingPlayers()}
    function allTrainingPlayers(){return trainingDivisions().flatMap(d=>(d.teams||[]).flatMap(t=>(t.players||[]).map(p=>({...p,team:t,division:d}))))}
    function selectedTrainingPlayers(){const ids=new Set(trainingSelection);return allTrainingPlayers().filter(p=>ids.has(p.id))}
    function playerMetric(p){return trainingScenario==="shoot"?`${shotKmh(p)} km/h`:`${speedKmh(p)} km/h`}
    function renderTrainingPlayers(){const team=currentTrainingTeam(),list=$("trainingPlayers");if(!list)return;if(!team){list.innerHTML="";renderTrainingSelection();return}const picked=new Set(trainingSelection),stat=trainingScenario==="shoot"?"SHT":"SPD";list.innerHTML=(team.players||[]).map(p=>`<button class="training-player ${picked.has(p.id)?"green":""}" data-player="${safe(p.id)}" type="button"><b>${safe(p.name)}</b><br>${safe(p.role)} ${stat} ${playerMetric(p)}</button>`).join("");list.querySelectorAll("[data-player]").forEach(b=>b.onclick=()=>toggleTrainingPlayer(b.dataset.player));renderTrainingSelection()}
    function renderTrainingSelection(){const box=$("trainingSelected"),speedStart=$("startSpeedTest"),shootStart=$("startShootTest"),players=selectedTrainingPlayers();if(!box)return;box.innerHTML=players.length?players.map(p=>`<span class="training-chip" style="--shirt:${safe(p.shirt||p.team?.shirt||"#fff")};--trim:${safe(p.trim||p.team?.trim||"#111")}">${safe(p.name)} ${playerMetric(p)}</span>`).join(""):(trainingScenario==="shoot"?"Select 1+ players":"Select 2+ players");if(speedStart){speedStart.classList.toggle("hide",trainingScenario!=="speed");speedStart.disabled=players.length<2}if(shootStart){shootStart.classList.toggle("hide",trainingScenario!=="shoot");shootStart.disabled=players.length<1}}
    function setTrainingScenario(mode){trainingScenario=mode;trainingRace=null;trainingShot=null;$("speedScenario").classList.toggle("green",mode==="speed");$("shootScenario").classList.toggle("green",mode==="shoot");$("speedSetup").classList.remove("hide");$("trainingMsg").textContent="";$("trainingResult").textContent="";renderTrainingPlayers();renderTraining()}
    function toggleTrainingPlayer(id){if(!id)return;trainingRace=null;trainingShot=null;const i=trainingSelection.indexOf(id);if(i>=0)trainingSelection.splice(i,1);else trainingSelection.push(id);renderTrainingPlayers();renderTraining()}
    function clearTrainingSelection(){trainingSelection=[];trainingRace=null;trainingShot=null;$("trainingResult").textContent="";renderTrainingPlayers();renderTraining()}
    function startSpeedRace(){const players=selectedTrainingPlayers();if(players.length<2)return;const count=players.length,usable=.78,left=.5-usable/2;trainingLast=0;trainingShot=null;trainingRace={started:performance.now(),done:false,runners:players.map((p,i)=>{let lane=count===1?.5:left+usable*(i/(count-1)),kmh=speedKmh(p),real=kmh>0?105/(kmh/3.6):0;return{...p,x:lane,y:.965,v:0,kmh,realTime:real,finish:null}})};$("trainingPanel").classList.add("hide");$("trainingResult").textContent=""}
    function startShootTest(){const players=selectedTrainingPlayers();if(!players.length)return;const count=players.length,usable=.78,left=.5-usable/2;trainingLast=0;trainingRace=null;trainingShot={started:performance.now(),done:false,shots:players.map((p,i)=>{let lane=count===1?.5:left+usable*(i/(count-1)),kmh=shotKmh(p),duration=clamp(1.72-kmh/150*1.05,.55,1.72);return{...p,x:lane,y:.84,ballX:lane,ballY:.84,ballZ:0,kmh,duration,delay:0,finish:null}})};$("trainingPanel").classList.add("hide");$("trainingResult").textContent="";shotSound()}
    function trainingUnits(){if(trainingRace?.runners?.length)return trainingRace.runners;if(trainingShot?.shots?.length)return trainingShot.shots.map(s=>({...s,y:.84,rating:s.stats?.shooting??s.rating??50}));return selectedTrainingPlayers().map((p,i,arr)=>{let usable=.78,left=.5-usable/2,lane=arr.length===1?.5:left+usable*(i/(arr.length-1||1));return{...p,x:lane,y:trainingScenario==="shoot"?.84:.965,rating:trainingScenario==="shoot"?(p.stats?.shooting??p.rating??50):(p.stats?.speed??p.rating??50)}})}
    function trainingBall(){if(trainingShot?.shots?.length)return{x:-1,y:-1,z:0,vx:0,vy:0,vz:0};return{x:.5,y:.5,z:0,vx:0,vy:0,vz:0}}
    function trainingRenderMatch(){const units=trainingUnits();return{id:"training",status:"training",teams:{home:{name:"TRAINING",shirt:"#ffffff",trim:"#222"},away:{name:"",shirt:"#ffffff",trim:"#222"}},units:{home:units.map((r,i)=>({id:r.id,name:r.name,role:r.role||"ST",rating:r.rating??r.stats?.speed??50,shirt:r.shirt||r.team?.shirt,trim:r.trim||r.team?.trim,x:r.x,y:r.y})),away:[]},ball:trainingBall(),referee:null,engine:{freeKick:null},score:[0,0],events:[]}}
    function updateTrainingRace(now){if(!trainingRace)return;let dt=trainingLast?Math.min(.05,(now-trainingLast)/1000):0;trainingLast=now;if(!dt||trainingRace.done)return;let finished=0;trainingRace.runners.forEach(r=>{if(r.finish!==null){finished++;return}let target=Math.max(.035,r.kmh/45*.31);r.v+=(target-r.v)*Math.min(1,dt*3.2);r.y-=r.v*dt;if(r.y<=.035){r.y=.035;r.finish=(now-trainingRace.started)/1000;finished++}});if(finished===trainingRace.runners.length&&!trainingRace.done){trainingRace.done=true;let rows=[...trainingRace.runners].sort((a,b)=>b.kmh-a.kmh);$("trainingResult").textContent=rows.map((r,i)=>`${i+1}. ${r.name} ${r.kmh.toFixed(1)} km/h`).join("   ")}}
    function updateTrainingShot(now){if(!trainingShot)return;let dt=trainingLast?Math.min(.05,(now-trainingLast)/1000):0;trainingLast=now;if(!dt||trainingShot.done)return;let finished=0;trainingShot.shots.forEach(s=>{let elapsed=(now-trainingShot.started)/1000-s.delay;if(elapsed<0)return;if(s.finish!==null){finished++;return}let t=clamp(elapsed/s.duration,0,1),ease=1-Math.pow(1-t,2.2);s.ballY=.84-(.78*ease);s.ballX=clamp(s.x+Math.sin(t*Math.PI)*(.015+(100-(s.stats?.shotcontrol??s.rating??50))/3200),.04,.96);s.ballZ=Math.sin(t*Math.PI)*(.035+s.kmh/150*.055);if(t>=1){s.ballY=.06;s.ballZ=0;s.finish=elapsed;finished++;shotSound()}});if(finished===trainingShot.shots.length&&!trainingShot.done){trainingShot.done=true;let rows=[...trainingShot.shots].sort((a,b)=>b.kmh-a.kmh);$("trainingResult").textContent=rows.map((s,i)=>`${i+1}. ${s.name} ${s.kmh.toFixed(1)} km/h`).join("   ")}}
    function drawTrainingBall(g,x,y,z,br){let bx=p.x+p.w*x,by=p.y+p.h*y-bz(z),r=br||Math.max(4,p.w*.012);g.fillStyle="rgba(0,0,0,.28)";g.beginPath();g.ellipse(bx,by+r*1.45,r*1.15,r*.35,0,0,7);g.fill();g.fillStyle="#fff";g.strokeStyle="#111";g.lineWidth=1.3;g.beginPath();g.arc(bx,by,r,0,7);g.fill();g.stroke()}
    function bz(z){return(z||0)*p.h*.45}
    function drawTrainingOverlay(){const g=$("field").getContext("2d");if(!p.w)return;g.save();if(trainingRace?.runners?.length){g.strokeStyle="rgba(255,221,69,.9)";g.lineWidth=Math.max(2,p.w*.006);g.beginPath();g.moveTo(p.x,p.y+p.h*.965);g.lineTo(p.x+p.w,p.y+p.h*.965);g.moveTo(p.x,p.y+p.h*.035);g.lineTo(p.x+p.w,p.y+p.h*.035);g.stroke();g.font=Math.max(9,p.w*.025)+"px Arial";g.textAlign="center";g.textBaseline="bottom";trainingRace.runners.forEach(r=>{let x=p.x+p.w*r.x,y=p.y+p.h*r.y;g.fillStyle="#fff";g.strokeStyle="#000";g.lineWidth=3;g.strokeText(`${r.name} ${r.kmh.toFixed(1)}`,x,y-18);g.fillText(`${r.name} ${r.kmh.toFixed(1)}`,x,y-18)})}if(trainingShot?.shots?.length){trainingShot.shots.forEach(s=>{let sx=p.x+p.w*s.x,sy=p.y+p.h*.84;drawTrainingBall(g,s.ballX,s.ballY,s.ballZ);g.font=Math.max(9,p.w*.022)+"px Arial";g.textAlign="center";g.fillStyle="#fff";g.strokeStyle="#000";g.lineWidth=3;g.strokeText(`${s.name} ${s.kmh.toFixed(1)} km/h`,sx,sy-18);g.fillText(`${s.name} ${s.kmh.toFixed(1)} km/h`,sx,sy-18)})}g.restore()}
    function renderTraining(){if(!trainingMode)return;const now=performance.now();if(trainingRace)updateTrainingRace(now);else if(trainingShot)updateTrainingShot(now);$("wait").classList.add("hide");$("hud").classList.add("hide");$("controls").classList.add("hide");$("lineup").classList.add("hide");$("events").innerHTML="";$("goalBanner").classList.add("hide");$("toMenu").classList.remove("hide");const old=match,tm=trainingRenderMatch();match=tm;drawField(tm.teams.home,tm.teams.away,{ball:tm.ball,units:{home:unitMap(tm.units.home),away:{}}});drawTrainingOverlay();match=old}
    function openTrainingMenu(){goMainMenu(true)}
    async function openTraining(mode="speed"){stopPoll();stopCrowd();setMatch(null);trainingMode=true;trainingScenario=mode;trainingLast=0;trainingRace=null;trainingShot=null;show("match");pushAppHistory();$("trainingPanel").classList.remove("hide");$("speedSetup").classList.remove("hide");$("toMenu").textContent="MENU";await loadTrainingData();setTrainingScenario(mode);renderTraining()}
    function closeTraining(){goBackOrMenu()}
    function toggleTrainingMenu(){const p=$("trainingPanel");p.classList.toggle("hide");if(!p.classList.contains("hide")){renderTrainingPlayers();renderTrainingSelection()}}
    function money(v){return "£"+Math.round(Number(v||0)).toLocaleString("en-GB")}
    function signedMoney(v){const n=Math.round(Number(v||0));return `${n<0?"-":""}£${Math.abs(n).toLocaleString("en-GB")}`}
    function shortDate(v){if(!v)return "";const d=new Date(Number(v)*1000);return isNaN(d)?String(v):d.toLocaleString("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})}
    function isLoanPlayer(p){return !!(p?.emergencyLoan||p?.loanPlayer||String(p?.id||"").startsWith("loan_"))}
    function transferInfo(p){if(isLoanPlayer(p))return "Emergency loan cover";if(!p?.purchasedFrom)return "";const when=shortDate(p.purchasedAt),price=p.purchasePrice?` for ${money(p.purchasePrice)}`:"";return `Bought from ${safe(p.purchasedFrom)}${p.purchasedFromDivision?` - ${safe(p.purchasedFromDivision)}`:""}${when?` on ${safe(when)}`:""}${price}`}
    function skillChangeText(c){if(!c)return "";const before=Number(c.before||0),after=Number(c.after||0),delta=Number(c.delta||0),raw=Number(c.rawDelta||0);return delta?`<br>Team skill ${before} -> ${after} (${delta>0?"+":""}${delta})`:`<br>Team skill unchanged at ${after}${raw>0?" (raw skill improved, rounded S stayed the same)":""}`}
    function signingNotice(p,c){const buttons=`<br><button data-open-lineup-after-signing type="button">SET LINEUP</button><button data-dismiss-signing-notice type="button">LATER</button>`;if(!p)return `<b>SIGNING COMPLETE</b>Player joined your squad${buttons}`;const info=transferInfo(p);return `<b>SIGNING COMPLETE</b>${safe(p.name||"Player")} joined your squad${info?`<br>${info}`:""}${skillChangeText(c)}${buttons}`}
    function bindSigningNoticeAction(box){if(!box)return;box.querySelectorAll("[data-open-lineup-after-signing]").forEach(b=>b.onclick=()=>{clearSquadSwap();managerBrowseNotice="";managerMarketNotice="";openManagerTeam(me?.name,{backTarget:"league"})});box.querySelectorAll("[data-dismiss-signing-notice]").forEach(b=>b.onclick=()=>{managerBrowseNotice="";managerMarketNotice="";box.innerHTML="";box.classList.add("hide")})}
    function benchFullText(r){return `Squad is full (max ${Number(r?.maxBench||22)} reserves). Sell or include a player in the deal before buying more.`}
    function normalizedManagerUsers(){return (managerUsers||[]).map(u=>({...u,name:String(u?.name||"")}))}
    function readyManagerUsers(){return normalizedManagerUsers().filter(u=>u.ready)}
    function managerTeamLine(u){return u?.team?`${u.team.name}`:"NO TEAM"}
    function teamLookupKey(value){return String(value||"").toLowerCase().split(":").pop().replace(/_/g,"-")}
    function managerUserByName(name){const key=String(name||"").toLowerCase();return normalizedManagerUsers().find(u=>u.name.toLowerCase()===key)||null}
    function managerTeamById(id){const key=teamLookupKey(id);if(!key)return null;return (teamChoices||[]).find(t=>teamLookupKey(t?.id)===key||teamLookupKey(t?.sourceId)===key)||null}
    function managerTeamKey(team){return teamLookupKey(team?.sourceId||team?.id||team?.name||"")}
    function managerDefaultTeamForUser(name){const u=managerUserByName(name);return u?.team||((String(name||"").toLowerCase()===String(me?.name||"").toLowerCase())?me?.team:null)}
    function managerDraftTeamFor(name){
      const key=String(name||"").toLowerCase();
      if(!key)return null;
      const selected=managerTeamById(managerDraftTeams[key]);
      if(selected)return selected;
      const fallback=managerDefaultTeamForUser(key);
      if(fallback?.id)managerDraftTeams[key]=fallback.id;
      return managerTeamById(fallback?.id)||fallback||null
    }
    function managerTeamChoiceList(selectedTeam=null){
      const seen=new Set(),teams=[];
      (teamChoices||[]).forEach(t=>{const k=managerTeamKey(t);if(k&&!seen.has(k)){seen.add(k);teams.push(t)}});
      if(selectedTeam&&managerTeamKey(selectedTeam)&&!seen.has(managerTeamKey(selectedTeam)))teams.unshift(selectedTeam);
      return teams
    }
    function managerSoloUserKey(){return String(me?.name||"").toLowerCase()}
    function managerSelectableTeamList(){return managerTeamChoiceList().filter(t=>!t?.taken)}
    function managerSoloSelectedTeam(){
      const key=managerSoloUserKey();
      if(!key)return null;
      const selected=managerTeamById(managerDraftTeams[key]);
      if(selected)return selected;
      const fallback=managerDefaultTeamForUser(key),team=managerTeamById(fallback?.id||fallback?.sourceId)||fallback||managerSelectableTeamList()[0]||null;
      if(team?.id||team?.sourceId)managerDraftTeams[key]=team.id||team.sourceId;
      return team
    }
    function chooseManagerSoloTeam(id){
      if(managerCreateMode!=="solo")return;
      const team=managerTeamById(id);
      if(!team||team.taken)return;
      managerDraftTeams[managerSoloUserKey()]=team.id||team.sourceId||id;
      renderManagerCreate()
    }
    function renderManagerSoloCreate(){
      const key=managerSoloUserKey(),list=$("managerUsers"),start=$("startManagerLeague"),count=$("managerCount"),picked=$("managerPicked"),teams=managerSelectableTeamList(),selected=managerSoloSelectedTeam(),selectedKey=managerTeamKey(selected);
      count.textContent="";count.classList.add("hide");picked.textContent="";picked.classList.add("hide");
      managerPicked=key?[key]:[];
      start.textContent="START SOLO GAME";
      start.disabled=!selected;
      start.title=selected?"":"Choose a team";
      list.innerHTML=teams.length?`<div class="manager-solo-team-list">${teams.map(t=>{const active=managerTeamKey(t)===selectedKey;return `<button class="manager-solo-team ${active?"selected":""}" data-manager-solo-team-id="${safe(t.id||t.sourceId||"")}" type="button">${teamFlag(t)}<b>${safe(t.name||t.id||"")}</b>${teamChoiceSkillHtml(t)}</button>`}).join("")}</div>`:`<div class="manager-meta">No teams available</div>`
    }
    function managerTeamPickerHtml(key,team,attrsForTeam){
      const open=managerTeamMenuOpen===key,selectedKey=managerTeamKey(team),teams=managerTeamChoiceList(team);
      return `<div class="manager-team-picker ${open?"open":""}" data-manager-team-picker="${safe(key)}"><button class="manager-team-button" data-manager-team-toggle="${safe(key)}" type="button">${team?teamFlag(team):""}<span>${safe(team?.name||"Choose team")}</span></button><div class="manager-team-menu ${open?"open":"hide"}" data-manager-team-menu="${safe(key)}">${teams.map(t=>`<button class="team-option ${managerTeamKey(t)===selectedKey?"green":""}" ${attrsForTeam(t)} type="button">${teamChoiceSkillHtml(t)}${teamFlag(t)}<b>${safe(t.name||t.id||"")}</b></button>`).join("")}</div></div>`
    }
    function managerCreateTeamPickerHtml(name,team){return managerTeamPickerHtml(`create:${String(name||"").toLowerCase()}`,team,t=>`data-manager-team-id="${safe(t.id||t.sourceId||"")}" data-manager-team-user="${safe(name)}"`)}
    function managerInviteTeamPickerHtml(inv,user,team){return managerTeamPickerHtml(`invite:${safe(inv?.id||"")}:${String(user||"").toLowerCase()}`,team,t=>`data-invite-team-id="${safe(t.id||t.sourceId||"")}" data-invite-id="${safe(inv?.id||"")}" data-invite-user="${safe(user)}"`)}
    function managerTeamMenuFromEvent(e){return e?.target instanceof Element?e.target.closest(".manager-team-menu"):null}
    function rememberManagerTeamMenuScroll(menu){const key=menu?.dataset?.managerTeamMenu||"";if(key)managerTeamMenuScrollTop[key]=menu.scrollTop||0}
    function positionManagerTeamMenu(){
      const key=managerTeamMenuOpen;
      if(!key)return;
      const menu=Array.from(document.querySelectorAll(".manager-team-menu.open")).find(m=>m.dataset.managerTeamMenu===key);
      const button=menu?.closest(".manager-team-picker")?.querySelector(".manager-team-button");
      if(!menu||!button)return;
      const rect=button.getBoundingClientRect(),vw=window.innerWidth||document.documentElement.clientWidth||0,vh=window.innerHeight||document.documentElement.clientHeight||0,margin=8,gap=4;
      const width=Math.max(160,Math.min(rect.width,vw-margin*2)),left=clamp(rect.left,margin,Math.max(margin,vw-width-margin)),below=Math.max(0,vh-rect.bottom-gap-margin),above=Math.max(0,rect.top-gap-margin),wanted=Math.min(menu.scrollHeight||248,360),dropUp=below<Math.min(220,wanted)&&above>below,available=Math.max(82,dropUp?above:below),height=Math.max(82,Math.min(wanted,available)),top=dropUp?Math.max(margin,rect.top-gap-height):Math.min(Math.max(margin,vh-margin-height),rect.bottom+gap);
      menu.style.left=`${Math.round(left)}px`;
      menu.style.top=`${Math.round(top)}px`;
      menu.style.width=`${Math.round(width)}px`;
      menu.style.maxHeight=`${Math.round(height)}px`;
      menu.classList.toggle("drop-up",dropUp)
    }
    function restoreManagerTeamMenuScroll(){
      const key=managerTeamMenuOpen;
      if(!key)return;
      const apply=()=>{document.querySelectorAll(".manager-team-menu").forEach(menu=>{if(menu.dataset.managerTeamMenu===key&&managerTeamMenuScrollTop[key]!=null)menu.scrollTop=managerTeamMenuScrollTop[key]||0});positionManagerTeamMenu()};
      apply();requestAnimationFrame(apply)
    }
    function renderTeamPickerOwners(){
      if(currentManagerSection()==="managerCreate"){renderManagerCreate();restoreManagerTeamMenuScroll();return}
      renderMenuInvite();renderManagerInviteUi();restoreManagerTeamMenuScroll()
    }
    function managerDraftTeamsPayload(names){const out={};(names||[]).forEach(name=>{const team=managerDraftTeamFor(name);if(team?.id||team?.sourceId)out[String(name||"").toLowerCase()]=team.id||team.sourceId});return out}
    function managerDuplicateTeamUsers(names,teamForName=managerDraftTeamFor){
      const seen=new Map(),dupes=new Set();
      (names||[]).forEach(name=>{const key=managerTeamKey(teamForName(name));if(!key)return;if(seen.has(key)){dupes.add(seen.get(key));dupes.add(String(name||"").toLowerCase())}else seen.set(key,String(name||"").toLowerCase())});
      return dupes
    }
    function managerCatalogTeam(team={},user=""){team=team&&typeof team==="object"?team:{};const seasonTeam=managerSeason?.teamsByUser?.[user]?.team||{},merged={...seasonTeam,...team,logo:team.logo||seasonTeam.logo||""},keys=new Set([merged.sourceId,merged.id,seasonTeam.sourceId,seasonTeam.id].map(teamLookupKey).filter(Boolean)),name=String(merged.name||"").trim().toLowerCase();for(const div of managerDivisions||[]){for(const row of div?.teams||[]){const rowKeys=[row?.sourceId,row?.id].map(teamLookupKey);if(rowKeys.some(k=>keys.has(k))||(name&&String(row?.name||"").trim().toLowerCase()===name))return {...row,...merged,logo:merged.logo||row.logo||""}}}return merged}
    function fixtureOddsLine(f){const o=f?.odds;if(!o)return "";const cell=value=>`<span><em class="odds-percent">${safe(Math.round(Number(value||0)))}%</em></span>`;return `<div class="manager-odds"><div class="manager-odds-line fixture-odds-line"><span></span>${cell(o.home)}${cell(o.draw)}${cell(o.away)}</div></div>`}
    function fixtureTeamHtml(team,id,skill){team=managerCatalogTeam(team,id);const n=Number(skill),humans=new Set(managerSeason?.humanManagers||[]),isSelf=me?.name&&id===me.name,isHuman=!isSelf&&humans.has(id),cls=isSelf?" fixture-team-self":isHuman?" fixture-team-human":"",skillHtml=Number.isFinite(n)?`<small class="manager-team-skill">(${Math.round(n)})</small>`:"";return `${teamFlag(team)}<span class="manager-team-copy"><span class="manager-team-name${cls}">${safe(team?.name||id)}</span>${skillHtml}</span>`}
    function managerTeamName(user){return managerSeason?.teamsByUser?.[user]?.team?.name||user||"TEAM"}
    function fixtureDecisionText(f){if(f?.status!=="played"||f?.decidedBy!=="PEN")return "";const p=f.penaltyScore,score=Array.isArray(p)?` ${p[0]}-${p[1]}`:"";return `PEN${score} ${managerTeamName(f.winner).toUpperCase()} WINS`}
    function fixtureDecisionLine(f){const text=fixtureDecisionText(f);return text?`<div class="manager-odds">${safe(text)}</div>`:""}
    function managerLiveSimulationIndex(f){const rows=managerSeason?.liveSimulations||[],ri=Number(f?.roundIndex),fi=Number(f?.fixtureIndex),sid=String(f?.seasonId||""),h=String(f?.home||""),a=String(f?.away||"");for(let i=0;i<rows.length;i++){const lf=rows[i]?.fixture||{},lri=Number(lf.roundIndex),lfi=Number(lf.fixtureIndex),lsid=String(lf.seasonId||rows[i]?.sourceSeasonId||"");if(Number.isInteger(ri)&&Number.isInteger(fi)&&lri===ri&&lfi===fi&&(!sid||!lsid||sid===lsid))return i;if(h&&a&&String(lf.home||"")===h&&String(lf.away||"")===a&&String(lf.status||"")==="simulating"&&(!sid||!lsid||sid===lsid))return i}return-1}
    function managerFixtureHtml(f){let h=f?.homeTeam||managerSeason?.teamsByUser?.[f.home]?.team,a=f?.awayTeam||managerSeason?.teamsByUser?.[f.away]?.team,sc=f.score?`${f.score[0]}-${f.score[1]}`:"VS",status=f.status==="played"?"FT":(f.status==="watching"||f.status==="simulating")?"LIVE":"",statusCls=status==="LIVE"?" live":status==="FT"?" played":"",statusCell=status?`<span class="manager-fixture-status${statusCls}">${status}</span>`:"",liveIndex=managerLiveSimulationIndex(f),liveAttrs=liveIndex>=0?` data-live-sim="${liveIndex}" role="button" tabindex="0" title="WATCH LIVE"`:"",liveCls=liveIndex>=0?" manager-live-fixture":"",emptyCls=status?"":" no-status";return `<div class="manager-fixture${liveCls}${emptyCls}"${liveAttrs}>${statusCell}<span class="manager-fixture-team manager-fixture-home">${fixtureTeamHtml(h,f.home,f?.strength?.home)}</span><b class="manager-fixture-score">${sc}</b><span class="manager-fixture-team manager-fixture-away">${fixtureTeamHtml(a,f.away,f?.strength?.away)}</span></div>${fixtureDecisionLine(f)}${fixtureOddsLine(f)}`}
    function managerRoundMeta(r,i,fixture=null){const f=fixture||(r?.fixtures||[]).find(x=>x.status==="pending"||x.status==="watching")||(r?.fixtures||[]).find(x=>x.home===me?.name||x.away===me?.name)||(r?.fixtures||[])[0]||{},rawFi=Number(f?.fixtureIndex),foundFi=Number.isInteger(rawFi)?rawFi:(r?.fixtures||[]).findIndex(x=>x===f);return{round:r?.round,roundIndex:i,fixtureIndex:foundFi>=0?foundFi:undefined,phase:r?.phase||f.phase||"league",playoff:r?.playoff,cupName:r?.cupName||f.cupName||"",fixture:f}}
    function managerAutoStartMeta(meta=null){if(!meta?.fixture)return null;const roundIndex=meta.roundIndex??meta.fixture.roundIndex,fixtureIndex=meta.fixtureIndex??meta.fixture.fixtureIndex;return{seasonId:String(meta.seasonId||managerSeason?.id||""),user:String(meta.user||me?.name||""),round:meta.round,roundLabel:managerRoundTitle(meta),roundIndex,fixtureIndex,phase:meta.phase,playoff:meta.playoff,cupName:meta.cupName,createdAt:Number(meta.createdAt||Date.now()),fixture:{...meta.fixture,round:meta.round,roundLabel:managerRoundTitle(meta),roundIndex,fixtureIndex,phase:meta.phase||meta.fixture.phase,playoff:meta.playoff}}}
    function managerAutoStartStorageKey(){return`yspManagerAutoStart:${encodeURIComponent(String(me?.name||"guest"))}`}
    function managerAutoStartConsumedKey(){return`yspManagerAutoStartConsumed:${encodeURIComponent(String(me?.name||"guest"))}`}
    function managerAutoFixtureKey(meta=null){const f=meta?.fixture||meta||{},seasonId=String(meta?.seasonId||managerSeason?.id||""),user=String(meta?.user||me?.name||""),ri=Number(meta?.roundIndex??f.roundIndex),fi=Number(meta?.fixtureIndex??f.fixtureIndex);return seasonId&&user&&Number.isInteger(ri)&&Number.isInteger(fi)?`${seasonId}:${user}:${ri}:${fi}:${String(f.home||"")}:${String(f.away||"")}`:""}
    function loadManagerAutoConsumed(){try{return JSON.parse(sessionStorage.getItem(managerAutoStartConsumedKey())||"{}")||{}}catch(e){return{}}}
    function managerAutoStartConsumed(meta=null){const key=managerAutoFixtureKey(meta);if(!key)return false;const seen=loadManagerAutoConsumed(),at=Number(seen[key]||0);return at>0&&Date.now()-at<30*60*1000}
    function markManagerAutoStartConsumed(meta=null){const key=managerAutoFixtureKey(meta);if(!key)return;try{const seen=loadManagerAutoConsumed(),now=Date.now();seen[key]=now;Object.keys(seen).forEach(k=>{if(now-Number(seen[k]||0)>30*60*1000)delete seen[k]});sessionStorage.setItem(managerAutoStartConsumedKey(),JSON.stringify(seen))}catch(e){}}
    function saveManagerAutoStart(meta){try{if(meta)sessionStorage.setItem(managerAutoStartStorageKey(),JSON.stringify(meta))}catch(e){}}
    function clearStoredManagerAutoStart(){try{sessionStorage.removeItem(managerAutoStartStorageKey())}catch(e){}}
    function forgetManagerAutoStart(){managerAutoStartFixture=null;clearStoredManagerAutoStart()}
    function managerAutoStartFresh(meta=null){const at=Number(meta?.createdAt||0);return at>0&&Date.now()-at<10*60*1000}
    function loadManagerAutoStart(){if(managerAutoStartFixture){if(!managerAutoStartFresh(managerAutoStartFixture)||managerAutoStartConsumed(managerAutoStartFixture)){forgetManagerAutoStart();return null}return managerAutoStartFixture}if(!managerSeason?.id)return null;try{const raw=sessionStorage.getItem(managerAutoStartStorageKey());if(!raw)return null;const meta=JSON.parse(raw);if(!meta?.fixture||!managerAutoStartFresh(meta)||String(meta.seasonId||"")!==String(managerSeason.id)||String(meta.user||"")!==String(me?.name||"")||managerAutoStartConsumed(meta)){clearStoredManagerAutoStart();return null}managerAutoStartFixture=meta;return meta}catch(e){clearStoredManagerAutoStart();return null}}
    function rememberManagerAutoStart(meta=null){const next=managerAutoStartMeta(meta);if(!next||managerAutoStartConsumed(next))return null;managerAutoStartFixture=next;saveManagerAutoStart(managerAutoStartFixture);return managerAutoStartFixture}
    function managerActiveAutoStartStatus(meta=null){const status=String(meta?.fixture?.status||"pending");return status==="pending"||status==="watching"||status==="simulating"}
    function managerAutoStartArmedFor(meta=null){const remembered=managerAutoStartFixture||loadManagerAutoStart(),target=managerAutoStartMeta(meta);if(!remembered||!target||managerAutoStartConsumed(remembered)||!managerActiveAutoStartStatus(target))return false;const key=managerAutoFixtureKey(remembered),targetKey=managerAutoFixtureKey(target);return !!key&&key===targetKey}
    function consumeManagerAutoStartFor(meta=null){const remembered=managerAutoStartFixture||loadManagerAutoStart(),target=managerAutoStartMeta(meta?.fixture?meta:{fixture:meta||{},round:meta?.round,roundLabel:meta?.roundLabel,roundIndex:meta?.roundIndex,fixtureIndex:meta?.fixtureIndex,phase:meta?.phase,playoff:meta?.playoff,cupName:meta?.cupName});if(!remembered||!target)return;const key=managerAutoFixtureKey(remembered),targetKey=managerAutoFixtureKey(target);if(key&&key===targetKey){markManagerAutoStartConsumed(target);forgetManagerAutoStart()}}
    function managerAfterContinueStorageKey(){return`yspManagerAfterContinueStart:${encodeURIComponent(String(me?.name||"guest"))}`}
    function clearStoredAfterContinueStart(){try{sessionStorage.removeItem(managerAfterContinueStorageKey())}catch(e){}}
    function rememberAfterContinueStart(vote=null){if(!managerSeason?.id||!me?.name||!vote)return;const roundIndex=Number(vote.roundIndex);try{sessionStorage.setItem(managerAfterContinueStorageKey(),JSON.stringify({seasonId:String(managerSeason.id),user:String(me.name),afterRoundIndex:Number.isInteger(roundIndex)?roundIndex:-1,createdAt:Date.now()}))}catch(e){}}
    function loadAfterContinueStart(){if(!managerSeason?.id)return null;try{const raw=sessionStorage.getItem(managerAfterContinueStorageKey());if(!raw)return null;const meta=JSON.parse(raw);if(String(meta?.seasonId||"")!==String(managerSeason.id)||String(meta?.user||"")!==String(me?.name||"")){clearStoredAfterContinueStart();return null}return meta}catch(e){clearStoredAfterContinueStart();return null}}
    function managerOwnRoundFixtureMeta(roundIndex){const i=Number(roundIndex);if(!Number.isInteger(i)||i<0||!managerSeason)return null;const r=(managerSeason.rounds||[])[i];if(!r)return null;const user=String(me?.name||"");const f=(r.fixtures||[]).find(x=>String(x.home||"")===user||String(x.away||"")===user);return f?managerRoundMeta(r,i,f):null}
    function managerOwnRoundFixtureStatus(roundIndex){return String(managerOwnRoundFixtureMeta(roundIndex)?.fixture?.status||"")}
    function managerRoundVotePassive(vote=null){const v=vote||managerSeason?.simVote;if(!v)return false;return !!(v.passiveRoundWait||v.mineContinuePending||v.mineRoundPlayed||managerOwnRoundFixtureStatus(v.roundIndex)==="played")}
    function managerReadyVoteLocallyArmed(vote=null){const v=vote||managerSeason?.simVote;if(!v?.mineReady||v.mineContinuePending||managerRoundVotePassive(v))return false;const meta=managerOwnRoundFixtureMeta(v.roundIndex);return !!(meta&&managerActiveAutoStartStatus(meta)&&managerAutoStartArmedFor(meta))}
    function rememberManagerAutoStartFromReadyVote(){const vote=managerSeason?.simVote;if(!vote?.mineReady||vote?.mineContinuePending||managerRoundVotePassive(vote))return;const meta=managerOwnRoundFixtureMeta(vote.roundIndex);if(!meta)return;const status=String(meta.fixture?.status||"");if(status==="pending"||status==="watching"||status==="simulating")rememberManagerAutoStart(meta)}
    function managerFindFixtureMeta(ref=null){if(!ref||!managerSeason)return null;const ri=Number(ref.roundIndex),fi=Number(ref.fixtureIndex);if(Number.isInteger(ri)&&ri>=0){const r=(managerSeason.rounds||[])[ri],f=r?.fixtures?.[fi];if(f)return managerRoundMeta(r,ri,f)}const h=String(ref.home||ref.fixture?.home||""),a=String(ref.away||ref.fixture?.away||"");for(let i=0;i<(managerSeason.rounds||[]).length;i++){const r=managerSeason.rounds[i],f=(r.fixtures||[]).find(x=>String(x.home||"")===h&&String(x.away||"")===a&&["played","simulating"].includes(String(x.status||"")));if(f)return managerRoundMeta(r,i,f)}return null}
    function managerActiveRoundIndex(){const vote=managerSeason?.simVote||managerSeason?.watchVote,vi=Number(vote?.roundIndex);if(Number.isInteger(vi)&&vi>=0&&(managerSeason?.rounds||[])[vi])return vi;for(let i=0;i<(managerSeason?.rounds||[]).length;i++){if((managerSeason.rounds[i].fixtures||[]).some(f=>f.status==="pending"||f.status==="watching"))return i}return-1}
    function managerPendingRound(){const i=managerActiveRoundIndex(),r=(managerSeason?.rounds||[])[i];return r?managerRoundMeta(r,i):null}
    function nextManagerFixture(){const user=me?.name,i=managerActiveRoundIndex(),r=(managerSeason?.rounds||[])[i],vote=effectiveRoundVote();if(!user||!r)return null;if(Number(vote?.roundIndex)===i&&managerReadyVoteLocallyArmed(vote))return null;for(const f of r.fixtures||[]){if(f.status==="pending"&&(f.home===user||f.away===user))return managerRoundMeta(r,i,f)}return null}
    function nextManagerFixturePreview(){const user=me?.name;if(!user)return null;for(let i=0;i<(managerSeason?.rounds||[]).length;i++){const r=managerSeason.rounds[i];for(const f of r.fixtures||[]){if((f.status==="pending"||f.status==="watching")&&(f.home===user||f.away===user))return managerRoundMeta(r,i,f)}}return null}
    function localRoundVote(){
      const humans=new Set(managerSeason?.humanManagers||[]),user=me?.name||"";
      if(!humans.size)return null;
      for(const r of managerSeason?.rounds||[]){
        const pending=(r.fixtures||[]).some(f=>f.status==="pending"||f.status==="watching");
        if(!pending)continue;
        const ready=[],waiting=[],seen=new Set();
        let minePlayed=false;
        for(const f of r.fixtures||[]){
          [f.home,f.away].forEach(name=>{
            if(!humans.has(name)||seen.has(name))return;
            seen.add(name);
            if(f.status==="played"){ready.push(name);if(name===user)minePlayed=true}else waiting.push(name);
          });
        }
        if(!ready.length&&!waiting.length)return null;
        return{round:r.round,ready,waiting,readyCount:ready.length,neededCount:ready.length+waiting.length,mineReady:ready.includes(user),mineRoundPlayed:minePlayed,mineFixtureStatus:minePlayed?"played":"",passiveRoundWait:minePlayed,allReady:waiting.length===0};
      }
      return null;
    }
    function effectiveRoundVote(){return managerSeason?.simVote||managerSeason?.watchVote||localRoundVote()}
    function effectiveSimRoundVote(){return managerSeason?.simVote||localRoundVote()}
    function managerCpuOnlyActionLabel(){const p=managerPendingRound();if(!p)return "FINISH SEASON";const phase=String(p.phase||"").toLowerCase(),round=String(p.round||"").toUpperCase();if(phase==="cup")return "FINISH CUP";if(phase==="playoff"||p.playoff)return round.includes("FINAL")?"FINISH SEASON":"FINISH PLAYOFFS";return "FINISH SEASON"}
    function managerNextRoundPayload(meta=null){const m=meta||managerPendingRound()||{},payload={simKey:managerSeason?.simVote?.key||"",speedPct:managerLocalMatchSpeedPct},roundIndex=Number(m.roundIndex??m.fixture?.roundIndex),phase=String(m.phase||m.fixture?.phase||"");if(Number.isInteger(roundIndex)&&roundIndex>=0)payload.roundIndex=roundIndex;if(phase)payload.roundPhase=phase;const fixtureIndex=Number(m.fixtureIndex??m.fixture?.fixtureIndex);if(Number.isInteger(fixtureIndex)&&fixtureIndex>=0)payload.fixtureIndex=fixtureIndex;return payload}
    function managerRoundContinuePayload(meta=null){const m=meta||managerSeason?.simVote||{},payload={},rawRoundIndex=m.roundIndex??m.fixture?.roundIndex,roundIndex=rawRoundIndex===""||rawRoundIndex===null||rawRoundIndex===undefined?NaN:Number(rawRoundIndex);if(Number.isInteger(roundIndex)&&roundIndex>=0){payload.roundIndex=roundIndex;const round=(managerSeason?.rounds||[])[roundIndex]||{},phase=String(m.roundPhase||m.phase||m.fixture?.phase||round.phase||"");if(phase)payload.roundPhase=phase}const simKey=String(m.simKey||m.key||"");if(simKey)payload.simKey=simKey;return payload}
    function managerRoundLabel(r){return (r.phase||"")==="cup"?(r.cupName||"CUP"):r.playoff?"PLAYOFF":"ROUND"}
    function managerRoundTitle(r){return (r.phase||"")==="cup"?(r.round||r.cupName||"CUP"):`${managerRoundLabel(r)} ${r.round||""}`}
    function managerMatchTypeLine(meta={},fixture=null){const phase=String(meta.phase||fixture?.phase||"league").toLowerCase(),roundText=String(meta.round||fixture?.round||"").trim();if(phase==="cup")return `CUP MATCH${roundText?` | ${roundText}`:""}`;if(phase==="playoff"||meta.playoff||fixture?.playoff)return `PLAYOFF MATCH${roundText?` | ${roundText}`:""}`;if(phase==="friendly")return "FRIENDLY MATCH";if(phase==="training")return "TRAINING MATCH";return `LEAGUE MATCH${roundText?` | ROUND ${roundText}`:""}`}
    function currentLiveMatchTypeText(){if(trainingMode)return "TRAINING MATCH";const mf=match?.managerFixture;if(mf){if(mf.phase||mf.round||mf.playoff)return managerMatchTypeLine(mf,mf);if(managerSeason?.rounds){const round=(managerSeason.rounds||[])[Number(mf.roundIndex)]||{},fixture=(round.fixtures||[])[Number(mf.fixtureIndex)]||{};return managerMatchTypeLine({round:round.round||fixture.round,phase:fixture.phase||round.phase||"league",playoff:!!(fixture.playoff||round.playoff),cupName:fixture.cupName||round.cupName||""},fixture)}return "MANAGER MATCH"}return "FRIENDLY MATCH"}
    function managerMatchCardKey(match){const f=match?.fixture||{};return `${match?.round??""}:${f.roundIndex??""}:${f.fixtureIndex??""}:${f.home??""}:${f.away??""}`}
    function managerLastMatchCard(label,match){if(!match?.fixture)return "";const meta={round:match.round,phase:match.fixture?.phase||"league",playoff:match.fixture?.phase==="playoff"};return `<div class="manager-last"><b><span class="manager-inline-label">${safe(label)}</span> ${safe(managerMatchTypeLine(meta,match.fixture))}</b>${managerFixtureHtml(match.fixture)}</div>`}
    function seasonTeamLine(id,fallbackTeam=null,extraClass=""){const base=fallbackTeam||managerSeason?.teamsByUser?.[id]?.team||null,t=base||id?managerCatalogTeam(base||{},id):null,cls=extraClass?` ${safe(extraClass)}`:"";return id||t?`<span class="season-team${cls}">${teamFlag(t)}<span>${safe(t?.name||id||"TEAM")}</span></span>`:`<span class="season-team${cls}"><span>None</span></span>`}
    function movementTeamLine(item){const t=item.team||item,method=item.method?`<small>${safe(String(item.method).toUpperCase())}</small>`:"";return `<span class="season-team">${teamFlag(t)}<span>${safe(t?.name||item.user||"TEAM")}</span>${method}</span>`}
    function movementTeamsHtml(items){const rows=(items||[]).map(movementTeamLine);if(!rows.length)return `<span class="season-team"><span>None</span></span>`;if(rows.length===2)return `${rows[0]}<span class="season-report-gap"></span>${rows[1]}`;return rows.join("")}
    function seasonReportRow(label,html,teamClass="season-report-teams"){return `<div class="season-report-row"><div class="season-report-label">${safe(label)}</div><div class="${safe(teamClass)}">${html}</div></div>`}
    function playoffSummaryHtml(){const rows=(managerSeason?.rounds||[]).filter(r=>r.playoff).flatMap(r=>(r.fixtures||[]).map(f=>({round:r.round,...f}))).filter(f=>f.status==="played");if(!rows.length)return "";return `<div class="season-report-section"><b>PLAYOFF MATCHES</b><div class="season-report-list">${rows.map(f=>{const score=f.score?`${f.score[0]}-${f.score[1]}`:"v",decision=fixtureDecisionText(f);return `<div class="season-match"><span class="season-round">${safe(f.round)}</span>${seasonTeamLine(f.home,null,"season-home")}<span class="season-score">${safe(score)}</span>${seasonTeamLine(f.away,null,"season-away")}${decision?`<div class="season-decision">${safe(decision)}</div>`:""}</div>`}).join("")}</div></div>`}
    function cupFinalFixture(c){const winner=String(c?.winner||""),runner=String(c?.runnerUp||""),key=String(c?.key||"");let found=null;(managerSeason?.rounds||[]).forEach(r=>{if((r.phase||"")!=="cup"||(key&&String(r.cupKey||"")!==key))return;(r.fixtures||[]).forEach(f=>{const home=String(f.home||""),away=String(f.away||"");if(f.status==="played"&&winner&&runner&&((home===winner&&away===runner)||(home===runner&&away===winner)))found=f})});return found}
    function cupScoreText(c,f){if(!f?.score)return "v";return String(f.home||"")===String(c?.winner||"")?`${f.score[0]}-${f.score[1]}`:`${f.score[1]}-${f.score[0]}`}
    function cupReportHtml(r){const cups=(r?.cups&&r.cups.length?r.cups:(r?.cup?[r.cup]:[])).filter(c=>c&&c.status==="finished");if(!cups.length)return "";return `<div class="season-report-section"><b>CUPS</b><div class="season-report-list">${cups.map(c=>{const f=cupFinalFixture(c),decision=fixtureDecisionText(f);return `<div class="season-match"><span class="season-round">${safe(c.name||"Cup")}</span>${seasonTeamLine(c.winner,null,"season-home")}<span class="season-score">${safe(cupScoreText(c,f))}</span>${seasonTeamLine(c.runnerUp,null,"season-away")}${decision?`<div class="season-decision">${safe(decision)}</div>`:""}</div>`}).join("")}</div></div>`}
    function seasonPlayerReportLine(p,mode){return `<div class="season-report-row"><span class="season-report-label">${safe(p.role||"")}</span><div><b>${safe(p.name||"Player")}</b> (${safe(p.teamName||p.user||"")}) | ${mode==="work"?"distance "+safe(p.distanceMeters||0)+"m":"avg impact "+safe(p.avgImpact??0)} | games ${safe(p.reports||0)} | touch ${safe(p.touches||0)} | shot ${safe(p.shots||0)} | tackle ${safe(p.tackles||0)}</div></div>`}
    function seasonPlayerReportHtml(r){const pr=r?.playerReport||{},work=pr.workhorses||[],best=pr.best||[];if(!work.length&&!best.length)return "";return `<div class="season-report-section"><b>HUMAN PLAYER REPORT</b>${work.length?`<div class="season-report-section"><b>WORKHORSES</b>${work.map(p=>seasonPlayerReportLine(p,"work")).join("")}</div>`:""}${best.length?`<div class="season-report-section"><b>BEST PLAYERS</b>${best.map(p=>seasonPlayerReportLine(p,"best")).join("")}</div>`:""}</div>`}
    function seasonGrowthStatLabel(stat){const row=statMap().find(([k])=>k===stat);return row?row[1]:String(stat||"").toUpperCase()}
    function seasonPlayerGrowthLine(p){const reasons=(p.reasons||[]).join(" + "),stat=p.statGain?` | ${safe(seasonGrowthStatLabel(p.stat))} ${safe(p.statBefore)} -> ${safe(p.statAfter)}`:"",value=p.valueBoostPct?` | value +${safe(p.valueBoostPct)}%`:"",rank=p.topScorerRank?` | scorer #${safe(p.topScorerRank)} (${safe(p.goals||0)} goals)`:"",praise=p.praisePoints?` | praise ${safe(p.praisePoints)} pts`:"";return `<div class="season-report-row"><span class="season-report-label">BOOST</span><div><b>${safe(p.playerName||"Player")}</b> (${safe(p.user||"")})${stat}${value}${rank}${praise}${reasons?` | ${safe(reasons)}`:""}</div></div>`}
    function seasonPlayerGrowthHtml(r){const rows=r?.playerGrowth||[];if(!rows.length)return "";return `<div class="season-report-section"><b>PLAYER GROWTH</b>${rows.map(seasonPlayerGrowthLine).join("")}</div>`}
    function seasonFinanceReportHtml(){if(!managerFinance)return "";const f=managerFinance,start=managerSeason?.financeStart||{},delta=k=>Math.max(0,Number(f?.[k]||0)-Number(start?.[k]||0)),match=delta("income"),season=delta("seasonAwards"),transfers=delta("transferIncome"),total=match+season+transfers;if(total<=0)return "";const rows=[["TOTAL MONEY IN",total],["MATCH INCOME",match],["GATE",delta("gateIncome")],["MERCH",delta("merchIncome")],["MATCH BONUS",delta("bonusIncome")],["CUP MONEY",delta("cupIncome")],["SEASON MONEY",season],["TRANSFER SALES",transfers]].filter(([label,value])=>label==="TOTAL MONEY IN"||value>0);return `<div class="season-report-section"><b>FINANCE</b>${rows.map(([label,value])=>seasonReportRow(label,`<b>${safe(money(value))}</b>`)).join("")}</div>`}
    function managerJobOfferReasonText(o){const reason=String(o?.reason||""),rank=Number(o?.rank||0);if(reason==="league_title")return "League title season. A club above wants to talk.";if(reason==="playoff_promotion")return "Playoff promotion. Smaller chance, but the higher league noticed.";if(reason==="direct_promotion")return "Direct promotion season. A higher-division club is interested.";if(reason==="top_flight_title")return "Title-winning season. Another top-flight club is interested.";return rank?`Finished ${safe(rank)}. Same-division club is interested.`:"Same-division club is interested."}
    function managerJobOfferTeamUser(o){const team=o?.team||{},direct=String(o?.teamUser||"").trim(),id=String(team.id||team.sourceId||"").trim();return direct||(id?`cpu:${id}`:"")}
    function managerJobOffersHtml(){const offers=(managerSeason?.jobOffers||[]).filter(o=>o&&String(o.status||"pending")!=="rejected");if(!offers.length)return "";return `<div class="season-report-section manager-job-offers"><b>JOB OFFERS</b>${offers.map(o=>{const accepted=String(o.status||"pending")==="accepted",team=o.team||{},teamUser=managerJobOfferTeamUser(o);return `<div class="manager-job-offer ${accepted?"accepted":""}"><button class="manager-job-main manager-job-team-button" data-job-team="${safe(teamUser)}" type="button" ${teamUser?"":"disabled"}>${teamFlag(team)}<div><strong>${safe(team.name||"Team")}</strong><span>${safe(o.targetDivision||"Division")} | ${safe(o.reasonLabel||"Offer")} | VIEW CLUB</span><small>${managerJobOfferReasonText(o)}</small></div></button><div class="manager-job-actions">${accepted?`<b>ACCEPTED</b>`:`<button class="green" data-job-offer="${safe(o.id)}" data-job-decision="accept" type="button">ACCEPT</button><button data-job-offer="${safe(o.id)}" data-job-decision="decline" type="button">DECLINE</button>`}</div></div>`}).join("")}</div>`}
    function seasonReportHtml(){const r=managerSeason?.seasonReport;if(managerSeason?.status!=="finished"||!r)return "";const promoted=movementTeamsHtml(r.promoted||[]),relegated=movementTeamsHtml(r.relegatedFromAbove||[]);return `<div class="manager-playoff season-report"><div class="season-report-title">SEASON REPORT</div><div class="season-report-section"><b>SEASON MOVEMENT</b>${seasonReportRow(`Promoted to ${r.promotedToDivision||"division above"}`,promoted,"season-report-teams season-movement-teams")}${seasonReportRow(`Relegated from ${r.relegatedFromDivision||"division above"}`,relegated,"season-report-teams season-movement-teams")}</div>${managerJobOffersHtml()}${seasonFinanceReportHtml()}${cupReportHtml(r)}${playoffSummaryHtml()}${seasonPlayerGrowthHtml(r)}${seasonPlayerReportHtml(r)}</div>`}
    function statMap(){return [["shooting","SHT"],["passing","PAS"],["tackling","TAC"],["heading","HEA"],["passcontrol","PCL"],["shotcontrol","SCL"],["speed","SPD"],["crit","CRT"],["stamina","STA"],["strength","STR"],["positioning","POS"],["vision","VIS"],["composure","CMP"],["aggression","AGR"],["discipline","DIS"],["crossing","CRS"],["dribbling","DRB"],["workrate","WRK"],["keeping","KEEP"]]}
    function statLine(p){const s=p.stats||{};return statMap().filter(([k])=>s[k]!==undefined).map(([k,l])=>`${l} ${s[k]}`).join(" ")}
    function managerBoostPct(p){return Number(p?.hiredManagerBoostPct||0)}
    function playerConditionMultiplier(p){const daily=dailyFormPct(p)?1+dailyFormPct(p)/100:1,manager=managerBoostPct(p)?1+managerBoostPct(p)/100:1;return daily*manager}
    function adjustedStatValue(p,k){const base=Number(p?.stats?.[k]??0),m=playerConditionMultiplier(p);return m&&Math.abs(m-1)>.0001?Math.max(0,Math.min(100,Math.round(base*m))):base}
    function statValueHtml(p,k){const base=Number(p?.stats?.[k]??0),adjusted=adjustedStatValue(p,k);return `${safe(base)}${adjusted!==base?` <small>${safe(adjusted)}</small>`:""}`}
    function statChips(p){const s=p.stats||{};return statMap().filter(([k])=>s[k]!==undefined).map(([k,l])=>`<div class="team-stat"><span>${l}</span><span>${statValueHtml(p,k)}</span></div>`).join("")}
    function playerDisplayRole(p){return p?.displayRole||p?.naturalRole||p?.role||"-"}
    function playerSlotRole(p){return p?.slotRole||p?.role||p?.naturalRole||"-"}
    function playerRoleTokens(p){const raw=[p?.displayRole,p?.naturalRole,p?.role].filter(Boolean).join("/");return [...new Set(String(raw||"-").toUpperCase().split("/").map(r=>r.trim()).filter(Boolean))]}
    function playerPrimaryRole(p){return playerRoleTokens(p)[0]||String(playerSlotRole(p)||"").toUpperCase()||"-"}
    function playerRating(p){return Number(p?.effectiveRating??p?.rating??0)}
    function playerBaseRating(p){return Number(p?.baseRating??p?.rating??p?.effectiveRating??0)}
    function playerFormGeneratedRating(p){const base=playerBaseRating(p),m=playerConditionMultiplier(p);return m&&Math.abs(m-1)>.0001?Math.max(0,Math.min(100,Math.round(base*m))):base}
    function managerBoostLabel(p){const v=managerBoostPct(p);return v?`TEAM +${safe(v)}%`:""}
    function formationRatingHtml(p){const base=playerBaseRating(p),formed=playerFormGeneratedRating(p);return `<span class="formation-rating-main">OVR ${safe(base)}${formed!==base?` (${safe(formed)})`:""}</span>`}
    function formationBoostHtml(p){const pct=dailyFormPct(p),boost=managerBoostPct(p),lines=`${pct?`<small class="formation-form-ovr ${pct>0?"up":"down"}">${pct>0?"+":""}${safe(pct)}% OVR</small>`:""}${boost?`<small class="formation-form-ovr up">+${safe(boost)}% TEAM</small>`:""}`;return lines?`<span class="formation-rating-boosts">${lines}</span>`:""}
    function benchRatingHtml(p){const base=playerBaseRating(p),pct=dailyFormPct(p),boost=managerBoostPct(p),formed=playerFormGeneratedRating(p),lines=`${pct?`<em class="bench-form-ovr ${pct>0?"up":"down"}">${pct>0?"+":""}${safe(pct)}% OVR</em>`:""}${boost?`<em class="bench-form-ovr up">+${safe(boost)}% TEAM</em>`:""}`;return `<span class="bench-rating-main">OVR ${safe(base)}${formed!==base?` (${safe(formed)})`:""}</span>${lines?`<span class="bench-rating-boosts">${lines}</span>`:""}`
    }
    function playerFootText(p){const f=String(p?.foot||"").toUpperCase();return f==="L"?"L-foot":f==="R"?"R-foot":f==="B"?"Both feet":""}
    function playerAgeText(p){const age=Number(p?.age||0);return age?`Age ${safe(age)}`:""}
    function playerBonusText(p){const b=Number(p?.footBonus||0);return b>0?`OVR +${b}`:b<0?`OVR ${b}`:""}
    function canonicalUiRole(role){const r=String(role||"").toUpperCase().trim(),map={GOALKEEPER:"GK",KEEPER:"GK","LEFT BACK":"LB","RIGHT BACK":"RB","CENTRE BACK":"CB","CENTER BACK":"CB","LEFT MIDFIELD":"LM","RIGHT MIDFIELD":"RM",MIDFIELD:"CM",MIDFIELDER:"CM",FORWARD:"ST",ATTACKER:"ST",STRIKER:"ST",CF:"ST",FW:"ST"};return map[r]||(["GK","LB","RB","CB","LM","RM","CM","ST"].includes(r)?r:"")}
    function uiRolePair(role){const r=canonicalUiRole(role);if(["LB","RB"].includes(r))return "fullback";if(["LM","RM"].includes(r))return "wide-mid";return r}
    function playerPositionPenalty(p){return 0}
    function playerMetaText(p){return [isLoanPlayer(p)?"LOAN":playerFootText(p),playerAgeText(p),playerBonusText(p),managerBoostLabel(p)].filter(Boolean).join(" | ")}
    function dailyFormPct(p){return Number(p?.dailyFormPct||0)}
    function dailyFormLabel(p){const v=dailyFormPct(p);return v?`FORM ${v>0?"+":""}${v}%`:""}
    function dailyFormDot(p,extra=""){const v=dailyFormPct(p);if(!v)return "";const cls=v>0?"up":"down";return `<span class="daily-form-dot ${cls}${extra?` ${safe(extra)}`:""}" title="${safe(dailyFormLabel(p))}"></span>`}
    function dailyFormText(p){const v=dailyFormPct(p);if(!v)return "";const cls=v>0?"up":"down";return `<span class="daily-form-text ${cls}">${safe(dailyFormLabel(p))}</span>`}
    function playerCardInfo(p){const c=p?.matchCards||p?.cards||{};let yellow=Math.max(Number(c.yellow??c.yellows??0),Number(p?.yellowCards??p?.yellows??0)),red=Math.max(Number(c.red??c.reds??0),Number(p?.redCards??p?.reds??0)),secondYellow=!!c.secondYellow||Number(p?.secondYellowReds||0)>0,directRed=!!c.directRed||Number(p?.directReds||0)>0;if(secondYellow){yellow=Math.max(2,yellow);red=Math.max(1,red)}if(yellow>=2){red=Math.max(1,red);if(!directRed)secondYellow=true}return yellow||red?{yellow,red,secondYellow,directRed}:null}
    function playerCardText(p){const c=playerCardInfo(p);if(!c)return "";const parts=[];if(c.yellow)parts.push(`${c.yellow} yellow`);if(c.red)parts.push(c.secondYellow?"red (2 yellows)":"red");return parts.join(", ")}
    function playerCardBadges(p,extra=""){const c=playerCardInfo(p);if(!c)return "";return `<span class="player-card-badges${extra?` ${safe(extra)}`:""}" title="${safe(playerCardText(p))}">${c.yellow?`<span class="player-card-badge yellow">${c.yellow>1?safe(c.yellow):""}</span>`:""}${c.red?`<span class="player-card-badge red">${c.red>1?safe(c.red):""}</span>`:""}</span>`}
    function injuryInfo(p){return p?.injury||null}
    function injuryLabel(p){const i=injuryInfo(p);if(!i)return "";const n=Number(i.remaining||0);return `INJURED ${n} MATCH${n===1?"":"ES"}${i.reason?` - ${i.reason}`:""}`}
    function injuryBadge(p,extra=""){const label=injuryLabel(p);return label?`<span class="injury-badge${extra?` ${safe(extra)}`:""}" title="${safe(label)}">!</span>`:""}
    function injuryText(p){const label=injuryLabel(p);return label?`<span class="injury-text">${safe(label)}</span>`:""}
    function trainingInfo(p){return p?.training||null}
    function trainingLabel(p){const t=trainingInfo(p);if(!t)return "";const n=Number(t.remaining||0),stat=t.statLabel||String(t.stat||"STAT").toUpperCase(),gain=Number(t.gain||2);return `TRAINING ${stat} +${gain} | ${n} MATCH${n===1?"":"ES"}`}
    function trainingBadge(p,extra=""){const label=trainingLabel(p);return label?`<span class="training-badge${extra?` ${safe(extra)}`:""}" title="${safe(label)}">T</span>`:""}
    function trainingText(p){const label=trainingLabel(p);return label?`<span class="training-text">${safe(label)}</span>`:""}
    function formationStatPreview(p){const s=p.stats||{},role=playerPrimaryRole(p),sets={GK:[["keeping","KEEP"],["passcontrol","PCL"],["speed","SPD"]],ST:[["shooting","SHT"],["shotcontrol","SCL"],["speed","SPD"]],CB:[["tackling","TAC"],["heading","HEA"],["strength","STR"]],LB:[["speed","SPD"],["tackling","TAC"],["crossing","CRS"]],RB:[["speed","SPD"],["tackling","TAC"],["crossing","CRS"]],CM:[["passing","PAS"],["vision","VIS"],["tackling","TAC"]],LM:[["speed","SPD"],["crossing","CRS"],["dribbling","DRB"]],RM:[["speed","SPD"],["crossing","CRS"],["dribbling","DRB"]]};return (sets[role]||[["passing","PAS"],["speed","SPD"],["workrate","WRK"]]).filter(([k])=>s[k]!==undefined).map(([k,l])=>`${l} ${s[k]}`).join(" ")}
    function formationCoord(value,scale,min,max){const n=Number(value);return Math.max(min,Math.min(max,50+(((Number.isFinite(n)?n:.5)*100)-50)*scale))}
    function formationCompactBoard(){return typeof matchMedia==="function"&&matchMedia("(max-aspect-ratio:4/5)").matches}
    function formationXCoord(value){return formationCompactBoard()?formationCoord(value,1.1,11,89):formationCoord(value,1.22,5,95)}
    function formationBoardY(value){const n=Number(value),y=Number.isFinite(n)?n:.7,top=.47,bottom=.94,min=formationCompactBoard()?11:12.5,max=78,ratio=Math.max(0,Math.min(1,(y-top)/(bottom-top)));return min+ratio*(max-min)}
    function formationSlotYOffset(role){const r=String(role||"").toUpperCase();if(r==="ST")return -4;if(["CB","LB","RB","LWB","RWB"].includes(r))return -7;if(["CM","LM","RM","DM","CDM","AM","CAM"].includes(r))return -4;return -5}
    function shirtStyle(team){return `style="--shirt:${safe(team?.shirt||"#ffffff")};--trim:${safe(team?.trim||"#111111")}"`}
    function shortPlayerName(name){const parts=String(name||"Player").trim().split(/\s+/);return parts.length>1?parts[parts.length-1]:parts[0]}
    function formationNameStyle(name){const len=[...shortPlayerName(name)].length,scale=len>=13?.64:len>=11?.72:len>=9?.82:len>=7?.92:1;return `--formation-name-size:${(13*scale).toFixed(1)}px;--formation-name-mobile-size:${(9.5*scale).toFixed(1)}px`}
    function squadPickAttrs(p,editable,source="list"){return editable?` data-squad-player="${safe(p.id)}" data-squad-source="${safe(source)}" role="button" tabindex="0"`:""}
    function squadPickClass(p,editable,extra=""){const picked=squadSwapFirst&&String(squadSwapFirst)===String(p.id),second=squadSwapSecond&&String(squadSwapSecond)===String(p.id),active=picked||second,penalty=playerPositionPenalty(p)<0,injured=!!injuryInfo(p),training=!!trainingInfo(p);return `${extra}${editable?" squad-pick":""}${active?" selected":""}${active&&squadSwapBusy?" swapping":""}${penalty?" position-penalty":""}${injured?" injured":""}${training?" training":""}`}
    function setSquadPlacementMode(on){squadPlacementMode=!!on;$("managerTeamPage")?.classList.toggle("squad-placement-active",squadPlacementMode)}
    function clearSquadSwap(){squadSwapFirst=null;squadSwapSecond=null;squadSwapBusy=false;squadSwapFirstSource="";squadBenchActionPlayer=null;setSquadPlacementMode(false)}
    function managerSkillStatKeys(p){const keys=["shooting","passing","tackling","heading","passcontrol","shotcontrol","speed","crit","stamina","strength","positioning","vision","composure","aggression","discipline","crossing","dribbling","workrate"];if(playerPrimaryRole(p)==="GK")keys.push("keeping");return keys}
    function playerSkillPoints(p){const s=p?.stats||{},keys=managerSkillStatKeys(p).filter(k=>s[k]!==undefined);return keys.length?keys.reduce((n,k)=>n+Number(s[k]||0),0):playerRating(p)*8}
    function formationDisplaySkill(players){const list=players||[];if(!list.length)return 0;const raw=list.reduce((n,p)=>n+playerSkillPoints(p),0)*(16/list.length);return Math.max(0,Math.min(100,Math.round(raw/29000*100)))}
    function formationHtml(players,team,editable=false){
      if(!players.length)return "";
      const skill=formationDisplaySkill(players);
      return `<div class="team-formation"><div class="formation-skill-label">S = ${safe(skill)}</div>${players.map(p=>{
        const x=formationXCoord(p.homeX??p.x??.5),y=formationBoardY(p.homeY??p.y??.5),stats=formationStatPreview(p),role=playerDisplayRole(p),slot=playerSlotRole(p),yOffset=formationSlotYOffset(slot),rating=playerBaseRating(p),formedRating=playerFormGeneratedRating(p),meta=playerMetaText(p),form=dailyFormLabel(p),cards=playerCardText(p),injury=injuryLabel(p),training=trainingLabel(p),penalty=playerPositionPenalty(p),boostHtml=formationBoostHtml(p),roleLong=String(role||"").length>3||String(role||"").includes("/");
        return `<div class="${squadPickClass(p,editable,"formation-player")}${boostHtml?" has-formation-boost":""}"${squadPickAttrs(p,editable,"formation")} title="${safe(p.name||"Player")} | ${safe(role)}${role!==slot?` in ${safe(slot)} slot`:""} | OVR ${safe(rating)}${form?` (${safe(formedRating)})`:""}${injury?` | ${safe(injury)}`:""}${training?` | ${safe(training)}`:""}${form?` | ${safe(form)}`:""}${cards?` | ${safe(cards)}`:""}${penalty?` | ${safe(penalty)}% position`:""}${meta?` | ${safe(meta)}`:""}${stats?` | ${safe(stats)}`:""}" style="--x:${x}%;--y:${y}%;--formation-y-offset:${yOffset}mm;--shirt:${safe(team?.shirt||"#ffffff")};--trim:${safe(team?.trim||"#111111")}">${injuryBadge(p,"formation-injury-badge")}${trainingBadge(p,"formation-training-badge")}${dailyFormDot(p,"formation-form-dot")}${playerCardBadges(p,"formation-card-badges")}<span class="formation-head${roleLong?" long-role":""}">${safe(role)}</span><b style="${formationNameStyle(p.name)}">${safe(shortPlayerName(p.name))}</b><span class="formation-rating">${formationRatingHtml(p)}</span>${stats?`<span class="formation-mini">${safe(stats)}</span>`:""}<span class="formation-penalty ${penalty<0?"":"empty"}">${penalty<0?safe(penalty):"&nbsp;"}%</span>${boostHtml}</div>`
      }).join("")}</div>`
    }
    function squadFilterDefs(){return[{id:"keeper",label:"KEEPER",roles:["GK"]},{id:"backs",label:"DEFENDERS",roles:["CB","LB","RB","LWB","RWB"]},{id:"mid",label:"MID",roles:["CM","LM","RM","DM","CDM","AM","CAM"]},{id:"striker",label:"STRIKER",roles:["ST","CF","LW","RW","LF","RF"]}]}
    function squadFilterButtonsHtml(){return `<div class="squad-filter-row">${squadFilterDefs().map(f=>`<button class="${squadRoleFilter===f.id?"active":""}" data-squad-filter="${safe(f.id)}" type="button">${safe(f.label)}</button>`).join("")}</div>`}
    function squadUtilityActionsHtml(editable){
      const scout=managerFinance?.hiredScout||null,scoutLevel=Number(scout?.level||0),autoTrain=!!managerFinance?.scoutSearch?.autoTrainBench,autoTrainLabel=scoutLevel>=3?`AUTO TRAIN: ${autoTrain?"ON":"OFF"}`:"AUTO TRAIN: LOCKED";
      return `<button id="managerTeamStatsButton" type="button">STATS</button>${editable?`<button id="managerTeamAutoTrainingButton" class="${autoTrain?"active":""}" type="button">${safe(autoTrainLabel)}</button><button id="managerTeamBestLineup" class="green" type="button">BEST</button>`:""}`
    }
    function squadMatchActionsHtml(editable){
      const controls=squadUtilityActionsHtml(editable);
      if(!editable)return controls?`<div class="manager-squad-match-actions viewer">${controls}</div>`:"";
      if(!managerSeason)return `<div class="manager-squad-match-actions">${controls}<button type="button" disabled>NO MATCH</button></div>`;
      if(managerSeason.status==="finished")return `<div class="manager-squad-match-actions">${controls}<button type="button" disabled>SEASON FINISHED</button></div>`;
      const own=nextManagerFixture(),preview=own||nextManagerFixturePreview(),pending=managerPendingRound(),vote=effectiveRoundVote(),needsContinue=!!vote?.mineContinuePending,waitNames=(vote?.waiting||[]).map(u=>String(u||"").toUpperCase()).filter(Boolean),continueWait=managerRoundVotePassive(vote),waitingForMe=!!(vote?.waiting||[]).some(u=>String(u||"").toLowerCase()===String(me?.name||"").toLowerCase()),mineWaiting=!!(vote&&!continueWait&&!vote.allReady&&!needsContinue&&vote.mineReady&&managerReadyVoteLocallyArmed(vote)&&waitNames.length),waiting=!!(vote&&!needsContinue&&waitNames.length&&(!waitingForMe||continueWait)),waitText=waitNames.length?`WAITING FOR ${waitNames.join(", ")}`:"WAITING",previewStatus=String(preview?.fixture?.status||""),autoStarting=managerAutoStartArmedFor(preview)&&previewStatus!=="pending";
      if(mineWaiting)return `<div class="manager-squad-match-actions">${controls}<button class="manager-ready-waiting" type="button" data-waiting="1" disabled>READY - ${safe(waitText)}</button></div>`;
      if(waiting&&continueWait)return `<div class="manager-squad-match-actions">${controls}<button type="button" disabled>ROUND WAITING</button></div>`;
      if(waiting)return `<div class="manager-squad-match-actions">${controls}<button type="button" data-waiting="1" disabled>${safe(waitText)}</button></div>`;
      if(needsContinue)return `<div class="manager-squad-match-actions">${controls}<button type="button" disabled>ROUND UPDATING...</button></div>`;
      if(autoStarting)return `<div class="manager-squad-match-actions">${controls}<button type="button" disabled>MATCH STARTING...</button></div>`;
      if(preview)return `<div class="manager-squad-match-actions">${controls}<button id="managerTeamNextRound" class="green manager-start-game" type="button" aria-label="START GAME" title="START GAME">START GAME</button></div>`;
      if(pending){const cpuLabel=managerCpuOnlyActionLabel();return `<div class="manager-squad-match-actions">${controls}<button id="managerTeamCpuRound" class="green manager-start-game" type="button" aria-label="${safe(cpuLabel)}" title="${safe(cpuLabel)}">${safe(cpuLabel)}</button></div>`}
      return `<div class="manager-squad-match-actions">${controls}<button type="button" disabled>NO MATCH</button></div>`
    }
    function squadRoleMatches(p,filter=squadRoleFilter){if(!filter)return true;const def=squadFilterDefs().find(f=>f.id===filter),roles=playerRoleTokens(p);return !!def&&roles.some(role=>def.roles.includes(role))}
    function filteredSquadPlayers(players){return (players||[]).filter(p=>squadRoleMatches(p))}
    function squadRosterButtonHtml(key,label,count){const open=!!squadRosterOpen[key];return `<button class="squad-section-toggle ${open?"open":""}" data-squad-section="${safe(key)}" type="button" aria-expanded="${open?"true":"false"}"><span>${safe(label)}</span><small>${safe(count)}</small></button>`}
    function squadRosterButtonsHtml(starters,bench){return `<div class="squad-roster-row">${squadRosterButtonHtml("start","STARTING",(starters||[]).length)}${squadRosterButtonHtml("bench","BENCH",(bench||[]).length)}</div>`}
    function squadOpenRosterHtml(starters,team,editable,filterName=""){let html="",emptyRole=filterName?filterName.toLowerCase()+" ":"";if(squadRosterOpen.start)html+=`<div class="squad-section open"><div class="team-section-title">STARTING</div>${starters.length?`<div class="team-player-list">${starters.map(p=>managerPlayerHtml(p,"START",team,editable)).join("")}</div>`:`<div class="manager-meta">No ${safe(emptyRole)}starting players</div>`}</div>`;return html}
    function benchTrayPlayerHtml(p,team,editable){const role=playerDisplayRole(p),rating=playerBaseRating(p),formedRating=playerFormGeneratedRating(p),form=dailyFormLabel(p),cards=playerCardText(p),injury=injuryLabel(p),training=trainingLabel(p),meta=playerMetaText(p),stats=formationStatPreview(p),active=editable&&String(squadBenchActionPlayer||"")===String(p.id||""),canAct=active&&!training,actions=canAct?`<div class="manager-bench-actions"><button data-bench-action="sell" data-bench-player="${safe(p.id)}" type="button">SELL</button><button data-bench-action="swap" data-bench-player="${safe(p.id)}" type="button">SWAP IN</button><button data-bench-action="training" data-bench-player="${safe(p.id)}" type="button">TRAINING</button></div>`:"";return `<div class="manager-bench-cell"><div class="${squadPickClass(p,editable,"manager-bench-chip")}"${squadPickAttrs(p,editable,"bench")} title="${safe(p.name||"Player")} | ${safe(role)} | OVR ${safe(rating)}${form?` (${safe(formedRating)})`:""}${injury?` | ${safe(injury)}`:""}${training?` | ${safe(training)}`:""}${form?` | ${safe(form)}`:""}${cards?` | ${safe(cards)}`:""}${meta?` | ${safe(meta)}`:""}${stats?` | ${safe(stats)}`:""}" ${shirtStyle(team)}>${injuryBadge(p,"bench-injury-badge")}${trainingBadge(p,"bench-training-badge")}${dailyFormDot(p,"bench-form-dot")}${playerCardBadges(p,"bench-card-badges")}<span class="bench-chip-role">${safe(role)}</span><b style="${formationNameStyle(p.name)}">${safe(shortPlayerName(p.name))}</b><small class="bench-chip-rating">${benchRatingHtml(p)}</small></div>${actions}</div>`}
    function squadBenchTrayHtml(bench,team,editable){return `<div class="manager-bench-tray"><div class="team-section-title">BENCH</div>${bench.length?`<div class="manager-bench-strip">${bench.map(p=>benchTrayPlayerHtml(p,team,editable)).join("")}</div>`:`<div class="manager-meta">No bench players</div>`}</div>`}
    function squadInjuryRowsHtml(starters,bench){
      const rows=[...(starters||[]).map(p=>({...p,_squadGroup:"STARTING"})),...(bench||[]).map(p=>({...p,_squadGroup:"BENCH"}))].filter(p=>injuryInfo(p)||trainingInfo(p));
      if(!rows.length)return "";
      return `<div class="manager-squad-injuries"><div class="team-section-title">UNAVAILABLE</div>${rows.map(p=>{const t=trainingInfo(p),i=injuryInfo(p)||{},n=Number((t||i).remaining||0),reason=t?`Training ${(t.statLabel||t.stat||"STAT").toString().toUpperCase()} +${Number(t.gain||2)}`:(i.reason||"Injured"),badge=t?trainingBadge(p):injuryBadge(p);return `<div class="manager-squad-injury-row">${badge}<b>${safe(p.name||"Player")}</b><small>${safe(playerDisplayRole(p))} | ${safe(p._squadGroup)} | ${safe(reason)} | ${safe(n)} match${n===1?"":"es"} left</small></div>`}).join("")}</div>`
    }
    function toggleSquadSection(key){if(!Object.prototype.hasOwnProperty.call(squadRosterOpen,key))return;squadRosterOpen[key]=!squadRosterOpen[key];refreshSquadSetup()}
    function renderManagerTeamSquadList(starters,bench,team,editable){
      const box=$("managerTeamSquadList");if(!box)return;
      setSquadPlacementMode(!!(editable&&squadPlacementMode&&squadSwapFirst));
      squadRoleFilter="";
      squadRosterOpen.start=false;
      squadRosterOpen.bench=false;
      const rosterHtml="",benchTrayHtml=squadBenchTrayHtml(bench,team,editable),injuryRowsHtml=squadInjuryRowsHtml(starters,bench),matchActions=squadMatchActionsHtml(editable),topMenu=matchActions?`<div class="manager-squad-top-menu">${matchActions}</div>`:"";
      box.innerHTML=(starters.length||bench.length)?`<div class="manager-squad-layout">${topMenu}<div class="manager-formation-pane">${formationHtml(starters,team,editable)}</div><div class="manager-roster-pane">${rosterHtml}${benchTrayHtml}${injuryRowsHtml}</div></div>`:`<div class="manager-meta">No players</div>`;
      if(squadPlacementMode)requestAnimationFrame(()=>{box.scrollTop=0});
      document.querySelectorAll("#managerTeamPage [data-squad-filter]").forEach(b=>b.onclick=()=>setSquadRoleFilter(b.dataset.squadFilter));
      document.querySelectorAll("#managerTeamPage [data-squad-section]").forEach(b=>b.onclick=()=>toggleSquadSection(b.dataset.squadSection));
      $("managerTeamBestLineup")?.addEventListener("click",optimizeManagerLineup);
      $("managerTeamNextRound")?.addEventListener("click",playManagerViewedRound);
      $("managerTeamCpuRound")?.addEventListener("click",playManagerCpuRound);
      $("managerTeamRoundContinue")?.addEventListener("click",continueManagerRound);
      $("managerTeamStatsButton")?.addEventListener("click",()=>{if(!managerActionLocked("team_stats"))renderManagerFullSquadPage()});
      $("managerTeamAutoTrainingButton")?.addEventListener("click",toggleSquadAutoTraining);
      updateManagerReadyIndicators();
      setManagerBusy(managerBusy)
    }
    function setSquadRoleFilter(filter){clearSquadSwap();squadRoleFilter=squadRoleFilter===filter?"":filter;const sq=currentTeamDetails?.squad||{},team=currentTeamDetails?.team||{},editable=!!currentTeamDetails?.editable;renderManagerTeamSquadList(sq.starters||[],sq.bench||[],team,editable);if(editable)bindSquadPickers();renderReplacementList()}
    function managerPlayerHtml(p,group,team,editable=false){
      const transfer=transferInfo(p),role=playerDisplayRole(p),rating=playerRating(p),meta=playerMetaText(p),form=dailyFormText(p),injury=injuryText(p),training=trainingText(p),source=group==="BENCH"?"bench":"list";
      return `<div class="${squadPickClass(p,editable,`team-player-card ${group==="BENCH"?"bench":""}`)}"${squadPickAttrs(p,editable,source)} ${shirtStyle(team)}><div class="team-role">${safe(role)}</div><div class="team-player-main"><b>${injuryBadge(p)}${trainingBadge(p)}${dailyFormDot(p)}${safe(p.name)}</b><small>${safe(group)}${injury?` | ${injury}`:""}${training?` | ${training}`:""}${form?` | ${form}`:""}${meta?` | ${safe(meta)}`:""} | Goals ${safe(p.goals||0)} | Value ${money(p.value||0)}${transfer?`<br>${transfer}`:""}</small></div><div class="team-rating">${safe(rating)}<span>OVR</span></div><div class="team-stats">${statChips(p)}</div></div>`
    }
    function fullSquadStarterGroup(p){const role=String(playerPrimaryRole(p)||playerSlotRole(p)||"").toUpperCase();if(role==="GK")return "gk";if(["CB","LB","RB","LWB","RWB"].includes(role))return "def";if(["CM","LM","RM","DM","CDM","AM","CAM"].includes(role))return "mid";return "st"}
    function playerFormAdjustedValue(value,p){const base=Number(value||0),m=playerConditionMultiplier(p);return m&&Math.abs(m-1)>.0001?Math.max(0,Math.min(100,Math.round(base*m))):base}
    function fullSquadStatValueHtml(p,value){const base=Number(value||0),adjusted=playerFormAdjustedValue(base,p),cls=adjusted>=base?"up":"down";return `${safe(base)}${adjusted!==base?` <small class="${cls}">(${safe(adjusted)})</small>`:""}`}
    function fullSquadRatingHtml(p){const base=playerBaseRating(p),pct=dailyFormPct(p),formed=playerFormGeneratedRating(p),age=Number(p?.age||0);return `<span>OVR ${safe(base)}${pct?` (${safe(formed)})`:""}</span>${age?`<span>AGE ${safe(age)}</span>`:""}`}
    function countryFlagEmoji(code){code=String(code||"").toLowerCase();if(["gb-eng","gb-sct","gb-wls","gb-nir","ie","xk"].includes(code)||!/^[a-z]{2}$/.test(code))return"";return code.toUpperCase().split("").map(ch=>String.fromCodePoint(127397+ch.charCodeAt(0))).join("")}
    function playerOriginFlag(p){const label=String(p?.nationality||p?.country||"").trim(),code=String(p?.nationalityCode||p?.countryCode||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-"),knownCss=["gb-eng","gb-sct","gb-wls","gb-nir","ie"].includes(code),emoji=countryFlagEmoji(code),fallback=code&&!knownCss&&!emoji?code.slice(0,2).toUpperCase():"";return `<span class="player-origin-flag${code?` origin-${safe(code)}`:" unknown"}${emoji?" emoji":""}" title="${safe(label||"Unknown nationality")}" aria-label="${safe(label||"Unknown nationality")}">${emoji?safe(emoji):(fallback?safe(fallback):(!code?"?":""))}</span>`}
    function fullSquadStatChips(p){const s=p.stats||{},seen=new Set(statMap().map(([k])=>k));let rows=Number(p?.age||0)?[`<div class="team-stat"><span>AGE</span><span>${safe(p.age)}</span></div>`]:[];rows.push(...statMap().filter(([k])=>s[k]!==undefined).map(([k,l])=>`<div class="team-stat"><span>${safe(l)}</span><span>${fullSquadStatValueHtml(p,s[k])}</span></div>`));Object.keys(s).filter(k=>!seen.has(k)).sort().forEach(k=>rows.push(`<div class="team-stat"><span>${safe(k.toUpperCase())}</span><span>${fullSquadStatValueHtml(p,s[k])}</span></div>`));return rows.join("")}
    function fullSquadPlayerRowHtml(p,group,team,index){const key=`${String(p.id||p.name||"player").replace(/[^a-z0-9_-]/gi,"_")}_${index}`,role=playerDisplayRole(p),roleClass=`role-${fullSquadStarterGroup(p)}`,markers=`${dailyFormDot(p)}${playerCardBadges(p)}${injuryBadge(p)}${trainingBadge(p)}`;return `<div class="manager-full-squad-item" ${shirtStyle(team)}><button class="manager-full-squad-player" data-full-squad-player="${safe(key)}" type="button">${playerOriginFlag(p)}<span class="manager-full-squad-role ${safe(roleClass)}">${safe(role)}</span><b><em>${safe(p.name||"Player")}</em>${markers?`<i>${markers}</i>`:""}</b><strong>${fullSquadRatingHtml(p)}</strong></button><div class="manager-full-squad-stats hide" data-full-squad-stats="${safe(key)}"><div class="team-stats">${fullSquadStatChips(p)}</div></div></div>`}
    function bindManagerFullSquadRows(){document.querySelectorAll("[data-full-squad-player]").forEach(btn=>{btn.onclick=()=>{const key=btn.dataset.fullSquadPlayer,stats=document.querySelector(`[data-full-squad-stats="${CSS.escape(key)}"]`);if(!stats)return;stats.classList.toggle("hide");btn.classList.toggle("open",!stats.classList.contains("hide"))}})}
    function renderManagerFullSquadPage(){const details=currentManagerSection()==="managerTeamPage"?currentTeamDetails:null,src=details?.squad||managerSquad||{},team=details?.team||me?.team||{},starters=src.starters||[],bench=src.bench||[],defs=[["gk","GK"],["def","DEFENDERS"],["mid","MIDFIELDERS"],["st","STRIKERS"]];let idx=0,html=defs.map(([id,label])=>{const players=starters.filter(p=>fullSquadStarterGroup(p)===id);return players.length?`<div class="manager-full-squad-section"><div class="team-section-title">${safe(label)}</div>${players.map(p=>fullSquadPlayerRowHtml(p,"START",team,idx++)).join("")}</div>`:""}).join("");if(bench.length)html+=`<div class="manager-full-squad-section"><div class="team-section-title">BENCH</div>${bench.map(p=>fullSquadPlayerRowHtml(p,"BENCH",team,idx++)).join("")}</div>`;$("managerFullSquadList").innerHTML=html||`<div class="manager-meta">No players</div>`;showManagerSection("managerFullSquadPage");bindManagerFullSquadRows()}
    function ownMarketListing(p){return !!(p&&me?.name&&String(p.marketListedByUser||"")===String(me.name)&&p.marketPayoutSettled===false)}
    function managerTransferPlayerHtml(p,action,group,team){
      const isBuy=action==="buy",loan=isLoanPlayer(p),ownListing=isBuy&&ownMarketListing(p),amount=loan&&!isBuy?"TEMP":isBuy?money(p.price||p.value||0):money(managerSaleBasePrice(p)),attr=loan&&!isBuy?"":ownListing?`data-remove-market="${safe(p.id)}"`:isBuy?`data-buy="${safe(p.id)}"`:`data-sell="${safe(p.id)}"`,label=loan&&!isBuy?"LOAN COVER":ownListing?"REMOVE":isBuy?"BUY PLAYER":"SELL PLAYER",source=isBuy&&p.sourceTeam?` | ${safe(p.sourceTeam)}${p.sourceDivision?` - ${safe(p.sourceDivision)}`:""}${ownListing?" | LISTED BY YOU":""}`:"",transfer=!isBuy?transferInfo(p):"",role=playerDisplayRole(p),rating=playerRating(p),meta=playerMetaText(p),form=dailyFormText(p),injury=injuryText(p),amountLabel=loan&&!isBuy?"TYPE":ownListing?"ASKING":isBuy?"COST":"BASE SELL";
      return `<div class="team-player-card market-player-card ${group==="BENCH"?"bench":""}${injuryInfo(p)?" injured":""}" ${attr} role="button" tabindex="0" ${shirtStyle(team)}><div class="team-role">${safe(role)}</div><div class="team-player-main"><b>${injuryBadge(p)}${dailyFormDot(p)}${safe(p.name)}</b><small>${safe(group)}${source}${injury?` | ${injury}`:""}${form?` | ${form}`:""}${meta?` | ${safe(meta)}`:""} | ${ownListing?"Asking":isBuy?"Price":"Base sell"} ${amount}${transfer?`<br>${transfer}`:""}</small></div><div class="team-rating">${safe(rating)}<span>OVR</span></div><div class="team-stats">${statChips(p)}</div><div class="team-player-action"><b>${safe(label)}</b><span>${amountLabel} ${amount}</span></div></div>`
    }
    function trophyVisualClass(t){const kind=String(t?.visual||t?.kind||"").toLowerCase();if(kind.includes("runner")||kind.includes("silver"))return"medal silver";if(kind.includes("promotion")||kind.includes("medal")||kind.includes("top_scorer")||kind.includes("golden"))return"medal";return"cup"}
    function trophyIconHtml(t){return`<span class="team-trophy-icon ${trophyVisualClass(t)}" aria-hidden="true"><i></i></span>`}
    function trophiesHtml(items){items=items||[];return items.length?`<div class="team-trophies">${items.map(t=>`<div class="team-trophy-row">${trophyIconHtml(t)}<b>${safe(t.seasonYear||"")}</b><div><span>${safe(t.title||"Trophy")}</span><br>${safe(t.detail||"")}</div></div>`).join("")}</div>`:`<div class="team-trophy-empty">No trophies yet</div>`}
    function allSquadPlayers(){return[...(managerSquad?.starters||[]).map(p=>({...p,group:"START"})),...(managerSquad?.bench||[]).map(p=>({...p,group:"BENCH"}))]}
    function activeBenchTrainingCount(){return new Set(allSquadPlayers().filter(p=>trainingInfo(p)).map(p=>String(p.id||p.name||""))).size}
    function sumPlayers(players,key){return players.reduce((n,p)=>n+Number(p[key]||0),0)}
    function economyCard(label,value,cls=""){return `<div class="manager-economy-card ${cls}"><b>${safe(value)}</b><span>${safe(label)}</span></div>`}
    function economyLine(label,value,cls="",note=""){return `<div class="manager-economy-line ${cls}"><span>${safe(label)}${note?`<small>${safe(note)}</small>`:""}</span><b>${safe(value)}</b></div>`}
    function economyLines(rows,emptyText="Nothing booked"){const visible=(rows||[]).filter(r=>r&&(!r.optional||Number(r.amount||0)>0));return visible.length?visible.map(r=>economyLine(r.label,r.value,r.cls||"",r.note||"")).join(""):`<div class="manager-meta">${safe(emptyText)}</div>`}
    function economyBlock(title,meta,debtRows,incomeRows,netLabel,netValue){const good=Number(netValue||0)>=0;return `<div class="manager-economy-section"><h3>${safe(title)}</h3>${meta?`<div class="manager-economy-meta">${safe(meta)}</div>`:""}<div class="manager-economy-column"><h4>DEBTS & EXPENSES</h4>${economyLines(debtRows,"No debts or expenses booked")}</div><div class="manager-economy-column"><h4>INCOME</h4>${economyLines(incomeRows,"No income booked")}</div><div class="manager-economy-net ${good?"good":"bad"}"><span>${safe(netLabel)}</span><b>${signedMoney(netValue)}</b></div></div>`}
    function financeDelta(start,key){return Math.max(0,Number(managerFinance?.[key]||0)-Number(start?.[key]||0))}
    function financePhaseText(phase){phase=String(phase||"league").toLowerCase();if(phase==="cup")return "CUP MATCH";if(phase==="playoff")return "PLAYOFF MATCH";return "LEAGUE MATCH"}
    function lastRoundEconomyHtml(){const r=managerFinance?.lastMatchFinance;if(!r)return economyBlock("LAST ROUND","No match economy has been booked yet.",[],[], "ROUND NET",0);const score=Array.isArray(r.score)?`${Number(r.score[0]||0)}-${Number(r.score[1]||0)}`:"",result=String(r.result||"").toUpperCase(),meta=[financePhaseText(r.phase),score,result].filter(Boolean).join(" | "),loanDebt=Number(r.loanDebtAfter||managerFinance?.loan?.current?.remaining||0),incomeRows=[{label:"Gate",value:money(r.gateIncome||0),amount:r.gateIncome,optional:true,cls:"good"},{label:"Merch",value:money(r.merchIncome||0),amount:r.merchIncome,optional:true,cls:"good"},{label:"Match bonus",value:money(r.bonusIncome||0),amount:r.bonusIncome,optional:true,cls:"good"},{label:"Cup money",value:money(r.cupIncome||0),amount:r.cupIncome,optional:true,cls:"good"}],debtRows=[{label:"Loan debt left",value:money(loanDebt),amount:loanDebt,optional:true,cls:"bad"},{label:"Loan payment",value:signedMoney(-Number(r.loanPayment||0)),amount:r.loanPayment,optional:true,cls:"bad"},{label:"Wages",value:signedMoney(-Number(r.wages||0)),amount:r.wages,optional:true,cls:"bad"}];return economyBlock("LAST ROUND",meta,debtRows,incomeRows,"ROUND NET",Number(r.net||0))}
    function seasonEconomyHtml(){
      const start=managerSeason?.financeStart||{},startBalance=Number(managerSeason?.startBalance??managerFinance?.startBalance??0),seasonNet=Number(managerFinance?.balance||0)-startBalance,loanDebt=Number(managerFinance?.loan?.current?.remaining||0),loanBorrowed=financeDelta(start,"loanBorrowed"),hasExpenseStart=["wages","loanRepaid","transferSpent","staffSpent","scoutSpent","arenaSpent","merchSpent"].some(k=>Object.prototype.hasOwnProperty.call(start,k)),matchIncome=financeDelta(start,"income"),incomeRows=[{label:"Gate",value:money(financeDelta(start,"gateIncome")),amount:financeDelta(start,"gateIncome"),optional:true,cls:"good"},{label:"Merch",value:money(financeDelta(start,"merchIncome")),amount:financeDelta(start,"merchIncome"),optional:true,cls:"good"},{label:"Match bonus",value:money(financeDelta(start,"bonusIncome")),amount:financeDelta(start,"bonusIncome"),optional:true,cls:"good"},{label:"Cup money",value:money(financeDelta(start,"cupIncome")),amount:financeDelta(start,"cupIncome"),optional:true,cls:"good"},{label:"Season money",value:money(financeDelta(start,"seasonAwards")),amount:financeDelta(start,"seasonAwards"),optional:true,cls:"good"},{label:"Transfer sales",value:money(financeDelta(start,"transferIncome")),amount:financeDelta(start,"transferIncome"),optional:true,cls:"good"}];
      let expenseRows=[{label:"Current loan debt",value:money(loanDebt),amount:loanDebt,optional:true,cls:"bad"},{label:"New loan taken",value:money(loanBorrowed),amount:loanBorrowed,optional:true,cls:"bad"}];
      if(hasExpenseStart){
        expenseRows=expenseRows.concat([{label:"Wages paid",value:signedMoney(-financeDelta(start,"wages")),amount:financeDelta(start,"wages"),optional:true,cls:"bad"},{label:"Loan paid",value:signedMoney(-financeDelta(start,"loanRepaid")),amount:financeDelta(start,"loanRepaid"),optional:true,cls:"bad"},{label:"Transfer buys",value:signedMoney(-financeDelta(start,"transferSpent")),amount:financeDelta(start,"transferSpent"),optional:true,cls:"bad"},{label:"Staff",value:signedMoney(-financeDelta(start,"staffSpent")),amount:financeDelta(start,"staffSpent"),optional:true,cls:"bad"},{label:"Scout fees",value:signedMoney(-financeDelta(start,"scoutSpent")),amount:financeDelta(start,"scoutSpent"),optional:true,cls:"bad"},{label:"Arena build",value:signedMoney(-financeDelta(start,"arenaSpent")),amount:financeDelta(start,"arenaSpent"),optional:true,cls:"bad"},{label:"Merch upgrade",value:signedMoney(-financeDelta(start,"merchSpent")),amount:financeDelta(start,"merchSpent"),optional:true,cls:"bad"}]);
      }else{
        const knownIncome=matchIncome+financeDelta(start,"seasonAwards")+financeDelta(start,"transferIncome")+loanBorrowed,estimatedSpend=Math.max(0,knownIncome-seasonNet);
        expenseRows.push({label:"Season spending",value:signedMoney(-estimatedSpend),amount:estimatedSpend,optional:true,cls:"bad",note:"estimated from balance"});
      }
      const meta=`Start ${money(startBalance)} | Balance ${money(managerFinance?.balance||0)}${matchIncome?` | Match income ${money(matchIncome)}`:""}`;
      return economyBlock("SEASON TOTAL",meta,expenseRows,incomeRows,"SEASON NET",seasonNet)
    }
    function arenaExpansionHtml(){const f=managerFinance||{},build=f.arenaBuild||null,next=f.arenaNext||null,level=Number(f.arenaLevel||0),max=Number(f.arenaMaxLevel||10),avg=Number(f.arenaAverageAttendance||0),last=Number(f.arenaLastAttendance||0);let action="";if(build){action=`<div class="arena-build-grid"><span><b>LEVEL ${safe(build.level||level+1)}</b>BUILDING</span><span><b>+${Number(build.seats||0).toLocaleString("en-GB")}</b>SEATS</span><span><b>${safe(build.roundsLeft||0)}/${safe(build.roundsTotal||0)}</b>ROUNDS LEFT</span></div>`}else if(next){action=`<div class="arena-build-grid"><span><b>LEVEL ${safe(next.level)}</b>NEXT</span><span><b>+${Number(next.seats||0).toLocaleString("en-GB")}</b>SEATS</span><span><b>${money(next.cost||0)}</b>COST</span><span><b>${safe(next.rounds||0)}</b>ROUNDS</span></div><button id="arenaBuildButton" class="arena-build-action green" type="button">BUILD ARENA</button>`}else{action=`<div class="manager-meta">Arena is fully expanded.</div>`}return `<h3>EXPAND ECONOMY</h3><div class="arena-build-grid"><span><b>${safe(level)}/${safe(max)}</b>ARENA LEVEL</span><span><b>${Number(f.arenaCapacity||0).toLocaleString("en-GB")}</b>SEATS</span><span><b>${avg?avg.toLocaleString("en-GB"):"-"}</b>AVG VISITORS</span><span><b>${last?last.toLocaleString("en-GB"):"-"}</b>LAST VISITORS</span></div>${action}`}
    function bindArenaExpansion(){const b=$("arenaBuildButton");if(b)b.onclick=startArenaExpansion}
    function merchUpgradeHtml(){const f=managerFinance||{},level=Number(f.merchLevel||0),max=Number(f.merchMaxLevel||5),boost=Number(f.merchBoostPct||0),next=f.merchNext||null,income=Number(f.merchIncome||0),spent=Number(f.merchSpent||0);let action="";if(next){action=`<div class="arena-build-grid"><span><b>LEVEL ${safe(next.level)}</b>NEXT</span><span><b>+${safe(next.boostPct||0)}%</b>MERCH BOOST</span><span><b>${money(next.cost||0)}</b>COST</span></div><button id="managerMerchUpgradeButton" class="arena-build-action green" type="button">UPGRADE MERCH</button>`}else{action=`<div class="manager-meta">Merch is fully upgraded.</div>`}return `<div class="manager-loan-box"><h3>MERCH</h3><div class="arena-build-grid"><span><b>${safe(level)}/${safe(max)}</b>MERCH LEVEL</span><span><b>+${safe(boost)}%</b>CURRENT BOOST</span><span><b>${money(income)}</b>MERCH INCOME</span><span><b>${money(spent)}</b>UPGRADE SPENT</span></div>${action}</div>`}
    function bindMerchUpgrade(){const b=$("managerMerchUpgradeButton");if(b)b.onclick=startMerchUpgrade}
    function managerLoanRate(years){const opts=managerFinance?.loan?.rateOptions||[],found=opts.find(o=>Number(o.years)===Number(years));return Number(found?.ratePct??opts[0]?.ratePct??6)}
    function managerLoanPaymentPreview(amount,years){const loan=managerFinance?.loan||{},payments=Math.max(1,Number(years||1)*Number(loan.paymentsPerYear||46)),rate=managerLoanRate(years),interest=Math.round(Number(amount||0)*rate/100/5000)*5000,total=Number(amount||0)+interest,payment=Math.max(500,Math.round(Math.ceil(total/payments)/500)*500);return{rate,interest,total,payment,payments}}
    function managerLoanHtml(){const loan=managerFinance?.loan||{},current=loan.current||null;if(current){return `<div class="manager-loan-box"><h3>BANK LOAN</h3><div class="arena-build-grid"><span><b>${money(current.remaining||0)}</b>DEBT LEFT</span><span><b>${money(current.paymentPerMatch||0)}</b>PER MATCH</span><span><b>${safe(current.paymentsLeft||0)}/${safe(current.paymentsTotal||0)}</b>PAYMENTS LEFT</span><span><b>${safe(current.ratePct||0)}%</b>INTEREST</span><span><b>${money(current.cashBorrowed||current.principal||0)}</b>BORROWED</span><span><b>${money(current.interestTotal||0)}</b>INTEREST TOTAL</span></div><div class="manager-meta">A new loan is locked until this one is paid.</div></div>`}const max=Number(loan.maxAmount||0),min=Number(loan.minAmount||50000),step=Number(loan.step||50000),start=Number(loan.startBalance||managerFinance?.startBalance||0),defaultAmount=Math.min(max,Math.max(min,Math.round((max*.25)/step)*step)),opts=(loan.rateOptions||[]).map(o=>`<option value="${safe(o.years)}">${safe(o.years)} year${Number(o.years)===1?"":"s"} | ${safe(o.ratePct)}%</option>`).join("");return `<div class="manager-loan-box"><h3>BANK LOAN</h3><div class="arena-build-grid"><span><b>${money(start)}</b>START ECONOMY</span><span><b>${money(max)}</b>MAX LOAN</span><span><b>1-5</b>YEARS</span></div><div class="manager-loan-form"><label><span>AMOUNT</span><input id="managerLoanAmount" type="number" min="${safe(min)}" max="${safe(max)}" step="${safe(step)}" value="${safe(defaultAmount||min)}"></label><label><span>PAY BACK</span><select id="managerLoanYears">${opts}</select></label><button id="managerLoanButton" class="green" type="button">TAKE LOAN</button></div><div id="managerLoanPreview" class="manager-loan-preview"></div></div>`}
    function updateManagerLoanPreview(){const amountInput=$("managerLoanAmount"),yearsInput=$("managerLoanYears"),box=$("managerLoanPreview");if(!amountInput||!yearsInput||!box)return;const loan=managerFinance?.loan||{},step=Number(loan.step||50000),min=Number(loan.minAmount||50000),max=Number(loan.maxAmount||0),amount=clamp(Math.round(Number(amountInput.value||0)/step)*step,min,max),years=Number(yearsInput.value||1),p=managerLoanPaymentPreview(amount,years);box.innerHTML=`Borrow ${money(amount)} | Interest ${money(p.interest)} (${safe(p.rate)}%) | Total ${money(p.total)} | ${money(p.payment)} per match`}
    async function startManagerLoan(){const amountInput=$("managerLoanAmount"),yearsInput=$("managerLoanYears"),loan=managerFinance?.loan||{};if(!amountInput||!yearsInput||managerActionLocked("manager_loan"))return;const step=Number(loan.step||50000),min=Number(loan.minAmount||50000),max=Number(loan.maxAmount||0),amount=clamp(Math.round(Number(amountInput.value||0)/step)*step,min,max),years=clamp(Number(yearsInput.value||1),1,5),p=managerLoanPaymentPreview(amount,years);if(!await askConfirm("BANK LOAN",`Borrow ${money(amount)}?\nPay back over ${years} year${years===1?"":"s"} at ${p.rate}%.\nTotal ${money(p.total)}, about ${money(p.payment)} per match.`,`TAKE LOAN`,`CANCEL`,false))return;setManagerBusy(true);try{const r=await api("managerTakeLoan",{amount,years});if(!r.ok)return msg("managerMsg",r.error==="active_loan"?"You already have an active loan":r.error==="loan_too_high"?`Max loan is ${money(r.maxAmount||max)}`:r.error==="bad_amount"?"Choose a loan amount first":"Could not take loan");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;renderManagerSeason();renderManagerEconomyPage();msg("managerMsg",`Loan added: ${money(amount)}`)}finally{setManagerBusy(false)}}
    function bindManagerLoan(){const amount=$("managerLoanAmount"),years=$("managerLoanYears"),button=$("managerLoanButton");if(amount)amount.oninput=updateManagerLoanPreview;if(years)years.onchange=updateManagerLoanPreview;if(button)button.onclick=startManagerLoan;updateManagerLoanPreview()}
    function transferEconomyHtml(){const players=allSquadPlayers(),f=managerFinance||{},squadValue=Number(f.squadValue||0)||sumPlayers(players,"value");return [["BALANCE",money(f.balance||0)],["TRANSFERS",signedMoney(-Number(f.transferSpent||0))],["STAFF",signedMoney(-Number(f.staffSpent||0))],["SCOUT",signedMoney(-Number(f.scoutSpent||0))],["SQUAD VALUE",money(squadValue)]].map(([label,value])=>`<span><b>${safe(value)}</b>${safe(label)}</span>`).join("")}
    function renderTransferEconomy(id){const box=$(id);if(!box)return;box.classList.toggle("hide",!managerFinance);box.innerHTML=managerFinance?transferEconomyHtml():""}
    function currentStaffManager(){return managerFinance?.hiredManager||null}
    function staffManagerLevel(option){const options=managerFinance?.staffManagers||[],direct=Number(option?.level||0);if(direct>0)return direct;const index=options.findIndex(o=>String(o.id||"")===String(option?.id||"")||Number(o.boostPct||0)===Number(option?.boostPct||0));return index>=0?index+1:0}
    function currentStaffManagerLevel(){const current=currentStaffManager();if(!current)return 0;const options=managerFinance?.staffManagers||[],found=options.find(o=>String(o.id||"")===String(current.id||"")||Number(o.boostPct||0)===Number(current.boostPct||0));return found?staffManagerLevel(found):staffManagerLevel(current)}
    function staffManagerCardHtml(option){const boost=Number(option?.boostPct||0),level=staffManagerLevel(option),currentLevel=currentStaffManagerLevel(),cost=Number(option?.cost||0),hired=currentLevel>=level&&level>0,locked=!hired&&level!==currentLevel+1,canPay=Number(managerFinance?.balance||0)>=cost,label=hired?"HIRED":locked?"LOCKED":currentLevel>0?"BUY NEXT":"HIRE",note=hired?"ACTIVE":locked?"BUY PREVIOUS STEP FIRST":money(cost);return `<div class="manager-staff-card ${hired?"hired":""} ${locked?"locked":""}"><div><b>${safe(option.name||"Manager")}</b><small>STEP ${safe(level||"-")} | BOOST +${safe(boost)}% | ${safe(note)}</small></div><button data-hire-staff-manager="${safe(option.id)}" type="button" ${hired||locked||!canPay?"disabled":""}>${safe(label)}</button></div>`}
    function renderManagerStaffBox(){const box=$("managerStaffBox");if(!box)return;const options=managerFinance?.staffManagers||[],current=currentStaffManager();box.innerHTML=`<div class="manager-staff-head"><b>HIRE MANAGER</b><span>${current?`${safe(current.name||"Manager")} | +${safe(current.boostPct||0)}% TEAM BOOST`:"NO MANAGER HIRED"}</span></div><div class="manager-staff-grid">${options.map(staffManagerCardHtml).join("")}</div>`;box.querySelectorAll("[data-hire-staff-manager]").forEach(b=>b.onclick=()=>hireStaffManager(b.dataset.hireStaffManager))}
    async function hireStaffManager(managerId){if(!managerId||managerActionLocked("hire_staff_manager"))return;setManagerBusy(true);try{const r=await api("hireStaffManager",{managerId});if(!r.ok)return msg("managerMsg",r.error==="no_money"?"Not enough money":r.error==="already_hired"?"You already have that manager":r.error==="locked_step"?"Buy the previous Booster Trainer first":r.error==="not_enough_fit_players"?`Not enough fit players (${safe(r.fitPlayers||0)}/11)`:"Could not hire manager");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;renderManagerSeason();renderManagerTransfersPage();msg("managerMsg",`${safe(r.hiredManager?.name||"Manager")} hired. Best lineup set.`)}finally{setManagerBusy(false)}}
    function currentScout(){return managerFinance?.hiredScout||null}
    function scoutUpgradeCost(option){const current=currentScout(),currentCost=Number(current?.cost||0),currentLevel=Number(current?.level||0),level=Number(option?.level||0);return currentLevel>=level?0:Math.max(0,Number(option?.cost||0)-currentCost)}
    function scoutCardHtml(option){const current=currentScout(),level=Number(option?.level||0),currentLevel=Number(current?.level||0),cost=scoutUpgradeCost(option),hired=currentLevel>=level,canPay=Number(managerFinance?.balance||0)>=cost,label=hired?"HIRED":currentLevel>0?"UPGRADE":"HIRE",tags=[`LEVEL ${level}`,`${safe(option.feePct||0)}% FEE`,option.canBrowse?"BROWSE":"MARKET",option.canAutoBuy?"AUTO BUY":""].filter(Boolean).join(" | ");return `<div class="manager-staff-card ${hired?"hired":""}"><div><b>${safe(option.name||"Scout")}</b><small>${tags}<br>${safe(option.description||"")}${hired?" | ACTIVE":` | ${money(cost||option.cost||0)}`}</small></div><button data-hire-scout="${safe(option.id)}" type="button" ${hired||!canPay?"disabled":""}>${safe(label)}</button></div>`}
    function scoutSearch(){return managerFinance?.scoutSearch||{role:"ST",stat:"shooting",minStat:80,maxPrice:0,scope:"market",autoBuy:false}}
    function scoutStatLabel(k){const row=statMap().find(([id])=>id===k);return row?row[1]:String(k||"").toUpperCase()}
    function scoutSearchPayload(){return{role:$("scoutRole")?.value||"ST",stat:$("scoutStat")?.value||"shooting",minStat:clamp(Number($("scoutMinStat")?.value||80),1,100),maxPrice:Math.max(0,Math.round(Number($("scoutMaxPrice")?.value||0))),scope:$("scoutScope")?.value||"market",autoBuy:!!($("scoutAutoBuy")?.checked),autoTrainBench:!!($("scoutAutoTrainBench")?.checked)}}
    function scoutResultHtml(p,index){const stat=p.scoutStat||scoutSearch().stat||"shooting",statValue=Number(p.scoutStatValue??p.stats?.[stat]??0),source=String(p.scoutSource||"market").toUpperCase(),team=p.sourceTeam?` | ${safe(p.sourceTeam)}`:"",division=p.sourceDivision?` - ${safe(p.sourceDivision)}`:"",age=Number(p.age||0)>0?` | AGE ${safe(p.age)}`:"",action=source==="BROWSE"?"MAKE BID":"BUY PLAYER";return `<div class="manager-scout-result" data-scout-result="${safe(index)}" role="button" tabindex="0"><em>${safe(playerDisplayRole(p))}</em><div><b>${safe(p.name||"Player")}</b><small>${source}${team}${division}<br>OVR ${safe(playerRating(p))}${age} | ${safe(scoutStatLabel(stat))} ${safe(statValue)} | ${money(p.price||p.value||0)}</small></div><button data-scout-result-buy="${safe(index)}" type="button">${safe(action)}</button></div>`}
    function openScoutTransferOffer(index){const p=managerScoutResults[Number(index)];if(!p)return;const source=String(p.scoutSource||"market").toLowerCase(),kind=source==="browse"?"browse":"market",teamUser=kind==="browse"?String(p.sourceTeamId||""):"";if(kind==="browse"&&!teamUser)return msg("managerMsg","Scout report is missing club data");openTransferOffer(kind,p,teamUser,{context:"scout"})}
    function bindScoutResults(box=$("managerScoutBox")){if(!box)return;box.querySelectorAll("[data-scout-result]").forEach(el=>{const run=()=>openScoutTransferOffer(el.getAttribute("data-scout-result"));el.onclick=run;el.onkeydown=e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();run()}}});box.querySelectorAll("[data-scout-result-buy]").forEach(btn=>{btn.onclick=e=>{e.preventDefault();e.stopPropagation();openScoutTransferOffer(btn.getAttribute("data-scout-result-buy"))}})}
    function scoutDropdownHtml(id,label,value,options,disabled=false){const current=options.find(o=>String(o[0])===String(value))||options[0]||["","-"],rows=options.map(o=>`<button class="manager-scout-drop-option ${String(o[0])===String(current[0])?"active":""}" data-scout-value="${safe(o[0])}" data-scout-label="${safe(o[1])}" type="button">${safe(o[1])}</button>`).join("");return `<label class="manager-scout-dropdown"><span>${safe(label)}</span><input id="${safe(id)}" type="hidden" value="${safe(current[0])}"><button class="manager-scout-drop-button" type="button" ${disabled?"disabled":""}><b>${safe(current[1])}</b></button><div class="manager-scout-drop-list hide">${rows}</div></label>`}
    function bindScoutDropdowns(box=$("managerScoutBox")){if(!box)return;box.querySelectorAll(".manager-scout-dropdown").forEach(drop=>{const button=drop.querySelector(".manager-scout-drop-button"),list=drop.querySelector(".manager-scout-drop-list"),input=drop.querySelector("input");if(!button||!list||!input)return;button.onclick=e=>{e.preventDefault();box.querySelectorAll(".manager-scout-dropdown.open").forEach(d=>{if(d!==drop){d.classList.remove("open");d.querySelector(".manager-scout-drop-list")?.classList.add("hide")}});drop.classList.toggle("open");list.classList.toggle("hide",!drop.classList.contains("open"))};list.querySelectorAll("[data-scout-value]").forEach(opt=>{opt.onclick=e=>{e.preventDefault();input.value=opt.dataset.scoutValue||"";button.querySelector("b").textContent=opt.dataset.scoutLabel||opt.textContent||"";list.querySelectorAll(".active").forEach(x=>x.classList.remove("active"));opt.classList.add("active");drop.classList.remove("open");list.classList.add("hide")}})})}
    function renderManagerScoutBox(){const box=$("managerScoutBox");if(!box)return;const current=currentScout(),options=managerFinance?.scoutCatalog||[],search=scoutSearch(),roleOpts=marketRoles().map(r=>[r,r]),statOpts=(managerFinance?.scoutStatOptions||statMap().map(([k])=>k)).map(k=>[k,scoutStatLabel(k)]),canBrowse=!!current?.canBrowse,canAuto=!!current?.canAutoBuy,scopeOptions=[["market","OPEN MARKET"],["browse","BROWSE"],["all","MARKET + BROWSE"]].filter(([id])=>id==="market"||canBrowse),disabled=!current,disabledAttr=disabled?"disabled":"",head=current?`${safe(current.name||"Scout")} | LEVEL ${safe(current.level||1)} | ${safe(current.feePct||0)}% AUTO FEE`:"NO SCOUT HIRED",results=managerScoutResults.length?`<div class="manager-scout-results">${managerScoutResults.map(scoutResultHtml).join("")}</div>`:`<div class="manager-meta">No scout results yet.</div>`;box.innerHTML=`<div class="manager-staff-head"><b>SCOUT</b><span>${head}</span></div><div class="manager-staff-grid">${options.map(scoutCardHtml).join("")}</div><div class="manager-scout-form">${scoutDropdownHtml("scoutRole","ROLE",search.role||"ST",roleOpts,disabled)}${scoutDropdownHtml("scoutStat","STAT",search.stat||"shooting",statOpts,disabled)}<label><span>MIN STAT</span><input id="scoutMinStat" type="number" min="1" max="100" value="${safe(search.minStat||80)}" ${disabledAttr}></label><label><span>MAX PRICE</span><input id="scoutMaxPrice" type="number" min="0" step="25000" value="${safe(search.maxPrice||0)}" ${disabledAttr}></label>${scoutDropdownHtml("scoutScope","SCOPE",search.scope||"market",scopeOptions,disabled)}<label class="manager-scout-check"><input id="scoutAutoBuy" type="checkbox" ${search.autoBuy&&canAuto?"checked":""} ${current&&canAuto?"":"disabled"}><span>AUTO BUY</span></label><label class="manager-scout-check wide"><input id="scoutAutoTrainBench" type="checkbox" ${search.autoTrainBench&&canAuto?"checked":""} ${current&&canAuto?"":"disabled"}><span>AUTO TRAIN BENCH</span></label></div><div class="manager-scout-actions"><button id="scoutSave" type="button" ${disabledAttr}>SAVE</button><button id="scoutRun" class="green" type="button" ${disabledAttr}>RUN SCOUT</button></div>${managerScoutNotice?`<div class="manager-market-notice">${managerScoutNotice}</div>`:""}${results}`;box.querySelectorAll("[data-hire-scout]").forEach(b=>b.onclick=()=>hireScout(b.dataset.hireScout));bindScoutDropdowns(box);const save=$("scoutSave"),run=$("scoutRun");if(save)save.onclick=saveScoutSearch;if(run)run.onclick=runScout;bindSigningNoticeAction(box);bindScoutResults(box)}
    async function hireScout(scoutId){if(!scoutId||managerActionLocked("hire_scout"))return;setManagerBusy(true);try{const r=await api("hireScout",{scoutId});if(!r.ok)return msg("managerMsg",r.error==="no_money"?"Not enough money":r.error==="already_hired"?"You already have that scout":"Could not hire scout");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerScoutNotice=`<b>SCOUT HIRED</b>${safe(r.hiredScout?.name||"Scout")} is ready.`;renderManagerSeason();showManagerScoutBox();msg("managerMsg",`${safe(r.hiredScout?.name||"Scout")} hired`)}finally{setManagerBusy(false)}}
    function scoutAutoTrainingText(rows){rows=rows||[];return rows.length?` Chief Scout started training for ${rows.map(t=>safe(t.playerName||"Player")).join(", ")}.`:""}
    async function saveScoutSearch(){if(!currentScout()||managerActionLocked("save_scout"))return;setManagerBusy(true);try{const r=await api("saveScoutSearch",{search:scoutSearchPayload()});if(!r.ok)return msg("managerMsg",r.error==="no_scout"?"Hire a scout first":"Could not save scout search");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerScoutNotice=`<b>SEARCH SAVED</b>Scout profile updated.${scoutAutoTrainingText(r.autoTraining)}`;renderManagerSeason();renderManagerScoutBox();msg("managerMsg","Scout search saved")}finally{setManagerBusy(false)}}
    function updateSquadAutoTrainingButton(){const b=$("managerTeamAutoTrainingButton");if(!b)return;const scout=currentScout(),level=Number(scout?.level||0),on=!!managerFinance?.scoutSearch?.autoTrainBench;b.textContent=level>=3?`AUTO TRAIN: ${on?"ON":"OFF"}`:"AUTO TRAIN: LOCKED";b.classList.toggle("active",on&&level>=3)}
    async function toggleSquadAutoTraining(){const scout=currentScout(),level=Number(scout?.level||0);if(!scout)return msg("managerMsg","Hire Chief Scout to use auto training");if(level<3)return msg("managerMsg","Upgrade to Chief Scout to use auto training");if(managerActionLocked("toggle_auto_training"))return;const search={...scoutSearch(),autoTrainBench:!managerFinance?.scoutSearch?.autoTrainBench};setManagerBusy(true);try{const r=await api("saveScoutSearch",{search});if(!r.ok)return msg("managerMsg",r.error==="no_scout"?"Hire Chief Scout to use auto training":"Could not save auto training");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;if(currentTeamDetails&&currentTeamDetailsUser===me?.name)currentTeamDetails.squad=r.managerSquad||currentTeamDetails.squad;renderManagerSeason();refreshSquadSetup();updateSquadAutoTrainingButton();const rows=r.autoTraining||[],names=rows.map(t=>String(t.playerName||"Player")).join(", ");msg("managerMsg",search.autoTrainBench?`Auto training enabled${names?` | Started: ${names}`:""}`:"Auto training disabled")}finally{setManagerBusy(false)}}
    async function runScout(){if(!currentScout()||managerActionLocked("run_scout"))return;setManagerBusy(true);try{const r=await api("runScout",{search:scoutSearchPayload()});if(!r.ok)return msg("managerMsg",r.error==="bench_full"?benchFullText(r):r.error==="no_money"?"Not enough money":r.error==="no_scout"?"Hire a scout first":"Scout could not run");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);managerScoutResults=r.scoutResults||[];const trainingText=scoutAutoTrainingText(r.autoTraining);if(r.status==="auto_bought"){managerScoutNotice=signingNotice(r.boughtPlayer,r.skillChange)+`<br>Scout fee ${money(r.scoutFee||0)}${trainingText?`<br>${trainingText}`:""}`}else if(r.status==="none"){managerScoutNotice=`<b>NO MATCH</b>No player matched your scout profile.${trainingText}`}else if(r.autoBuySkipped){managerScoutNotice=`<b>SCOUT FOUND PLAYERS</b>No affordable auto-buy match. Results below.${trainingText}`}else{managerScoutNotice=`<b>SCOUT FOUND ${safe(managerScoutResults.length)}</b>Best matches below.${trainingText}`}renderManagerSeason();renderManagerScoutBox();msg("managerMsg",r.status==="auto_bought"?`${safe(r.boughtPlayer?.name||"Player")} signed by scout`:managerScoutResults.length?`Scout found ${managerScoutResults.length}`:"Scout found no match")}finally{setManagerBusy(false)}}
    function bidStep(base){return Math.max(1,Math.round(Number(base||0)*.05))}
    function managerSaleBasePrice(p){let saleBase=Number(p?.value||0),purchase=Number(p?.purchasePrice||0);if(purchase>0&&purchase<saleBase*.6)saleBase=purchase;return Math.max(25000,Math.round((saleBase*.62)/25000)*25000)}
    function managerSaleChance(base,ask){base=Math.max(1,Number(base||0));const ratio=Number(ask||0)/base;return clamp(Math.round(78-(ratio-1)*95),5,96)}
    function transferOfferSquadPlayers(){return allSquadPlayers().filter(p=>!isLoanPlayer(p)&&!trainingInfo(p)).sort((a,b)=>Number(b.value||0)-Number(a.value||0)||playerRating(b)-playerRating(a))}
    function transferOfferPlayerValue(id){const p=transferOfferSquadPlayers().find(x=>String(x.id)===String(id));return p?Number(p.value||0):0}
    function transferOfferPlayerById(id){return transferOfferSquadPlayers().find(x=>String(x.id)===String(id))||null}
    function maxTransferOfferPlayers(){return transferOffer?.kind==="browse"&&String(transferOffer?.teamUser||"").startsWith("cpu:")?3:1}
    function transferOfferSelectedPlayerIds(){return String($("transferOfferPlayerSelect")?.value||"").split(",").map(x=>x.trim()).filter(Boolean)}
    function setTransferOfferSelectedPlayerIds(ids){const input=$("transferOfferPlayerSelect");if(input)input.value=[...new Set((ids||[]).map(String).filter(Boolean))].slice(0,maxTransferOfferPlayers()).join(",")}
    function transferOfferPlayersByIds(ids){return (ids||[]).map(transferOfferPlayerById).filter(Boolean)}
    function transferOfferPlayersValue(ids){return transferOfferPlayersByIds(ids).reduce((sum,p)=>sum+Number(p.value||0),0)}
    function transferOfferPayload(){const ids=transferOfferSelectedPlayerIds(),payload={cashOffer:Math.max(0,Math.round(Number(transferOffer?.cashOffer||0))),offerPlayerId:ids[0]||""};if(transferOffer?.kind==="browse")payload.offerPlayerIds=ids;if(transferOffer?.listOnly)payload.listOnly=true;return payload}
    function closeTransferOfferPlayerMenu(){const list=$("transferOfferPlayerList");if(list)list.classList.add("hide")}
    function transferOfferChoiceHtml(players,maxPlayers=1){players=players||[];if(!players.length)return `<span class="transfer-player-choice"><b>NO PLAYER INCLUDED</b><small>Cash bid only${maxPlayers>1?` | max ${maxPlayers} players`:""}</small></span>`;return `<span class="transfer-player-choice"><b>${players.length===1?safe(players[0].name):`${players.length} PLAYERS INCLUDED`}</b><small>${players.map(p=>safe(p.name)).join(" + ")} | ${money(players.reduce((sum,p)=>sum+Number(p.value||0),0))}</small></span>`}
    function renderTransferOfferPlayerPicker(){const input=$("transferOfferPlayerSelect"),button=$("transferOfferPlayerButton"),list=$("transferOfferPlayerList");if(!input||!button||!list)return;const ids=transferOfferSelectedPlayerIds(),selected=transferOfferPlayersByIds(ids),players=transferOfferSquadPlayers(),maxPlayers=maxTransferOfferPlayers();button.innerHTML=transferOfferChoiceHtml(selected,maxPlayers);list.innerHTML=`<button class="transfer-player-option ${!ids.length?"active":""}" data-transfer-offer-player="" type="button"><b>NO PLAYER INCLUDED</b><small>Cash bid only</small></button>`+players.map(p=>{const active=ids.includes(String(p.id));return `<button class="transfer-player-option ${active?"active":""}" data-transfer-offer-player="${safe(p.id)}" type="button"><b>${safe(p.name)}${active?" | SELECTED":""}</b><small>${safe(p.group||"SQUAD")} | ${safe(playerDisplayRole(p))} | ${money(p.value||0)}</small></button>`}).join("")}
    function chooseTransferOfferPlayer(id){const maxPlayers=maxTransferOfferPlayers();if(!id){setTransferOfferSelectedPlayerIds([]);closeTransferOfferPlayerMenu();renderTransferOfferModal();return}let ids=transferOfferSelectedPlayerIds();if(maxPlayers<=1){setTransferOfferSelectedPlayerIds([id]);closeTransferOfferPlayerMenu();renderTransferOfferModal();return}if(ids.includes(id))ids=ids.filter(x=>x!==id);else if(ids.length<maxPlayers)ids.push(id);else transferOffer.maxPlayerMsg=`Max ${maxPlayers} players in one bid`;setTransferOfferSelectedPlayerIds(ids);renderTransferOfferModal();$("transferOfferPlayerList")?.classList.remove("hide")}
    function renderTransferOfferModal(){
      if(!transferOffer)return;
      const player=transferOffer.player||{},base=Number(transferOffer.basePrice||0),cash=Number(transferOffer.cashOffer||0),selling=transferOffer.kind==="sell",countering=transferOffer.kind==="counter",humanListing=selling&&(!!transferOffer.listOnly||((managerSeason?.humanManagers||[]).length>1)),offerIds=transferOfferSelectedPlayerIds(),maxPlayers=maxTransferOfferPlayers(),offerPlayers=(selling||countering)?[]:transferOfferPlayersByIds(offerIds),offerValue=(selling||countering)?0:transferOfferPlayersValue(offerIds),total=cash+offerValue,balance=Number(managerFinance?.balance||0);
      $("transferBidLabel").textContent=countering?"COUNTER PRICE":selling?"ASKING PRICE":"CASH BID";
      $("transferOfferPlayerLabel").textContent=maxPlayers>1?`PLAYERS TO INCLUDE (MAX ${maxPlayers})`:"PLAYER TO INCLUDE";
      $("transferOfferPlayerLabel").classList.toggle("hide",selling||countering);
      $("transferOfferPlayerPicker").classList.toggle("hide",selling||countering);
      $("transferOfferSubmit").textContent=countering?"SEND COUNTER":selling?(humanListing?"LIST PLAYER":"TRY SELL"):"SEND BID";
      $("transferOfferPlayer").innerHTML=`<b>${safe(player.name||"Player")}</b>${safe(playerDisplayRole(player))} | OVR ${safe(playerRating(player))} | ${countering?"current bid":selling?"base sell":"asking"} ${money(base)}`;
      $("transferBidValue").textContent=money(cash);
      if(countering){
        const old=Number(transferOffer.currentOffer||base);
        $("transferOfferSummary").innerHTML=[["CURRENT",money(old)],["COUNTER",money(cash)],["STATUS","SEND"]].map(([l,v])=>`<div class="transfer-offer-card"><b>${v}</b><span>${l}</span></div>`).join("");
        $("transferOfferMsg").textContent=cash<=old?"Raise above current offer":"Counter offer";
        $("transferOfferSubmit").disabled=cash<=old;
        return;
      }
      if(selling){
        const chance=managerSaleChance(base,cash),hint=cash>base?"Higher price lowers the chance of a deal":cash<base?"Lower price improves the chance of a deal":"Normal asking price";
        if(humanListing){
          $("transferOfferSummary").innerHTML=[["BASE SELL",money(base)],["ASKING",money(cash)],["CPU INTEREST",`${chance}%`]].map(([l,v])=>`<div class="transfer-offer-card"><b>${v}</b><span>${l}</span></div>`).join("");
          $("transferOfferMsg").textContent=hint;
          $("transferOfferSubmit").disabled=false;
          return;
        }
        $("transferOfferSummary").innerHTML=[["BASE SELL",money(base)],["ASKING",money(cash)],["CHANCE",`${chance}%`]].map(([l,v])=>`<div class="transfer-offer-card"><b>${v}</b><span>${l}</span></div>`).join("");
        $("transferOfferMsg").textContent=hint;
        $("transferOfferSubmit").disabled=false;
        return;
      }
      $("transferOfferSummary").innerHTML=[["ASKING",money(base)],["CASH",`${money(cash)} / ${money(balance)}`],["PLAYERS",offerPlayers.length?`${offerPlayers.length}/${maxPlayers} ${money(offerValue)}`:"NONE"],["TOTAL BID",money(total)]].map(([l,v])=>`<div class="transfer-offer-card"><b>${v}</b><span>${l}</span></div>`).join("");
      $("transferOfferMsg").textContent=transferOffer.maxPlayerMsg|| (total<base?"Total bid is below asking price":cash>balance?"Not enough cash balance":"");
      transferOffer.maxPlayerMsg="";
      $("transferOfferSubmit").disabled=cash>balance;
      renderTransferOfferPlayerPicker();
    }
    function openTransferOffer(kind,player,teamUser="",options={}){const base=kind==="sell"?managerSaleBasePrice(player):Number(player?.price||player?.value||0);transferOffer={kind,player,teamUser,basePrice:base,cashOffer:base,maxPlayerMsg:"",listOnly:!!options.listOnly,context:options.context||""};$("transferOfferTitle").textContent=kind==="browse"?"MAKE TRANSFER BID":kind==="sell"?(options.listOnly?"LIST PLAYER":"SELL PLAYER"):"BUY PLAYER";$("transferOfferPlayerSelect").value="";$("transferOfferMsg").textContent="";closeTransferOfferPlayerMenu();$("transferOfferModal").classList.remove("hide");renderTransferOfferModal()}
    function openDealCounterOffer(id){const o=[...(managerTransferOffers?.incoming||[])].find(x=>String(x.id)===String(id));if(!o)return;const current=Number(o.cashOffer||0),base=Number(o.basePrice||current),cash=Math.max(base,current+bidStep(base||current));transferOffer={kind:"counter",offerId:id,player:o.player||{},basePrice:current,currentOffer:current,cashOffer:cash};$("transferOfferTitle").textContent="COUNTER OFFER";$("transferOfferPlayerSelect").value="";$("transferOfferMsg").textContent="";closeTransferOfferPlayerMenu();$("transferOfferModal").classList.remove("hide");renderTransferOfferModal()}
    function closeTransferOffer(){transferOffer=null;closeTransferOfferPlayerMenu();$("transferOfferModal").classList.add("hide");$("transferOfferMsg").textContent=""}
    function changeTransferBid(dir){if(!transferOffer)return;const min=transferOffer.kind==="sell"?Math.max(1,Math.round(Number(transferOffer.basePrice||0)*.25)):0;transferOffer.cashOffer=Math.max(min,Number(transferOffer.cashOffer||0)+dir*bidStep(transferOffer.basePrice));renderTransferOfferModal()}
    function openMarketTransferOffer(id){const p=(managerMarket||[]).find(x=>String(x.id)===String(id));if(p)openTransferOffer("market",p)}
    async function removeMarketListing(id){if(!id||managerActionLocked("remove_market_listing"))return;setManagerBusy(true);try{const r=await api("removeMarketListing",{playerId:id});if(!r.ok)return msg("managerMsg",r.error==="listing_locked"?"This player has already been sold":r.error==="forbidden"?"You can only remove your own listing":"Could not remove listing");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;setManagerTransferOffers(r.managerTransferOffers||managerTransferOffers);renderManagerMarketPage();renderManagerSeason();msg("managerMsg","Player removed from market")}finally{setManagerBusy(false)}}
    function squadActionPlayerById(id){return currentTeamPlayers().find(x=>String(x.id)===String(id))||allSquadPlayers().find(x=>String(x.id)===String(id))||null}
    function openSquadSellOffer(id,options={}){const p=squadActionPlayerById(id);if(!p)return;if(trainingInfo(p))return msg("managerMsg","Player is away on training");openTransferOffer("sell",p,"",options)}
    function browseOfferPlayerById(id){const sq=managerBrowseTeamDetails?.squad||{};return[...(sq.starters||[]),...(sq.bench||[])].find(p=>String(p.id)===String(id))||null}
    function openBrowseTransferOffer(teamUser,id){const p=browseOfferPlayerById(id);if(p)openTransferOffer("browse",p,teamUser)}
    function managerEconomyPlayerHtml(p,team){const meta=playerMetaText(p);return `<div class="team-player-card ${p.group==="BENCH"?"bench":""}" ${shirtStyle(team)}><div class="team-role">${safe(playerDisplayRole(p))}</div><div class="team-player-main"><b>${safe(p.name)}</b><small>${safe(p.group)}${meta?` | ${safe(meta)}`:""} | Value ${money(p.value||0)} | Wage ${money(p.wage||0)} | Goals ${safe(p.goals||0)}</small></div><div class="team-rating">${safe(playerRating(p))}<span>OVR</span></div><div class="team-stats">${statChips(p)}</div></div>`}
    function managerBrowsePlayerHtml(p,group,team){const amount=money(p.price||p.value||0),source=p.sourceTeam?` | ${safe(p.sourceTeam)}${p.sourceDivision?` - ${safe(p.sourceDivision)}`:""}`:"",role=playerDisplayRole(p),meta=playerMetaText(p);return `<div class="team-player-card market-player-card ${group==="BENCH"?"bench":""}" data-browse-buy="${safe(p.id)}" role="button" tabindex="0" ${shirtStyle(team)}><div class="team-role">${safe(role)}</div><div class="team-player-main"><b>${safe(p.name)}</b><small>${safe(group)}${source}${meta?` | ${safe(meta)}`:""} | Asking ${amount} | Wage ${money(p.wage||0)}</small></div><div class="team-rating">${safe(playerRating(p))}<span>OVR</span></div><div class="team-stats">${statChips(p)}</div><div class="team-player-action"><b>MAKE BID</b><span>BASE ${amount}</span></div></div>`}
    function bindTransferCards(list,attr,handler){list.querySelectorAll(`[${attr}]`).forEach(c=>{const run=()=>handler(c.getAttribute(attr));c.onclick=run;c.onkeydown=e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();run()}}})}
    function managerTeamRecord(userId){const table=managerSeason?.table||[],row=table.find(r=>r.user===userId);return row?{rank:table.indexOf(row)+1,...row}:null}
    function managerDivisionRecord(userId){const d=managerViewDivision,rows=d?.teams||d?.table||[],idx=rows.findIndex(t=>String(t.id||t.user||"")===String(userId));return idx>=0?{rank:idx+1,divisionName:d.name,...rows[idx]}:null}
    function managerAnyDivisionRecord(userId){for(const d of managerDivisions||[]){const rows=d?.teams||d?.table||[],idx=rows.findIndex(t=>String(t.id||t.user||"")===String(userId));if(idx>=0)return{rank:idx+1,divisionName:d.name,...rows[idx]}}return null}
    function managerTeamFinanceHtml(finance){if(!finance)return "";const rows=[["BALANCE",money(finance.balance||0)],["START",money(finance.startBalance||0)],["SQUAD VALUE",money(finance.squadValue||0)],["WAGES",money(finance.weeklyWages||0)]];return `<div class="team-economy-strip">${rows.map(([label,value])=>`<div class="team-economy-cell"><b>${safe(value)}</b><span>${safe(label)}</span></div>`).join("")}</div>`}
    function currentTeamPlayers(){const sq=currentTeamDetails?.squad||{};return[...(sq.starters||[]).map(p=>({...p,group:"START"})),...(sq.bench||[]).map(p=>({...p,group:"BENCH"}))]}
    function currentTeamPlayer(id){return currentTeamPlayers().find(p=>String(p.id)===String(id))}
    function fallbackRoles(role){role=String(role||"").toUpperCase().split("/")[0];if(role==="GK")return [["GK"],["CB","LB","RB","CM","LM","RM","ST"]];if(["CB","LB","RB"].includes(role))return [[role],["CB","LB","RB"],["CM","LM","RM"],["ST"]];if(["CM","LM","RM","LW","RW"].includes(role))return [[role],["CM","LM","RM"],["ST"],["CB","LB","RB"]];return [[role],["ST"],["CM","LM","RM"],["CB","LB","RB"]]}
    function playerMatchesAnyRole(p,roles){const tokens=playerRoleTokens(p);return tokens.some(r=>roles.includes(r))}
    function replacementCandidates(target){const all=currentTeamPlayers().filter(p=>String(p.id)!==String(target?.id)),targetRole=playerPrimaryRole(target);for(const roles of fallbackRoles(targetRole)){const group=all.filter(p=>playerMatchesAnyRole(p,roles));if(group.length)return group.sort((a,b)=>marketRoleScore(b,targetRole)-marketRoleScore(a,targetRole)||playerRating(b)-playerRating(a))}return all.sort((a,b)=>playerRating(b)-playerRating(a))}
    function renderReplacementList(){const box=$("managerReplacementList");if(!box)return;box.classList.add("hide");box.innerHTML=""}
    function refreshSquadSetup(){const sq=currentTeamDetails?.squad||{},team=currentTeamDetails?.team||{},editable=!!currentTeamDetails?.editable;renderManagerTeamSquadList(sq.starters||[],sq.bench||[],team,editable);if(editable)bindSquadPickers();renderReplacementList()}
    function toggleBenchPlayerActions(id){if(!id||currentTeamDetailsUser!==me?.name||squadSwapBusy)return;const p=squadActionPlayerById(id);if(trainingInfo(p))return msg("managerMsg",trainingLabel(p));const next=String(squadBenchActionPlayer||"")===String(id)?null:String(id);clearSquadSwap();squadBenchActionPlayer=next;refreshSquadSetup();msg("managerMsg",next?"Choose SELL, SWAP IN or TRAINING":"")}
    function startBenchSwapIn(id){if(!id||currentTeamDetailsUser!==me?.name||squadSwapBusy)return;squadBenchActionPlayer=null;squadSwapFirst=id;squadSwapSecond=null;squadSwapFirstSource="bench";setSquadPlacementMode(false);refreshSquadSetup();msg("managerMsg","Choose player on pitch to replace")}
    function openBenchSellOffer(id){if(!id||currentTeamDetailsUser!==me?.name||squadSwapBusy)return;const p=squadActionPlayerById(id);if(isLoanPlayer(p))return msg("managerMsg","Loan cover cannot be sold");squadBenchActionPlayer=null;refreshSquadSetup();openSquadSellOffer(id,{listOnly:true})}
    async function startBenchTraining(id){if(!id||currentTeamDetailsUser!==me?.name||squadSwapBusy)return;const p=squadActionPlayerById(id);if(isLoanPlayer(p))return msg("managerMsg","Loan cover cannot train");if(injuryInfo(p))return msg("managerMsg","Injured player cannot train");if(trainingInfo(p))return msg("managerMsg",trainingLabel(p));if(activeBenchTrainingCount()>=MAX_BENCH_TRAINING)return msg("managerMsg",`Max ${MAX_BENCH_TRAINING} bench players can train at once`);squadBenchActionPlayer=null;refreshSquadSetup();setManagerBusy(true);try{const r=await api("startPlayerTraining",{playerId:id});if(!r.ok){const err=r.error||"",max=Number(r.maxTraining||MAX_BENCH_TRAINING);return msg("managerMsg",err==="training_limit"?`Max ${max} bench players can train at once`:err==="loan_player"?"Loan cover cannot train":err==="injured"?"Injured player cannot train":err==="already_training"?"Player is already training":err==="not_bench"?"Only bench players can train":"Could not start training")}managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;if(currentTeamDetails&&currentTeamDetailsUser===me?.name)currentTeamDetails.squad=r.managerSquad||currentTeamDetails.squad;renderManagerSeason();refreshSquadSetup();const t=r.training||{};msg("managerMsg",`${t.playerName||p?.name||"Player"} training ${t.statLabel||"STAT"} +${t.gain||2} | away ${t.duration||5} matches`)}finally{setManagerBusy(false)}}
    function bindSquadPickers(){const box=$("managerTeamSquadList");if(!box)return;box.querySelectorAll("[data-squad-player]").forEach(el=>{const run=()=>{const id=el.getAttribute("data-squad-player"),source=el.getAttribute("data-squad-source")||"list";if(source==="bench"&&!squadSwapFirst&&!squadPlacementMode)return toggleBenchPlayerActions(id);if(source==="bench"&&squadSwapFirst&&squadSwapFirstSource==="bench"){if(String(squadSwapFirst)===String(id)){clearSquadSwap();refreshSquadSetup();msg("managerMsg","")}else msg("managerMsg","Choose player on pitch to replace");return}squadBenchActionPlayer=null;pickSquadPlayer(id,source)};el.onclick=run;el.onkeydown=e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();run()}}});box.querySelectorAll("[data-bench-action]").forEach(btn=>{btn.onclick=e=>{e.preventDefault();e.stopPropagation();const id=btn.getAttribute("data-bench-player")||"",action=btn.getAttribute("data-bench-action");if(action==="sell")openBenchSellOffer(id);else if(action==="training")startBenchTraining(id);else startBenchSwapIn(id)}})}
    async function pickSquadPlayer(id,source="list"){
      if(!id||currentTeamDetailsUser!==me?.name||squadSwapBusy)return;
      const fromPitch=source==="formation";
      if(!squadSwapFirst){
        squadBenchActionPlayer=null;
        squadSwapFirst=id;
        squadSwapFirstSource=source;
        squadSwapSecond=null;
        setSquadPlacementMode(!fromPitch);
        refreshSquadSetup();
        msg("managerMsg",fromPitch?"Choose another player on pitch to swap":"Choose player on pitch to replace");
        return
      }
      if(String(squadSwapFirst)===String(id)){
        clearSquadSwap();
        refreshSquadSetup();
        msg("managerMsg","");
        return
      }
      const first=squadSwapFirst;
      squadSwapSecond=id;
      squadSwapBusy=true;
      refreshSquadSetup();
      msg("managerMsg",fromPitch?"Swapping positions...":"Updating formation...");
      const r=await api("swapSquadPlayers",{firstId:first,secondId:id});
      clearSquadSwap();
      if(!r.ok){
        refreshSquadSetup();
        return msg("managerMsg",r.error==="player_training"?"Player is away on training":"Could not swap players")
      }
      squadRosterOpen.bench=false;
      managerSeason=r.managerSeason||managerSeason;
      managerFinance=r.managerFinance||managerFinance;
      managerSquad=r.managerSquad||managerSquad;
      if(r.managerSquad&&currentTeamDetails){
        currentTeamDetails.squad=r.managerSquad;
        refreshSquadSetup();
      }else{
        await openManagerTeam(currentTeamDetailsUser,{record:false});
      }
      renderManagerSeason();
      msg("managerMsg",fromPitch?"Positions swapped":"Formation updated")
    }
    function renderFormationControls(d,editable){const old=$("managerFormationControls");if(old){old.classList.add("hide");old.innerHTML=""}const box=$("managerTeamFormationControls");if(!box)return;if(!editable){box.classList.add("hide");box.innerHTML="";return}const current=d.formation||d.squad?.formation||managerSquad?.formation||"4-4-2",options=d.formationOptions||d.squad?.formationOptions||managerSquad?.formationOptions||["4-4-2","5-3-2","4-3-3","4-5-1","3-5-2","4-2-3-1"];box.classList.remove("hide");box.innerHTML=options.map(f=>`<button class="${f===current?"active":""}" data-formation="${safe(f)}" type="button">${safe(f)}</button>`).join("");box.querySelectorAll("[data-formation]").forEach(b=>b.onclick=()=>setManagerFormation(b.dataset.formation))}
    function formationErrorText(r,fallback){return r?.error==="not_enough_fit_players"?`Not enough fit players for a full XI${Number.isFinite(Number(r.fitPlayers))?` (${safe(r.fitPlayers)}/11 fit)`:""}`:fallback}
    async function setManagerFormation(formation){clearSquadSwap();const r=await api("setSquadFormation",{formation});if(!r.ok)return msg("managerMsg",formationErrorText(r,"Could not set formation"));managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;await openManagerTeam(me?.name);renderManagerSeason();msg("managerMsg",`Formation ${formation}`)}
    async function optimizeManagerLineup(){if(managerActionLocked("optimize_lineup")||currentTeamDetailsUser!==me?.name)return;clearSquadSwap();const formation=currentTeamDetails?.squad?.formation||managerSquad?.formation||"4-4-2";setManagerBusy(true);msg("managerMsg","Optimizing lineup...");try{const r=await api("setSquadFormation",{formation});if(!r.ok)return msg("managerMsg",formationErrorText(r,"Could not optimize lineup"));managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;await openManagerTeam(me?.name,{record:false});renderManagerSeason();msg("managerMsg","Best lineup set")}finally{setManagerBusy(false)}}
    function setManagerTeamInfoOpen(on){managerTeamInfoOpen=!!on;const meta=$("managerTeamMeta"),btn=$("managerTeamInfoToggle");if(meta)meta.classList.toggle("hide",!managerTeamInfoOpen);if(btn){btn.classList.toggle("open",managerTeamInfoOpen);btn.setAttribute("aria-expanded",managerTeamInfoOpen?"true":"false")}}
    function toggleManagerTeamInfo(){setManagerTeamInfoOpen(!managerTeamInfoOpen)}
    async function openManagerTeam(userId,options={}){
      if(!userId)return;
      if(currentTeamDetailsUser&&currentTeamDetailsUser!==userId)clearSquadSwap();
      if(Object.prototype.hasOwnProperty.call(options,"backTarget"))managerTeamBackTarget=options.backTarget||"";
      else if(currentManagerSection()!=="managerTeamPage")managerTeamBackTarget="";
      currentTeamDetailsUser=userId;
      let r;
      try{r=await api("managerTeamDetails",{teamUser:userId})}
      catch(e){clientDebugLog("manager_team_details_error",e?.message||String(e||"team load failed"),{teamUser:userId,stack:e?.stack||""},"manager",true);return msg("managerMsg","Could not load team")}
      if(!r.ok)return msg("managerMsg","Could not load team");
      const d=r.teamDetails||{},team=d.team||{},sq=d.squad||{},starters=sq.starters||[],bench=sq.bench||[],record=managerTeamRecord(userId)||managerDivisionRecord(userId)||managerAnyDivisionRecord(userId)||d.record,type=d.managerType==="human"?"USER TEAM":"LEAGUE TEAM",division=d.divisionName||record?.divisionName||managerSeason?.divisionName||managerViewDivision?.name||"",editable=d.managerType==="human"&&userId===me?.name,financeHtml=managerTeamFinanceHtml(d.finance);
      currentTeamDetails={team,squad:sq,editable,details:d};
      $("managerTeamTitle").innerHTML=`<div class="team-profile-static"><div class="team-profile-hero">${teamFlag(team)}<div><div class="team-profile-name">${safe(team.name||userId)}</div><div class="team-profile-sub">${safe(type)}${division?` | ${safe(division)}`:""}</div></div></div></div>`;
      $("managerTeamMeta").innerHTML=`<div class="team-metrics"><div class="team-metric"><b>${record?record.rank:"-"}</b><span>POSITION</span></div><div class="team-metric"><b>${Math.round(Number(d.strength||0))}</b><span>SKILL</span></div><div class="team-metric"><b>${record?.won!==undefined?`${record.won||0}-${record.drawn||0}-${record.lost||0}`:"-"}</b><span>W-D-L</span></div><div class="team-metric"><b>${record?.gf!==undefined?record.gf||0:"-"}</b><span>GOALS</span></div><div class="team-metric"><b>${record?.ga!==undefined?record.ga||0:"-"}</b><span>GOALS AGAINST</span></div><div class="team-metric"><b>${record?.points!==undefined?record.points||0:"-"}</b><span>POINTS</span></div><div class="team-metric"><b>${starters.length+bench.length}</b><span>PLAYERS</span></div></div>${financeHtml}<div id="managerTeamFormationControls" class="manager-filter-row manager-formation-inline hide"></div>`;
      setManagerTeamInfoOpen(true);
      renderFormationControls(d,editable);
      renderManagerTeamSquadList(starters,bench,team,editable);
      if(editable){bindSquadPickers();renderReplacementList()}else renderReplacementList();
      showManagerSection("managerTeamPage",options.record!==false);
      if(managerTeamBackTarget==="league")$("managerBack").textContent="BACK TO LEAGUE"
    }
    function backFromManagerTeam(){if(managerTeamBackTarget==="league"||managerTeamBackTarget==="season"){managerTeamBackTarget="";clearSquadSwap();msg("managerMsg","");renderManagerSeason();showManagerSection("managerHome",false);replaceAppHistory();return}goBackOrMenu()}
    function inviteDraftKey(inv,user=me?.name){return `${String(inv?.id||"")}:${String(user||"").toLowerCase()}`}
    function inviteTeamForUser(inv,user,useDraft=false){
      const name=String(user||"").toLowerCase(),draft=useDraft?managerInviteDraftTeams[inviteDraftKey(inv,name)]:"";
      if(draft){const t=managerTeamById(draft);if(t)return t}
      const stored=inv?.teamsByUser?.[name]||inv?.teamsByUser?.[user];
      if(stored){const t=managerTeamById(stored.id||stored.sourceId)||stored;if(t)return t}
      return managerDefaultTeamForUser(name)
    }
    function inviteTeamsHtml(inv,currentSelectable=false){
      const users=(inv?.users||[]).map(u=>String(u||"").toLowerCase()).filter(Boolean),self=String(me?.name||"").toLowerCase();
      if(currentSelectable){const current=inviteTeamForUser(inv,self,false);if(!managerInviteDraftTeams[inviteDraftKey(inv,self)]&&current?.id)managerInviteDraftTeams[inviteDraftKey(inv,self)]=current.id}
      const teamFor=name=>inviteTeamForUser(inv,name,currentSelectable&&name===self),dupes=managerDuplicateTeamUsers(users,teamFor);
      return `<div class="invite-team-list">${users.map(name=>{const team=teamFor(name),isSelf=name===self,accepted=!!inv?.accepted?.[name],conflict=dupes.has(name),needsTeamChoice=isSelf&&currentSelectable&&(conflict||!team),select=needsTeamChoice?managerInviteTeamPickerHtml(inv,name,team):`<span>${teamFlag(team||{})}${safe(team?.name||"Choose team")}</span>`;return `<div class="invite-team-row ${isSelf?"self":""} ${conflict?"conflict":""}"><b>${safe(name.toUpperCase())}</b>${select}<small>${accepted?"READY":"WAITING"}</small></div>`}).join("")}</div>`
    }
    function inviteStatusHtml(inv){const ready=(inv.ready||Object.keys(inv.accepted||{})).filter(Boolean),waiting=inv.waiting||[];return `${safe(inv.readyCount??ready.length)}/${safe(inv.neededCount??(inv.users||[]).length)} ready${ready.length?`<br>Ready: ${safe(ready.join(", "))}`:""}${waiting.length?`<br>Waiting: ${safe(waiting.join(", "))}`:""}${inviteTeamsHtml(inv,false)}`}
    function managerPendingSentInvite(){const user=String(me?.name||"");if(!user)return null;return (managerInvites||[]).find(inv=>inv&&String(inv.from||"")===user&&!inv.needsMe&&(inv.waiting||[]).length)||null}
    function managerInviteWaitingNames(source=null){return (source?.inviteWaiting||source?.waiting||managerPendingSentInvite()?.waiting||[]).map(u=>String(u||"").toUpperCase()).filter(Boolean)}
    function managerInviteWaitingLabel(source=null){const names=managerInviteWaitingNames(source);return names.length?`WAITING FOR ${names.join(", ")}`:"WAITING FOR INVITED PLAYERS"}
    function managerInviteWaitingMessage(source=null){const names=managerInviteWaitingNames(source);return names.length?`Waiting for ${names.join(", ")}`:"Waiting for invited players"}
    function managerInviteBlocksProgress(messageId="managerMsg"){const inv=managerPendingSentInvite();if(!inv)return false;renderManagerInviteUi();msg(messageId,managerInviteWaitingMessage(inv));return true}
    function hasManagerIncomingInvite(){return (managerInvites||[]).some(inv=>inv&&inv.needsMe)}
    function renderInviteTarget(id,options={}){const box=$(id);if(!box)return;const incoming=(managerInvites||[]).find(x=>x.needsMe),inv=incoming||(!options.incomingOnly?(managerInvites||[])[0]:null);if(!inv){box.classList.add("hide");box.classList.remove("invite-alert","invite-action-box");box.innerHTML="";return}box.classList.remove("hide");box.classList.toggle("invite-alert",!!inv.needsMe);box.classList.toggle("invite-action-box",!!inv.needsMe);if(inv.needsMe){const self=String(me?.name||"").toLowerCase(),teamFor=name=>inviteTeamForUser(inv,name,String(name||"").toLowerCase()===self),dupes=managerDuplicateTeamUsers((inv.users||[]).map(String),teamFor),ownTeam=teamFor(self),ownConflict=dupes.has(self),disabled=!ownTeam||ownConflict;box.innerHTML=`<div class="invite-card"><div class="invite-card-title">INVITED BY ${safe(String(inv.from||"").toUpperCase())}</div>${inviteTeamsHtml(inv,true)}${ownConflict?`<div class="invite-card-warning">Choose another team</div>`:""}<button class="invite-join" data-accept-invite="${safe(inv.id)}" type="button" ${disabled?"disabled":""}>JOIN LEAGUE</button></div>`;box.querySelector("[data-accept-invite]")?.addEventListener("click",()=>acceptManagerInvite(inv.id,managerInviteDraftTeams[inviteDraftKey(inv,self)]||ownTeam?.id||ownTeam?.sourceId||""));return}box.classList.remove("invite-action-box");box.innerHTML=`<b>MANAGER INVITE SENT</b><br>${inviteStatusHtml(inv)}`}
    function renderManagerInviteUi(){renderInviteTarget("managerInviteBox");renderInviteTarget("managerActionInvite",{incomingOnly:true});restoreManagerTeamMenuScroll()}
    function renderMenuInvite(){renderInviteTarget("inviteBox");restoreManagerTeamMenuScroll()}
    function acceptedInviteIds(invites,user){return new Set((invites||[]).filter(inv=>inv&&!inv.needsMe&&(inv.users||[]).includes(user)&&inv.accepted?.[user]).map(inv=>String(inv.id||"")).filter(Boolean))}
    async function openManagerFromStartedInvite(){setRoute("manager");clearManagerView("Loading manager mode");show("manager");await loadManager(false);replaceAppHistory()}
    async function refreshMenuInvite(){if(menuInvitePollBusy||visibleScreen()!=="menu"||!me||document.hidden)return;menuInvitePollBusy=true;try{const acceptedBefore=acceptedInviteIds(managerInvites,me?.name),r=await api("state",{}, {quiet:true});if(!r.ok)return;if(checkLoadedVersion(r.appVersion))return;if(visibleScreen()!=="menu"||!me)return;if(!r.user)return;const nextInvites=r.managerInvites||[],acceptedStillWaiting=nextInvites.some(inv=>acceptedBefore.has(String(inv.id||""))),acceptedInviteStarted=acceptedBefore.size>0&&!acceptedStillWaiting&&!!(r.managerCanContinue??r.managerHasSeason);if(Array.isArray(r.teams))fillTeams(r.teams);me=r.user;managerUsers=r.managerUsers||managerUsers;setManagerStateFlags(r);setManagerTurnAlerts(r.managerTurnAlerts);managerInvites=nextInvites;syncAdminControls();syncMenuControls();renderUserTop();renderMenuInvite();if(r.match){setMatch(r.match);show("match");renderMatch();syncHistoryFromState();startPoll();return}if(acceptedInviteStarted){await openManagerFromStartedInvite()}}finally{menuInvitePollBusy=false}}
    function startMenuInvitePoll(){if(menuInvitePoll||!me)return;refreshMenuInvite();menuInvitePoll=setInterval(refreshMenuInvite,MENU_INVITE_POLL_MS)}
    function stopMenuInvitePoll(){if(menuInvitePoll)clearInterval(menuInvitePoll);menuInvitePoll=null;menuInvitePollBusy=false}
    function closeManagerSaveMenu(){["managerSaveList"].forEach(id=>$(id)?.classList.add("hide"))}
    function managerSaveRows(){return managerSaves.length?managerSaves.map(s=>{const mode=s.modeLabel||String(s.mode||((s.users||[]).length>1?"ONLINE":"SOLO")).toUpperCase(),users=(s.users||[]).join(" + "),title=`${mode} | ${users||"Manager"} | ${s.divisionName||"Manager"} | ${s.seasonYear||""}`.trim();return `<div class="manager-save-row"><button class="manager-save-load" data-manager-save="${safe(s.id)}" type="button"><b>${safe(title)}</b><small>saved by ${safe(s.savedBy||"-")} | ${safe(s.savedAtText||"")}<br>${safe(s.match||"Autosave")} ${safe(s.score||"")}</small></button>${s.canDelete?`<button class="manager-save-delete orange" data-delete-save="${safe(s.id)}" type="button" aria-label="DELETE SAVE ${safe(s.label||s.file)}">X</button>`:`<span></span>`}</div>`}).join(""):`<div class="manager-save-empty">No manager saves found</div>`}
    function renderManagerSaves(){["managerSaveList","managerSavesList"].forEach(id=>{const list=$(id);if(!list)return;list.innerHTML=managerSaveRows();list.querySelectorAll("[data-manager-save]").forEach(b=>b.onclick=()=>loadManagerSave(b.dataset.managerSave));list.querySelectorAll("[data-delete-save]").forEach(b=>b.onclick=e=>{e.stopPropagation();deleteManagerSave(b.dataset.deleteSave)})})}
    function managerSaveMessageId(){return visibleScreen()==="managerSavesPage"?"managerSavesMsg":visibleScreen()==="optionsPage"?"optionsMsg":"menuMsg"}
    async function refreshManagerSaves(messageId=managerSaveMessageId()){const r=await api("managerSaveList");if(!r.ok){managerSaves=[];managerHasAnySave=false;syncMenuControls();renderManagerSaves();return msg(messageId,"Could not load saves")}managerSaves=r.managerSaves||[];managerHasAnySave=!!(r.managerHasAnySave??managerSaves.length);setManagerTurnAlerts(r.managerTurnAlerts);setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);syncMenuControls();renderManagerSaves();syncManagerActions();msg(messageId,managerSaves.length?"":"No manager saves found")}
    async function openManagerSaves(record=true){stopPoll();stopCrowd();stopManagerPoll();setRoute("");setMatch(null);renderUserTop();managerSaves=[];renderManagerSaves();msg("managerSavesMsg","Loading saves...");show("managerSavesPage");if(record)pushAppHistory();await refreshManagerSaves("managerSavesMsg")}
    async function loadManagerSave(id,options={}){const save=managerSaves.find(s=>s.id===id)||{};if(!id)return;if(!options.skipConfirm&&!await askConfirm("CONTINUE",`Continue ${save.label||id}?`,`CONTINUE`,`CANCEL`,false))return;const r=await api("loadManagerSave",{saveId:id});if(!r.ok)return msg(managerSaveMessageId(),r.error==="missing_users"?`Missing users: ${(r.missingUsers||[]).join(", ")}`:"Could not load save");closeManagerSaveMenu();me=r.user||me;teamChoices=r.teams||teamChoices;managerInvites=r.managerInvites||[];managerSeason=null;managerFinance=null;managerSquad=null;managerMarket=[];managerDivisions=[];setManagerTransferOffers(r.managerTransferOffers||{incoming:[],outgoing:[],notices:[]});setManagerStateFlags({managerHasSeason:!!(r.managerHasSeason??r.managerCanContinue),managerCanContinue:r.managerCanContinue??r.managerHasSeason,managerHasAnySave:r.managerHasAnySave,managerPrivateChatAlerts:r.managerPrivateChatAlerts,managerSaveUsers:r.managerSaveUsers});setManagerTurnAlerts(r.managerTurnAlerts);setRoute("manager");clearManagerView("Loading manager mode");show("manager");await loadManager(false);replaceAppHistory();msg("managerMsg",options.message||"Manager mode loaded")}
    async function deleteManagerSave(id){const save=managerSaves.find(s=>s.id===id)||{};if(!id)return;if(!await askConfirm("ARE YOU SURE?",`Delete ${save.label||id}?`,`DELETE`,`CANCEL`))return;const r=await api("deleteManagerSave",{saveId:id});if(!r.ok)return msg(managerSaveMessageId(),r.error==="forbidden"?"You cannot delete this save":"Could not delete save");managerSaves=r.managerSaves||[];managerSeason=r.managerSeason||null;setManagerStateFlags({managerHasSeason:!!(r.managerHasSeason??managerSeason),managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave??managerSaves.length,managerPrivateChatAlerts:r.managerPrivateChatAlerts});setManagerTurnAlerts(r.managerTurnAlerts);syncMenuControls();renderManagerSaves();msg(managerSaveMessageId(),"Save deleted")}
    async function acceptManagerInvite(id,teamId=""){const r=await api("acceptManagerInvite",{inviteId:id,teamId});if(!r.ok)return msg("menuMsg",r.error==="duplicate_human_team"?"Two invited users have the same team. Pick different teams for this league.":r.error==="user_without_team"?"Choose a team first":"Could not accept invite");me=r.user||me;teamChoices=r.teams||teamChoices;managerInvites=r.managerInvites||[];managerSeason=r.managerSeason||managerSeason;setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave});renderMenuInvite();renderManagerInviteUi();syncManagerActions();if(managerSeason){setRoute("manager");show("manager");await loadManager();setTimeout(refreshManager,400)}else{if(visibleScreen()==="menu")startMenuInvitePoll();msg("menuMsg","Invite accepted")}}
    function managerScrollSnapshot(){return{season:$("managerSeason")?.scrollTop||0,table:document.querySelector("#managerSeason .manager-table")?.scrollTop||0,division:$("managerDivisionList")?.scrollTop||0}}
    function restoreManagerScroll(s){if(!s)return;const apply=()=>{const season=$("managerSeason"),table=document.querySelector("#managerSeason .manager-table"),division=$("managerDivisionList");if(season)season.scrollTop=s.season||0;if(table)table.scrollTop=s.table||0;if(division)division.scrollTop=s.division||0};apply();requestAnimationFrame(apply)}
    function injuryBlockMessage(r={}){const blocks=r.injuryBlocks||[],players=blocks.flatMap(b=>(b.players||[]).map(p=>`${b.team?.name||b.user}: ${p.playerName}`));if(players.length)return `Move unavailable starter to bench: ${players.join(", ")}`;const own=r.injuryBlock||managerSeason?.injuryBlock,ownPlayers=own?.blockedStarters||[];return ownPlayers.length?`Move unavailable starter to bench: ${ownPlayers.map(p=>p.playerName).join(", ")}`:"Move unavailable starter to bench before match"}
    function applyManagerResponseState(r={}){if(r.managerSeason)managerSeason=r.managerSeason;updateManagerSaveUsersFromResponse(r);if(r.managerFinance)managerFinance=r.managerFinance;if(r.managerSquad)managerSquad=r.managerSquad;if(r.managerMarket)managerMarket=r.managerMarket;if(r.managerDivisions)managerDivisions=r.managerDivisions;if("managerTurnAlerts"in r)setManagerTurnAlerts(r.managerTurnAlerts);if("managerPrivateChatAlerts"in r)setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);syncManagerActions()}
    function handleManagerInjuryBlock(r,messageId="managerMsg"){if(!r?.injuryBlocked)return false;managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;syncManagerActions();renderManagerSeason();msg(messageId,injuryBlockMessage(r));return true}
    function bindManagerJobOffers(root=document){root.querySelectorAll("[data-job-team]").forEach(b=>{b.onclick=()=>openManagerJobOfferTeam(b.dataset.jobTeam)});root.querySelectorAll("[data-job-offer]").forEach(b=>{b.onclick=()=>respondManagerJobOffer(b.dataset.jobOffer,b.dataset.jobDecision)})}
    async function openManagerJobOfferTeam(teamUser){if(!teamUser)return;await openManagerTeam(teamUser,{backTarget:"season",record:true})}
    async function respondManagerJobOffer(offerId,decision){if(!offerId||managerActionLocked("job_offer"))return;const accept=decision==="accept";if(accept&&!await askConfirm("JOB OFFER","Take this job for next season?\nYour squad changes to the new club.","ACCEPT","CANCEL",false))return;setManagerBusy(true);try{const r=await api("managerJobOfferDecision",{offerId,decision});if(!r.ok)return msg("managerMsg",r.error==="team_taken"?"That club is already taken":r.error==="offer_closed"?"That offer is closed":"Could not update job offer");me=r.user||me;teamChoices=r.teams||teamChoices;applyManagerResponseState(r);setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave});renderUserTop();syncMenuControls();syncAdminControls();renderManagerSeason();msg("managerMsg",accept?"Job accepted. Press NEXT SEASON when ready.":"Job declined")}finally{setManagerBusy(false)}}
    function managerInjuryHtml(){const info=managerSeason?.injuryBlock;if(!info)return "";const blocked=info.blockedStarters||[],active=info.active||[],rows=(blocked.length?blocked:active);if(!rows.length)return "";const lines=rows.map(p=>`${safe(p.playerName)} - ${safe(p.reason||"Unavailable")} (${safe(p.remaining||0)} match${Number(p.remaining||0)===1?"":"es"})`).join("<br>");return `<div class="manager-playoff manager-injury-alert"><b>${blocked.length?"SQUAD BLOCK":"UNAVAILABLE"}</b><br>${lines}${blocked.length?`<br>Move unavailable player out of STARTING before match.`:""}</div>`}
    function managerFinanceWarningHtml(){const seasonYear=Number(managerSeason?.seasonYear||0),applied=managerFinance?.pointDeductionApplied,warning=managerFinance?.debtWarning,pending=managerFinance?.pointDeductionPending;if(applied&&Number(applied.seasonYear||0)===seasonYear)return `<div class="manager-playoff manager-finance-warning"><b>FINANCE PENALTY</b><br>-${safe(applied.points||10)} points applied this season. Balance stayed below 0.</div>`;if(warning&&Number(warning.seasonYear||warning.deadlineSeasonYear||0)===seasonYear)return `<div class="manager-playoff manager-finance-warning"><b>FINANCE WARNING</b><br>Get balance above 0 before season ends or next season starts on -${safe(warning.points||10)} points.</div>`;if(pending&&Number(pending.seasonYear||0)===seasonYear)return `<div class="manager-playoff manager-finance-warning"><b>FINANCE PENALTY</b><br>-${safe(pending.points||10)} points will apply when this season starts.</div>`;return ""}
    function managerFormArrowHtml(row){const trend=String(row?.formTrend||"");if(trend==="up")return `<span class="manager-form-arrow up" title="Form top +${safe(row.formBonusPct||3)}%" aria-label="Form top +${safe(row.formBonusPct||3)}%"></span>`;if(trend==="down")return `<span class="manager-form-arrow down" title="Form dip ${safe(row.formBonusPct||-3)}%" aria-label="Form dip ${safe(row.formBonusPct||-3)}%"></span>`;return `<span class="manager-form-empty" aria-hidden="true"></span>`}
    function managerLeagueZoneClass(rank,total,rules){const direct=Number(rules?.direct||0),ps=Number(rules?.playoffStart||0),pe=Number(rules?.playoffEnd||0),relegation=Number(rules?.relegation||0),relegationStart=total-relegation+1,e=rules?.europe||{},clStart=Number(e.championsLeagueStart||0),clEnd=Number(e.championsLeagueEnd||0),uelStart=Number(e.europaLeagueStart||0),uelEnd=Number(e.europaLeagueEnd||0),ueclStart=Number(e.conferenceLeagueStart||0),ueclEnd=Number(e.conferenceLeagueEnd||0),isDirect=rank<=direct&&direct>0,isPlayoff=ps&&rank>=ps&&rank<=pe,isRelegation=relegation>0&&rank>=relegationStart,isCl=clStart>0&&clEnd>=clStart&&rank>=clStart&&rank<=clEnd,isUel=uelStart>0&&uelEnd>=uelStart&&rank>=uelStart&&rank<=uelEnd,isUecl=ueclStart>0&&ueclEnd>=ueclStart&&rank>=ueclStart&&rank<=ueclEnd,nationalLeagueBye=direct===1&&ps===2&&pe===7&&(rank===2||rank===3);let cls=isDirect?" direct":(isPlayoff?` playoff${nationalLeagueBye?" playoff-bye league-orange":""}`:"");if(isCl)cls+=" europe-cl";if(isUel)cls+=" europe-uel";if(isUecl)cls+=" europe-uecl";if(isRelegation)cls+=" relegation";return cls}
    function managerLeagueTableHtml(rows,rules,humans=new Set()){rows=rows||[];const body=rows.map((r,i)=>{const rank=i+1,isHuman=humans.has(r.user)||r.managerType==="human",cls=managerLeagueZoneClass(rank,rows.length,rules);return `<div class="manager-row${cls}"><span>${rank}</span><span><button class="manager-team-link" data-manager-team="${safe(r.user||r.id)}" type="button">${teamFlag(r.team)} ${isHuman?`<span class="human-dot" title="Human manager">H</span>`:""}<span class="manager-team-name">${safe(r.team?.name||r.user||r.id)}</span></button></span><span>${Math.round(Number(r.strength||0))}</span><span>${r.played||0}</span><span>${r.won||0}</span><span>${r.drawn||0}</span><span>${r.lost||0}</span><span>${r.gf||0}</span><span>${r.ga||0}</span><span>${r.points||0}</span><span class="manager-form-cell">${managerFormArrowHtml(r)}</span></div>`}).join("");return `<div class="manager-row head"><span>#</span><span>TEAM</span><span>$</span><span>P</span><span>W</span><span>D</span><span>L</span><span>GF</span><span>GA</span><span>PTS</span><span>F</span></div>${body}`}
    function managerWaitingText(names=[]){const mine=String(me?.name||"").toLowerCase(),raw=(names||[]).map(u=>String(u||"").trim()).filter(Boolean),waitingForMe=!!mine&&raw.some(u=>u.toLowerCase()===mine),others=raw.filter(u=>!mine||u.toLowerCase()!==mine).map(u=>u.toUpperCase());if(waitingForMe&&!others.length)return "For you";const otherText=others.length?`${others.length===1?"user":"users"} ${others.join(", ")}`:"";if(waitingForMe&&otherText)return `For you and ${otherText}`;return otherText?`For ${otherText}`:""}
    function managerLiveSimulationMeta(live){const f=live?.fixture||{},roundIndex=Number(f.roundIndex),round=(live?.round??f.round??""),r=Number.isInteger(roundIndex)&&String(f.seasonId||"")===String(managerSeason?.id||"")?(managerSeason?.rounds||[])[roundIndex]:null,phase=String(live?.phase||f.phase||r?.phase||"league");return{round,roundIndex,fixtureIndex:Number(f.fixtureIndex),seasonId:String(f.seasonId||live?.sourceSeasonId||""),phase,playoff:!!(live?.playoff||f.playoff||r?.playoff||phase==="playoff"),cupName:live?.cupName||f.cupName||r?.cupName||"",divisionName:live?.divisionName||f.divisionName||"",fixture:f}}
    function managerFixturePlaybackProgress(fixture={},live=null,min=.02){const f=fixture||live?.fixture||{},speed=normalizeManagerMatchSpeedPct(f.playbackSpeedPct||100),started=Number(f.playbackStartedAt||0);if(started>0&&typeof TL_PRO_MATCH_SECONDS!=="undefined"){const elapsed=managerServerNow()-started,duration=Math.max(4,TL_PRO_MATCH_SECONDS/(speed/100));return clamp(elapsed/duration,min,.985)}const duration=Math.max(1,Number(live?.duration||65)),reveal=clamp(Number(live?.revealIn??f.resultRevealIn??duration),0,duration);return clamp((duration-reveal)/duration,min,.985)}
    function managerLiveSimulationProgress(live){return managerFixturePlaybackProgress(live?.fixture||{},live,.02)}
    function managerLiveSimulationCard(live,index){if(!live?.fixture)return "";const meta=managerLiveSimulationMeta(live),humans=(live.humans||[]).map(u=>String(u||"").toUpperCase()).filter(Boolean),label=humans.length?`${humans.join(", ")} LIVE:`:"LIVE:";return `<div class="manager-last manager-live-card" data-live-sim="${safe(index)}" role="button" tabindex="0"><b><span class="manager-inline-label">${safe(label)}</span> ${safe(managerMatchTypeLine(meta,live.fixture))}</b>${managerFixtureHtml(live.fixture)}</div>`}
    function bindManagerLiveSimulationLinks(root=document){if(!root)return;root.querySelectorAll("[data-live-sim]").forEach(el=>{const open=e=>{e?.preventDefault();e?.stopPropagation();openManagerLiveSimulation(Number(el.dataset.liveSim))};el.onclick=open;el.onkeydown=e=>{if(e.key==="Enter"||e.key===" "){open(e)}}})}
    async function openManagerLiveSimulation(index){const live=(managerSeason?.liveSimulations||[])[Number(index)],fixture=live?.fixture;if(!fixture||managerActionLocked("open_live_simulation"))return;stopManagerSimAnimation();setManagerBusy(true);msg("managerMsg","Loading live match...");try{const meta=managerLiveSimulationMeta(live),report=live.report||null,viewFixture={...fixture,round:meta.round,roundLabel:managerRoundTitle(meta),roundIndex:meta.roundIndex,fixtureIndex:meta.fixtureIndex,phase:meta.phase,playoff:meta.playoff,cupName:meta.cupName,divisionName:meta.divisionName,_tlReport:report,_spectatorLive:!managerMatchSpeedCanControl(fixture),_liveProgress:managerLiveSimulationProgress(live)};await tlProLoadFixtureDetails(viewFixture);msg("managerMsg","");renderTouchlinesView(viewFixture)}finally{setManagerBusy(false)}}
    function managerLiveSimulationIndexForFixture(ref=null){const rows=managerSeason?.liveSimulations||[],ri=Number(ref?.roundIndex),fi=Number(ref?.fixtureIndex),sid=String(ref?.seasonId||managerSeason?.id||""),h=String(ref?.home||""),a=String(ref?.away||"");for(let i=0;i<rows.length;i++){const f=rows[i]?.fixture||{},fsid=String(f.seasonId||rows[i]?.sourceSeasonId||"");if(Number.isInteger(ri)&&Number.isInteger(fi)&&Number(f.roundIndex)===ri&&Number(f.fixtureIndex)===fi&&(!sid||!fsid||sid===fsid))return i;if(h&&a&&String(f.home||"")===h&&String(f.away||"")===a&&String(f.status||"")==="simulating")return i}return-1}
    function syncTouchlinesPlaybackFromSeason(){const state=touchlinesView;if(!state?.fixture||state.finished||!managerSeason)return;const index=managerLiveSimulationIndexForFixture(state.fixture),live=index>=0?(managerSeason.liveSimulations||[])[index]:null,fixture=live?.fixture||managerFindFixtureMeta(state.fixture)?.fixture;if(!fixture)return;state.fixture={...state.fixture,playbackSpeedPct:fixture.playbackSpeedPct,playbackStartedAt:fixture.playbackStartedAt,playbackPending:fixture.playbackPending,resultRevealIn:fixture.resultRevealIn};const speed=normalizeManagerMatchSpeedPct(fixture.playbackSpeedPct||managerMatchSpeedPct);if(speed!==normalizeManagerMatchSpeedPct(managerMatchSpeedPct))setManagerMatchSpeedPct(speed,false);else renderManagerMatchSpeedControls();tlProSyncToServerPlayback(state,fixture,false)}
    async function maybeResumeOwnLiveSimulation(section=""){if((section||currentManagerSection())==="managerSimPage"||managerSimRunning||managerActionLocked("resume_live_simulation")||visibleScreen()!=="manager")return false;const user=String(me?.name||""),rows=managerSeason?.liveSimulations||[];if(!user||!rows.length)return false;const index=rows.findIndex(live=>{const f=live?.fixture||{};return String(f.status||"")==="simulating"&&(String(f.home||"")===user||String(f.away||"")===user)});if(index<0)return false;await openManagerLiveSimulation(index);return true}
    function renderManagerSeason(){
      const box=$("managerSeason");if(!box)return;
      const scroll=managerScrollSnapshot();
      if(!managerSeason){box.classList.remove("hide");box.innerHTML=`<div class="manager-meta">No active manager league. Start a new league from Manager Menu.</div>`;return}
      if(managerSeason.status==="finished"){managerBusy=false;managerBusySince=0}
      const rules=managerSeason.promotionRules||{},tableRows=managerSeason.table||[];
      const humans=new Set(managerSeason.humanManagers||[]),table=tableRows.map((r,i)=>{let rank=i+1,isHuman=humans.has(r.user),cls=managerLeagueZoneClass(rank,tableRows.length,rules);return `<div class="manager-row${cls}"><span>${rank}</span><span><button class="manager-team-link" data-manager-team="${safe(r.user)}" type="button">${teamFlag(r.team)} ${isHuman?`<span class="human-dot" title="Human manager">H</span>`:""}<span class="manager-team-name">${safe(r.team?.name||r.user)}</span></button></span><span>${Math.round(Number(r.strength||0))}</span><span>${r.played||0}</span><span>${r.won||0}</span><span>${r.drawn||0}</span><span>${r.lost||0}</span><span>${r.gf||0}</span><span>${r.ga||0}</span><span>${r.points||0}</span><span class="manager-form-cell">${managerFormArrowHtml(r)}</span></div>`}).join("");
      const upcoming=nextManagerFixture(),previewNext=upcoming||nextManagerFixturePreview(),pendingRound=managerPendingRound(),roundVote=effectiveRoundVote(),hasRoundWait=roundVote&&!upcoming&&(roundVote.waiting||[]).length,nextMatch=previewNext?`<div class="manager-last"><b><span class="manager-inline-label">NEXT:</span> ${safe(managerMatchTypeLine(previewNext,previewNext.fixture))}</b>${managerFixtureHtml(previewNext.fixture)}</div>`:pendingRound&&!hasRoundWait?`<div class="manager-last"><b>${safe(managerCpuOnlyActionLabel())}</b><div class="manager-match-type">${safe(managerMatchTypeLine(pendingRound,pendingRound.fixture))}</div>${managerFixtureHtml(pendingRound.fixture)}</div>`:"";
      const ownLastKey=managerMatchCardKey(managerSeason.lastMatch),otherLastMatches=Object.values(managerSeason.humanLastMatches||{}).filter(m=>m?.fixture&&String(m.user||"")!==String(me?.name||"")&&managerMatchCardKey(m)!==ownLastKey);
      const last=`${managerLastMatchCard("LAST:",managerSeason.lastMatch)}${otherLastMatches.map(m=>managerLastMatchCard(`${String(m.user||"USER").toUpperCase()} LAST:`,m)).join("")}`;
      const liveSimRows=managerSeason.liveSimulations||[],liveSims=liveSimRows.map(managerLiveSimulationCard).join("");
      const playoff=(managerSeason.playoffActive||managerSeason.status==="playoff")?`<div class="manager-playoff"><b>PLAYOFF NOW</b><br>${safe(rules.text||"")}</div>`:"";
      const vote=roundVote,passiveRoundWait=managerRoundVotePassive(vote),continueRoundWait=!!vote?.continueRequired||passiveRoundWait,voteMode=continueRoundWait?"ROUND":(vote?.mode==="watch"?"WATCH":"ROUND"),readyWord=continueRoundWait?"DONE":"READY",showRoundWait=vote&&!vote.allReady&&Number(vote.readyCount||0)>0,readyLines=(vote?.ready||[]).map(u=>`<div class="manager-waiting-ready">USER ${safe(String(u).toUpperCase())} ${safe(readyWord)}</div>`).join(""),waitingText=managerWaitingText(vote?.waiting||[]),waitingNames=(vote?.waiting||[]).map(u=>String(u||"").toUpperCase()).filter(Boolean).join(", "),waitingLabel=continueRoundWait?"Still to finish":"Waiting",waitingValue=continueRoundWait?waitingNames:waitingText,simVote=showRoundWait?`<div class="manager-playoff manager-waiting-card"><div class="manager-waiting-title">${safe(continueRoundWait?"ROUND WAITING":`${voteMode} WAITING`)}</div><div class="manager-waiting-round">Round ${safe(vote.round||"")} <span>|</span> ${safe(vote.readyCount||0)}/${safe(vote.neededCount||0)} ${safe(readyWord.toLowerCase())}</div>${readyLines}${waitingValue?`<div class="manager-waiting-for"><span>${safe(waitingLabel)}: <strong>${safe(waitingValue)}</strong></span></div>`:""}</div>`:"";
      const injuries=managerInjuryHtml(),financeWarning=managerFinanceWarningHtml();
      renderUserTop();
      const startBalance=managerSeason.startBalance,startBalanceText=startBalance===null||startBalance===undefined?"":`<span class="manager-finance-start">Start of season ${safe(money(startBalance))}</span>`;
      const finance=managerFinance?`<div class="manager-meta manager-finance-line"><span class="manager-finance-balance">BALANCE <b>${safe(money(managerFinance.balance))}</b></span>${startBalanceText}</div>`:"";
      const humanOutcomes=Object.entries(managerSeason.outcome||{}).filter(([u])=>(managerSeason.humanManagers||[]).includes(u));
      const outcome=managerSeason.status==="finished"?`<div class="manager-meta manager-outcome">${humanOutcomes.map(([u,o])=>`${safe(u)} ${o==="promoted"?"promoted":o==="relegated"?"relegated":"stayed"}`).join(" | ")}</div>`:"";
      const movement=seasonReportHtml();
      const continueWait=(managerSeason.continueWait||[]).filter(Boolean),continueWaiting=managerSeason.status==="finished"&&continueWait.length>0,continueText=continueWaiting?`WAITING FOR ${continueWait.map(u=>String(u).toUpperCase()).join(", ")}`:"NEXT SEASON";
      const waitForSeasons=continueWaiting?`<div class="manager-playoff"><b>WAITING FOR SEASON FINISH</b><br>${safe(continueWait.join(", "))} must finish this season before next season can start.</div>`:"";
      const pendingInvite=managerPendingSentInvite(),inviteWaitingLabel=managerInviteWaitingLabel(pendingInvite),waitForInvites=pendingInvite?`<div class="manager-playoff"><b>WAITING FOR INVITES</b><br>${safe(managerInviteWaitingNames(pendingInvite).join(", "))} must accept before this league can continue.</div>`:"";
      const waitingForMe=!!(vote?.waiting||[]).some(u=>String(u||"").toLowerCase()===String(me?.name||"").toLowerCase()),needsRoundContinue=!!vote?.mineContinuePending,roundWaiting=hasRoundWait&&!needsRoundContinue&&(!waitingForMe||passiveRoundWait);
      const leagueSquad=`<button id="managerLeagueSquad" type="button">SQUAD</button>`,previewStatus=String(previewNext?.fixture?.status||""),autoStarting=managerAutoStartArmedFor(previewNext)&&previewStatus!=="pending";
      const cpuActionLabel=managerCpuOnlyActionLabel();
      const viewMatch=pendingInvite?`<button type="button" disabled>${safe(inviteWaitingLabel)}</button>`:needsRoundContinue?`<button type="button" disabled>ROUND UPDATING...</button>`:roundWaiting?(continueRoundWait?`<button type="button" disabled>ROUND WAITING</button>`:`<button type="button" data-waiting="1" disabled>${waitingText?`WAITING: ${safe(waitingText)}`:"WAITING"}</button>`):autoStarting?`<button type="button" disabled>MATCH STARTING...</button>`:previewNext?`<button id="managerNextRound" class="green manager-start-game" type="button" aria-label="START GAME" title="START GAME">START GAME</button>`:pendingRound?`<button id="managerNextRound" class="green manager-start-game" type="button" data-manager-sim-action="cpu" aria-label="${safe(cpuActionLabel)}" title="${safe(cpuActionLabel)}">${safe(cpuActionLabel)}</button>`:"";
      const next=managerSeason.status==="finished"?`<button id="continueManagerSeason" class="green" type="button" data-waiting="${continueWaiting||pendingInvite?1:0}" ${continueWaiting||pendingInvite?"disabled":""}>${safe(pendingInvite?inviteWaitingLabel:continueText)}</button>`:`${viewMatch}${leagueSquad}`;
      const abort="";
      const abortConfirm=managerAbortConfirm?`<div class="manager-confirm"><b>ARE YOU SURE?</b><div class="row"><button id="abortManagerYes" class="orange" type="button">YES</button><button id="abortManagerNo" type="button">NO</button></div></div>`:"";
      box.classList.remove("hide");
      const tableBlock=`${liveSimRows.length?`<div class="manager-meta">Live result updates after full time</div>`:""}<div class="manager-table"><div class="manager-row head"><span>#</span><span>TEAM</span><span>$</span><span>P</span><span>W</span><span>D</span><span>L</span><span>GF</span><span>GA</span><span>PTS</span><span>F</span></div>${table}</div>`;
      box.innerHTML=`${waitForInvites}${waitForSeasons}${simVote}${liveSims}${injuries}${financeWarning}${nextMatch}${finance}<div class="manager-button-row manager-main-actions">${next}${abort}</div>${last}${playoff}${outcome}${movement}${abortConfirm}${tableBlock}`;
      bindManagerLiveSimulationLinks(box);
      bindManagerJobOffers(box);
      box.querySelectorAll("[data-manager-team]").forEach(b=>b.onclick=()=>openManagerTeam(b.dataset.managerTeam));
      $("managerNextRound")?.addEventListener("click",managerMainViewClick);
      $("managerWatchMatch")?.addEventListener("click",watchManagerMatch);
      $("managerRoundContinue")?.addEventListener("click",continueManagerRound);
      $("managerLeagueSquad")?.addEventListener("click",()=>{if(!managerActionLocked("league_squad"))openManagerTeam(me?.name)});
      $("managerCpuRound")?.addEventListener("click",playManagerCpuRound);
      $("continueManagerSeason")?.addEventListener("click",continueManagerSeason);
      $("abortManagerLeague")?.addEventListener("click",showAbortManagerConfirm);
      $("abortManagerYes")?.addEventListener("click",abortManagerLeague);
      $("abortManagerNo")?.addEventListener("click",()=>{managerAbortConfirm=false;renderManagerSeason()});
      updateManagerReadyIndicators();
      setManagerBusy(managerBusy);
      restoreManagerScroll(scroll);
    }
    function managerSections(){return["managerHome","managerCreate","managerSquadPage","managerFullSquadPage","managerMarketPage","managerEconomyPage","managerTransfersPage","managerDealsPage","managerBrowsePage","managerBrowseTeamPage","managerDivisionPage","managerScorersPage","managerAssistsPage","managerReportsPage","managerChatPage","managerCupsPage","managerSimPage","managerFixturesPage","managerViewTeamsPage","managerStatsInfoPage","managerTrophiesPage","managerTeamPage"]}
    function managerHasResumableGame(){return !!(touchlinesView&&!touchlinesView.finished)}
    function syncManagerLeagueOptionText(){const b=$("managerLeagueOption");if(!b)return;const resume=managerHasResumableGame();b.textContent=resume?"RESUME GAME":"LEAGUE TABLE";b.title=resume?"Resume the live match":"League table"}
    function syncManagerActionVisibility(){const action=$("managerActionMenu"),visible=visibleScreen()==="manager"&&!!managerSeason;if(action)action.classList.toggle("hide",!visible);syncManagerLeagueOptionText();if(!visible)closeManagerActionMenu()}
    function showManagerSection(id,record=true){if(id!=="managerSimPage"&&typeof pauseManagerSimAnimation==="function")pauseManagerSimAnimation();if(!["managerSimPage","managerTransfersPage","managerDealsPage"].includes(id))clearManagerDealReturn();managerSections().forEach(x=>$(x).classList.toggle("hide",x!==id));syncManagerActionVisibility();syncManagerLeagueOptionText();const back=$("managerBack");if(back)back.classList.add("hide");closeManagerMenus();syncManagerMenuMusic();if(record&&visibleScreen()==="manager")pushAppHistory()}
    function currentManagerSection(){return managerSections().find(id=>$(id)&&!$(id).classList.contains("hide"))||""}
    function clearManagerDealReturn(){managerDealReturnSection="";managerDealReturnView=null;managerDealReturnFixture=null}
    function rememberManagerDealReturn(){const fromMatch=currentManagerSection()==="managerSimPage"||!!touchlinesView||managerSimRunning;if(!fromMatch&&managerDealReturnSection==="managerSimPage")return true;if(!fromMatch)return false;managerDealReturnSection="managerSimPage";if(touchlinesView){managerDealReturnView=touchlinesView;managerDealReturnFixture=touchlinesView.fixture||managerDealReturnFixture}return true}
    function resumeManagerDealReturn(){if(managerDealReturnSection!=="managerSimPage")return false;const view=managerDealReturnView,fixture=managerDealReturnFixture;clearManagerDealReturn();msg("managerMsg","");if(view){try{if(view.raf)cancelAnimationFrame(view.raf)}catch(e){}view.raf=0;view.lastTs=0;touchlinesView=view;managerSimRunning=!view.finished;showManagerSection("managerSimPage",false);$("managerSimPage")?.classList.add("touchlines-live");try{tlProDraw(view);tlProHud(view)}catch(err){tlProRenderError(err);return true}if(view.finished){stopCrowd();syncManagerMenuMusic();if(typeof tlProShowBackButton==="function")tlProShowBackButton();if(typeof tlProShowPostMatchReport==="function")tlProShowPostMatchReport(view);return true}playCrowd();syncManagerMenuMusic();view.raf=requestAnimationFrame(tlProLoop);return true}if(fixture){renderTouchlinesView(fixture);return true}return false}
    function resumeManagerDealReturnOrBack(){if(resumeManagerDealReturn())return;goBackOrMenu()}
    function resumeManagerDealReturnIfNeeded(){return currentManagerSection()==="managerDealsPage"&&resumeManagerDealReturn()}
    function clearManagerView(text=""){managerAutoStartFixture=null;clearManagerDealReturn();managerSections().forEach(x=>$(x).classList.add("hide"));$("managerActionMenu")?.classList.add("hide");$("managerBack")?.classList.add("hide");closeManagerMenus();if(String(text||"").toLowerCase().includes("loading manager"))setManagerMessage("",false);else managerStatus(text,true)}
    function bindManagerActionMenuScroll(){
      const l=$("managerActionList");if(!l||l.dataset.scrollBound==="1")return;
      l.dataset.scrollBound="1";
      const scrollable=()=>l.scrollHeight>l.clientHeight+2;
      l.addEventListener("wheel",e=>{if(!scrollable())return;l.scrollTop+=e.deltaY;e.preventDefault()},{passive:false});
    }
    function syncManagerActionMenuGeometry(open=false){const m=$("managerActionMenu"),l=$("managerActionList"),b=$("managerActionButton"),matchOpen=!!open&&currentManagerSection()==="managerSimPage";if(!m||!l)return;if(!matchOpen){["position","left","right","top","bottom","zIndex","display","gridTemplateRows","minHeight","maxHeight","overflow","boxSizing"].forEach(p=>m.style[p]="");["alignSelf","height","maxHeight","minHeight","overflowY","overflowX","overscrollBehavior","webkitOverflowScrolling","touchAction","pointerEvents"].forEach(p=>l.style[p]="");return}const mobile=matchMedia("(max-aspect-ratio:4/5)").matches,top=mobile?58:68,buttonH=Math.max(42,b?.offsetHeight||0,mobile?54:58),reserve=buttonH+(mobile?10:12),height=Math.max(180,Math.floor(innerHeight-top-reserve));Object.assign(m.style,{position:"fixed",left:"0px",right:"0px",top:`${top}px`,bottom:"0px",zIndex:"120",display:"grid",gridTemplateRows:"minmax(0, 1fr) auto",minHeight:"0",maxHeight:"none",overflow:"hidden",boxSizing:"border-box"});Object.assign(l.style,{alignSelf:"stretch",height:`${height}px`,maxHeight:`${height}px`,minHeight:"0",overflowY:"auto",overflowX:"hidden",overscrollBehavior:"contain",webkitOverflowScrolling:"touch",touchAction:"pan-y",pointerEvents:"auto"})}
    function setManagerActionMenuOpen(open){const m=$("managerActionMenu"),l=$("managerActionList"),b=$("managerActionButton"),screen=$("manager");if(!m||!l)return;bindManagerActionMenuScroll();syncManagerLeagueOptionText();m.classList.toggle("open",!!open);l.classList.toggle("hide",!open);if(screen){screen.classList.toggle("manager-menu-open",!!open);screen.classList.toggle("manager-match-menu-open",!!open&&currentManagerSection()==="managerSimPage")}syncManagerActionMenuGeometry(open);if(b)b.setAttribute("aria-expanded",open?"true":"false");if(open)requestAnimationFrame(()=>{syncManagerActionMenuGeometry(true);l.scrollTop=0})}
    function closeManagerActionMenu(){setManagerActionMenuOpen(false)}
    function closeManagerMenus(){closeManagerActionMenu()}
    function managerVoteNames(vote){return (vote?.ready||[]).map(u=>String(u||"").toUpperCase()).filter(Boolean)}
    function updateReadyButton(id,vote,base){const b=$(id);if(!b)return;const names=managerVoteNames(vote),waiting=(vote?.waiting||[]).map(u=>String(u||"").toUpperCase()).filter(Boolean),passive=managerRoundVotePassive(vote),hasReady=!!(vote&&!vote.allReady&&names.length&&!passive),isStartGame=id==="managerNextRound"||id==="managerTeamNextRound",mineReady=hasReady&&!!vote.mineReady&&(!isStartGame||managerReadyVoteLocallyArmed(vote)),waitingButton=b.dataset.waiting==="1",mineWaiting=mineReady&&waitingButton&&waiting.length;b.classList.toggle("manager-ready-waiting",mineReady);if(passive&&waitingButton){b.textContent="ROUND WAITING";b.title=waiting.length?`Still to finish: ${waiting.join(", ")}`:"Round waiting";return}if(waitingButton&&!mineReady){b.title=waiting.length?`Waiting for ${waiting.join(", ")}`:"Waiting";return}b.textContent=mineWaiting?`READY - WAITING FOR ${waiting.join(", ")}`:(mineReady?`${base} ${safe(vote.readyCount||names.length)}/${safe(vote.neededCount||names.length)} READY`:base);b.title=mineWaiting?`Ready. Waiting for ${waiting.join(", ")}`:(hasReady?`${base}: ${names.join(", ")} READY`:base)}
    function managerPrimaryActionLabel(){return nextManagerFixture()||nextManagerFixturePreview()?"START GAME":managerPendingRound()?managerCpuOnlyActionLabel():"START GAME"}
    function updateManagerReadyIndicators(){const simVote=effectiveSimRoundVote(),primaryLabel=managerPrimaryActionLabel();updateReadyButton("managerNextRound",simVote,primaryLabel);updateReadyButton("managerTeamNextRound",simVote,"START GAME");updateReadyButton("managerTeamCpuRound",simVote,primaryLabel);updateReadyButton("managerSimSeasonButton",managerSeason?.simSeasonVote,"SIM SEASON");updateReadyButton("adminSimSeason",managerSeason?.simSeasonVote,"SIMULATE WHOLE SEASON")}
    function setManagerTransferOffers(offers){managerTransferOffers={incoming:[...(offers?.incoming||[])],outgoing:[...(offers?.outgoing||[])],notices:[...(offers?.notices||[])]};const latest=(managerTransferOffers.notices||[])[0];if(latest&&currentManagerSection()==="managerBrowseTeamPage"){managerBrowseNotice=dealNoticeHtml(latest);const n=$("managerBrowseNotice");if(n){n.innerHTML=managerBrowseNotice;n.classList.remove("hide")}}syncManagerActions();if(currentManagerSection()==="managerDealsPage")renderManagerDealOffers()}
    function hasDealAlerts(){return (managerTransferOffers?.incoming||[]).length>0||(managerTransferOffers?.notices||[]).length>0}
    function managerChatSeenKey(){return`yspManagerChatSeen:${encodeURIComponent(String(me?.name||"guest"))}:${encodeURIComponent(String(managerSeason?.managerGameId||managerSeason?.id||"none"))}`}
    function managerLatestOtherChatAt(){const mine=String(me?.name||""),msgs=[...(managerSeason?.chatMessages||[])].filter(m=>String(m?.user||"")!==mine);return msgs.reduce((max,m)=>Math.max(max,Number(m?.sentAt||0)),0)}
    function managerChatSeenAt(){try{return Number(localStorage.getItem(managerChatSeenKey())||0)}catch(e){return 0}}
    function markManagerChatSeen(){const latest=(managerSeason?.chatMessages||[]).reduce((max,m)=>Math.max(max,Number(m?.sentAt||0)),0);try{localStorage.setItem(managerChatSeenKey(),String(latest))}catch(e){}}
    function hasLeagueChatAlerts(){return managerLatestOtherChatAt()>managerChatSeenAt()}
    function hasChatAlerts(){return hasLeagueChatAlerts()||hasPrivateChatAlerts()}
    function managerBusyStale(){return !!(managerBusy&&!managerSimRunning&&(!managerBusySince||Date.now()-managerBusySince>MANAGER_BUSY_STALE_MS))}
    function clearStaleManagerBusy(reason=""){
      if(!managerBusyStale())return false;
      clientDebugLog("manager_busy_reset",reason||"stale manager busy cleared",{busyFor:Date.now()-Number(managerBusySince||0),section:typeof currentManagerSection==="function"?currentManagerSection():"",screen:currentScreen},"manager",true);
      managerBusy=false;
      managerBusySince=0;
      return true
    }
    function managerInteractionBusy(){clearStaleManagerBusy("interaction_check");return managerBusy&&managerSeason?.status!=="finished"}
    function managerActionLocked(reason=""){return managerBusy&&!clearStaleManagerBusy(reason)}
    function setManagerBusy(on){managerBusy=!!on;managerBusySince=managerBusy?Date.now():0;const busy=managerInteractionBusy();["managerNextRound","managerTeamNextRound","managerCpuRound","managerTeamCpuRound","managerRoundContinue","managerTeamRoundContinue","managerTeamBestLineup","managerTeamStatsButton","managerTeamAutoTrainingButton","managerSimSeasonButton","adminSimSeason","managerWatchMatch","continueManagerSeason","abortManagerLeague","startManagerLeague","cancelManagerCreate","managerActionButton","arenaBuildButton","managerMerchUpgradeButton","transfersStaff","transfersScout","scoutSave","scoutRun"].forEach(id=>{const b=$(id);if(b)b.disabled=busy||b.dataset.waiting==="1"});document.querySelectorAll("[data-manager-action],[data-manager-view-team]").forEach(b=>b.disabled=busy||b.hidden||b.dataset.waiting==="1");if(busy)document.querySelectorAll("[data-hire-staff-manager],[data-hire-scout]").forEach(b=>b.disabled=true);syncAdminControls();syncManagerMenuMusic()}
    function managerSeasonStarted(season=managerSeason){
      if(!season)return false;
      if("started"in season)return !!season.started;
      if(season.simVote||season.watchVote||season.simSeasonVote)return true;
      if((season.table||[]).some(row=>Number(row?.played||0)>0))return true;
      return (season.rounds||[]).some(round=>(round.fixtures||[]).some(f=>String(f?.status||"pending")!=="pending"||Number(f?.playbackStartedAt||0)>0))
    }
    function canInviteMoreManagers(){return !!me?.name&&!managerPendingSentInvite()&&(!managerSeason||!managerSeasonStarted(managerSeason))}
    function syncManagerActions(){
      const active=!!managerSeason&&managerSeason.status!=="finished",canInviteMore=canInviteMoreManagers();
      syncManagerActionVisibility();
      renderManagerTurnAlerts();
      [["managerMainMenuOption",!!me],["managerLeagueOption",!!managerSeason],["managerCreateOption",canInviteMore],["managerTopScorersOption",!!managerSeason],["managerDivisionsOption",!!managerSeason],["managerCupsOption",!!managerSeason],["managerReportsOption",!!managerSeason],["managerChatOption",!!managerSeason],["managerFixturesOption",!!managerSeason],["managerEconomyOption",!!managerSeason],["managerTransfersOption",!!managerSeason],["managerLineupOption",!!managerSeason],["managerTrophiesOption",!!managerSeason],["managerStatsInfoOption",!!managerSeason],["managerOptionsOption",!!managerSeason],["managerAdminOption",!!me?.admin],["managerAbortOption",active]].forEach(([id,on])=>setMenuOptionVisible(id,on));
      const dealAlert=hasDealAlerts(),chatAlert=hasChatAlerts(),turnAlert=hasManagerTurnAlerts(),inviteAlert=hasManagerIncomingInvite();
      $("managerActionButton")?.classList.toggle("manager-deal-alert",dealAlert||chatAlert||turnAlert||inviteAlert);
      $("managerTransfersOption")?.classList.toggle("manager-deal-alert",dealAlert);
      $("managerChatOption")?.classList.toggle("manager-deal-alert",chatAlert);
      $("managerChatUsers")?.classList.toggle("manager-deal-alert",hasPrivateChatAlerts());
	      $("transfersDeals")?.classList.toggle("manager-deal-alert",dealAlert);
	      updateManagerReadyIndicators();
	    }
	    async function refreshManagerSectionAfterUpdate(section=currentManagerSection(),teamUser=currentTeamDetailsUser){
	      if(section==="managerTeamPage"&&teamUser){await openManagerTeam(teamUser,{record:false});return true}
	      return false
	    }
	    async function renderManagerAfterStartVote(section=currentManagerSection(),teamUser=currentTeamDetailsUser){
	      if(await refreshManagerSectionAfterUpdate(section,teamUser))return;
	      renderManagerSeason();
	      if(section==="managerHome"||!section)showManagerSection("managerHome",false)
	    }
	    function renderManagerSquadPage(){const list=$("managerSquadList"),starters=(managerSquad?.starters||[]).filter(p=>!isLoanPlayer(p)&&!trainingInfo(p)),bench=(managerSquad?.bench||[]).filter(p=>!isLoanPlayer(p)&&!trainingInfo(p)),team=me?.team||{},role=String(managerSquadSellRoleFilter||"").toUpperCase();renderManagerSquadSellFilters();if(role){const players=sortedSquadSellPlayers(starters,bench);list.innerHTML=players.length?`<div class="team-section-title">${safe(role)} PLAYERS</div>${players.map(p=>managerTransferPlayerHtml(p,"sell",p.group||"PLAYER",team)).join("")}`:`<div class="manager-meta">No ${safe(role)} players in your squad</div>`}else{list.innerHTML=(starters.length||bench.length)?`${starters.length?`<div class="team-section-title">STARTING</div>${starters.map(p=>managerTransferPlayerHtml(p,"sell","START",team)).join("")}`:""}${bench.length?`<div class="team-section-title">BENCH</div>${bench.map(p=>managerTransferPlayerHtml(p,"sell","BENCH",team)).join("")}`:""}`:`<div class="manager-meta">No sellable players</div>`}bindTransferCards(list,"data-sell",openSquadSellOffer)}
    function marketRoles(){return["ALL","GK","CB","LB","RB","CM","LM","RM","ST"]}
    function playerStatNum(p,k){return Number(p?.stats?.[k]??0)}
    function marketRoleScore(p,role){const r=String(role||"").toUpperCase(),rating=playerRating(p),s=k=>playerStatNum(p,k);if(!r)return rating+s("composure")*.08+s("positioning")*.08+s("workrate")*.05;const score={GK:s("keeping")*2.6+s("passcontrol")*.7+s("shotcontrol")*.45+s("positioning")*.55+s("composure")*.45+s("speed")*.2,CB:s("tackling")*1.45+s("heading")*1.1+s("strength")*.9+s("positioning")*.9+s("discipline")*.55+s("passing")*.25,LB:s("speed")*1.05+s("stamina")*.75+s("crossing")*.9+s("tackling")*.8+s("passing")*.45+s("workrate")*.65,RB:s("speed")*1.05+s("stamina")*.75+s("crossing")*.9+s("tackling")*.8+s("passing")*.45+s("workrate")*.65,CM:s("passing")*1.2+s("vision")*1.05+s("positioning")*.8+s("passcontrol")*.75+s("tackling")*.55+s("workrate")*.55+s("composure")*.65,LM:s("speed")*1.0+s("crossing")*1.1+s("dribbling")*.9+s("passing")*.65+s("stamina")*.55+s("workrate")*.45,RM:s("speed")*1.0+s("crossing")*1.1+s("dribbling")*.9+s("passing")*.65+s("stamina")*.55+s("workrate")*.45,ST:s("shooting")*1.55+s("shotcontrol")*1.1+s("speed")*.75+s("heading")*.65+s("composure")*.85+s("positioning")*.8+s("crit")*.35}[r];return (score??rating)+rating*.55}
    function playerMatchesRole(p,role){role=String(role||"").toUpperCase();return !role||playerRoleTokens(p).includes(role)}
    function sortedSquadSellPlayers(starters,bench){let players=[...(starters||[]).map(p=>({...p,group:"START"})),...(bench||[]).map(p=>({...p,group:"BENCH"}))].filter(p=>!isLoanPlayer(p)&&!trainingInfo(p)),role=String(managerSquadSellRoleFilter||"").toUpperCase();if(role)players=players.filter(p=>playerMatchesRole(p,role));players.sort((a,b)=>marketRoleScore(b,role)-marketRoleScore(a,role)||playerRating(b)-playerRating(a)||Number(b.value||0)-Number(a.value||0));return players}
    function renderManagerSquadSellFilters(){const box=$("managerSquadFilters");if(!box)return;box.innerHTML=marketRoles().map(r=>`<button class="${(managerSquadSellRoleFilter||"")===(r==="ALL"?"":r)?"active":""}" data-squad-sell-role="${r==="ALL"?"":r}" type="button">${safe(r)}</button>`).join("");box.querySelectorAll("[data-squad-sell-role]").forEach(b=>b.onclick=()=>{managerSquadSellRoleFilter=b.dataset.squadSellRole||"";renderManagerSquadPage()})}
    function sortedMarketPlayers(){let players=[...(managerMarket||[])],role=String(managerMarketRoleFilter||"").toUpperCase();if(role)players=players.filter(p=>playerMatchesRole(p,role));players.sort((a,b)=>marketRoleScore(b,role)-marketRoleScore(a,role)||playerRating(b)-playerRating(a)||Number(b.price||b.value||0)-Number(a.price||a.value||0));return players}
    function renderManagerMarketFilters(){const box=$("managerMarketFilters");if(!box)return;box.innerHTML=marketRoles().map(r=>`<button class="${(managerMarketRoleFilter||"")===(r==="ALL"?"":r)?"active":""}" data-market-role="${r==="ALL"?"":r}" type="button">${safe(r)}</button>`).join("");box.querySelectorAll("[data-market-role]").forEach(b=>b.onclick=()=>{managerMarketRoleFilter=b.dataset.marketRole||"";renderManagerMarketPage()})}
    function renderManagerMarketPage(){renderTransferEconomy("managerMarketEconomy");const notice=$("managerMarketNotice");if(notice){notice.innerHTML=managerMarketNotice;notice.classList.toggle("hide",!managerMarketNotice);bindSigningNoticeAction(notice)}renderManagerMarketFilters();const list=$("managerMarketList"),team={shirt:"#1b5fd0",trim:"#ffdd45"},players=sortedMarketPlayers(),role=managerMarketRoleFilter?`${managerMarketRoleFilter} `:"";list.innerHTML=players.length?players.map(p=>managerTransferPlayerHtml(p,"buy","MARKET",team)).join(""):`<div class="manager-meta">No ${safe(role)}players on market</div>`;bindTransferCards(list,"data-buy",openMarketTransferOffer);bindTransferCards(list,"data-remove-market",removeMarketListing)}
    function statInfoRows(){return[["HOME/AWAY","Advantage","Home team gets a small match boost, about +4.5%. Away team has no boost, so the same two teams are slightly less likely to win away."],["FOOT","Preferred foot","L/R/B means left, right or both feet. Wide players get +1 OVR on their correct side and -1 on the wrong side."],["SHT","Shooting","Finishing, shot choice and goal threat."],["PAS","Passing","Pass accuracy, tempo and safer buildup."],["TAC","Tackling","Ball winning, defensive duels and pressure."],["HEA","Heading","Aerial duels, crosses, corners and clearances."],["PCL","Passcontrol","First touch when receiving passes and keeping possession."],["SCL","Shotcontrol","Shot contact, low shots, accuracy under pressure."],["SPD","Speed","Sprint pace, recovery runs and breaks behind defense."],["CRT","Crit","Chance for special high-impact moments in shots and duels."],["STA","Stamina","How long the player keeps level late in matches."],["STR","Strength","Physical duels, shielding and contact balance."],["POS","Positioning","Being in the right zone for attacks, defense and rebounds."],["VIS","Vision","Finding better passes, switches and through balls."],["CMP","Composure","Calm decisions when pressed or near goal."],["AGR","Aggression","How hard the player presses and challenges."],["DIS","Discipline","Lower foul/card risk and cleaner defending."],["CRS","Crossing","Wide delivery from flanks and set-up for headers."],["DRB","Dribbling","Carrying the ball, beating pressure and wide attacks."],["WRK","Workrate","Off-ball movement, tracking back and support runs."],["KEEP","Keeping","Goalkeeper saves, catching and keeper control."]]}
    function roleStatInfoRows(){return[["GK","Goalkeeper","KEEP Keeping, PCL Passcontrol, POS Positioning, CMP Composure."],["CB","Centre Back","TAC Tackling, HEA Heading, STR Strength, POS Positioning, DIS Discipline."],["LB/RB","Full Back","SPD Speed, TAC Tackling, CRS Crossing, STA Stamina, WRK Workrate."],["CM","Midfielder","PAS Passing, VIS Vision, PCL Passcontrol, POS Positioning, WRK Workrate."],["LM/RM","Wide Mid","CRS Crossing, SPD Speed, DRB Dribbling, PAS Passing, STA Stamina."],["ST","Striker","SHT Shooting, SCL Shotcontrol, POS Positioning, CMP Composure, SPD Speed."]]}
    function renderManagerStatsInfoPage(){const roles=roleStatInfoRows().map(([code,name,text])=>`<div class="manager-info-row"><b>${safe(code)} ${safe(name)}</b><span>${safe(text)}</span></div>`).join(""),stats=statInfoRows().map(([code,name,text])=>`<div class="manager-info-row"><b>${safe(code)} ${safe(name)}</b><span>${safe(text)}</span></div>`).join(""),game=gameInfoRows().map(([code,text])=>`<div class="manager-info-row"><b>${safe(code)}</b><span>${safe(text)}</span></div>`).join("");$("managerStatsInfoList").innerHTML=`<div class="manager-info-title">ROLE STATS</div>${roles}<div class="manager-info-title">STAT INFO</div>${stats}<div class="manager-info-title">GAME INFO</div>${game}`;showManagerSection("managerStatsInfoPage")}
    function gameInfoRows(){return[["FOOT SIDE","LB/LM works best with left foot, RB/RM works best with right foot. Correct side gives +1 OVR, wrong side gives -1 OVR, both feet gives +1 on either side."],["POSITION","Players can be placed anywhere without a -10% OVR penalty. Best Lineup still prefers natural roles, and left/right foot side bonus still applies."],["SQUAD MARKS","Red marks in Squad Setup are for injuries/cards, not wrong-position penalties."],["OVR","OVR starts from the player's stats, then foot side, daily form and team boost are applied."],["PLAYER IDS","Each player has a permanent ID stored on the player. Shirt number is separate, so transfers and match reports can track the same player after he moves club."],["TEAM SKILL","The league S number shows squad depth. It uses raw skill points from the squad's best 16 players, so it is useful when judging the whole club."],["MATCH POWER","When a match is simulated, the engine uses only the starting XI on the pitch. Bench players do not improve match power until they are selected into the team."],["MATCH FLOW","The starting XI is split into attack, midfield, defense and keeper power. Player roles and stats decide which part of the team they affect most."],["DAILY FORM","Before each fixture, daily form normally gives one starter +10% and one different starter -10%. If the club is in formtop, there is no -10% player and two different players get +10% instead. Dots are locked to players until the fixture is played."],["STAFF MANAGER","Booster Trainers must be bought step by step. Each step costs its full listed price, gives +0.5% more team boost, and keeps the best fit XI set in Squad and before matches."],["INJURIES","Each human manager can get 0-5 random injuries per season. They trigger before a round, last 1-3 matches, and show with a red injury badge in Squad Setup."],["INJURY BLOCK","If an injured player is still in STARTING, match start stops. A hired Booster Trainer moves injured starters out automatically when you have 11 fit players; otherwise press BEST."],["MATCH REPORTS","Watched manager matches store compact player summaries: distance, ball time, touches, passes, shots, tackles, fouls, saves and complaints."],["REPORT LABELS","Workhorse means most running. Slacker means lowest running outfield player. Underperformer means bad impact. Inefficient means he ran but did not help enough."],["PLAYER GROWTH","At season end, players with heavy praise from reports gain +2 on their most important role stat and +6% value. League top scorer places 1/2/3 add +90%/+60%/+40% value."],["PLAYER TALK NOTE","A terrible report should later unlock rest, bonus, gift or threat actions. Threat should show a warning first because the player can quit."],["CONDITION NOTE","Future injuries, fitness and daily form should adjust a player's effective stats before match power is calculated. That means the same squad S can stay high while today's starting XI plays weaker or stronger."],["ODDS","1 / X / 2 comes from both teams' match power, recent form and home advantage. It is chance, not a fixed result."],["HOME BOOST","The home team gets a small match profile boost, currently about +4.5%, and the goal model starts slightly higher for the home side."],["FORM CURVE","Three straight league wins give a green up arrow, +3% match power and formtop daily form: two +10% players and no -10% player. Three straight league losses give a red down arrow and -3%. Draws reset the streak; cup matches do not count."],["GOALS","Scorers are picked from the match engine when you watch, or weighted by role and attacking stats when simmed. After a team has scored 5, the chance for the next goal is halved, then halved again for every goal after that."],["PENS","Penalties exist. Penalty goals are counted in Top Scorers with the pen number in parentheses."],["ASSISTS","Assists are tracked separately. Midfielders and wide players are more likely to assist, with passing and vision helping."],["TRANSFERS","Browse transfers can be rejected or countered. Better players and higher-division clubs are harder and more expensive to buy."]]}
    async function renderManagerTrophiesPage(){const list=$("managerTrophiesList");if(!list||!me?.name)return;list.innerHTML="";showManagerSection("managerTrophiesPage");const r=await api("managerTeamDetails",{teamUser:me.name});if(!r.ok)return msg("managerMsg","Could not load trophies");const d=r.teamDetails||{};list.innerHTML=trophiesHtml(d.trophies||[])}
    function renderManagerEconomyPage(){const players=allSquadPlayers(),squadValue=Number(managerFinance?.squadValue||0)||sumPlayers(players,"value"),weekly=Number(managerFinance?.weeklyWages||0)||sumPlayers(players,"wage"),loanDebt=Number(managerFinance?.loan?.current?.remaining||0);$("managerEconomySummary").innerHTML=[economyCard("BALANCE",money(managerFinance?.balance||0),Number(managerFinance?.balance||0)>=0?"good":"bad"),economyCard("LOAN DEBT",money(loanDebt),loanDebt>0?"bad":""),economyCard("WAGES/MATCH",signedMoney(-weekly),"bad"),economyCard("SQUAD VALUE",money(squadValue)),lastRoundEconomyHtml()].join("");$("managerEconomyExpand").innerHTML=arenaExpansionHtml()+merchUpgradeHtml()+managerLoanHtml()+seasonEconomyHtml();bindArenaExpansion();bindMerchUpgrade();bindManagerLoan();showManagerSection("managerEconomyPage")}
    async function startArenaExpansion(){const next=managerFinance?.arenaNext;if(!next||managerActionLocked("arena_expansion"))return;if(!await askConfirm("BUILD ARENA",`Expand arena by ${Number(next.seats||0).toLocaleString("en-GB")} seats?\nCost ${money(next.cost||0)}. Build time ${next.rounds||0} rounds.`,`BUILD`,`CANCEL`,false))return;setManagerBusy(true);try{const r=await api("managerStartArenaExpansion");if(!r.ok)return msg("managerMsg",r.error==="no_money"?"Not enough money":r.error==="arena_building"?"Arena build already running":r.error==="arena_max"?"Arena is fully expanded":"Could not start arena build");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;renderManagerSeason();renderManagerEconomyPage();msg("managerMsg","Arena build started")}finally{setManagerBusy(false)}}
    async function startMerchUpgrade(){const next=managerFinance?.merchNext;if(!next||managerActionLocked("merch_upgrade"))return;if(!await askConfirm("UPGRADE MERCH",`Upgrade merch to level ${next.level}/${next.maxLevel||5}?\nCost ${money(next.cost||0)}.\nMerch boost becomes +${next.boostPct||0}%.`,`UPGRADE`,`CANCEL`,false))return;setManagerBusy(true);try{const r=await api("managerUpgradeMerch");if(!r.ok)return msg("managerMsg",r.error==="no_money"?"Not enough money":r.error==="merch_max"?"Merch is fully upgraded":"Could not upgrade merch");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;renderManagerSeason();renderManagerEconomyPage();msg("managerMsg",`Merch upgraded to level ${safe(r.managerFinance?.merchLevel||next.level)}`)}finally{setManagerBusy(false)}}
    function dealOfferText(o){const p=o?.player||{},cash=Number(o?.cashOffer||0),offerPlayer=o?.offerPlayer,offerValue=Number(o?.offerValue||0),total=Number(o?.offerTotal||cash+offerValue);return `${safe(p.name||"Player")} | ${o?.countered?"counter":"cash"} ${money(cash)}${offerPlayer?` + ${safe(offerPlayer.name||"player")} ${money(offerValue)}`:""} | total ${money(total)}`}
    function dealNoticeTitle(n){const type=String(n?.type||"");return type==="accepted"?"DEAL ACCEPTED":type==="counter_accepted"?"COUNTER ACCEPTED":type==="counter_rejected"?"COUNTER DECLINED":"DEAL DECLINED"}
    function dealNoticeHtml(n){const type=String(n?.type||""),seller=n?.sellerTeam?.name||n?.seller||"Manager",buyer=n?.buyerTeam?.name||n?.buyer||"Manager",player=n?.player?.name||"Player";if(type==="counter_accepted")return `<b>COUNTER ACCEPTED</b>${safe(buyer)} accepted your counter for ${safe(player)}.`;if(type==="counter_rejected")return `<b>COUNTER DECLINED</b>${safe(buyer)} declined your counter for ${safe(player)}.`;return `<b>${type==="accepted"?"DEAL ACCEPTED":"DEAL DECLINED"}</b>${safe(seller)} ${type==="accepted"?"accepted":"declined"} your bid for ${safe(player)}.`}
    function managerDealNoticeCard(n){return `<div class="manager-deal-card incoming"><div><b>${dealNoticeTitle(n)}</b><small>${dealOfferText(n)}<br>${dealNoticeHtml(n).replace(/<b>.*?<\/b>/,"")}</small></div><div class="manager-deal-actions"><button class="green" data-deal-notice="${safe(n.id)}" type="button">OK</button></div></div>`}
    function managerDealCard(o,type){const incoming=type==="incoming",viewer=me?.name||"",sellerAction=incoming&&o.seller===viewer,buyerAction=incoming&&o.buyer===viewer,sellerName=o.sellerTeam?.name||o.seller,buyerName=o.buyerTeam?.name||o.buyer,other=sellerAction?buyerName:sellerName,title=sellerAction?`${safe(other)} WANTS A DEAL`:buyerAction?`COUNTER OFFER`:o.seller===viewer&&o.countered?`COUNTER SENT`:`WAITING FOR ${safe(other)}`,note=sellerAction?"They want your player":buyerAction?`${safe(sellerName)} wants ${money(o.cashOffer||0)}`:o.seller===viewer&&o.countered?`Waiting for ${safe(buyerName)}`:"You sent this bid",actions=sellerAction?`<div class="manager-deal-actions"><button class="green" data-deal-accept="${safe(o.id)}" type="button">ACCEPT</button><button data-deal-counter="${safe(o.id)}" type="button">COUNTER</button><button class="orange" data-deal-reject="${safe(o.id)}" type="button">REJECT</button></div>`:buyerAction?`<div class="manager-deal-actions"><button class="green" data-deal-accept="${safe(o.id)}" type="button">ACCEPT</button><button class="orange" data-deal-reject="${safe(o.id)}" type="button">DECLINE</button></div>`:"";return `<div class="manager-deal-card ${incoming?"incoming":"outgoing"}"><div><b>${title}</b><small>${dealOfferText(o)}<br>${note}</small></div>${actions}</div>`}
    function renderManagerDealOffers(){const box=$("managerDealsList");if(!box)return;const incoming=managerTransferOffers?.incoming||[],outgoing=managerTransferOffers?.outgoing||[],notices=managerTransferOffers?.notices||[],total=incoming.length+outgoing.length+notices.length,summary=$("managerDealsSummary");if(summary)summary.textContent=total?`${incoming.length} incoming | ${outgoing.length} outgoing | ${notices.length} notice${notices.length===1?"":"s"}`:"No active deal offers";box.innerHTML=total?`${notices.map(managerDealNoticeCard).join("")}${incoming.map(o=>managerDealCard(o,"incoming")).join("")}${outgoing.map(o=>managerDealCard(o,"outgoing")).join("")}`:`<div class="manager-meta">No deal offers right now.</div>`;box.querySelectorAll("[data-deal-accept]").forEach(b=>b.onclick=()=>decideManagerDeal(b.dataset.dealAccept,"accept"));box.querySelectorAll("[data-deal-reject]").forEach(b=>b.onclick=()=>decideManagerDeal(b.dataset.dealReject,"reject"));box.querySelectorAll("[data-deal-counter]").forEach(b=>b.onclick=()=>openDealCounterOffer(b.dataset.dealCounter));box.querySelectorAll("[data-deal-notice]").forEach(b=>b.onclick=()=>dismissManagerDealNotice(b.dataset.dealNotice))}
    async function decideManagerDeal(offerId,decision){if(!offerId||managerActionLocked("deal_decision"))return;setManagerBusy(true);try{const r=await api("managerTransferOfferDecision",{offerId,decision});if(!r.ok)return msg("managerMsg",r.error==="bench_full"?benchFullText(r):r.error==="no_money"?"Buyer does not have enough money":r.error==="no_replacement"?"A starter needs a bench replacement":r.error==="offer_expired"?"Offer expired":"Could not update deal");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;setManagerTransferOffers(r.managerTransferOffers||managerTransferOffers);renderManagerDealOffers();renderManagerSeason();if(resumeManagerDealReturnIfNeeded())return;msg("managerMsg",decision==="accept"?"Deal accepted":"Deal declined")}finally{setManagerBusy(false)}}
    async function counterManagerDeal(offerId,offer){if(!offerId||managerActionLocked("deal_counter"))return;setManagerBusy(true);try{const r=await api("managerTransferOfferCounter",{offerId,...offer});if(!r.ok)return msg("managerMsg",r.error==="counter_too_low"?"Raise the counter":r.error==="offer_expired"?"Offer expired":"Could not send counter");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;setManagerTransferOffers(r.managerTransferOffers||managerTransferOffers);renderManagerDealOffers();renderManagerSeason();if(resumeManagerDealReturnIfNeeded())return;msg("managerMsg",r.status==="accepted"?"Counter accepted":r.status==="counter_rejected"?"Counter declined":"Counter sent")}finally{setManagerBusy(false)}}
    async function dismissManagerDealNotice(noticeId){if(!noticeId)return;const r=await api("managerTransferNoticeSeen",{noticeId});if(r.ok){setManagerTransferOffers(r.managerTransferOffers||{incoming:[],outgoing:[],notices:[]});resumeManagerDealReturnIfNeeded()}}
    function showManagerStaffBox(){renderManagerStaffBox();$("managerScoutBox")?.classList.add("hide");$("managerStaffBox")?.classList.remove("hide");$("managerStaffBox")?.scrollIntoView({block:"nearest"})}
    function showManagerScoutBox(){renderManagerScoutBox();$("managerStaffBox")?.classList.add("hide");$("managerScoutBox")?.classList.remove("hide");$("managerScoutBox")?.scrollIntoView({block:"nearest"})}
    function renderManagerDealsPage(){rememberManagerDealReturn();renderManagerDealOffers();showManagerSection("managerDealsPage")}
    function renderManagerTransfersPage(){rememberManagerDealReturn();renderTransferEconomy("managerTransfersEconomy");renderManagerStaffBox();renderManagerScoutBox();$("managerStaffBox")?.classList.add("hide");$("managerScoutBox")?.classList.add("hide");showManagerSection("managerTransfersPage")}
    function renderManagerBrowsePage(level=managerBrowseLevel||5){renderTransferEconomy("managerBrowseEconomy");managerBrowseLevel=Number(level)||5;const div=(managerDivisions||[]).find(d=>Number(d.level)===managerBrowseLevel)||(managerDivisions||[])[0];if(!div)return msg("managerMsg","Could not load divisions");managerBrowseLevel=Number(div.level||managerBrowseLevel);$("managerBrowseMeta").textContent=`${div.name} | ${(div.teams||[]).length} clubs | choose a club to make bids`;$("managerBrowseLevels").innerHTML=(managerDivisions||[]).map(d=>`<button class="manager-level-button ${Number(d.level)===managerBrowseLevel?"active":""}" data-browse-level="${safe(d.level)}" type="button">${safe(d.name)}</button>`).join("");$("managerBrowseTeams").innerHTML=(div.teams||[]).map(t=>`<button class="manager-user" data-browse-team="${safe(t.id)}" type="button">${teamFlag(t.team)} <b>${safe(t.team?.name||t.id)}</b><small>Skill ${Math.round(Number(t.strength||0))} | squad browse</small></button>`).join("");$("managerBrowseLevels").querySelectorAll("[data-browse-level]").forEach(b=>b.onclick=()=>renderManagerBrowsePage(b.dataset.browseLevel));$("managerBrowseTeams").querySelectorAll("[data-browse-team]").forEach(b=>b.onclick=()=>{managerBrowseNotice="";managerBrowseRoleFilter="";openManagerBrowseTeam(b.dataset.browseTeam)});showManagerSection("managerBrowsePage")}
    function renderManagerBrowseFilters(){const box=$("managerBrowseFilters");if(!box)return;box.innerHTML=marketRoles().map(r=>`<button class="${(managerBrowseRoleFilter||"")===(r==="ALL"?"":r)?"active":""}" data-browse-role="${r==="ALL"?"":r}" type="button">${safe(r)}</button>`).join("");box.querySelectorAll("[data-browse-role]").forEach(b=>b.onclick=()=>{managerBrowseRoleFilter=b.dataset.browseRole||"";renderManagerBrowseTeamDetails()})}
    function sortedBrowsePlayers(starters,bench){let all=[...(starters||[]).map(p=>({...p,_browseGroup:"START"})),...(bench||[]).map(p=>({...p,_browseGroup:"BENCH"}))],role=String(managerBrowseRoleFilter||"").toUpperCase();if(role)all=all.filter(p=>playerMatchesRole(p,role));all.sort((a,b)=>marketRoleScore(b,role)-marketRoleScore(a,role)||playerRating(b)-playerRating(a)||Number(b.price||b.value||0)-Number(a.price||a.value||0));return all}
    function renderManagerBrowseTeamDetails(){renderTransferEconomy("managerBrowseTeamEconomy");const d=managerBrowseTeamDetails||{},userId=managerBrowseTeam;if(!userId)return;const team=d.team||{},sq=d.squad||{},starters=sq.starters||[],bench=sq.bench||[],players=starters.length+bench.length,notice=$("managerBrowseNotice"),role=managerBrowseRoleFilter?`${managerBrowseRoleFilter} `:"";$("managerBrowseTeamTitle").innerHTML=`<div class="team-profile-hero">${teamFlag(team)}<div><div class="team-profile-name">${safe(team.name||userId)}</div><div class="team-profile-sub">TRANSFER BROWSE${d.divisionName?` | ${safe(d.divisionName)}`:""}</div></div></div>`;$("managerBrowseTeamMeta").textContent=`${players} available players | skill ${Math.round(Number(d.strength||0))} | bids can be rejected or countered`;notice.innerHTML=managerBrowseNotice;notice.classList.toggle("hide",!managerBrowseNotice);bindSigningNoticeAction(notice);renderManagerBrowseFilters();const list=$("managerBrowsePlayerList");if(managerBrowseRoleFilter){const filtered=sortedBrowsePlayers(starters,bench);list.innerHTML=filtered.length?`<div class="team-section-title">${safe(managerBrowseRoleFilter)} PLAYERS</div>${filtered.map(p=>managerBrowsePlayerHtml(p,p._browseGroup||"PLAYER",team)).join("")}`:`<div class="manager-meta">No ${safe(role)}players in this squad</div>`}else{list.innerHTML=players?`${starters.length?`<div class="team-section-title">STARTING</div>${starters.map(p=>managerBrowsePlayerHtml(p,"START",team)).join("")}`:""}${bench.length?`<div class="team-section-title">BENCH</div>${bench.map(p=>managerBrowsePlayerHtml(p,"BENCH",team)).join("")}`:""}`:`<div class="manager-meta">No available players</div>`}bindTransferCards(list,"data-browse-buy",id=>openBrowseTransferOffer(userId,id));showManagerSection("managerBrowseTeamPage")}
    async function openManagerBrowseTeam(userId){if(!userId)return;managerBrowseTeam=userId;const r=await api("browseTeamDetails",{teamUser:userId});if(!r.ok)return msg("managerMsg",r.error==="human_transfer_locked"?"That manager is not available for deals":"Could not load browse team");managerBrowseTeamDetails=r.teamDetails||{};renderManagerBrowseTeamDetails()}
    function renderManagerDivision(level){const scroll=managerScrollSnapshot(),divisions=managerDivisions||[],div=divisions.find(d=>Number(d.level)===Number(level));if(!div)return msg("managerMsg","Could not load division");managerViewDivision=div;$("managerDivisionTitle").textContent=div.name;const hasStats=(div.topScorers||[]).length||(div.topAssists||[]).length||String(div.seasonId||"")!=="";const levelBox=$("managerDivisionLevels");if(levelBox){const buttons=divisions.map(d=>`<button class="${Number(d.level)===Number(div.level)?"active":""}" data-manager-division-level="${safe(d.level)}" type="button">${safe(d.name||"DIVISION")}</button>`);if(hasStats)buttons.splice(Math.max(0,buttons.length-1),0,`<button class="green" data-manager-division-scorers="${safe(div.level)}" type="button">TOP SCORERS</button>`);levelBox.innerHTML=buttons.join("");levelBox.querySelectorAll("[data-manager-division-level]").forEach(b=>b.onclick=()=>renderManagerDivision(b.dataset.managerDivisionLevel));levelBox.querySelectorAll("[data-manager-division-scorers]").forEach(b=>b.onclick=()=>renderManagerScorersPage(false,div))}const actionBox=$("managerDivisionActions");if(actionBox){actionBox.innerHTML="";actionBox.classList.add("hide")}const rows=div.table||div.teams||[],meta=$("managerDivisionMeta");if(meta){meta.textContent="";meta.classList.add("hide")}const humans=new Set(div.humanManagers||[]);$("managerDivisionList").innerHTML=managerLeagueTableHtml(rows,div.promotionRules||{},humans);$("managerDivisionList").querySelectorAll("[data-manager-team]").forEach(b=>b.onclick=()=>openManagerTeam(b.dataset.managerTeam));showManagerSection("managerDivisionPage");restoreManagerScroll(scroll)}
    function renderManagerViewTeamsPage(){const divisions=managerDivisions||[];$("managerViewTeamsPageList").innerHTML=divisions.length?divisions.map(d=>`<button data-manager-view-team="${safe(d.level)}" type="button">${safe(d.name||"DIVISION")}</button>`).join(""):`<div class="manager-meta">No divisions</div>`;showManagerSection("managerViewTeamsPage")}
    function managerScorerSource(){return managerScorersContext||managerSeason||{}}
    function managerStatContextTitle(){const src=managerScorerSource();return src?.statContext?.label||src?.name||managerSeason?.statContext?.label||"League"}
    function managerStatTeam(s){const src=managerScorerSource();return s?.team||src?.teamsByUser?.[s?.user]?.team||managerSeason?.teamsByUser?.[s?.user]?.team||{}}
    function managerStatTeamName(s){const t=managerStatTeam(s);return t?.name||s?.teamName||s?.user||"Team"}
    function managerStatInitials(name){return String(name||"Player").trim().split(/\s+/).filter(Boolean).slice(0,2).map(x=>x[0]||"").join("").toUpperCase()||"P"}
    function managerStatEmpty(text){return `<div class="manager-stat-empty">${safe(text)}</div>`}
    function managerStatRow(s,i,mode="goals"){const goals=Number(s?.goals||0),assists=Number(s?.assists||0),pens=Number(s?.penalties||0),main=mode==="assists"?assists:goals,rank=i+1,team=managerStatTeam(s),teamName=managerStatTeamName(s),player=s?.player||"Player",rankClass=rank===1?" first":rank===2?" second":rank===3?" third":"";return `<div class="manager-stat-row${rankClass}"><span class="manager-stat-rank">${safe(rank)}</span><span class="manager-stat-player"><i>${safe(managerStatInitials(player))}</i><span><b>${safe(player)}</b><small>${safe(teamName)}</small></span></span><span class="manager-stat-club">${teamFlag(team)}<em>${safe(teamName)}</em></span><b class="manager-stat-main">${safe(main)}</b><span>${safe(mode==="assists"?goals:assists)}</span><span>${safe(pens)}</span></div>`}
    function managerStatTable(rows,mode="goals",emptyText="No stats yet"){rows=rows||[];const main=mode==="assists"?"A":"G",other=mode==="assists"?"G":"A";return `<div class="manager-stat-table"><div class="manager-stat-row head"><span>#</span><span>PLAYER</span><span>CLUB</span><b>${main}</b><span>${other}</span><span>PEN</span></div>${rows.length?rows.map((s,i)=>managerStatRow(s,i,mode)).join(""):managerStatEmpty(emptyText)}</div>`}
    function managerScorerRows(rows){return managerStatTable(rows,"goals","No goals yet")}
    function managerAssistRows(rows){return managerStatTable(rows,"assists","No assists yet")}
    function managerOwnPlayerRows(rows){return managerStatTable(rows,"goals","No goals or assists yet")}
    function managerScorersHero(rows,cup=false){const leader=(rows||[])[0],title=cup?"CUP GOLDEN BOOT":"LEAGUE GOLDEN BOOT",scope=cup?"Cup goals":"League goals";if(!leader)return `<div class="manager-scorers-hero empty"><div><span>${safe(title)}</span><b>${safe(scope)}</b><small>No goals recorded yet</small></div></div>`;const team=managerStatTeam(leader),teamName=managerStatTeamName(leader),player=leader.player||"Player",goals=Number(leader.goals||0),assists=Number(leader.assists||0),pens=Number(leader.penalties||0);return `<div class="manager-scorers-hero"><div class="manager-scorers-hero-copy"><span>${safe(title)}</span><b>${safe(scope)}</b><small>${safe(managerStatContextTitle())}</small></div><div class="manager-scorers-leader"><span class="manager-scorers-number">#1</span><i>${safe(managerStatInitials(player))}</i><div><b>${safe(player)}</b><small>${teamFlag(team)} ${safe(teamName)}</small></div><strong>${safe(goals)}<span>GOALS</span></strong><em>${safe(assists)} A | ${safe(pens)} PEN</em></div></div>`}
    function managerStatSection(title,sub,html){return `<section class="manager-stat-section"><div class="manager-stat-heading"><b>${safe(title)}</b><span>${safe(sub)}</span></div>${html}</section>`}
    function managerScorersHtml(){
      const src=managerScorerSource(),divisionMode=!!managerScorersContext,cup=!divisionMode&&managerScorersScope==="cup",topCupScorers=src?.topCupScorers||[],topCupAssists=src?.topCupAssists||[],rows=cup?topCupScorers:(src?.topScorers||[]),assistRows=cup?topCupAssists:(src?.topAssists||[]),ownRows=cup?(src?.ownCupPlayerStats||[]):(src?.ownLeaguePlayerStats||[]),ownTitle=cup?"MY TEAM CUP STATS":"MY TEAM LEAGUE STATS",scope=cup?"CUP":"LEAGUE";
      const tabs=divisionMode?`<div class="manager-filter-row manager-scorers-tabs manager-scorers-tabs-single"><button class="active" type="button">${safe(src?.name||"DIVISION")}</button></div>`:`<div class="manager-filter-row manager-scorers-tabs"><button class="${!cup?"active":""}" data-scorer-scope="league" type="button">LEAGUE</button><button class="${cup?"active":""}" data-scorer-scope="cup" type="button">CUP${topCupScorers.length?` (${safe(topCupScorers.reduce((sum,row)=>sum+Number(row?.goals||0),0))})`:""}</button></div>`;
      const cupPreview=!divisionMode&&!cup&&(topCupScorers.length||topCupAssists.length)?`${managerStatSection("CUP TOP SCORERS","CUP GOALS",managerScorerRows(topCupScorers))}${managerStatSection("CUP TOP ASSISTS","CUP ASSISTS",managerAssistRows(topCupAssists))}`:"";
      const ownSection=(!divisionMode||ownRows.length)?managerStatSection(ownTitle,"GOALS + ASSISTS",managerOwnPlayerRows(ownRows)):"";
      return `<div class="manager-scorers-board">${tabs}${managerScorersHero(rows,cup)}${managerStatSection("TOP SCORERS",`${scope} GOALS`,managerScorerRows(rows))}${managerStatSection("TOP ASSISTS",`${scope} ASSISTS`,managerAssistRows(assistRows))}${cupPreview}${ownSection}</div>`
    }
    function managerAssistsHtml(){return `<div class="manager-meta">${safe(managerStatContextTitle())}</div>${managerAssistRows(managerSeason?.topAssists||[])}`}
    function managerChatImageHtml(m){const img=m?.image;if(!img?.url)return "";return `<a class="manager-chat-image" href="${safe(img.url)}" target="_blank" rel="noopener"><img src="${safe(img.url)}" alt="${safe(img.name||"Chat image")}" loading="lazy"></a>`}
    function managerChatRowHtml(m){const mine=String(m.user||"")===String(me?.name||""),text=String(m.text||"");return `<div class="manager-chat-row ${mine?"mine":""}"><div class="manager-chat-meta">${teamFlag(m.team||{})}<b>${safe(m.user||"")}</b><span>${safe(shortDate(m.sentAt))}</span></div>${text?`<div class="manager-chat-text">${safe(text)}</div>`:""}${managerChatImageHtml(m)}</div>`}
    function managerChatNearBottom(list){return !list||list.scrollTop+list.clientHeight>=list.scrollHeight-28}
    function scrollManagerChatBottom(list){if(!list)return;const run=()=>{list.dataset.autoScroll="1";list.scrollTop=list.scrollHeight;setTimeout(()=>{delete list.dataset.autoScroll},80)};requestAnimationFrame(()=>{run();requestAnimationFrame(run)});list.querySelectorAll("img").forEach(img=>{if(!img.complete)img.addEventListener("load",()=>scrollManagerChatBottom(list),{once:true})})}
    function bindManagerChatScroll(list){if(!list||list.dataset.scrollBound)return;list.dataset.scrollBound="1";list.addEventListener("scroll",()=>{if(list.dataset.autoScroll==="1")return;list.dataset.userScrolledUp=managerChatNearBottom(list)?"0":"1"},{passive:true})}
    function managerChatDisplayTarget(){return String(managerPrivateChatTarget||"").trim()}
    function managerChatTargetLabel(){const target=managerChatDisplayTarget();if(!target)return "";const u=(managerUsers||[]).find(x=>String(x?.name||"").toLowerCase()===target.toLowerCase());return String(u?.name||target)}
    function managerChatMessages(){return managerChatDisplayTarget()?managerPrivateChatMessages:(managerSeason?.chatMessages||[])}
    function managerChatEmptyText(){return managerChatDisplayTarget()?`No private messages with ${managerChatTargetLabel()} yet`:"No messages yet"}
    function managerChatTitleText(){return managerChatDisplayTarget()?`CHATROOM | ${managerChatTargetLabel().toUpperCase()}`:"CHATROOM"}
    async function refreshManagerRegisteredUsers(options={}){
      const r=await api("managerRegisteredUsers",{}, {quiet:!!options.quiet});
      if(!r.ok)return false;
      managerUsers=Array.isArray(r.managerUsers)?r.managerUsers:managerUsers;
      setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);
      return true
    }
    function renderManagerChatUsersPanel(){
      const panel=$("managerChatUsersPanel");if(!panel)return;
      const mine=String(me?.name||"").toLowerCase(),target=managerChatDisplayTarget().toLowerCase(),users=(managerUsers||[]).filter(u=>String(u?.name||"").toLowerCase()!==mine);
      const leagueActive=!managerChatDisplayTarget(),leagueAlert=hasLeagueChatAlerts();
      const league=`<button class="manager-chat-user ${leagueActive?"active":""} ${leagueAlert?"manager-deal-alert":""}" data-manager-chat-league="1" type="button"><b>LEAGUE CHAT</b><span></span></button>`;
      const rows=users.map(u=>{const name=String(u?.name||""),alert=managerPrivateChatAlertFor(name),active=target&&name.toLowerCase()===target,team=u?.team;return `<button class="manager-chat-user ${active?"active":""} ${alert?"manager-deal-alert":""}" data-manager-private-user="${safe(name)}" type="button"><span><b>${teamFlag(team||{})}${safe(name.toUpperCase())}</b><small>${safe(team?.name||"No team")}</small></span>${alert?`<span class="manager-chat-unread">${safe(alert.count||1)}</span>`:"<span></span>"}</button>`}).join("");
      panel.innerHTML=league+(rows||`<div class="manager-meta">No registered users</div>`);
    }
    function setManagerChatUsersOpen(open){const panel=$("managerChatUsersPanel");if(!panel)return;renderManagerChatUsersPanel();panel.classList.toggle("hide",!open)}
    async function toggleManagerChatUsers(){const panel=$("managerChatUsersPanel"),open=panel?.classList.contains("hide");if(open)await refreshManagerRegisteredUsers({quiet:true});setManagerChatUsersOpen(open)}
    function renderManagerChatList(options={}){
      const list=$("managerChatList");if(!list)return;bindManagerChatScroll(list);
      const title=$("managerChatPage")?.querySelector(".manager-title");if(title)title.textContent=managerChatTitleText();
      const input=$("managerChatInput");if(input)input.placeholder=managerChatDisplayTarget()?`Private message to ${managerChatTargetLabel()}`:"Message";
      if(currentManagerSection()==="managerChatPage"&&!managerChatDisplayTarget()){markManagerChatSeen();syncManagerActions()}
      const forceBottom=!!options.forceBottom,wasBottom=managerChatNearBottom(list),userScrolledUp=list.dataset.userScrolledUp==="1",msgs=managerChatMessages(),shouldBottom=forceBottom||wasBottom||!list.dataset.touched||!userScrolledUp;
      list.innerHTML=msgs.length?msgs.map(managerChatRowHtml).join(""):`<div class="manager-meta">${safe(managerChatEmptyText())}</div>`;
      list.dataset.touched="1";renderManagerChatUsersPanel();syncManagerActions();
      if(shouldBottom){list.dataset.userScrolledUp="0";scrollManagerChatBottom(list)}
    }
    function renderManagerChatPage(){managerPrivateChatTarget="";managerPrivateChatMessages=[];showManagerSection("managerChatPage");setManagerChatUsersOpen(false);markManagerChatSeen();renderManagerChatList({forceBottom:true});syncManagerActions()}
    function openManagerLeagueChat(){managerPrivateChatTarget="";managerPrivateChatMessages=[];markManagerChatSeen();setManagerChatUsersOpen(false);renderManagerChatList({forceBottom:true})}
    async function openManagerPrivateChat(target,options={}){
      target=String(target||"").trim();if(!target)return false;
      const r=await api("managerPrivateChatOpen",{target},{quiet:!!options.quiet});
      if(!r.ok){if(r.error==="bad_user"){managerPrivateChatTarget="";managerPrivateChatMessages=[];renderManagerChatList({forceBottom:true});msg("managerMsg","User not found");return false}msg("managerMsg",r.error==="self_message"?"Choose another user":"Could not open private chat");return false}
      managerPrivateChatTarget=String(r.privateChatTarget||target);managerPrivateChatMessages=Array.isArray(r.privateChatMessages)?r.privateChatMessages:[];if(Array.isArray(r.managerUsers))managerUsers=r.managerUsers;setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);if(options.keepUsersOpen)renderManagerChatUsersPanel();else setManagerChatUsersOpen(false);renderManagerChatList({forceBottom:!options.keepScroll});return true
    }
    async function sendManagerChat(){const input=$("managerChatInput"),text=String(input?.value||"").trim();if(!text)return;if(input)input.disabled=true;try{const target=managerChatDisplayTarget(),r=target?await api("managerPrivateChatPost",{target,text}):await api("managerChatPost",{text});if(!r.ok)return msg("managerMsg",r.error==="empty_message"?"Write a message first":r.error==="bad_user"?"User not found":"Could not send message");setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);if(target){managerPrivateChatTarget=String(r.privateChatTarget||target);managerPrivateChatMessages=Array.isArray(r.privateChatMessages)?r.privateChatMessages:managerPrivateChatMessages}else{managerSeason=r.managerSeason||managerSeason;if(managerSeason&&Array.isArray(r.chatMessages))managerSeason.chatMessages=r.chatMessages}if(input)input.value="";renderManagerChatList({forceBottom:true})}finally{if(input)input.disabled=false}}
    function readChatImageFile(file){return new Promise((resolve,reject)=>{const reader=new FileReader();reader.onload=()=>resolve(String(reader.result||""));reader.onerror=()=>reject(reader.error||new Error("Could not read image"));reader.readAsDataURL(file)})}
    function loadChatImage(dataUrl){return new Promise((resolve,reject)=>{const img=new Image();img.onload=()=>resolve(img);img.onerror=()=>reject(new Error("Could not load image"));img.src=dataUrl})}
    async function prepareChatImageDataUrl(file){const dataUrl=await readChatImageFile(file);if(/^image\/gif$/i.test(file.type||""))return dataUrl;try{const img=await loadChatImage(dataUrl),maxSide=1600,scale=Math.min(1,maxSide/Math.max(img.naturalWidth||1,img.naturalHeight||1));if(scale>=1&&Number(file.size||0)<1400000)return dataUrl;const c=document.createElement("canvas");c.width=Math.max(1,Math.round((img.naturalWidth||1)*scale));c.height=Math.max(1,Math.round((img.naturalHeight||1)*scale));c.getContext("2d").drawImage(img,0,0,c.width,c.height);return c.toDataURL("image/jpeg",.84)}catch(e){return dataUrl}}
    async function uploadManagerChatImage(file){if(!file)return;const size=Number(file.size||0),isGif=/^image\/gif$/i.test(file.type||"");if(!/^image\/(png|jpe?g|webp|gif)$/i.test(file.type||""))return msg("managerMsg","Choose an image file");if(size>12*1024*1024||isGif&&size>5*1024*1024)return msg("managerMsg","Image is too large. Try a smaller one.");const upload=$("managerChatUpload"),input=$("managerChatInput");if(upload)upload.disabled=true;msg("managerMsg","Uploading image...");try{const target=managerChatDisplayTarget(),dataUrl=await prepareChatImageDataUrl(file),payload={name:file.name,type:file.type,size:file.size,text:String(input?.value||"").trim(),dataUrl},r=target?await api("managerPrivateChatUpload",{...payload,target}):await api("managerChatUpload",payload);if(!r.ok)return msg("managerMsg",r.error==="image_too_large"?"Image is too large. Try a smaller one.":r.error==="bad_image_type"?"Image type not allowed":r.error==="bad_user"?"User not found":"Could not upload image");setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);if(target){managerPrivateChatTarget=String(r.privateChatTarget||target);managerPrivateChatMessages=Array.isArray(r.privateChatMessages)?r.privateChatMessages:managerPrivateChatMessages}else{managerSeason=r.managerSeason||managerSeason;if(managerSeason&&Array.isArray(r.chatMessages))managerSeason.chatMessages=r.chatMessages}if(input)input.value="";renderManagerChatList({forceBottom:true});msg("managerMsg","")}catch(e){clientDebugLog("manager_chat_upload_error",e?.message||String(e||"upload failed"),{stack:e?.stack||""},"manager",true);msg("managerMsg","Could not upload image")}finally{if(upload)upload.disabled=false;const picker=$("managerChatImageInput");if(picker)picker.value=""}}
    function reportBehavior(p){const b=String(p?.behavior||"OK");if(b==="SLACKED"&&String(p?.role||"").toUpperCase()!=="GK"&&Number(p?.distanceMeters||0)>=220)return "INEFFICIENT";return b}
    function reportBelongsToViewer(r){const user=String(me?.name||"");return !user||String(r?.home||"")===user||String(r?.away||"")===user}
    function viewerMatchReports(){return (managerSeason?.matchReports||[]).filter(reportBelongsToViewer)}
    function reportHumanPlayers(r){const user=String(me?.name||""),humans=new Set(managerSeason?.humanManagers||[]),sideUser={home:String(r?.home||""),away:String(r?.away||"")};if(user&&(sideUser.home===user||sideUser.away===user))return (r?.players||[]).filter(p=>sideUser[p.side]===user);return (r?.players||[]).filter(p=>humans.has(sideUser[p.side]))}
    function reportTop(players,key,lowest=false){const list=[...(players||[])].filter(p=>Number.isFinite(Number(p?.[key])));if(!list.length)return null;list.sort((a,b)=>lowest?Number(a[key])-Number(b[key]):Number(b[key])-Number(a[key]));return list[0]}
    function reportSlacker(players){let list=[...(players||[])].filter(p=>String(p?.role||"").toUpperCase()!=="GK"&&Number.isFinite(Number(p?.distanceMeters)));if(!list.length)list=[...(players||[])].filter(p=>Number.isFinite(Number(p?.distanceMeters)));if(!list.length)return null;list.sort((a,b)=>Number(a.distanceMeters||0)-Number(b.distanceMeters||0)||Number(a.impact||0)-Number(b.impact||0));return list[0]}
    function reportSideUser(r,side){return String(side==="away"?(r?.away||""):(r?.home||""))}
    function reportSideTeam(r,side){const reportTeam=side==="away"?(r?.awayTeam||{}):(r?.homeTeam||{});return managerCatalogTeam(reportTeam,reportSideUser(r,side))}
    function reportHumanTitle(r,kind){const humans=new Set(managerSeason?.humanManagers||[]),h=reportSideTeam(r,"home"),a=reportSideTeam(r,"away"),sc=r.score||[0,0],homeHuman=humans.has(String(r.home||"")),awayHuman=humans.has(String(r.away||""));if(homeHuman&&awayHuman)return `${safe(kind)} | ${teamFlag(h)} ${safe(h.name||r.home)} ${safe(sc[0]??0)}-${safe(sc[1]??0)} ${teamFlag(a)} ${safe(a.name||r.away)}`;if(homeHuman)return `${safe(kind)} | ${teamFlag(h)} ${safe(h.name||r.home)} vs ${teamFlag(a)} ${safe(a.name||r.away)} | result ${safe(sc[0]??0)}-${safe(sc[1]??0)}`;if(awayHuman)return `${safe(kind)} | ${teamFlag(a)} ${safe(a.name||r.away)} vs ${teamFlag(h)} ${safe(h.name||r.home)} | result ${safe(sc[1]??0)}-${safe(sc[0]??0)}`;return safe(kind)}
    function reportSideName(r,side){const team=reportSideTeam(r,side),user=reportSideUser(r,side);return team?.name||user||String(side||"team").toUpperCase()}
    function reportViewerSide(r){const user=String(me?.name||""),teamName=String(me?.team?.name||"").toLowerCase(),teamId=String(me?.team?.id||"").toLowerCase();for(const side of ["home","away"]){const sideUser=reportSideUser(r,side),team=reportSideTeam(r,side),name=String(team?.name||"").toLowerCase(),id=String(team?.id||team?.sourceId||"").toLowerCase();if(user&&sideUser===user)return side;if(teamName&&name===teamName)return side;if(teamId&&id===teamId)return side}return"home"}
    function reportScoreParts(r){const sc=Array.isArray(r?.score)?r.score:[0,0];return [Number(sc[0]||0),Number(sc[1]||0)]}
    function reportSigned(value){const n=Number(value||0),rounded=Math.round(n*10)/10;return `${rounded>0?"+":""}${Number.isInteger(rounded)?rounded:rounded.toFixed(1)}`}
    function reportMinute(g){const n=Number(g?.minute??g?.at??0)||0;return Math.max(1,Math.min(120,Math.round(n)))}
    function reportCardBadges(p){const c=p?.cards||{},yellow=Math.max(Number(c.yellow??c.yellows??0)||0,Number(p?.yellows||0)||0),red=Math.max(Number(c.red??c.reds??0)||0,Number(p?.reds||0)||0),second=!!c.secondYellow||Number(p?.secondYellowReds||0)>0,direct=!!c.directRed||Number(p?.directReds||0)>0;return `${yellow?`<span class="match-report-card-badge yellow">${yellow>1?safe(yellow):""}Y</span>`:""}${red?`<span class="match-report-card-badge red">${second?"2Y":direct?"DR":"R"}</span>`:""}`}
    function reportTeamBlock(r,side){const team=reportSideTeam(r,side),label=side==="home"?"HOME":"AWAY";return `<div class="match-report-team ${safe(side)}">${teamFlag(team)}<span><b>${safe(reportSideName(r,side))}</b><small>${label}</small></span></div>`}
    function reportWinnerLabel(r){const [home,away]=reportScoreParts(r);if(home===away)return "DRAW";return `${safe(reportSideName(r,home>away?"home":"away"))} WIN`}
    function reportHeadline(r){const [home,away]=reportScoreParts(r),homeName=reportSideName(r,"home"),awayName=reportSideName(r,"away");if(home===away)return `${safe(homeName)} and ${safe(awayName)} shared the points`;return `${safe(home>away?homeName:awayName)} beat ${safe(home>away?awayName:homeName)}`}
    function reportGoalRows(r){const goals=[...(r?.goalScorers||[])].filter(g=>["home","away"].includes(String(g?.side||""))).sort((a,b)=>reportMinute(a)-reportMinute(b)||Number(a?.seq||0)-Number(b?.seq||0));if(!goals.length)return `<div class="match-report-empty">No goals in this match</div>`;return `<div class="match-report-goal-list">${goals.map(g=>{const side=String(g.side||"home"),assist=String(g.assist||"").trim();return `<div class="match-report-goal ${safe(side)}"><span>${safe(reportMinute(g))}'</span><div><b><i></i>${safe(g.scorer||"Unknown")}${g.penalty?` <em>PEN</em>`:""}</b><small>${safe(g.team||reportSideName(r,side))}${assist?` | A: ${safe(assist)}`:""}</small></div></div>`}).join("")}</div>`}
    function reportStatValue(stats,key,side){return Number(stats?.[key]?.[side]||0)||0}
    function reportStatMetric(label,home,away,homeText=null,awayText=null,viewerSide="home"){const h=Number(home)||0,a=Number(away)||0,total=Math.max(1,Math.abs(h)+Math.abs(a)),homePct=Math.max(8,Math.min(92,Math.round(h/total*100))),awayPct=100-homePct,cls=viewerSide==="away"?" view-away":" view-home";return `<div class="match-report-stat${cls}" style="--home:${homePct}%;--away:${awayPct}%"><b>${safe(homeText??h)}</b><div><span>${safe(label)}</span><i></i></div><b>${safe(awayText??a)}</b></div>`}
    function reportStatsGrid(r){const viewerSide=reportViewerSide(r),stats=r?.teamStats||{},ph=reportStatValue(stats,"possession","home"),pa=reportStatValue(stats,"possession","away"),pt=ph+pa,homePoss=pt>0?Math.round(ph/pt*100):50,awayPoss=100-homePoss,homeCards=reportStatValue(stats,"yellows","home")+reportStatValue(stats,"reds","home"),awayCards=reportStatValue(stats,"yellows","away")+reportStatValue(stats,"reds","away");return `<div class="match-report-panel"><div class="match-report-section-title">MATCH STATS</div>${reportStatMetric("POSSESSION",homePoss,awayPoss,`${homePoss}%`,`${awayPoss}%`,viewerSide)}${reportStatMetric("SHOTS",reportStatValue(stats,"shots","home"),reportStatValue(stats,"shots","away"),null,null,viewerSide)}${reportStatMetric("TOUCHES",reportStatValue(stats,"touches","home"),reportStatValue(stats,"touches","away"),null,null,viewerSide)}${reportStatMetric("TACKLES",reportStatValue(stats,"tackles","home"),reportStatValue(stats,"tackles","away"),null,null,viewerSide)}${reportStatMetric("SAVES",reportStatValue(stats,"saves","home"),reportStatValue(stats,"saves","away"),null,null,viewerSide)}${reportStatMetric("CARDS",homeCards,awayCards,null,null,viewerSide)}</div>`}
    function reportPlayerMini(p){if(!p)return `<em>-</em>`;return `<b>${safe(p.name||"Player")}</b><small>${safe(p.role||"")} | ${safe(p.teamName||"")} | impact ${safe(reportSigned(p.impact||0))}</small>`}
    function reportSpotlight(label,p){return `<div class="match-report-spotlight"><span>${safe(label)}</span>${reportPlayerMini(p)}</div>`}
    function reportSpotlights(players){const mostBall=reportTop(players,"possessionSeconds"),star=reportTop(players,"impact"),workhorse=reportTop(players,"distanceMeters"),slacker=reportSlacker(players),moaner=reportTop(players,"complaints"),worst=players.find(p=>p.terrible)||reportTop(players,"impact",true);return `<div class="match-report-panel"><div class="match-report-section-title">SPOTLIGHT</div><div class="match-report-spotlights">${reportSpotlight("STAR PLAYER",star)}${reportSpotlight("MOST BALL",mostBall)}${reportSpotlight("WORKHORSE",workhorse)}${reportSpotlight("SLACKER",slacker)}${Number(moaner?.complaints||0)>0?reportSpotlight("MOANER",moaner):""}${worst?reportSpotlight("UNDERPERFORMER",worst):""}</div></div>`}
    function reportCardsSection(r){const rows=[...(r?.cardedPlayers||[])].filter(p=>reportCardBadges(p)).sort((a,b)=>String(a.side||"").localeCompare(String(b.side||""))||String(a.name||"").localeCompare(String(b.name||"")));return `<div class="match-report-panel match-report-cards"><div class="match-report-section-title">CARDS</div>${rows.length?rows.map(p=>`<div class="match-report-card-row"><span>${reportCardBadges(p)}</span><b>${safe(p.name||"Player")}</b><small>${safe(p.teamName||reportSideName(r,p.side))}</small></div>`).join(""):`<div class="match-report-empty">No cards</div>`}</div>`}
    function reportPlayerRow(p){const cards=reportCardBadges(p);return `<div class="match-report-player-row"><span>${safe(p.role||"-")}</span><b>${safe(p.name||"Player")}${cards?` <i>${cards}</i>`:""}</b><em>${safe(reportSigned(p.impact||0))}</em><span>${safe(p.distanceMeters||0)}m</span><span>${safe(p.touches||0)}</span><span>${safe(p.passes||0)}</span><span>${safe(p.shots||0)}</span><span>${safe(p.tackles||0)}</span><small>${safe(reportBehavior(p))}</small></div>`}
    function reportPlayerTable(players){const rows=(players||[]).slice(0,12);return `<div class="match-report-player-table"><div class="match-report-section-title">PLAYER REPORT</div><div class="match-report-player-row head"><span>POS</span><b>PLAYER</b><em>IMP</em><span>DIST</span><span>TCH</span><span>PASS</span><span>SHOT</span><span>TCK</span><small>NOTE</small></div>${rows.length?rows.map(reportPlayerRow).join(""):`<div class="match-report-empty">No human player data</div>`}</div>`}
    function managerReportCard(r){const kind=r.simulated?"SIM REPORT":"WATCH REPORT",[home,away]=reportScoreParts(r),humanPlayers=reportHumanPlayers(r),players=humanPlayers.length?humanPlayers:[...(r?.players||[])],matchType=managerMatchTypeLine({phase:r?.phase,round:r?.round,playoff:r?.playoff},r),date=shortDate(r?.playedAt),winner=reportWinnerLabel(r);return `<article class="match-report-card"><header class="match-report-hero">${reportTeamBlock(r,"home")}<div class="match-report-score"><span>${safe(kind)}</span><b>${safe(home)} - ${safe(away)}</b><em>${winner}</em></div>${reportTeamBlock(r,"away")}</header><div class="match-report-meta-row"><span>FULL TIME</span><span>${safe(matchType)}</span>${date?`<span>${safe(date)}</span>`:""}</div><div class="match-report-lede">${reportHeadline(r)} after a ${safe(home)}-${safe(away)} finish.</div><section class="match-report-section"><div class="match-report-section-title">GOALS</div>${reportGoalRows(r)}</section><section class="match-report-panels">${reportStatsGrid(r)}${reportSpotlights(players)}${reportCardsSection(r)}</section>${reportPlayerTable(players)}</article>`}
    function managerReportsHtml(){const reports=viewerMatchReports();return reports.length?reports.map(managerReportCard).join(""):`<div class="manager-meta">No watched match reports yet</div>`}
    function managerCupName(cupKey,fixture={},round={}){const cup=(managerSeason?.cups||[]).find(c=>String(c.key||"")===String(cupKey||""));return fixture.cupName||round.cupName||cup?.name||"Cup"}
    function managerCupStageText(fixture={},round={}){const stage=String(fixture.cupStage||round.cupStage||"").toLowerCase(),label=String(round.round||fixture.round||"").trim();if(stage==="group")return "GROUP STAGE";if(stage==="league")return "LEAGUE PHASE";return label||"KNOCKOUT"}
    function managerCupResultForUser(f,user){if(f.status!=="played"||!Array.isArray(f.score))return "PENDING";const home=String(f.home||"")===user,gf=Number(f.score[home?0:1]||0),ga=Number(f.score[home?1:0]||0),winner=String(f.winner||"");if(winner)return winner===user?"W":"L";return gf>ga?"W":gf<ga?"L":"D"}
    function managerCupStatusInfo(cup,stat){const ongoing=!!cup?.ongoing||String(cup?.status||"")==="ongoing";if(ongoing||stat.active)return{text:`ONGOING${stat.pendingRound?` - NEXT ${stat.pendingRound}`:""}`,cls:"ongoing"};if(stat.winner)return{text:"WINNER",cls:"winner"};if(stat.runnerUp)return{text:"RUNNER-UP",cls:"runner-up"};if(stat.knockoutExit)return{text:`OUT - ${stat.knockoutExit}`,cls:"out"};if(stat.tableExit)return{text:`OUT - ${stat.tableExit}`,cls:"out"};if(String(cup?.status||"")==="finished")return{text:`OUT - ${stat.bestRound||"CUP"}`,cls:"out"};if(stat.tableOnly)return{text:stat.tableWaiting||"GROUP TABLE",cls:"waiting"};return{text:stat.bestRound||"NO MATCHES",cls:"waiting"}}
    function managerCupStatus(cup,stat){return managerCupStatusInfo(cup,stat).text}
    function managerCupMatchRow(m){const score=m.status==="played"&&Array.isArray(m.score)?`${safe(m.score[0])}-${safe(m.score[1])}`:"v",decision=m.decision?` | ${safe(m.decision)}`:"",cls=String(m.result||"").toLowerCase();return `<div class="manager-cup-match ${safe(cls)}"><span>${safe(m.round)}</span>${seasonTeamLine(m.home,null,"season-home")}<b>${safe(score)}</b>${seasonTeamLine(m.away,null,"season-away")}<em>${safe(m.result)}${decision}</em></div>`}
    function managerCupCard(cup,stat){const team=managerSeason?.teamsByUser?.[stat.user]?.team,gd=Number(stat.gf||0)-Number(stat.ga||0),matches=stat.matches.map(managerCupMatchRow).join(""),status=managerCupStatusInfo(cup,stat);return `<div class="manager-cup-card ${safe(status.cls)}"><div class="manager-cup-head">${seasonTeamLine(stat.user,team)}<strong class="${safe(status.cls)}">${safe(status.text)}</strong></div><div class="manager-cup-metrics"><span><b>${safe(stat.played)}</b> P</span><span><b>${safe(stat.wins)}</b> W</span><span><b>${safe(stat.draws)}</b> D</span><span><b>${safe(stat.losses)}</b> L</span><span><b>${safe(stat.gf)}-${safe(stat.ga)}</b> GF-GA</span><span><b>${gd>0?"+":""}${safe(gd)}</b> GD</span></div><div class="manager-cup-matches">${matches||`<div class="manager-meta">No cup matches</div>`}</div></div>`}
    function managerCupsHtml(){const humans=(managerSeason?.humanManagers||[]).map(String),cups=new Map(),cupDefs=new Map((managerSeason?.cups||[]).map((c,i)=>[String(c.key||c.name||i),{...c,_order:i}]));function ensureCup(key,name){if(!cups.has(key)){const def=cupDefs.get(key)||{};cups.set(key,{key,name:name||def.name||"Cup",def,order:Number(def._order??cups.size),stats:new Map()})}return cups.get(key)}function ensureStat(cup,user){if(!cup.stats.has(user))cup.stats.set(user,{user,played:0,wins:0,draws:0,losses:0,gf:0,ga:0,bestRound:"",pendingRound:"",knockoutExit:"",tableExit:"",tableOnly:false,tableWaiting:"",active:false,winner:false,runnerUp:false,matches:[]});return cup.stats.get(user)}(managerSeason?.rounds||[]).forEach((round,roundIndex)=>{(round.fixtures||[]).forEach((f,fixtureIndex)=>{const phase=String(f.phase||round.phase||"league").toLowerCase();if(phase!=="cup")return;const key=String(f.cupKey||round.cupKey||"cup"),cup=ensureCup(key,managerCupName(key,f,round)),stage=String(f.cupStage||round.cupStage||"").toLowerCase(),roundText=String(round.round||f.round||cup.name).trim();humans.forEach(user=>{if(String(f.home||"")!==user&&String(f.away||"")!==user)return;const stat=ensureStat(cup,user),home=String(f.home||"")===user,score=Array.isArray(f.score)?f.score:null,gf=score?Number(score[home?0:1]||0):0,ga=score?Number(score[home?1:0]||0):0,result=managerCupResultForUser(f,user),stageText=managerCupStageText(f,round);stat.bestRound=stage==="group"||stage==="league"?stageText:roundText;if(stage==="group"||stage==="league")stat.tableOnly=true;if(f.status==="pending"||f.status==="watching"){stat.active=true;stat.pendingRound=roundText}if(f.status==="played"&&score){stat.played++;stat.gf+=gf;stat.ga+=ga;if(result==="W")stat.wins++;else if(result==="L")stat.losses++;else stat.draws++;if(stage==="knockout"&&String(f.winner||"")&&String(f.winner||"")!==user)stat.knockoutExit=roundText;stat.matches.push({round:roundText,status:f.status,home:f.home,away:f.away,score:f.score,result,decision:f.decidedBy||"",roundIndex,fixtureIndex})}})})});cups.forEach(cup=>{humans.forEach(user=>{const stat=cup.stats.get(user);if(!stat)return;const cupOngoing=!!cup.def?.ongoing||String(cup.def?.status||"")==="ongoing";if(!cupOngoing&&String(cup.def?.winner||"")===user)stat.winner=true;if(!cupOngoing&&String(cup.def?.runnerUp||"")===user)stat.runnerUp=true;if(!stat.active&&!stat.knockoutExit&&stat.tableOnly){const cupStatus=String(cup.def?.status||"");stat.tableExit=cupStatus==="knockout"||cupStatus==="finished"?stat.bestRound||"GROUP STAGE":"";stat.tableWaiting=stat.tableExit?"":stat.bestRound||"GROUP TABLE"}})});const rows=[...cups.values()].sort((a,b)=>a.order-b.order||a.name.localeCompare(b.name)).map(cup=>{const cards=humans.map(user=>cup.stats.get(user)).filter(Boolean).map(stat=>managerCupCard(cup.def,stat)).join("");return cards?`<div class="manager-cup-section"><div class="manager-info-title">${safe(cup.name)}</div>${cards}</div>`:""}).filter(Boolean);return rows.length?rows.join(""):`<div class="manager-meta">No human cup matches yet</div>`}
    function managerFixturesHtml(){return (managerSeason?.rounds||[]).length?(managerSeason.rounds||[]).map(r=>`<div class="manager-round ${r.playoff||r.phase==="cup"?"playoff":""}"><div class="manager-meta">${safe(managerRoundTitle(r))}</div>${(r.fixtures||[]).map(managerFixtureHtml).join("")}</div>`).join(""):`<div class="manager-meta">No fixtures</div>`}
    function renderManagerScorersPage(resetScope=false,source=null){if(resetScope){managerScorersScope="league";managerScorersContext=null}if(source){managerScorersScope="league";managerScorersContext=source}$("managerScorersList").innerHTML=managerScorersHtml();$("managerScorersList").querySelectorAll("[data-scorer-scope]").forEach(b=>b.onclick=()=>{managerScorersScope=b.dataset.scorerScope||"league";renderManagerScorersPage()});showManagerSection("managerScorersPage")}
    function renderManagerAssistsPage(){$("managerAssistsList").innerHTML=managerAssistsHtml();showManagerSection("managerAssistsPage")}
    function renderManagerReportsPage(){$("managerReportsList").innerHTML=managerReportsHtml();showManagerSection("managerReportsPage")}
    function renderManagerCupsPage(){$("managerCupsList").innerHTML=managerCupsHtml();showManagerSection("managerCupsPage")}
    function renderManagerFixturesPage(){const box=$("managerFixturesList");box.innerHTML=managerFixturesHtml();bindManagerLiveSimulationLinks(box);showManagerSection("managerFixturesPage")}
    function renderManagerCreate(){
      $("managerCreate")?.classList.toggle("manager-create-solo",managerCreateMode==="solo");
      if(managerCreateMode==="solo")return renderManagerSoloCreate();
      const users=normalizedManagerUsers(),ready=readyManagerUsers(),own=ready.find(u=>u.name===me?.name),count=$("managerCount"),list=$("managerUsers"),picked=$("managerPicked"),start=$("startManagerLeague");
      count.textContent="";
      count.classList.add("hide");
      picked.textContent="";
      picked.classList.add("hide");
      if(!own){list.innerHTML=`<div class="manager-meta">Choose a team first</div>`;start.disabled=true;return}
      const pendingInvite=(managerInvites||[]).find(inv=>inv.from===me?.name&&!inv.needsMe);
      if(pendingInvite){list.innerHTML=`<div class="invite-box"><b>WAITING FOR PLAYERS</b><br>${inviteStatusHtml(pendingInvite)}</div>`;start.disabled=true;start.textContent="WAITING FOR PLAYERS";return}
      start.textContent="START MANAGER MODE";
      const readyNames=new Set(ready.map(u=>u.name));
      managerPicked=Array.from(new Set(managerPicked.filter(name=>readyNames.has(name))));
      if(me?.name&&!managerPicked.includes(me.name))managerPicked.unshift(me.name);
      const set=new Set(managerPicked);
      managerPicked.forEach(managerDraftTeamFor);
      const conflicts=managerDuplicateTeamUsers(managerPicked),missing=managerPicked.some(name=>!managerDraftTeamFor(name));
      list.innerHTML=users.map(u=>{const ownUser=u.name===me?.name,selected=set.has(u.name),conflict=selected&&conflicts.has(u.name.toLowerCase()),team=selected?managerDraftTeamFor(u.name):managerDefaultTeamForUser(u.name),needsTeamChoice=selected&&(conflict||!team),rowClasses=["manager-user-row",needsTeamChoice?"with-team-choice":"",selected?"selected":"",conflict?"conflict":"",!u.ready?"off":""].filter(Boolean).join(" "),buttonClasses=["manager-user",ownUser?"manager-user-own":"",selected&&!ownUser?"manager-user-selected":"",conflict?"manager-user-conflict":"",!u.ready?"off":""].filter(Boolean).join(" "),select=needsTeamChoice?`<div class="manager-team-choice"><span>TEAM</span>${managerCreateTeamPickerHtml(u.name,team)}</div>`:"",small=!u.ready?`<small>NO TEAM - LOGIN AND CHOOSE TEAM FIRST</small>`:"";return `<div class="${rowClasses}"><button class="${buttonClasses}" data-user="${safe(u.name)}" type="button" ${!u.ready?"disabled":""}><b>${safe(u.name.toUpperCase())}</b>${small}</button>${select}</div>`}).join("");
      start.disabled=managerPicked.length<1||missing||conflicts.size>0;
      start.title=conflicts.size?"Pick different teams for every selected user":"";
    }
    async function loadManager(record=true,startFreshWhenNoContinue=false){
      const r=await api("managerSetup");if(!r.ok)return msg("managerMsg","Could not load manager mode");
      if(Array.isArray(r.teams)&&r.teams.length)teamChoices=r.teams;
      managerUsers=r.managerUsers||[];managerSeason=r.managerSeason||null;managerInvites=r.managerInvites||[];managerFinance=r.managerFinance||null;managerSquad=r.managerSquad||null;managerMarket=r.managerMarket||[];managerDivisions=r.managerDivisions||[];setManagerTurnAlerts(r.managerTurnAlerts);setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);setManagerTransferOffers(r.managerTransferOffers);
      managerLastRevision=String(r.managerRevision||"");managerLastFullRefreshAt=Date.now();
      const canContinue=!!(r.managerCanContinue??!!managerSeason);
      if(startFreshWhenNoContinue&&!canContinue)managerSeason=null;
      setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:canContinue,managerHasAnySave:r.managerHasAnySave,managerPrivateChatAlerts:r.managerPrivateChatAlerts});
      managerAbortConfirm=false;
      renderUserTop();
      syncMenuControls();
      syncManagerActions();
      rememberManagerAutoStartFromReadyVote();
      if(await maybeResumeOwnLiveSimulation())return;
      if(await maybeAutoStartReadyMatch())return;
      await maybeAutoCloseCompletedRound();
      if(await maybeAutoStartAfterContinue())return;
      renderManagerInviteUi();renderManagerSeason();msg("managerMsg","");
      if(managerSeason)showManagerSection("managerHome",record);else openManagerCreate(record);
      startManagerPoll();
    }
    async function refreshManager(){
      if(managerPollBusy||$("manager").classList.contains("hide")||document.hidden)return;
      if(managerBusy&&!clearStaleManagerBusy("manager_poll"))return;
      managerPollBusy=true;
      try{
        const section=currentManagerSection(),hadSeason=!!managerSeason,status=await api("managerStatus",{}, {quiet:true});
        if(!status.ok)return;
        if(checkLoadedVersion(status.appVersion))return;
        applyManagerStatusResponse(status);
        renderUserTop();
        syncMenuControls();
        syncManagerActions();
        renderManagerInviteUi();
        if(!managerSeason&&!status.managerHasSeason&&section==="managerCreate"){managerLastRevision=String(status.managerRevision||managerLastRevision);if(!managerTeamMenuOpen)renderManagerCreate();return}
        const statusRevision=String(status.managerRevision||""),revisionChanged=!!statusRevision&&statusRevision!==managerLastRevision,forceFull=!!managerSeason&&Date.now()-managerLastFullRefreshAt>MANAGER_FULL_REFRESH_MS;
        if(!revisionChanged&&!forceFull){if(statusRevision)managerLastRevision=statusRevision;return}
        const r=await api("managerSetup",{}, {quiet:true});
        if(!r.ok)return;
        if(checkLoadedVersion(r.appVersion))return;
        if(Array.isArray(r.teams)&&r.teams.length)teamChoices=r.teams;
        managerUsers=r.managerUsers||[];
        managerSeason=r.managerSeason||null;
        managerInvites=r.managerInvites||[];
        managerFinance=r.managerFinance||null;
        managerSquad=r.managerSquad||null;
        managerMarket=r.managerMarket||[];
        managerDivisions=r.managerDivisions||[];
        setManagerTurnAlerts(r.managerTurnAlerts);
        setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);
        setManagerTransferOffers(r.managerTransferOffers);
        managerLastRevision=String(r.managerRevision||statusRevision||managerLastRevision);managerLastFullRefreshAt=Date.now();
        setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave,managerPrivateChatAlerts:r.managerPrivateChatAlerts});
        renderUserTop();
        syncMenuControls();
        syncManagerActions();
        renderManagerInviteUi();
        syncTouchlinesPlaybackFromSeason();
        rememberManagerAutoStartFromReadyVote();
        if(await maybeResumeOwnLiveSimulation(section))return;
        if(await maybeAutoStartReadyMatch(section))return;
        await maybeAutoCloseCompletedRound(section);
        if(await maybeAutoStartAfterContinue(section))return;
        renderManagerSeason();
        if(section==="managerChatPage"){if(managerChatDisplayTarget())await openManagerPrivateChat(managerChatDisplayTarget(),{quiet:true,keepScroll:true,keepUsersOpen:true});else renderManagerChatList()}
        if(managerSeason&&(!hadSeason||section==="managerCreate"||!section)){showManagerSection("managerHome",false);replaceAppHistory()}
        else if(!managerSeason&&section==="managerCreate"&&!managerTeamMenuOpen)renderManagerCreate()
      }catch(e){
        clientDebugLog("manager_poll_error",e?.message||String(e||"poll failed"),{stack:e?.stack||""},"manager",true);
      }finally{managerPollBusy=false}
    }
    function startManagerPoll(){if(managerPoll)return;refreshManager();managerPoll=setInterval(refreshManager,MANAGER_POLL_MS)}
    function stopManagerPoll(){if(managerPoll)clearInterval(managerPoll);managerPoll=null;managerPollBusy=false}
    async function openManager(){stopPoll();stopCrowd();stopManagerPoll();setMatch(null);trainingMode=false;setRoute("manager");managerSeason=null;managerFinance=null;managerSquad=null;managerMarket=[];setManagerTransferOffers({incoming:[],outgoing:[]});managerInvites=[];renderUserTop();clearManagerView();show("manager");await loadManager()}
    async function openManagerStart(){stopPoll();stopCrowd();stopManagerPoll();setMatch(null);trainingMode=false;setRoute("manager");managerSeason=null;managerFinance=null;managerSquad=null;managerMarket=[];setManagerTransferOffers({incoming:[],outgoing:[]});managerInvites=[];renderUserTop();clearManagerView();show("manager");await loadManager(true,true)}
    async function openNewManagerGame(options={}){
      if(!me?.name)return;
      if(managerHasSeason&&!options.skipConfirm&&!await askConfirm(options.title||"NEW SOLO GAME",options.message||"Start a clean solo manager game?\nChoose your team.\nActive manager progress resets when you press START, but saved games stay untouched.",options.ok||"START","CANCEL",false))return;
      stopPoll();stopCrowd();stopManagerPoll();setMatch(null);trainingMode=false;setRoute("manager");managerSeason=null;managerFinance=null;managerSquad=null;managerMarket=[];setManagerTransferOffers({incoming:[],outgoing:[]});managerInvites=[];renderUserTop();clearManagerView();show("manager");
      const r=await api("managerNewGameSetup").catch(e=>({ok:false,error:"fetch_failed"}));
      if(!r.ok){setRoute("");goMainMenu(true);return msg("menuMsg",r.error==="not_logged_in"?"Login again":r.error==="fetch_failed"?"Could not reach server":"Could not load users")}
      teamChoices=r.teams||teamChoices;managerUsers=r.managerUsers||[];managerInvites=r.managerInvites||[];managerFinance=null;managerSquad=null;managerMarket=[];managerDivisions=[];setManagerTransferOffers({incoming:[],outgoing:[],notices:[]});setManagerStateFlags(r);
      renderUserTop();syncMenuControls();syncManagerActions();renderManagerInviteUi();managerSeason=null;openManagerCreate(false,options.mode||"users");replaceAppHistory();
    }
    async function openInviteUserFromMenu(){
      if(managerHasSeason&&!await askConfirm("INVITE USER","Invite players to a clean online manager league?\nYour current league stays active until everyone accepts. When all accept, the new league starts.","INVITE","CANCEL",false))return;
      await openNewManagerGame({skipConfirm:true,mode:"users"});
    }
    function openManagerCreate(record=true,mode="users"){
      managerCreateMode=mode;
      managerTeamMenuOpen="";
      managerDraftTeams={};
      managerPicked=me?.name&&readyManagerUsers().some(u=>u.name===me.name)?[me.name]:[];
      msg("managerMsg","");
      showManagerSection("managerCreate",record);renderManagerCreate();
    }
    function toggleManagerUser(name){managerTeamMenuOpen="";name=String(name||"").toLowerCase();if(!readyManagerUsers().some(u=>u.name===name))return;if(name===me?.name){if(!managerPicked.includes(name))managerPicked.unshift(name);renderManagerCreate();return}const i=managerPicked.indexOf(name);if(i>=0)managerPicked.splice(i,1);else managerPicked.push(name);if(me?.name&&!managerPicked.includes(me.name))managerPicked.unshift(me.name);renderManagerCreate()}
    async function startManagerLeague(){
      if(managerActionLocked("start_manager_league"))return;
      const users=managerCreateMode==="solo"?[me.name]:(managerPicked.includes(me?.name)?managerPicked:[me.name,...managerPicked]);
      const conflicts=managerDuplicateTeamUsers(users),teamsByUser=managerDraftTeamsPayload(users);
      if(conflicts.size||Object.keys(teamsByUser).length!==users.length){renderManagerCreate();return msg("managerMsg",conflicts.size?"Two selected users have the same team. Pick different teams for this league.":"Choose a team for every selected user")}
      const activeLeague=!!managerSeason;
      if(activeLeague&&users.length>1&&!await askConfirm("INVITE PLAYERS","Invite selected players to a clean online manager league?\nYour current league stays active until everyone accepts. When all accept, the new league starts.","SEND INVITE","CANCEL",false))return;
      if(activeLeague&&users.length<=1&&!await askConfirm("NEW SOLO GAME","Start a clean solo manager game?\nCurrent active manager progress resets now.","START","CANCEL",false))return;
      setManagerBusy(true);clearManagerView("");
      try{
        const r=await api("createManagerSeason",{count:users.length,users,teamsByUser,freshStart:true});
        if(!r.ok){openManagerCreate(true,managerCreateMode||"users");return msg("managerMsg",r.error==="season_started"?"League already started":r.error==="user_without_team"?"A selected user needs a team":r.error==="duplicate_human_team"?"Two selected users have the same team. Pick different teams for this league.":"Could not start league")}
        me=r.user||me;teamChoices=r.teams||teamChoices;managerSeason=r.managerSeason||null;setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave,managerPrivateChatAlerts:r.managerPrivateChatAlerts});managerInvites=r.managerInvites||managerInvites;
        await loadManager(false);
        replaceAppHistory();
        if(r.managerInvite)setTimeout(refreshManager,500);
        msg("managerMsg",r.managerInvite?"Invite sent. Waiting for players.":"League started");
      }finally{setManagerBusy(false)}
    }
    function pauseManagerSimAnimation(){if(managerSimTimer){clearInterval(managerSimTimer);managerSimTimer=null}if(touchlinesView&&!touchlinesView.finished){if(touchlinesView.raf)cancelAnimationFrame(touchlinesView.raf);touchlinesView.raf=0;touchlinesView.lastTs=0;managerSimRunning=true;stopCrowd();syncManagerMenuMusic();return true}if(touchlinesView?.finished)stopManagerSimAnimation();return false}
    function stopManagerSimAnimation(){if(managerSimTimer){clearInterval(managerSimTimer);managerSimTimer=null}stopTouchlinesView();managerSimRunning=false;managerSimWhistledGoals.clear();syncManagerMenuMusic()}
    function managerSimTeam(user){return managerCatalogTeam(managerSeason?.teamsByUser?.[user]?.team||{},user)}
    function managerSimFixture(){const n=nextManagerFixture()||nextManagerFixturePreview();return n?{...n.fixture,round:n.round,roundLabel:managerRoundTitle(n),phase:n.phase,playoff:n.playoff,roundIndex:n.roundIndex??n.fixture?.roundIndex,fixtureIndex:n.fixtureIndex??n.fixture?.fixtureIndex}:null}
    function resetManagerSimScroll(){const apply=()=>{["managerSimPage","managerSimView"].forEach(id=>{const el=$(id);if(el)el.scrollTop=0});document.querySelectorAll("#managerSimPage .manager-sim-wrap,#managerSimPage .touchlines-page,#managerSimPage .sim-summary-table").forEach(el=>{el.scrollTop=0})};apply();requestAnimationFrame(apply)}
    function stopTouchlinesView(){if(touchlinesView?.raf)cancelAnimationFrame(touchlinesView.raf);touchlinesView=null;$("managerSimPage")?.classList.remove("touchlines-live","touchlines-report-open")}
    function resumeManagerSimAnimation(record=true){const state=touchlinesView;if(!state||state.finished)return false;if(state.raf)cancelAnimationFrame(state.raf);state.raf=0;state.lastTs=0;managerSimRunning=true;showManagerSection("managerSimPage",record);$("managerSimPage")?.classList.remove("touchlines-report-open");$("managerSimPage")?.classList.add("touchlines-live");const back=$("managerSimBack");if(back){back.classList.add("hide");back.textContent="BACK TO LEAGUE"}try{if(typeof tlProDraw==="function"&&state.stats){tlProDraw(state);tlProHud(state);state.raf=requestAnimationFrame(tlProLoop)}else{touchlinesDraw(state);touchlinesHud(state);state.raf=requestAnimationFrame(touchlinesLoop)}}catch(err){if(typeof tlProRenderError==="function")tlProRenderError(err);else touchlinesRenderError(err);return true}playCrowd();syncManagerMenuMusic();return true}
    function touchlinesHash(seed){let h=2166136261,s=String(seed||"touchlines");for(let i=0;i<s.length;i++){h^=s.charCodeAt(i);h=Math.imul(h,16777619)}return h>>>0}
    function touchlinesRng(seed){let x=touchlinesHash(seed)||1;return()=>{x^=x<<13;x^=x>>>17;x^=x<<5;return((x>>>0)%100000)/100000}}
    function touchlinesTeam(fixture,side){const id=fixture?.[side]||"",team=managerSimTeam(id),strength=Number(fixture?.strength?.[side]||0);return{ id, name:team?.name||id||side.toUpperCase(), shirt:team?.shirt||(side==="home"?"#ff6d10":"#11bcc7"), trim:team?.trim||"#111", strength:strength||46, team }}
    function touchlinesGeneratedPlayer(team,role,i){const base=Math.max(30,Math.min(80,Number(team.strength||46)+((i*7)%9)-4));return{id:`${team.id||team.name}-${role}-${i}`,name:`${role} ${i+1}`,role,slotRole:role,rating:base,stats:{shooting:base,passing:base,vision:base,dribbling:base,speed:base,tackling:base,keeping:role==="GK"?base:20,composure:base,positioning:base}}}
    function touchlinesSourcePlayers(team,fixtureSide){const isMine=String(team.id||"")===String(me?.name||""),src=isMine?(managerSquad?.starters||[]):[],roles=["GK","LB","CB","CB","RB","LM","CM","CM","RM","ST","ST"];return roles.map((role,i)=>src[i]||touchlinesGeneratedPlayer(team,role,i))}
    function touchlinesSlots(side){const home=side==="home",mx=x=>home?x:1-x;return[[.09,.50,"GK"],[.23,.18,"LB"],[.24,.39,"CB"],[.24,.61,"CB"],[.23,.82,"RB"],[.45,.20,"LM"],[.43,.40,"CM"],[.43,.60,"CM"],[.45,.80,"RM"],[.68,.38,"ST"],[.68,.62,"ST"]].map(([x,y,r])=>({x:mx(x),y,role:r}))}
    function touchlinesPlayers(team,side,fixtureSide){const slots=touchlinesSlots(side),source=touchlinesSourcePlayers(team,fixtureSide);return slots.map((slot,i)=>{const p=source[i]||touchlinesGeneratedPlayer(team,slot.role,i),role=playerSlotRole(p)||slot.role,rating=playerRating(p)||Number(p.rating||team.strength||46);return{side,index:i,id:p.id||`${side}-${i}`,name:shortPlayerName(p.name||slot.role),role:role==="-"?slot.role:role,rating,baseX:slot.x,baseY:slot.y,x:slot.x,y:slot.y,tx:slot.x,ty:slot.y,speed:.18+Math.max(0,Math.min(90,rating))/360,team}})}
    function createTouchlinesEngine(fixture){const home=touchlinesTeam(fixture,"home"),away=touchlinesTeam(fixture,"away"),seed=`${fixture?.home||""}-${fixture?.away||""}-${fixture?.roundIndex||""}-${fixture?.fixtureIndex||""}`,rng=touchlinesRng(seed),state={fixture,home,away,players:[...touchlinesPlayers(home,"home","home"),...touchlinesPlayers(away,"away","away")],ball:{x:.5,y:.5,vx:0,vy:0,owner:null,ownerSince:0,mode:"free",target:null,shot:null},score:{home:0,away:0},minute:0,events:[],rng,nextDecision:0,lastTs:0,finished:false,paused:false,lastHud:-1,passPairRun:{home:null,away:null}};touchlinesKickoff(state,rng()<.5?"home":"away");return state}
    function touchlinesSidePlayers(state,side){return state.players.filter(p=>p.side===side)}
    function touchlinesOpponent(side){return side==="home"?"away":"home"}
    function touchlinesAttackDir(side){return side==="home"?1:-1}
    function touchlinesOwner(state){const o=state.ball.owner;return o?state.players.find(p=>p.side===o.side&&p.index===o.index)||null:null}
    function touchlinesSetOwner(state,p){const prev=touchlinesOwner(state);if(prev&&prev.side!==p.side&&state.passPairRun){state.passPairRun.home=null;state.passPairRun.away=null}state.ball.owner={side:p.side,index:p.index};state.ball.ownerSince=state.minute||0;state.ball.mode="carry";state.ball.target=null;state.ball.shot=null;state.ball.x=p.x;state.ball.y=p.y}
    function touchlinesKickoff(state,side){state.players.forEach(p=>{p.x=p.baseX;p.y=p.baseY;p.tx=p.baseX;p.ty=p.baseY});if(state.passPairRun){state.passPairRun.home=null;state.passPairRun.away=null}const starters=touchlinesSidePlayers(state,side).filter(p=>p.role!=="GK"),p=starters[Math.floor(state.rng()*starters.length)]||touchlinesSidePlayers(state,side)[0];state.ball.x=.5;state.ball.y=.5;touchlinesSetOwner(state,p);state.nextDecision=0}
    function touchlinesEvent(state,text,side=""){const m=Math.max(1,Math.min(90,Math.floor(state.minute)));state.events.unshift({minute:m,text,side});state.events=state.events.slice(0,8)}
    function touchlinesNearestOpponent(state,p){let best=null,bd=9;for(const o of touchlinesSidePlayers(state,touchlinesOpponent(p.side))){const d=(o.x-p.x)**2+(o.y-p.y)**2;if(d<bd){bd=d;best=o}}return{player:best,dist:Math.sqrt(bd)}}
    function touchlinesPassPairKey(a,b){const x=`${a.side}:${a.id||a.index}`,y=`${b.side}:${b.id||b.index}`;return x<y?`${x}|${y}`:`${y}|${x}`}
    function touchlinesPairPassBlocked(state,p,target){const run=state.passPairRun?.[p.side];return !!(run&&run.count>=4&&run.key===touchlinesPassPairKey(p,target))}
    function touchlinesRememberPassPair(state,p,target){if(!state.passPairRun)state.passPairRun={home:null,away:null};const key=touchlinesPassPairKey(p,target),run=state.passPairRun[p.side];state.passPairRun[p.side]={key,count:run?.key===key?run.count+1:1}}
    function touchlinesMustPass(state){const since=Number(state.ball?.ownerSince);return Number.isFinite(since)&&state.minute-since>=5}
    function touchlinesChoosePass(state,p){const dir=touchlinesAttackDir(p.side),mates=touchlinesSidePlayers(state,p.side).filter(x=>x!==p&&x.role!=="GK");let best=null,bs=-99;for(const m of mates){if(touchlinesPairPassBlocked(state,p,m))continue;const forward=(m.x-p.x)*dir,dist=Math.hypot(m.x-p.x,m.y-p.y),wide=1-Math.abs(m.y-.5);const s=forward*.9+wide*.25-dist*.38+state.rng()*.45+(m.rating||45)/250;if(s>bs){bs=s;best=m}}return best||mates.find(m=>!touchlinesPairPassBlocked(state,p,m))||mates[0]}
    function touchlinesPass(state,p,target){if(!target)return;state.ball.owner=null;state.ball.mode="pass";state.ball.target={side:target.side,index:target.index};const d=Math.max(.01,Math.hypot(target.x-p.x,target.y-p.y)),speed=.72+Math.min(.28,(p.rating||45)/260);state.ball.vx=(target.x-p.x)/d*speed;state.ball.vy=(target.y-p.y)/d*speed;touchlinesRememberPassPair(state,p,target);touchlinesEvent(state,`${p.name} pass to ${target.name}`,p.side)}
    function touchlinesShoot(state,p){const side=p.side,dir=touchlinesAttackDir(side),goalX=side==="home"?1.035:-.035,pressure=touchlinesNearestOpponent(state,p).dist,onTarget=state.rng()<clamp(.42+(p.rating||45)/170-pressure*1.7, .12, .82),goalY=onTarget?(.44+state.rng()*.12):(.30+state.rng()*.40),d=Math.max(.01,Math.hypot(goalX-p.x,goalY-p.y));state.ball.owner=null;state.ball.mode="shot";state.ball.shot={side,scorer:p.name,onTarget};state.ball.vx=(goalX-p.x)/d*(.92+(p.rating||45)/260);state.ball.vy=(goalY-p.y)/d*(.92+(p.rating||45)/260);touchlinesEvent(state,`${p.name} shoots`,side)}
    function touchlinesDecision(state,p){const dir=touchlinesAttackDir(p.side),goalDistance=p.side==="home"?1-p.x:p.x,pressure=touchlinesNearestOpponent(state,p).dist,mustRelease=touchlinesMustPass(state);if(mustRelease&&goalDistance<.30&&state.rng()<clamp(.46+(p.rating||45)/190,.32,.82))return touchlinesShoot(state,p);if(mustRelease)return touchlinesPass(state,p,touchlinesChoosePass(state,p));if(goalDistance<.24&&state.rng()<.58+((p.rating||45)-45)/110)return touchlinesShoot(state,p);if(pressure<.065&&state.rng()<.40){if(state.rng()<clamp(.42+(p.rating||45)/160,.32,.78)){p.tx=clamp(p.x+dir*(.10+state.rng()*.10),.04,.96);p.ty=clamp(p.y+(state.rng()-.5)*.20,.08,.92);touchlinesEvent(state,`${p.name} dribbles`,p.side)}else{const opp=touchlinesNearestOpponent(state,p).player;if(opp){touchlinesSetOwner(state,opp);touchlinesEvent(state,`${opp.name} wins it`,opp.side)}}return}touchlinesPass(state,p,touchlinesChoosePass(state,p))}
    function touchlinesTick(state,dt){if(state.finished)return;state.minute+=dt*90/78;if(state.minute>=90){state.minute=90;state.finished=true;state.ball.owner=null;state.ball.vx=0;state.ball.vy=0;touchlinesEvent(state,`Full time ${state.score.home}-${state.score.away}`);managerSimRunning=false;stopCrowd();syncManagerMenuMusic()}const owner=touchlinesOwner(state);for(const p of state.players){const dir=touchlinesAttackDir(p.side),hasBall=owner===p,attack=p.side===state.ball.owner?.side;if(hasBall){p.tx=clamp(p.x+dir*.08,.05,.95);p.ty=clamp(p.y+(state.rng()-.5)*.05,.08,.92)}else{const push=attack ? .08 : -.05,follow=(state.ball.y-p.baseY)*.18;p.tx=clamp(p.baseX+dir*push+(state.ball.x-.5)*.12,.04,.96);p.ty=clamp(p.baseY+follow,.07,.93)}const sp=p.speed*dt*(hasBall ? .72 : 1);const dx=p.tx-p.x,dy=p.ty-p.y,d=Math.hypot(dx,dy);if(d>0){p.x+=dx/d*Math.min(sp,d);p.y+=dy/d*Math.min(sp,d)}}if(owner){state.ball.x=owner.x;state.ball.y=owner.y;if(state.minute>=state.nextDecision||touchlinesMustPass(state)){state.nextDecision=state.minute+1.2+state.rng()*2.4;touchlinesDecision(state,owner)}}else{state.ball.x+=state.ball.vx*dt;state.ball.y+=state.ball.vy*dt;state.ball.vx*=Math.pow(.90,dt*8);state.ball.vy*=Math.pow(.90,dt*8);if(state.ball.mode==="pass"&&state.ball.target){const t=state.players.find(p=>p.side===state.ball.target.side&&p.index===state.ball.target.index);if(t&&Math.hypot(t.x-state.ball.x,t.y-state.ball.y)<.035)touchlinesSetOwner(state,t)}if(state.ball.mode==="shot"&&(state.ball.x<-0.025||state.ball.x>1.025)){const sh=state.ball.shot||{},goal=state.ball.y>.425&&state.ball.y<.575&&sh.onTarget&&state.rng()>.26;if(goal){state.score[sh.side]++;touchlinesEvent(state,`GOAL - ${sh.scorer}`,sh.side);playAudio("crowdGoalSound",.85,true);touchlinesKickoff(state,touchlinesOpponent(sh.side))}else{touchlinesEvent(state,`Saved / wide`,touchlinesOpponent(sh.side||"home"));touchlinesKickoff(state,touchlinesOpponent(sh.side||"home"))}}if(state.ball.x<-.08||state.ball.x>1.08||state.ball.y<-.08||state.ball.y>1.08)touchlinesKickoff(state,state.rng()<.5?"home":"away")}}
    function touchlinesDraw(state){
      const c=$("touchlinesCanvas");if(!c)return;
      let r=c.getBoundingClientRect();
      if((r.width<40||r.height<40)&&c.parentElement){
        c.parentElement.style.minHeight=c.parentElement.style.minHeight||"360px";
        c.parentElement.style.height=c.parentElement.style.height||"56dvh";
        r=c.getBoundingClientRect();
      }
      const d=Math.min(2,devicePixelRatio||1),w=Math.max(320,r.width|0),h=Math.max(260,r.height|0);
      if(c.width!==Math.round(w*d)||c.height!==Math.round(h*d)){c.width=Math.round(w*d);c.height=Math.round(h*d)}
      const g=c.getContext("2d");g.setTransform(d,0,0,d,0,0);g.fillStyle="#08170c";g.fillRect(0,0,w,h);
      const px=18,py=14,pw=w-36,ph=h-28;
      for(let i=0;i<10;i++){g.fillStyle=i%2?"#1f8241":"#176d35";g.fillRect(px,py+ph*i/10,pw,ph/10+1)}
      g.strokeStyle="#efffed";g.lineWidth=2;g.strokeRect(px,py,pw,ph);
      g.beginPath();g.moveTo(px+pw/2,py);g.lineTo(px+pw/2,py+ph);g.stroke();
      g.beginPath();g.arc(px+pw/2,py+ph/2,Math.min(pw,ph)*.12,0,7);g.stroke();
      g.strokeRect(px,py+ph*.33,pw*.13,ph*.34);g.strokeRect(px+pw*.87,py+ph*.33,pw*.13,ph*.34);
      const sorted=[...state.players].sort((a,b)=>a.y-b.y);
      for(const p of sorted){
        const x=px+p.x*pw,y=py+p.y*ph,s=Math.max(9,Math.min(15,w*.018));
        g.fillStyle="rgba(0,0,0,.28)";g.beginPath();g.ellipse(x,y+s*.75,s*.9,s*.32,0,0,7);g.fill();
        g.fillStyle=p.team.shirt;g.strokeStyle=p.team.trim;g.lineWidth=2;g.beginPath();g.arc(x,y,s,0,7);g.fill();g.stroke();
        g.fillStyle="#fff";g.strokeStyle="#000";g.lineWidth=3;g.font=`900 ${Math.max(9,s*.75)}px Arial`;g.textAlign="center";g.textBaseline="middle";g.strokeText(p.role,x,y);g.fillText(p.role,x,y);
        g.font=`700 ${Math.max(9,s*.62)}px Arial`;g.strokeText(p.name,x,y+s*1.75);g.fillText(p.name,x,y+s*1.75);
      }
      const bx=px+state.ball.x*pw,by=py+state.ball.y*ph,br=Math.max(5,w*.008);
      g.fillStyle="rgba(0,0,0,.35)";g.beginPath();g.ellipse(bx,by+br*.55,br*1.15,br*.42,0,0,7);g.fill();
      g.fillStyle="#fff";g.strokeStyle="#111";g.lineWidth=1.5;g.beginPath();g.arc(bx,by,br,0,7);g.fill();g.stroke();
    }
    function touchlinesHud(state){const min=Math.floor(state.minute),score=$("touchlinesScore"),clock=$("touchlinesClock"),log=$("touchlinesLog");if(score)score.textContent=`${state.score.home} - ${state.score.away}`;if(clock)clock.textContent=state.finished?"FT":`${String(min).padStart(2,"0")}'`;if(log&&state.lastHud!==state.events.length){state.lastHud=state.events.length;log.innerHTML=state.events.map(e=>`<div class="touchlines-log-row ${safe(e.side||"")}"><b>${safe(e.minute)}'</b><span>${safe(e.text)}</span></div>`).join("")||`<div class="touchlines-log-row"><b>0'</b><span>Kickoff</span></div>`}}
    function touchlinesRenderError(err){const log=$("touchlinesLog");if(log)log.innerHTML=`<div class="touchlines-log-row"><b>ERR</b><span>${safe(err?.message||String(err||"Render error"))}</span></div>`;managerSimRunning=false;stopCrowd();syncManagerMenuMusic();console.error(err)}
    function touchlinesLoop(ts){const state=touchlinesView;if(!state)return;try{if(!state.lastTs)state.lastTs=ts;const dt=Math.min(.08,(ts-state.lastTs)/1000)*managerMatchSpeedFactor();state.lastTs=ts;touchlinesTick(state,dt);touchlinesDraw(state);touchlinesHud(state);if(!state.finished)state.raf=requestAnimationFrame(touchlinesLoop)}catch(err){touchlinesRenderError(err)}}
    function renderTouchlinesView(fixture){
      const home=touchlinesTeam(fixture,"home"),away=touchlinesTeam(fixture,"away");
      $("managerSimView").innerHTML=`<div class="touchlines-page"><div class="touchlines-head"><span>${teamFlag(home.team)}<b>${safe(home.name)}</b></span><strong id="touchlinesScore">0 - 0</strong><span class="away"><b>${safe(away.name)}</b>${teamFlag(away.team)}</span><em id="touchlinesClock">00'</em></div><div class="touchlines-stage"><canvas id="touchlinesCanvas"></canvas></div><div id="touchlinesLog" class="touchlines-log"></div></div>`;
      $("managerSimBack").classList.remove("hide");$("managerSimBack").textContent="BACK TO LEAGUE";showManagerSection("managerSimPage",true);
      touchlinesView=createTouchlinesEngine(fixture);managerSimRunning=true;syncManagerMenuMusic();playCrowd();touchlinesEvent(touchlinesView,"New engine test started");
      try{touchlinesDraw(touchlinesView);touchlinesHud(touchlinesView)}catch(err){touchlinesRenderError(err);return}
      touchlinesView.raf=requestAnimationFrame(touchlinesLoop);
    }
    const TL_PRO_FORMATIONS={
      "4-4-2":[["GK",.50,.94],["LB",.18,.80],["CB",.38,.82],["CB",.62,.82],["RB",.82,.80],["LM",.16,.64],["CM",.38,.67],["CM",.62,.67],["RM",.84,.64],["ST",.38,.55],["ST",.62,.55]],
      "5-3-2":[["GK",.50,.94],["LB",.12,.79],["CB",.30,.82],["CB",.50,.84],["CB",.70,.82],["RB",.88,.79],["CM",.30,.64],["CM",.50,.66],["CM",.70,.64],["ST",.40,.52],["ST",.60,.52]],
      "4-3-3":[["GK",.50,.94],["LB",.18,.80],["CB",.38,.82],["CB",.62,.82],["RB",.82,.80],["CM",.30,.66],["CM",.50,.68],["CM",.70,.66],["LM",.25,.52],["ST",.50,.48],["RM",.75,.52]],
      "4-5-1":[["GK",.50,.94],["LB",.18,.80],["CB",.38,.82],["CB",.62,.82],["RB",.82,.80],["LM",.14,.62],["CM",.32,.66],["CM",.50,.68],["CM",.68,.66],["RM",.86,.62],["ST",.50,.50]],
      "3-5-2":[["GK",.50,.94],["CB",.30,.82],["CB",.50,.84],["CB",.70,.82],["LM",.12,.63],["CM",.32,.66],["CM",.50,.68],["CM",.68,.66],["RM",.88,.63],["ST",.40,.52],["ST",.60,.52]],
      "4-2-3-1":[["GK",.50,.94],["LB",.18,.80],["CB",.38,.82],["CB",.62,.82],["RB",.82,.80],["CM",.40,.69],["CM",.60,.69],["LM",.22,.56],["CM",.50,.57],["RM",.78,.56],["ST",.50,.47]]
    };
    const TL_PRO_FORMATION_NAMES=Object.keys(TL_PRO_FORMATIONS),TL_PRO_MATCH_SECONDS=86,TL_PRO_HALFTIME_SECONDS=2;
    function tlProHash(seed){let h=2166136261,s=String(seed||"tl-pro");for(let i=0;i<s.length;i++){h^=s.charCodeAt(i);h=Math.imul(h,16777619)}return h>>>0}
    function tlProRng(seed){let x=tlProHash(seed)||1;return()=>{x^=x<<13;x^=x>>>17;x^=x<<5;return((x>>>0)%100000)/100000}}
    function tlProDir(side,state=null){const dir=side==="home"?1:-1;return state?.sidesSwitched?-dir:dir}
    function tlProOpp(side){return side==="home"?"away":"home"}
    function tlProRoleLine(role){role=String(role||"").toUpperCase();if(role==="GK")return 0;if(["CB","LB","RB","LWB","RWB"].includes(role))return .22;if(["CM","CDM"].includes(role))return .48;if(["LM","RM","CAM"].includes(role))return .58;return .78}
    function tlProNum(v,fallback=50){v=Number(v);return Number.isFinite(v)?v:fallback}
    function tlProStat(p,k,fallback){return tlProNum(p?.stats?.[k],fallback)}
    function tlProPlayerRating(p,fallback=46){return tlProNum(playerRating(p)||p?.rating||p?.ovr,fallback)}
    function tlProSkills(p,rating=46){const s=p?.stats||{},stat=(k,f=rating)=>tlProNum(s[k],f);return{passing:stat("passing"),vision:stat("vision"),control:stat("passcontrol",rating),shooting:stat("shooting"),shot:stat("shotcontrol",rating),dribble:stat("dribbling",rating),speed:stat("speed",rating),tackle:stat("tackling",rating),keep:stat("keeping",String(p?.role||"").toUpperCase()==="GK"?rating:25),position:stat("positioning",rating),compose:stat("composure",rating),work:stat("workrate",rating),strength:stat("strength",rating),heading:stat("heading",rating)}}
    function tlProFormationFor(team,detail={}){const f=detail?.formation||detail?.squad?.formation||(String(team?.id||"")===String(me?.name||"")?managerSquad?.formation:"");if(TL_PRO_FORMATIONS[f])return f;return TL_PRO_FORMATION_NAMES[tlProHash(`${team?.id||team?.name||"cpu"}:formation`)%TL_PRO_FORMATION_NAMES.length]}
    function tlProSlotPitch(slot,side){const role=slot[0],lat=Number(slot[1]),depth=Number(slot[2]),norm=clamp((.94-depth)/(.94-.47),0,1);let x=role==="GK"?.055:clamp(.09+norm*.76,.12,.86),y=clamp(side==="home"?lat:1-lat,.06,.94);if(role==="ST")x=Math.max(x,.72);return{role,x:side==="home"?x:1-x,y}}
    function tlProGeneratedPlayer(team,role,i,rng){const base=clamp(Number(team.strength||46)+((i*13)%11)-5+Math.round((rng()-.5)*7),28,82),wide=["LM","RM","LB","RB"].includes(role);return{id:`${team.id||team.name}-${role}-${i}`,name:`${role} ${i+1}`,role,slotRole:role,rating:base,stats:{shooting:role==="ST"?base+8:base-2,shotcontrol:role==="ST"?base+6:base,passing:role==="CM"?base+8:base,vision:["CM","LM","RM"].includes(role)?base+7:base,dribbling:wide||role==="ST"?base+7:base-1,speed:wide||role==="ST"?base+8:base,tackling:["CB","LB","RB","CM"].includes(role)?base+8:base-4,keeping:role==="GK"?base+12:18,composure:base,positioning:base,workrate:base,strength:["CB","ST"].includes(role)?base+7:base,heading:["CB","ST"].includes(role)?base+7:base}}}
    function tlProTeam(fixture,side){const detail=fixture?._tlDetails?.[side]||{},id=fixture?.[side]||"",team=detail.team||managerSimTeam(id)||{},strength=Number(fixture?.strength?.[side]??detail.strength??detail.rating??0)||46;return{id,name:team?.name||id||side.toUpperCase(),shirt:team?.shirt||(side==="home"?"#ff6d10":"#11bcc7"),trim:team?.trim||"#111",strength,team,detail,formation:tlProFormationFor({id,name:team?.name},detail)}}
    function tlProSourcePlayers(team,slots,rng){const mine=String(team.id||"")===String(me?.name||""),src=(team.detail?.squad?.starters||[]).length?team.detail.squad.starters:(mine?(managerSquad?.starters||[]):[]);return slots.map((slot,i)=>src[i]||tlProGeneratedPlayer(team,slot.role,i,rng))}
    function tlProPlayers(team,side,rng){const slots=(TL_PRO_FORMATIONS[team.formation]||TL_PRO_FORMATIONS["4-4-2"]).map(s=>tlProSlotPitch(s,side)),src=tlProSourcePlayers(team,slots,rng);return slots.map((slot,i)=>{const raw=src[i]||tlProGeneratedPlayer(team,slot.role,i,rng),role=(playerSlotRole(raw)||raw.role||slot.role).toUpperCase(),rating=tlProPlayerRating(raw,team.strength),skills=tlProSkills(raw,rating);return{side,index:i,id:String(raw.id||`${side}-${i}`),name:shortPlayerName(raw.name||slot.role),role:role==="-"?slot.role:role,slotRole:slot.role,rating,skills,shirtNumber:raw.shirtNumber||raw.legacyNumber||i+1,team,baseX:slot.x,baseY:slot.y,x:slot.x,y:slot.y,vx:0,vy:0,tx:slot.x,ty:slot.y,nextThink:0,nextTackle:0,recovery:0,energy:100,decision:"shape"}})}
    function tlProOwner(state){const o=state.ball.owner;return o?state.players.find(p=>p.side===o.side&&p.index===o.index)||null:null}
    function tlProSide(state,side){return state.players.filter(p=>p.side===side)}
    function tlProKeeper(state,side){return tlProSide(state,side).find(p=>p.role==="GK")||tlProSide(state,side)[0]}
    function tlProSetOwner(state,p,kind="carry"){if(state.possession!==p.side){if(state.passPairRun){state.passPairRun.home=null;state.passPairRun.away=null}state.possession=p.side;state.possessionStarted=state.minute}state.ball.owner={side:p.side,index:p.index};state.ball.ownerSince=state.minute||0;state.ball.mode="carry";state.ball.target=null;state.ball.shot=null;state.ball.intercept=null;state.ball.x=p.x;state.ball.y=p.y;state.ball.z=0;p.nextThink=state.minute+.25;state.focus=p;clientDebugLog("tl_owner",`${p.name} owns ball`,tlProDebugSnapshot(state,{owner:p.name,side:p.side,kind}),"touchlines")}
    function tlProRecordGoalEvent(state,text,side="",minute=0){const raw=String(text||""),match=raw.match(/^GOAL(?:\s*\((PEN|PENALTY)\)|\s+PEN)?\s*-\s*(.+)$/i);if(!match)return;const penalty=!!match[1]||/\bPENALTY\b/i.test(raw),body=String(match[2]||"").replace(/\s*\((?:PEN|PENALTY)\)\s*$/i,""),parts=body.split(/\s*\|\s*A:\s*/i),scorer=String(parts[0]||"").trim()||"Unknown",assist=penalty?"":String(parts[1]||"").trim(),goals=state.goalScorers||(state.goalScorers=[]),key=`${minute}:${side}:${scorer}:${assist}:${penalty?1:0}`;if(goals.some(g=>g.key===key))return;goals.push({key,minute,side,scorer,assist,penalty,team:side==="home"?state.home.name:side==="away"?state.away.name:""});state.goalFlash={key,text:penalty?`PENALTY GOAL!! ${scorer}`:`GOAL!! ${scorer}`,side,until:performance.now()+2000}}
    function tlProEvent(state,text,side="",importance=1){const m=Math.max(1,Math.min(90,Math.floor(state.minute)));state.events.unshift({minute:m,text,side,importance});state.events=state.events.slice(0,12);tlProRecordGoalEvent(state,text,side,m);if(state.debug)state.debug.lastEventMinute=state.minute;if(importance>=2)tlProMaybeReporter(state,true);clientDebugLog("tl_event",text,tlProDebugSnapshot(state,{side,importance}),"touchlines",importance>=2)}
    function tlProOfficialScore(report){return report?{home:Number(report?.score?.[0]||0),away:Number(report?.score?.[1]||0)}:null}
    function tlProGoalSpot(stateOrSide,sideOrY=.5,y=.5){const state=typeof stateOrSide==="string"?null:stateOrSide,side=typeof stateOrSide==="string"?stateOrSide:sideOrY,yy=typeof stateOrSide==="string"?sideOrY:y;return{x:tlProDir(side,state)>0?1.018:-.018,y:clamp(Number(yy)||.5,.44,.56)}}
    function tlProStartGoalHold(state,side,opp,y=.5){const spot=tlProGoalSpot(state,side,y);state.goalHold={side,opp,x:spot.x,y:spot.y,until:performance.now()+1500,kickoffMinute:Math.min(89.75,state.minute+1.35)};state.ball={...state.ball,x:spot.x,y:spot.y,z:0,owner:null,mode:"goal",target:null,shot:null,intercept:null,vx:0,vy:0};state.lastAction={type:"goal",side,from:{x:spot.x,y:spot.y},to:{x:spot.x,y:spot.y},until:state.goalHold.until}}
    function tlProHoldGoal(state){const hold=state.goalHold;if(!hold)return false;state.ball.owner=null;state.ball.mode="goal";state.ball.x=hold.x;state.ball.y=hold.y;state.ball.z=0;if(performance.now()>=hold.until&&state.minute>=hold.kickoffMinute){state.goalHold=null;tlProKickoff(state,hold.opp);return false}return true}
    function tlProScriptedGoals(report){if(!report)return[];return managerSimTimeline(report).filter(e=>e.kind==="goal").map((e,i)=>({side:e.side==="away"?"away":"home",minute:clamp(Number(e.minute||0),1,89),player:e.player||managerSimSidePlayer(report,e.side,i),assist:e.penalty?"":(e.assist||""),penalty:!!e.penalty,done:false,armed:false,shot:false}))}
    function tlProNameKey(name){return shortPlayerName(name).toLowerCase().replace(/[^a-z0-9]/g,"")}
    function tlProNameMatches(a,b){const ak=tlProNameKey(a),bk=tlProNameKey(b);return !!ak&&!!bk&&(ak===bk||ak.includes(bk)||bk.includes(ak))}
    function tlProScriptedRoleScore(p){const role=String(p?.slotRole||p?.role||"").toUpperCase(),order={ST:7,RM:5,LM:5,CM:4,CAM:4,RB:2,LB:2,CB:1,GK:0};return (order[role]??3)+(Number(p?.rating||0)/100)}
    function tlProFindScriptedPlayer(state,side,name){const list=tlProSide(state,side),key=tlProNameKey(name);if(key){const exact=list.find(p=>tlProNameKey(p.name)===key);if(exact)return exact;const partial=list.find(p=>{const pk=tlProNameKey(p.name);return pk&&(key.includes(pk)||pk.includes(key))});if(partial)return partial}return list.filter(p=>p.role!=="GK").sort((a,b)=>tlProScriptedRoleScore(b)-tlProScriptedRoleScore(a))[0]||list[0]||null}
    function tlProPlaceScriptedPlayer(p,x,y){if(!p)return;p.x=clamp(x,.04,.96);p.y=clamp(y,.08,.92);p.tx=p.x;p.ty=p.y;p.vx=0;p.vy=0;p.recovery=0;p.nextThink=0}
    function tlProStartScriptedPass(state,from,to,e){if(!from||!to||!e)return false;const dir=tlProDir(from.side,state),targetX=clamp(to.x+dir*.035,.04,.96),targetY=clamp(to.y,.08,.92),dist=Math.hypot(targetX-from.x,targetY-from.y);state.ball={x:from.x,y:from.y,z:0,owner:null,mode:"pass",fromX:from.x,fromY:from.y,targetX,targetY,elapsed:0,duration:clamp(dist/1.08,.24,.58),target:{side:to.side,index:to.index},quality:1,kind:"through",intercept:null,scriptedGoal:e};state.stats.passes[from.side]++;state.lastPass[from.side]={name:from.name,to:to.name,minute:state.minute};state.lastAction={type:"through",side:from.side,from:{x:from.x,y:from.y},to:{x:targetX,y:targetY},until:performance.now()+900};to.tx=targetX;to.ty=targetY;tlProEvent(state,`${from.name} threads it to ${to.name}`,from.side,.9);clientDebugLog("scripted_goal_pass",`${from.name} -> ${to.name}`,tlProDebugSnapshot(state,{goal:e.player,assist:e.assist}),"touchlines",true);return true}
    function tlProStartScriptedShot(state,p,e){if(!p||!e||e.done||state.ball.mode==="shot")return false;const side=e.side==="away"?"away":"home",opp=tlProOpp(side),target=e.targetScore??state.officialScore?.[side]??state.score[side]+1;if(state.score[side]>=target){e.done=true;state.scriptedGoalActive=null;return false}const goalY=clamp(.5+(state.rng()-.5)*.10,.42,.58),from={x:p.x,y:p.y},to=tlProGoalSpot(state,side,goalY),keeper=tlProKeeper(state,opp);p.lastShotMinute=state.minute;p.nextThink=state.minute+1.4;state.ball={x:from.x,y:from.y,z:0,owner:null,mode:"shot",fromX:from.x,fromY:from.y,targetX:to.x,targetY:to.y,elapsed:0,duration:clamp(Math.hypot(to.x-from.x,to.y-from.y)/1.34,.18,.52),shot:{side,scorer:e.player||p.name,onTarget:true,goalProb:1,keeper:keeper?.name||"GK",assist:e.penalty?"":(e.assist||""),penalty:!!e.penalty,scriptedGoal:e,targetScore:target},intercept:null};state.stats.shots[side]++;state.stats.onTarget[side]++;state.lastAction={type:"shot",side,from,to,until:performance.now()+1100};e.shot=true;tlProEvent(state,e.penalty?`${p.name} takes the penalty`:`${p.name} shoots`,side);playAudio("shotSound",.65,true);clientDebugLog("scripted_goal_shot",`${p.name} shoots for scripted goal`,tlProDebugSnapshot(state,{scorer:e.player||p.name,assist:e.assist,penalty:!!e.penalty,target}),"touchlines",true);return true}
    function tlProStartScriptedGoalAttack(state,e){const side=e.side==="away"?"away":"home",target=state.officialScore?.[side]??state.score[side]+1;if(state.score[side]>=target){e.done=true;return false}if(state.scriptedGoalActive)return false;const scorer=tlProFindScriptedPlayer(state,side,e.player),assistName=e.penalty?"":(e.assist&&e.assist!==e.player?e.assist:"");let passer=assistName?tlProFindScriptedPlayer(state,side,assistName):null;if(!scorer)return false;e.player=scorer.name;if(passer&&passer!==scorer)e.assist=passer.name;else{passer=null;e.assist=""}const dir=tlProDir(side,state),baseY=clamp(.5+((scorer.baseY||.5)-.5)*.42,.34,.66),scorerX=e.penalty?(dir>0?.89:.11):(dir>0?.79:.21),passerX=clamp(scorerX-dir*.12,.08,.92);tlProPlaceScriptedPlayer(scorer,scorerX,e.penalty?.5:baseY);e.armed=true;e.targetScore=target;state.scriptedGoalActive={event:e,side,scorerIndex:scorer.index,startedMinute:state.minute,shootAfter:state.minute+(e.penalty?.9:.28)};if(e.penalty){tlProSetOwner(state,scorer,"scripted_penalty");tlProEvent(state,`${side==="home"?state.home.name:state.away.name} PENALTY`,side,2)}else if(passer&&passer!==scorer){tlProPlaceScriptedPlayer(passer,passerX,clamp(baseY+(passer.baseY<.5?-.055:.055),.26,.74));tlProSetOwner(state,passer,"scripted_assist");tlProStartScriptedPass(state,passer,scorer,e)}else{tlProSetOwner(state,scorer,"scripted_goal");scorer.nextThink=state.minute+.04}if(!e.penalty)tlProEvent(state,`${side==="home"?state.home.name:state.away.name} attack`,side,.7);clientDebugLog("scripted_goal_attack",`Building visible goal for ${e.player}`,tlProDebugSnapshot(state,{side,scorer:scorer.name,assist:passer?.name||"",penalty:!!e.penalty,minute:e.minute,target}),"touchlines",true);return true}
    function tlProMaybeFireScriptedShot(state){const active=state.scriptedGoalActive,e=active?.event;if(!active||!e||e.done||state.ball.mode==="shot")return;const scorer=tlProSide(state,active.side).find(p=>p.index===active.scorerIndex)||tlProFindScriptedPlayer(state,active.side,e.player);if(!scorer)return;const owner=tlProOwner(state),late=state.minute-active.startedMinute>3.2;if(owner!==scorer){if(late){const dir=tlProDir(active.side,state);tlProPlaceScriptedPlayer(scorer,dir>0?.82:.18,clamp(.5+((scorer.baseY||.5)-.5)*.36,.36,.64));tlProSetOwner(state,scorer,"scripted_recover")}else return}if(state.minute<(active.shootAfter||0))return;tlProStartScriptedShot(state,scorer,e)}
    function tlProRunScriptedGoals(state){const goals=state.scriptedGoals||[];if(!goals.length||state.scriptedGoalActive)return;for(const e of goals){const trigger=Math.max(1,Number(e.minute||1)-1.1);if(e.done||e.armed||state.minute<trigger)continue;if(tlProStartScriptedGoalAttack(state,e))break}}
    function tlProKickoff(state,side){if(!state.openingKickoffSide&&state.minute<1)state.openingKickoffSide=side;state.players.forEach(p=>{p.x=p.baseX;p.y=p.baseY;p.vx=0;p.vy=0;p.tx=p.baseX;p.ty=p.baseY;p.recovery=0});if(state.passPairRun){state.passPairRun.home=null;state.passPairRun.away=null}const mids=tlProSide(state,side).filter(p=>["CM","LM","RM","ST"].includes(p.slotRole)),p=mids[Math.floor(state.rng()*mids.length)]||tlProSide(state,side)[0];state.ball.x=.5;state.ball.y=.5;state.ball.z=0;tlProSetOwner(state,p);state.lastAction={type:"kickoff",side,from:{x:.5,y:.5},to:{x:.5,y:.5},until:performance.now()+900};tlProEvent(state,side==="home"?`${state.home.name} kick off`:`${state.away.name} kick off`,side)}
    function tlProCreateEngine(fixture){const home=tlProTeam(fixture,"home"),away=tlProTeam(fixture,"away"),report=fixture?._tlReport||null,seed=`${fixture?.home||""}-${fixture?.away||""}-${fixture?.roundIndex||""}-${fixture?.fixtureIndex||""}-pro`,rng=tlProRng(seed),players=[...tlProPlayers(home,"home",rng),...tlProPlayers(away,"away",rng)],firstHalfAdded=Math.floor(rng()*4),state={fixture,home,away,players,rng,minute:0,half:1,firstHalfAdded,halfTimeStarted:false,halfTime:null,sidesSwitched:false,openingKickoffSide:null,finished:false,lastTs:0,lastHudKey:"",lastReporterKey:"",events:[],reporter:[],lastReporterMinute:-99,lastReporterScore:"0-0",score:{home:0,away:0},possession:"home",possessionStarted:0,stats:{pos:{home:0,away:0},passes:{home:0,away:0},shots:{home:0,away:0},onTarget:{home:0,away:0},tackles:{home:0,away:0}},lastPass:{home:null,away:null},passPairRun:{home:null,away:null},ball:{x:.5,y:.5,z:0,owner:null,ownerSince:0,mode:"free",target:null,shot:null,intercept:null},lastAction:null,focus:null,report,scriptedGoals:tlProScriptedGoals(report),scriptedGoalActive:null,officialScore:tlProOfficialScore(report),debug:{overlaps:{},lastOwner:null,lastOwnerX:0,lastOwnerY:0,lastOwnerSince:0,lastOwnerLog:0,lastEventMinute:0,lastNoActionLog:0}};clientDebugLog("tl_start","VIEW engine started",{fixture:{home:fixture?.home,away:fixture?.away,round:fixture?.round,phase:fixture?.phase},home:{name:home.name,formation:home.formation},away:{name:away.name,formation:away.formation},officialScore:state.officialScore,firstHalfAdded,players:players.map(p=>({name:p.name,side:p.side,role:p.role,slot:p.slotRole,x:p.x,y:p.y,rating:p.rating}))},"touchlines",true);tlProKickoff(state,rng()<.5?"home":"away");tlProMaybeReporter(state,true);return state}
    function tlProDebugSnapshot(state,extra={}){const owner=tlProOwner(state),ball=state?.ball||{};return{minute:Number(state?.minute||0).toFixed(2),score:{...state?.score},ball:{x:Number(ball.x||0).toFixed(3),y:Number(ball.y||0).toFixed(3),mode:ball.mode||"",owner:owner?`${owner.side}:${owner.name}`:""},lastAction:state?.lastAction?.type||"",...extra}}
    function tlProReportForState(state=touchlinesView){return state?.report||managerSimLatestReport(state?.fixture)||null}
    function tlProShowBackButton(){$("managerSimPage")?.classList.remove("touchlines-live");const back=$("managerSimBack");if(back){back.classList.remove("hide");back.textContent="BACK TO LEAGUE"}}
    function hideLocalLiveSimulation(fixture=null){if(!fixture||!Array.isArray(managerSeason?.liveSimulations))return;const index=managerLiveSimulationIndexForFixture(fixture);if(index>=0)managerSeason.liveSimulations=managerSeason.liveSimulations.filter((_,i)=>i!==index)}
    async function closeManagerSimToLeague(){const view=touchlinesView,finished=!!view?.finished;if(finished)hideLocalLiveSimulation(view.fixture);stopManagerSimAnimation();stopCrowd();msg("managerMsg","");showManagerSection("managerHome",false);renderManagerSeason();if(finished)await completeManagerLivePlayback(view);await refreshManager();if(finished)hideLocalLiveSimulation(view.fixture);renderManagerSeason()}
    function bindTouchlinesReportBack(){const btn=$("touchlinesReportBack");if(btn)btn.onclick=closeManagerSimToLeague}
    function tlProShowPostMatchReport(state=touchlinesView){const box=$("touchlinesMatchReport");if(!box)return;const report=tlProReportForState(state),back=`<button id="touchlinesReportBack" class="touchlines-report-back" type="button">BACK TO LEAGUE</button>`;$("managerSimPage")?.classList.add("touchlines-report-open");$("managerSimBack")?.classList.add("hide");box.classList.remove("hide");box.innerHTML=report?`${back}<div class="touchlines-post-title">MATCH REPORT</div>${managerReportCard(report)}`:`${back}<div class="touchlines-post-title">MATCH REPORT</div><div class="manager-meta">Match report is loading...</div>`;bindTouchlinesReportBack();requestAnimationFrame(()=>box.scrollIntoView({block:"start",behavior:"smooth"}))}
    async function completeManagerLivePlayback(state=touchlinesView){if(!state?.fixture||state.playbackCompleteDone||state.playbackCompleteBusy||!managerMatchSpeedCanControl(state.fixture))return null;const payload=managerPlaybackFixturePayload(state.fixture);if(!payload)return null;state.playbackCompleteBusy=true;try{const r=await api("managerLivePlaybackComplete",payload,{quiet:true});if(r?.ok!==false){state.playbackCompleteDone=true;applyManagerResponseState(r);const latest=managerSimLatestReport(state.fixture);if(latest)state.report=latest;return r||null}}catch(e){clientDebugLog("manager_playback_complete_error",e?.message||String(e||"playback complete failed"),{stack:e?.stack||"",fixture:payload},"manager",true)}finally{state.playbackCompleteBusy=false}return null}
    function tlProReporterText(state){
      const h=state.home.name,a=state.away.name,hs=state.score.home,as=state.score.away,shotsH=state.stats.shots.home,shotsA=state.stats.shots.away,onH=state.stats.onTarget.home,onA=state.stats.onTarget.away,tackles=state.stats.tackles.home+state.stats.tackles.away,total=Math.max(1,state.stats.pos.home+state.stats.pos.away),hp=Math.round(state.stats.pos.home/total*100),ap=100-hp,minute=Math.floor(state.minute);
      if(state.finished){if(hs===as)return `Full time. Tight and even: ${h} and ${a} both had spells, but neither found enough separation.`;const w=hs>as?h:a,l=hs>as?a:h;return `Full time. ${w} managed the key moments better and kept ${l} chasing the match.`}
      if(minute<6)return `Opening phase. Both teams are still feeling out the tempo, but ${state.possession==="home"?h:a} have settled on the ball first.`;
      if(hs!==as){const w=hs>as?h:a,l=hs>as?a:h,lead=Math.abs(hs-as);if(lead>=2)return `${w} have control of the scoreboard now. ${l} need to take more risks soon.`;return `${w} have the lead, but this still feels open. One clean attack can change the tone quickly.`}
      if(shotsH+shotsA<=1&&minute>18)return `Still cagey. The shape is compact and neither side is getting clean looks at goal.`;
      if(tackles>minute/3&&minute>12)return `A lot of contact in midfield. The match is getting scrappy, and second balls matter right now.`;
      if(hp>=62&&shotsH>=shotsA)return `${h} are controlling possession at ${hp}%, but they still need sharper final passes.`;
      if(ap>=62&&shotsA>=shotsH)return `${a} are controlling possession at ${ap}%, but they still need sharper final passes.`;
      if(shotsH>=shotsA+3)return `${h} are producing the better chances. ${a} are surviving, but pressure is building.`;
      if(shotsA>=shotsH+3)return `${a} are producing the better chances. ${h} are surviving, but pressure is building.`;
      if(onH+onA>=4)return `Both keepers are involved now. The game has opened up and the next goal feels close.`;
      return `Balanced spell. ${h} and ${a} are trading territory without anyone fully taking command.`;
    }
    function tlProMaybeReporter(state,force=false){
      if(!state)return;
      if(!Array.isArray(state.reporter))state.reporter=[];
      const minute=Math.max(0,Math.floor(state.minute)),scoreKey=`${state.score.home}-${state.score.away}`,scoreChanged=scoreKey!==state.lastReporterScore,due=force||scoreChanged||minute-state.lastReporterMinute>=9;
      if(!due)return;
      const text=tlProReporterText(state),stamp=state.finished?"FT":Math.max(1,minute);
      if(state.reporter[0]?.text===text&&!force&&!scoreChanged)return;
      state.reporter.unshift({minute:stamp,text});
      state.reporter=state.reporter.slice(0,6);
      state.lastReporterMinute=minute;
      state.lastReporterScore=scoreKey;
    }
    function tlProRenderReporter(state){
      const el=$("touchlinesReporter");if(!el)return;
      const rows=Array.isArray(state.reporter)?state.reporter:[];
      const key=rows.map(r=>`${r.minute}:${r.text}`).join("|");
      if(key===state.lastReporterKey)return;
      state.lastReporterKey=key;
      el.innerHTML=rows.map(r=>`<div class="touchlines-reporter-row"><b>${safe(r.minute)}${r.minute==="FT"?"":"'"} </b><span>${safe(r.text)}</span></div>`).join("")||`<div class="touchlines-reporter-row"><b>1'</b><span>Reporter is watching the early shape.</span></div>`;
    }
    function tlProMatchPressureTarget(state){
      const total=Math.max(.001,state.stats.pos.home+state.stats.pos.away),posHome=state.stats.pos.home/total,ballX=clamp(Number(state.ball?.x??.5),0,1),homeDir=tlProDir("home",state);
      const shotDiff=clamp((state.stats.shots.home-state.stats.shots.away)*3.2+(state.stats.onTarget.home-state.stats.onTarget.away)*4.8,-18,18);
      const owner=tlProOwner(state),ownerBoost=owner?(owner.side==="home"?5:-5):state.possession==="home"?3:-3;
      const zone=(ballX-.5)*homeDir*42,control=(posHome-.5)*26,scoreChase=clamp((state.score.away-state.score.home)*2.5,-6,6);
      return clamp(50+zone+control+shotDiff+ownerBoost+scoreChase,5,95);
    }
    function tlProMatchPressure(state){
      const target=tlProMatchPressureTarget(state);
      state.pressureValue=Number.isFinite(state.pressureValue)?lerp(state.pressureValue,target,.10):target;
      return clamp(state.pressureValue,5,95);
    }
    function tlProPressureStyle(value){
      const p=clamp(Number(value)||50,5,95),dist=Math.abs(p-50),left=Math.min(p,50),hot=dist>=38?"#b91024":dist>=25?"#f28a18":dist>=14?"#ffdd45":"#26da48",from=p>=50?"#26da48":hot,to=p>=50?hot:"#26da48";
      return `--tl-pressure-left:${left}%;--tl-pressure-width:${dist}%;--tl-pressure-ball:${p}%;--tl-pressure-from:${from};--tl-pressure-to:${to}`;
    }
    function tlProPressureVisualValue(state,value){const p=clamp(Number(value)||50,5,95);return clamp(50+(p-50)*tlProDir("home",state),5,95)}
    function tlProPressureText(state,value){
      const p=Number(value)||50,dist=Math.abs(p-50),team=p>=50?state.home.name:state.away.name,visual=tlProPressureVisualValue(state,p),arrow=visual>=50?"->":"<-";
      if(dist<8)return "EVEN PRESSURE";
      return arrow==="->"?`${team} PRESSURE ${arrow}`:`${arrow} ${team} PRESSURE`;
    }
    function tlProPossessionPct(state){
      const home=Number(state?.stats?.pos?.home||0),away=Number(state?.stats?.pos?.away||0),total=home+away;
      if(!(total>0))return{home:50,away:50};
      const hp=Math.round(home/total*100);
      return{home:hp,away:100-hp};
    }
    function tlProHeaderTeam(team,side,teamSide="home"){const label=teamSide==="away"?"AWAY TEAM":"HOME TEAM",copy=`<div class="touchlines-head-team-copy"><b>${safe(team.name)}</b><small>${label}</small></div>`;return side==="right"?`${copy}${teamFlag(team.team)}`:`${teamFlag(team.team)}${copy}`}
    function tlProUpdateHeader(state,scoreEl=null){
      const left=$("touchlinesHeadLeft"),right=$("touchlinesHeadRight"),score=scoreEl||$("touchlinesScore"),homeLeft=tlProDir("home",state)>0;
      if(score)score.textContent=homeLeft?`${state.score.home} - ${state.score.away}`:`${state.score.away} - ${state.score.home}`;
      if(left){const side=homeLeft?"home":"away";if(left.dataset.side!==side){left.dataset.side=side;left.innerHTML=tlProHeaderTeam(homeLeft?state.home:state.away,"left",side)}}
      if(right){const side=homeLeft?"away":"home";if(right.dataset.side!==side){right.dataset.side=side;right.innerHTML=tlProHeaderTeam(homeLeft?state.away:state.home,"right",side)}}
    }
    function tlProUpdatePressure(state){
      const track=$("touchlinesPressureTrack"),bar=$("touchlinesPressureFill"),label=$("touchlinesPressureLabel"),score=$("touchlinesPressureScore"),left=$("touchlinesPressureLeft")||$("touchlinesPressureHome"),right=$("touchlinesPressureRight")||$("touchlinesPressureAway");
      if(!track&&!bar&&!label&&!score&&!left&&!right)return;
      const p=tlProMatchPressure(state),pos=tlProPossessionPct(state),visual=tlProPressureVisualValue(state,p);
      const style=tlProPressureStyle(track?p:visual);
      if(track){track.setAttribute("style",style);track.classList.toggle("finished",!!state.finished);track.classList.toggle("switched",tlProDir("home",state)<0)}
      else if(bar)bar.setAttribute("style",style);
      if(label)label.textContent=tlProPressureText(state,p);
      if(score)score.textContent=`${pos.home} - ${pos.away}`;
      const homeLeft=tlProDir("home",state)>0;
      if(left)left.textContent=(homeLeft?state.home.name:state.away.name)||"HOME";
      if(right)right.textContent=(homeLeft?state.away.name:state.home.name)||"AWAY";
    }
    function tlProNearest(players,x,y,filter=()=>true){let best=null,bd=9;for(const p of players){if(!filter(p))continue;const d=(p.x-x)**2+(p.y-y)**2;if(d<bd){bd=d;best=p}}return{player:best,dist:Math.sqrt(bd)}}
    function tlProLineDistance(p,a,b){const vx=b.x-a.x,vy=b.y-a.y,len=vx*vx+vy*vy;if(len<.0001)return{dist:Math.hypot(p.x-a.x,p.y-a.y),t:0};const t=clamp(((p.x-a.x)*vx+(p.y-a.y)*vy)/len,0,1),x=a.x+vx*t,y=a.y+vy*t;return{dist:Math.hypot(p.x-x,p.y-y),t}}
    function tlProLaneClear(state,from,to,side){let min=.18;for(const o of tlProSide(state,tlProOpp(side))){const d=tlProLineDistance(o,from,to);if(d.t>.08&&d.t<.96)min=Math.min(min,d.dist)}return clamp((min-.018)/.09,0,1)}
    function tlProReceiverSpace(state,p){const n=tlProNearest(tlProSide(state,tlProOpp(p.side)),p.x,p.y).dist;return clamp(n/.16,0,1)}
    function tlProOffsideLine(state,side){const dir=tlProDir(side,state),def=tlProSide(state,tlProOpp(side)).slice().sort((a,b)=>a.x*dir-b.x*dir);if(def.length<2)return null;const second=def[def.length-2].x;return dir>0?Math.max(.5,state.ball.x,second):Math.min(.5,state.ball.x,second)}
    function tlProIsOffside(state,p){if(p.role==="GK")return false;const line=tlProOffsideLine(state,p.side);if(line===null)return false;const dir=tlProDir(p.side,state);return (p.x-line)*dir>.018}
    function tlProPressure(state,p){const n=tlProNearest(tlProSide(state,tlProOpp(p.side)),p.x,p.y).dist;return clamp(1-n/.14,0,1)}
    function tlProXg(state,p){const goalX=tlProDir(p.side,state)>0?1.02:-.02,goalY=.5,dist=Math.hypot(goalX-p.x,(goalY-p.y)*1.15),central=clamp(1-Math.abs(p.y-.5)*2.1,0,1),near=clamp(1-dist/.54,0,1),pressure=tlProPressure(state,p),skill=(p.skills.shooting+p.skills.shot+p.skills.compose)/300;return clamp((near*.42+central*.20+skill*.14-pressure*.30-.05),.01,.48)}
    function tlProPassPlayerKey(p){return `${p.side}:${p.id||p.index}`}
    function tlProPassPairKey(a,b){const x=tlProPassPlayerKey(a),y=tlProPassPlayerKey(b);return x<y?`${x}|${y}`:`${y}|${x}`}
    function tlProPairPassBlocked(state,p,target){const run=state.passPairRun?.[p.side];return !!(run&&run.count>=4&&run.key===tlProPassPairKey(p,target))}
    function tlProRememberPassPair(state,p,target){if(!state.passPairRun)state.passPairRun={home:null,away:null};const key=tlProPassPairKey(p,target),run=state.passPairRun[p.side],count=run?.key===key?run.count+1:1;state.passPairRun[p.side]={key,count};return count}
    function tlProMustRelease(state,p){const since=Number(state.ball?.ownerSince);return !!p&&Number.isFinite(since)&&state.minute-since>=5}
    function tlProEmergencyPass(state,p){
      const dir=tlProDir(p.side,state),from={x:p.x,y:p.y},mates=tlProSide(state,p.side).filter(m=>m!==p&&!tlProPairPassBlocked(state,p,m)),hasOutfield=mates.some(m=>m.role!=="GK");
      let best=null,bs=-99;
      for(const m of mates){
        if(hasOutfield&&m.role==="GK")continue;
        const to={x:clamp(m.x+dir*.018,.025,.975),y:clamp(m.y+(state.rng()-.5)*.025,.04,.96)},dist=Math.hypot(to.x-p.x,to.y-p.y),lane=tlProLaneClear(state,from,to,p.side),space=tlProReceiverSpace(state,m),forward=clamp(((to.x-p.x)*dir+.10)/.44,0,1),score=lane*.36+space*.22+forward*.16+(m.skills.control||50)/320-dist*.10+(state.rng()-.5)*.04;
        if(score>bs){bs=score;best={player:m,tx:to.x,ty:to.y,score,lane,dist,through:false}}
      }
      return best
    }
    function tlProBestPass(state,p,through=false){
      const dir=tlProDir(p.side,state),mates=tlProSide(state,p.side).filter(m=>m!==p&&m.role!=="GK"),from={x:p.x,y:p.y};
      let best=null,bs=-99;
      for(const m of mates){
        if(tlProPairPassBlocked(state,p,m))continue;
        let tx=m.x,ty=m.y;
        if(through){tx=clamp(m.x+dir*(.08+state.rng()*.07),.04,.96);ty=clamp(m.y+(state.rng()-.5)*.07,.06,.94)}
        const to={x:tx,y:ty},dist=Math.hypot(to.x-p.x,to.y-p.y);
        if(dist<.035||dist>.62)continue;
        const progress=clamp(((to.x-p.x)*dir+.12)/.48,0,1),lane=tlProLaneClear(state,from,to,p.side),space=tlProReceiverSpace(state,m),danger=tlProXg(state,{...m,x:to.x,y:to.y}),skill=(p.skills.passing+p.skills.vision+m.skills.control)/300,offside=through?false:tlProIsOffside(state,m),score=lane*.34+progress*.22+space*.18+danger*.16+skill*.18-dist*.16+(state.rng()-.5)*.06-(offside ? .55 : 0)+(through ? .04 : 0);
        if(score>bs){bs=score;best={player:m,tx:to.x,ty:to.y,score,lane,dist,through}}
      }
      return best
    }
    function tlProKeeperPass(state,p,long=false){
      const dir=tlProDir(p.side,state),from={x:p.x,y:p.y},mates=tlProSide(state,p.side).filter(m=>m!==p&&m.role!=="GK");
      const minDist=long ? .20 : .045, maxDist=long ? .52 : .34, lead=long ? .035 : .012, spread=long ? .035 : .018, distPenalty=long ? .10 : .30;
      let best=null,bs=-99;
      for(const m of mates){
        if(tlProPairPassBlocked(state,p,m))continue;
        const role=String(m.slotRole||m.role||""),dist=Math.hypot(m.x-p.x,m.y-p.y),forward=(m.x-p.x)*dir;
        if(dist<minDist||dist>maxDist||forward<-.03)continue;
        if(!long&&role==="ST")continue;
        const to={x:clamp(m.x+dir*lead,.025,.975),y:clamp(m.y+(state.rng()-.5)*spread,.04,.96)},lane=tlProLaneClear(state,from,to,p.side),space=tlProReceiverSpace(state,m),skill=(p.skills.passing+p.skills.vision+m.skills.control)/300;
        const roleBonus=long ? (["LM","RM","CM"].includes(role) ? .18 : role==="ST" ? .08 : 0) : (["CB","LB","RB"].includes(role) ? .24 : ["CM","LM","RM"].includes(role) ? .12 : 0);
        const score=lane*.38+space*.22+skill*.18+roleBonus+clamp(forward/.32,0,1)*.10-dist*distPenalty+(state.rng()-.5)*.04;
        if(score>bs){bs=score;best={player:m,tx:to.x,ty:to.y,score,lane,dist,through:false}}
      }
      return best
    }
    function tlProPassIntercept(state,side,from,to,quality){if(state.scriptedGoalActive?.side===side)return null;let best=null,bs=0;for(const o of tlProSide(state,tlProOpp(side))){const d=tlProLineDistance(o,from,to);if(d.t<.16||d.t>.90||d.dist>.06)continue;const score=(.06-d.dist)/.06*(o.skills.tackle+o.skills.position+o.skills.speed)/300*(1.24-quality);if(score>bs){bs=score;best={side:o.side,index:o.index,at:d.t,score}}}return best&&state.rng()<clamp(bs*.94,.035,.76)?best:null}
    function tlProStartPass(state,p,opt,kind="pass"){if(!opt?.player)return;const from={x:p.x,y:p.y},quality=clamp(.42+(p.skills.passing+p.skills.vision)/260+opt.lane*.24-tlProPressure(state,p)*.18,.18,.96),miss=state.rng()>quality,to={x:clamp(opt.tx+(miss?(state.rng()-.5)*.13:0),.025,.975),y:clamp(opt.ty+(miss?(state.rng()-.5)*.13:0),.04,.96)},dist=Math.hypot(to.x-from.x,to.y-from.y);state.ball={x:from.x,y:from.y,z:0,owner:null,mode:"pass",fromX:from.x,fromY:from.y,targetX:to.x,targetY:to.y,elapsed:0,duration:clamp(dist/(.82+p.skills.passing/180),.18,.74),target:{side:opt.player.side,index:opt.player.index},quality,kind,intercept:tlProPassIntercept(state,p.side,from,to,quality)};state.stats.passes[p.side]++;const pairRun=tlProRememberPassPair(state,p,opt.player);state.lastPass[p.side]={name:p.name,to:opt.player.name,minute:state.minute};state.lastAction={type:kind,side:p.side,from,to,until:performance.now()+900};opt.player.tx=to.x;opt.player.ty=to.y;clientDebugLog("tl_pass",`${p.name} -> ${opt.player.name}`,tlProDebugSnapshot(state,{kind,from:p.name,to:opt.player.name,pairRun,quality:Number(quality).toFixed(3),miss,lane:Number(opt.lane||0).toFixed(3),dist:Number(dist).toFixed(3),intercept:state.ball.intercept}),"touchlines");if(kind==="through"||opt.score>.72)tlProEvent(state,`${p.name} ${kind==="through"?"threads it to":"finds"} ${opt.player.name}`,p.side)}
    function tlProStartShot(state,p){const xg=tlProXg(state,p),goalX=tlProDir(p.side,state)>0?1.045:-.045,goalY=clamp(.5+(state.rng()-.5)*(.42-xg*.22),.30,.70),from={x:p.x,y:p.y},to={x:goalX,y:goalY},keeper=tlProKeeper(state,tlProOpp(p.side)),onTarget=state.rng()<clamp(.24+xg*.44+(p.skills.shooting+p.skills.shot)/520-tlProPressure(state,p)*.24,.08,.68),goalProb=onTarget?clamp(xg*.52+(p.skills.shooting+p.skills.compose)/720-(keeper?.skills.keep||45)/520,.025,.42):0;p.lastShotMinute=state.minute;p.nextThink=state.minute+1.2;state.ball={x:from.x,y:from.y,z:0,owner:null,mode:"shot",fromX:from.x,fromY:from.y,targetX:to.x,targetY:to.y,elapsed:0,duration:clamp(Math.hypot(to.x-from.x,to.y-from.y)/1.28,.18,.55),shot:{side:p.side,scorer:p.name,onTarget,goalProb,keeper:keeper?.name||"GK",assist:state.lastPass[p.side]?.name&&state.lastPass[p.side].to===p.name?state.lastPass[p.side].name:""},intercept:null};state.stats.shots[p.side]++;if(onTarget)state.stats.onTarget[p.side]++;state.lastAction={type:"shot",side:p.side,from,to,until:performance.now()+1100};clientDebugLog("tl_shot",`${p.name} shoots`,tlProDebugSnapshot(state,{scorer:p.name,xg:Number(xg).toFixed(3),onTarget,goalProb:Number(goalProb).toFixed(3),from,to}),"touchlines");tlProEvent(state,`${p.name} shoots`,p.side);playAudio("shotSound",.65,true)}
    function tlProCarry(state,p){const dir=tlProDir(p.side,state),pressure=tlProPressure(state,p),wide=(p.baseY-.5)*.06;p.tx=clamp(p.x+dir*(.045+state.rng()*.055-pressure*.035),.04,.96);p.ty=clamp(p.y+(state.rng()-.5)*.12+wide,.06,.94);p.decision=pressure>.45?"dribble":"carry";if(pressure>.58&&state.rng()<.28)tlProEvent(state,`${p.name} drives past pressure`,p.side,.5)}
    function tlProKeeperDecide(state,p){const pressure=tlProPressure(state,p),mustRelease=tlProMustRelease(state,p),short=tlProKeeperPass(state,p,false),clear=tlProKeeperPass(state,p,true);if(mustRelease){const forced=short||clear||tlProEmergencyPass(state,p);if(forced){tlProStartPass(state,p,forced,forced===clear?"clear":"pass");return}p.nextThink=state.minute+.25;return}if(short&&(pressure<.62||short.score>.58)){tlProStartPass(state,p,short,"pass");return}if(clear){tlProStartPass(state,p,clear,"clear");tlProEvent(state,`${p.name} clears to ${clear.player.name}`,p.side,.6);return}if(short){tlProStartPass(state,p,short,"pass");return}p.nextThink=state.minute+.45}
    function tlProDecide(state,p){const scripted=state.scriptedGoalActive;if(scripted?.side===p.side&&scripted.scorerIndex===p.index)return tlProStartScriptedShot(state,p,scripted.event);if(p.role==="GK")return tlProKeeperDecide(state,p);const pressure=tlProPressure(state,p),xg=tlProXg(state,p),shotReady=state.minute>=(p.lastShotMinute||-99)+1.8,mustRelease=tlProMustRelease(state,p);if(mustRelease){if(shotReady&&(xg>.22||((p.role==="ST"||xg>.16)&&state.rng()<.55+xg*.45)))return tlProStartShot(state,p);const forced=tlProBestPass(state,p,false)||tlProBestPass(state,p,true)||tlProEmergencyPass(state,p);if(forced)return tlProStartPass(state,p,forced,forced.through?"through":"pass");if(shotReady)return tlProStartShot(state,p)}if(shotReady&&(xg>.42||((p.role==="ST"||xg>.24)&&state.rng()<xg*.52)))return tlProStartShot(state,p);const through=tlProBestPass(state,p,true);if(through&&through.score>.72&&state.rng()<.42+through.score*.18)return tlProStartPass(state,p,through,"through");const pass=tlProBestPass(state,p,false);if(pass&&pass.score>.48&&(pressure>.34||state.rng()<.72))return tlProStartPass(state,p,pass,"pass");tlProCarry(state,p)}
    function tlProTryTackle(state,owner){if(state.scriptedGoalActive?.side===owner.side)return;const range=.041,n=tlProNearest(tlProSide(state,tlProOpp(owner.side)),owner.x,owner.y,p=>p.role!=="GK"),o=n.player;if(!o||n.dist>range||state.minute<o.nextTackle)return;o.nextTackle=state.minute+.9+state.rng()*1.2;const win=clamp(.34+(o.skills.tackle+o.skills.strength-owner.skills.dribble-owner.skills.compose)/240+(1-n.dist/range)*.26,.14,.78),foul=clamp(.035+(owner.skills.dribble-o.skills.tackle)/520,.02,.12);if(state.rng()<win){state.stats.tackles[o.side]++;tlProSetOwner(state,o);owner.recovery=.28;tlProEvent(state,`${o.name} wins the tackle`,o.side);return}if(state.rng()<foul){o.recovery=.45;tlProEvent(state,`${o.name} fouls ${owner.name}`,owner.side);owner.nextThink=state.minute+.18;return}o.recovery=.26;owner.tx=clamp(owner.x+tlProDir(owner.side,state)*.032,.04,.96)}
    function tlProTargetPlayers(state){
      const owner=tlProOwner(state),ball=state.ball;
      for(const p of state.players){
        const dir=tlProDir(p.side,state),attacking=(owner?owner.side:state.possession)===p.side,line=tlProRoleLine(p.slotRole||p.role);
        let tx=p.baseX,ty=p.baseY,sprint=false;
        if(p.role==="GK"){
          tx=dir>0?.045:.955;ty=clamp(.5+(ball.y-.5)*.40,.34,.66);
        }else if(ball.mode==="free"||ball.mode==="loose"){
          const n=tlProNearest(state.players,ball.x,ball.y,x=>x.role!=="GK");
          if(n.player===p){tx=ball.x;ty=ball.y;sprint=true}
          else{tx=p.baseX+(ball.x-p.baseX)*.16;ty=p.baseY+(ball.y-p.baseY)*.18}
        }else if(attacking){
          const advance=clamp((ball.x-.5)*dir,-.20,.26);
          tx=clamp(p.baseX+dir*(.035+advance*.32+line*.045),.04,.96);
          ty=clamp(p.baseY+(ball.y-p.baseY)*.11,.06,.94);
          if(owner&&owner!==p){
            if((p.x-owner.x)*dir<.03&&p.role!=="CB")tx=clamp(tx+dir*.055,.04,.96);
            if(["LM","RM","LB","RB"].includes(p.slotRole)){
              const lane=p.baseY<.5?-1:1;
              ty=clamp(p.baseY+lane*.025+(ball.y-p.baseY)*.06,.06,.94);
            }
          }
        }else{
          const compact=p.role==="ST"?.12:["LM","RM","CM"].includes(p.slotRole)?.28:.20,depth=p.role==="ST"?.00:["CM","LM","RM"].includes(p.slotRole)?.055:.09;
          tx=clamp(p.baseX-dir*depth+(ball.x-p.baseX)*.26,.04,.96);
          ty=clamp(p.baseY+(ball.y-p.baseY)*compact,.07,.93);
          if(owner&&Math.hypot(p.x-owner.x,p.y-owner.y)<.18&&["CM","LM","RM","ST"].includes(p.slotRole)){
            const sideOffset=(p.baseY<owner.y?-1:1)*.026+((p.index%3)-1)*.012;
            tx=clamp(owner.x-dir*(.034+line*.014),.04,.96);
            ty=clamp(owner.y+sideOffset,.07,.93);
            sprint=true;
          }
        }
        if(owner===p){
          tx=clamp(p.x+dir*(.05+Math.max(0,1-tlProPressure(state,p))*.08),.04,.96);
          ty=clamp(p.y+(state.rng()-.5)*.035,.05,.95);
        }
        p.tx=tx;p.ty=ty;p.sprint=sprint;
      }
    }
    function tlProMovePlayers(state,dt){for(const p of state.players){if(p.recovery>0){p.recovery=Math.max(0,p.recovery-dt);continue}const dx=p.tx-p.x,dy=p.ty-p.y,d=Math.hypot(dx,dy),max=(.105+p.skills.speed/420)*(p.sprint?1.48:1)*(p.energy/160+.46)*dt;if(d>.0001){const step=Math.min(max,d),nx=dx/d*step,ny=dy/d*step;p.x+=nx;p.y+=ny;p.vx=nx/Math.max(dt,.001);p.vy=ny/Math.max(dt,.001);p.energy=clamp(p.energy-(p.sprint ? .045 : .018)*dt*60,48,100)}else{p.vx*=.8;p.vy*=.8;p.energy=clamp(p.energy+.012*dt*60,48,100)}}}
    function tlProCompletePass(state){const b=state.ball,target=state.players.find(p=>p.side===b.target?.side&&p.index===b.target?.index);if(target&&Math.hypot(target.x-b.x,target.y-b.y)<(b.kind==="through" ? .085 : .065)){tlProSetOwner(state,target);return}state.ball.mode="loose";state.ball.owner=null;state.ball.vx=0;state.ball.vy=0;tlProEvent(state,"Loose ball","",.4)}
    function tlProCompleteShot(state){const sh=state.ball.shot||{},side=sh.side||"home",opp=tlProOpp(side),scripted=sh.scriptedGoal||null,target=sh.targetScore??scripted?.targetScore??state.officialScore?.[side]??99,goal=scripted?(sh.onTarget&&state.score[side]<target):(!state.report&&sh.onTarget&&state.rng()<sh.goalProb);if(goal){state.score[side]++;if(scripted){scripted.done=true;state.scriptedGoalActive=null}const penalty=!!(sh.penalty||scripted?.penalty),assist=!penalty&&sh.assist&&sh.assist!==sh.scorer?` | A: ${sh.assist}`:"";tlProEvent(state,`GOAL${penalty?" (PEN)":""} - ${sh.scorer}${assist}`,side,2);playAudio("crowdGoalSound",.85,true);whistleSound();state.lastPass.home=null;state.lastPass.away=null;tlProStartGoalHold(state,side,opp,state.ball.y);return}if(scripted){scripted.done=true;state.scriptedGoalActive=null;tlProKickoff(state,opp);return}if(sh.onTarget){const gk=tlProKeeper(state,opp);if(gk){gk.x=state.ball.x;gk.y=clamp(state.ball.y,.36,.64);tlProSetOwner(state,gk);tlProEvent(state,`${sh.keeper} saves`,opp)}}else{const gk=tlProKeeper(state,opp);if(gk)tlProSetOwner(state,gk);tlProEvent(state,"Shot wide",opp,.6)}}
    function tlProUpdateBall(state,dt){const owner=tlProOwner(state);if(owner){state.ball.x=clamp(owner.x+tlProDir(owner.side,state)*.012,.01,.99);state.ball.y=owner.y;state.ball.z=0;return}const b=state.ball;if(b.mode==="pass"||b.mode==="shot"){b.elapsed+=dt;const t=clamp(b.elapsed/Math.max(.05,b.duration||.4),0,1),ease=t*t*(3-2*t);b.x=lerp(b.fromX,b.targetX,ease);b.y=lerp(b.fromY,b.targetY,ease);b.z=Math.sin(Math.PI*t)*(b.mode==="shot"?.085:.045);if(b.mode==="pass"&&b.intercept&&t>=b.intercept.at){const p=state.players.find(x=>x.side===b.intercept.side&&x.index===b.intercept.index);if(p){p.x=b.x;p.y=b.y;tlProSetOwner(state,p);tlProEvent(state,`${p.name} reads the pass`,p.side);return}}if(t>=1){if(b.mode==="shot")tlProCompleteShot(state);else tlProCompletePass(state)}return}if(b.mode==="loose"||b.mode==="free"){const n=tlProNearest(state.players,b.x,b.y,p=>p.role!=="GK"||Math.abs(p.x-b.x)<.18);if(n.player&&n.dist<.032){tlProSetOwner(state,n.player);tlProEvent(state,`${n.player.name} collects`,n.player.side,.4)}}}
    function tlProSeparatePlayers(a,b,minGap=.026){
      let dx=a.x-b.x,dy=a.y-b.y,d=Math.hypot(dx,dy),current=d;
      if(d<.001){const angle=((a.index+1)*1.79+(b.index+1)*.73+(a.side===b.side?.4:1.1))%(Math.PI*2);dx=Math.cos(angle);dy=Math.sin(angle);d=1;current=0}
      const overlap=Math.max(0,minGap-current);
      if(overlap<=0)return false;
      const nx=dx/d,ny=dy/d,push=overlap/2+.004;
      a.x=clamp(a.x+nx*push,.025,.975);a.y=clamp(a.y+ny*push,.04,.96);
      b.x=clamp(b.x-nx*push,.025,.975);b.y=clamp(b.y-ny*push,.04,.96);
      a.tx=clamp((a.tx??a.x)+nx*push*.8,.025,.975);a.ty=clamp((a.ty??a.y)+ny*push*.8,.04,.96);
      b.tx=clamp((b.tx??b.x)-nx*push*.8,.025,.975);b.ty=clamp((b.ty??b.y)-ny*push*.8,.04,.96);
      a.vx=(a.vx||0)*.35;a.vy=(a.vy||0)*.35;b.vx=(b.vx||0)*.35;b.vy=(b.vy||0)*.35;
      return true;
    }
    function tlProResolveContacts(state){
      const dbg=state.debug;if(dbg&&!dbg.contacts)dbg.contacts={};
      const owner=tlProOwner(state),active=new Set();
      for(let pass=0;pass<2;pass++){
        for(let i=0;i<state.players.length;i++){
          for(let j=i+1;j<state.players.length;j++){
            const a=state.players[i],b=state.players[j];
            if(a.role==="GK"&&b.role==="GK")continue;
            const sameSide=a.side===b.side,ownerPair=owner===a||owner===b,minGap=sameSide?.030:ownerPair?.027:.024;
            if(Math.hypot(a.x-b.x,a.y-b.y)>=minGap)continue;
            const key=[a.side,a.id,b.side,b.id].sort().join("|");
            active.add(key);
            if(tlProSeparatePlayers(a,b,minGap)&&dbg){
              const rec=dbg.contacts[key]||{since:state.minute,lastLog:-99};
              if(!dbg.contacts[key])dbg.contacts[key]=rec;
              if(state.minute-rec.since>.55&&state.minute-rec.lastLog>2){
                rec.lastLog=state.minute;
                clientDebugLog("repeated_contact",`${a.name} and ${b.name} kept colliding`,tlProDebugSnapshot(state,{players:[{name:a.name,side:a.side,role:a.role,x:a.x,y:a.y},{name:b.name,side:b.side,role:b.role,x:b.x,y:b.y}]}),"touchlines",true);
              }
            }
          }
        }
      }
      if(dbg?.contacts)Object.keys(dbg.contacts).forEach(k=>{if(!active.has(k))delete dbg.contacts[k]});
    }
    function tlProDebugTick(state){
      const dbg=state.debug;if(!dbg)return;
      const activeKeys=new Set();
      for(let i=0;i<state.players.length;i++){
        for(let j=i+1;j<state.players.length;j++){
          const a=state.players[i],b=state.players[j];
          if(a.role==="GK"&&b.role==="GK")continue;
          const dist=Math.hypot(a.x-b.x,a.y-b.y);
          if(dist>.012)continue;
          const key=[a.side,a.id,b.side,b.id].sort().join("|");
          activeKeys.add(key);
          const rec=dbg.overlaps[key]||{since:state.minute,lastLog:-99};
          if(!dbg.overlaps[key])dbg.overlaps[key]=rec;
          if(state.minute-rec.since>1.2&&state.minute-rec.lastLog>2.5){
            rec.lastLog=state.minute;
            clientDebugLog("stuck_overlap",`${a.name} stuck on ${b.name}`,tlProDebugSnapshot(state,{players:[{name:a.name,side:a.side,role:a.role,x:a.x,y:a.y,tx:a.tx,ty:a.ty},{name:b.name,side:b.side,role:b.role,x:b.x,y:b.y,tx:b.tx,ty:b.ty}],dist:Number(dist).toFixed(4)}),"touchlines",true);
            tlProSeparatePlayers(a,b);
          }
        }
      }
      Object.keys(dbg.overlaps).forEach(k=>{if(!activeKeys.has(k))delete dbg.overlaps[k]});
      const owner=tlProOwner(state),ownerKey=owner?`${owner.side}:${owner.id}`:"";
      if(ownerKey){
        if(dbg.lastOwner!==ownerKey){dbg.lastOwner=ownerKey;dbg.lastOwnerX=owner.x;dbg.lastOwnerY=owner.y;dbg.lastOwnerSince=state.minute;dbg.lastOwnerLog=-99}
        const moved=Math.hypot(owner.x-dbg.lastOwnerX,owner.y-dbg.lastOwnerY);
        if(moved>.012){dbg.lastOwnerX=owner.x;dbg.lastOwnerY=owner.y;dbg.lastOwnerSince=state.minute}
        else if(state.minute-dbg.lastOwnerSince>3.2&&state.minute-dbg.lastOwnerLog>4){
          dbg.lastOwnerLog=state.minute;
          owner.nextThink=state.minute;
          clientDebugLog("stalled_owner",`${owner.name} held ball without moving`,tlProDebugSnapshot(state,{owner:{name:owner.name,side:owner.side,role:owner.role,x:owner.x,y:owner.y,tx:owner.tx,ty:owner.ty},stalledFor:Number(state.minute-dbg.lastOwnerSince).toFixed(2)}),"touchlines",true);
        }
      }else dbg.lastOwner="";
      if(state.minute-dbg.lastEventMinute>6&&state.minute-dbg.lastNoActionLog>6){
        dbg.lastNoActionLog=state.minute;
        clientDebugLog("stalled_activity","Match time running with no events",tlProDebugSnapshot(state,{noEventFor:Number(state.minute-dbg.lastEventMinute).toFixed(2)}),"touchlines",true);
      }
    }
    function tlProHalfTimeMinute(state){return 45+Math.max(0,Number(state.firstHalfAdded||0))}
    function tlProHalfTimeLabel(state){const added=Math.max(0,Number(state.firstHalfAdded||0));return added>0?`45+${added}`:"45"}
    function tlProStartHalfTime(state){const label=tlProHalfTimeLabel(state);state.halfTimeStarted=true;state.halfTime={active:true,duration:TL_PRO_HALFTIME_SECONDS,remaining:TL_PRO_HALFTIME_SECONDS,label};state.ball={x:.5,y:.5,z:0,owner:null,ownerSince:state.minute,mode:"halftime",target:null,shot:null,intercept:null,vx:0,vy:0};state.goalHold=null;if(state.scriptedGoalActive?.event&&!state.scriptedGoalActive.event.done){state.scriptedGoalActive.event.armed=false;state.scriptedGoalActive.event.shot=false}state.scriptedGoalActive=null;state.lastPass={home:null,away:null};state.passPairRun={home:null,away:null};state.players.forEach(p=>{p.switchFromX=p.x;p.switchFromY=p.y;p.switchToX=clamp(1-Number(p.baseX||p.x),.04,.96);p.switchToY=clamp(Number(p.baseY||p.y),.06,.94);p.vx=0;p.vy=0;p.recovery=0;p.nextThink=state.minute+.5});state.goalFlash={key:`half:${label}`,text:"HALF TIME",side:"",until:performance.now()+TL_PRO_HALFTIME_SECONDS*1000};tlProEvent(state,`HALF TIME ${label}'`,"",2);whistleSound();clientDebugLog("tl_halftime_start",`Half time at ${label}`,tlProDebugSnapshot(state,{firstHalfAdded:state.firstHalfAdded}),"touchlines",true)}
    function tlProRunHalfTime(state,dt){const half=state.halfTime;if(!half?.active)return false;half.remaining=Math.max(0,Number(half.remaining||0)-dt);const t=clamp(1-half.remaining/Math.max(.001,Number(half.duration||TL_PRO_HALFTIME_SECONDS)),0,1),ease=t*t*(3-2*t);state.ball={...state.ball,x:.5,y:.5,z:0,owner:null,mode:"halftime",vx:0,vy:0};state.players.forEach(p=>{const sx=Number(p.switchFromX??p.x),sy=Number(p.switchFromY??p.y),tx=Number(p.switchToX??(1-(p.baseX||p.x))),ty=Number(p.switchToY??p.baseY??p.y);p.x=lerp(sx,tx,ease);p.y=lerp(sy,ty,ease);p.tx=p.x;p.ty=p.y;p.vx=0;p.vy=0});if(half.remaining>0)return true;state.halfTime=null;state.half=2;state.sidesSwitched=true;state.minute=45;state.players.forEach(p=>{p.baseX=clamp(1-Number(p.baseX||p.x),.04,.96);p.x=p.baseX;p.y=clamp(Number(p.baseY||p.y),.06,.94);p.tx=p.x;p.ty=p.y;p.vx=0;p.vy=0;p.recovery=0;delete p.switchFromX;delete p.switchFromY;delete p.switchToX;delete p.switchToY});tlProKickoff(state,tlProOpp(state.openingKickoffSide||"home"));clientDebugLog("tl_halftime_end","Second half started",tlProDebugSnapshot(state,{kickoff:tlProOpp(state.openingKickoffSide||"home")}),"touchlines",true);return true}
    function tlProClockText(state){if(state.finished)return"FT";if(state.halfTime?.active)return`HT ${state.halfTime.label||tlProHalfTimeLabel(state)}'`;const added=Math.max(0,Number(state.firstHalfAdded||0));if(!state.halfTimeStarted&&added>0&&state.minute>=45){const extra=clamp(Math.floor(state.minute-45)+1,1,added);return`45+${extra}'`}return`${String(Math.floor(state.minute)).padStart(2,"0")}'`}
    function tlProTick(state,dt){if(state.finished)return;if(tlProRunHalfTime(state,dt))return;const minuteStep=dt*90/TL_PRO_MATCH_SECONDS,halfAt=tlProHalfTimeMinute(state);if(!state.halfTimeStarted&&state.minute<halfAt&&state.minute+minuteStep>=halfAt){const ratio=clamp((halfAt-state.minute)/Math.max(.001,minuteStep),0,1);state.stats.pos[state.possession]+=dt*ratio;state.minute=halfAt;tlProStartHalfTime(state);return}state.minute+=minuteStep;state.stats.pos[state.possession]+=dt;if(state.minute>=90){state.minute=90;if(state.officialScore){state.score.home=state.officialScore.home;state.score.away=state.officialScore.away}state.finished=true;state.ball.owner=null;state.ball.mode="done";state.scriptedGoalActive=null;state.goalHold=null;managerSimRunning=false;stopCrowd();syncManagerMenuMusic();tlProEvent(state,`Full time ${state.score.home}-${state.score.away}`,"",2);tlProShowBackButton();tlProShowPostMatchReport(state);completeManagerLivePlayback(state).then(()=>tlProShowPostMatchReport(state));return}if(tlProHoldGoal(state))return;tlProRunScriptedGoals(state);tlProTargetPlayers(state);const owner=tlProOwner(state);if(owner){tlProTryTackle(state,owner);const current=tlProOwner(state);if(current&&(state.minute>=current.nextThink||tlProMustRelease(state,current))){current.nextThink=state.minute+.65+state.rng()*1.35;tlProDecide(state,current)}}tlProMovePlayers(state,dt);tlProResolveContacts(state);tlProUpdateBall(state,dt);tlProMaybeFireScriptedShot(state);tlProDebugTick(state)}
    function tlProPitch(c){let r=c.getBoundingClientRect();if((r.width<40||r.height<40)&&c.parentElement){c.parentElement.style.minHeight="360px";r=c.getBoundingClientRect()}const d=Math.min(2,devicePixelRatio||1),w=Math.max(360,r.width|0),h=Math.max(280,r.height|0);if(c.width!==Math.round(w*d)||c.height!==Math.round(h*d)){c.width=Math.round(w*d);c.height=Math.round(h*d)}const g=c.getContext("2d");g.setTransform(d,0,0,d,0,0);const scale=Math.min(w/111,h/72),pw=105*scale,ph=68*scale,net=3*scale,x=(w-pw)/2,y=(h-ph)/2;return{g,w,h,x,y,pw,ph,net,scale}}
    function tlProPx(m,p){return{x:m.x+p.x*m.pw,y:m.y+p.y*m.ph}}
    function tlProDrawPitch(m,state){const g=m.g;g.fillStyle="#07140c";g.fillRect(0,0,m.w,m.h);for(let i=0;i<12;i++){g.fillStyle=i%2?"#1e8542":"#176d35";g.fillRect(m.x+i*m.pw/12,m.y,m.pw/12+1,m.ph)}g.save();g.translate(m.x,m.y);g.strokeStyle="#f2ffef";g.lineWidth=Math.max(1.4,m.scale*.35);g.strokeRect(0,0,m.pw,m.ph);g.beginPath();g.moveTo(m.pw/2,0);g.lineTo(m.pw/2,m.ph);g.stroke();g.beginPath();g.arc(m.pw/2,m.ph/2,9.15/68*m.ph,0,7);g.stroke();const penD=16.5/105*m.pw,penW=40.3/68*m.ph,gaD=5.5/105*m.pw,gaW=18.3/68*m.ph,cy=m.ph/2;g.strokeRect(0,cy-penW/2,penD,penW);g.strokeRect(m.pw-penD,cy-penW/2,penD,penW);g.strokeRect(0,cy-gaW/2,gaD,gaW);g.strokeRect(m.pw-gaD,cy-gaW/2,gaD,gaW);g.fillStyle="#f2ffef";g.beginPath();g.arc(11/105*m.pw,cy,Math.max(1.5,m.scale*.28),0,7);g.fill();g.beginPath();g.arc(m.pw-11/105*m.pw,cy,Math.max(1.5,m.scale*.28),0,7);g.fill();const goalH=7.32/68*m.ph,gy=cy-goalH/2;g.strokeStyle="rgba(242,255,239,.72)";g.strokeRect(-m.net,gy,m.net,goalH);g.strokeRect(m.pw,gy,m.net,goalH);for(let i=1;i<4;i++){g.beginPath();g.moveTo(-m.net,gy+goalH*i/4);g.lineTo(0,gy+goalH*i/4);g.moveTo(m.pw,gy+goalH*i/4);g.lineTo(m.pw+m.net,gy+goalH*i/4);g.stroke()}g.restore()}
    function tlProDrawPlayer(m,p,state){const g=m.g,pt=tlProPx(m,p),owner=tlProOwner(state),owned=owner===p,s=clamp(m.scale*1.35,8,16),shirt=p.role==="GK"?(p.side==="home"?"#ffe05d":"#49d7ff"):p.team.shirt,trim=p.team.trim||"#111";g.save();g.fillStyle="rgba(0,0,0,.34)";g.beginPath();g.ellipse(pt.x,pt.y+s*.78,s*.95,s*.34,0,0,7);g.fill();if(owned){g.strokeStyle="#ffdd45";g.lineWidth=Math.max(2,s*.18);g.beginPath();g.arc(pt.x,pt.y,s*1.42,0,7);g.stroke()}g.fillStyle=trim;g.beginPath();g.arc(pt.x,pt.y,s*1.05,0,7);g.fill();g.fillStyle=shirt;g.beginPath();g.arc(pt.x,pt.y,s*.86,0,7);g.fill();g.fillStyle="rgba(255,255,255,.26)";g.beginPath();g.arc(pt.x-s*.28,pt.y-s*.28,s*.22,0,7);g.fill();g.fillStyle="#fff";g.strokeStyle="#000";g.lineWidth=3;g.font=`900 ${Math.max(8,s*.72)}px Arial`;g.textAlign="center";g.textBaseline="middle";g.strokeText(p.slotRole||p.role,pt.x,pt.y);g.fillText(p.slotRole||p.role,pt.x,pt.y);g.font=`800 ${Math.max(8,s*.58)}px Arial`;g.strokeText(p.name,pt.x,pt.y+s*1.85);g.fillText(p.name,pt.x,pt.y+s*1.85);if(owned){g.fillStyle="#ffdd45";g.strokeStyle="#000";g.lineWidth=3;g.font=`900 ${Math.max(10,s*.86)}px Arial`;g.strokeText(String(p.shirtNumber||p.index+1),pt.x,pt.y-s*1.72);g.fillText(String(p.shirtNumber||p.index+1),pt.x,pt.y-s*1.72)}g.restore()}
    function tlProDrawBall(m,state){const g=m.g,b=state.ball,pt=tlProPx(m,b),br=clamp(m.scale*.62,5,9),z=(b.z||0)*m.ph*.60;g.fillStyle="rgba(0,0,0,.34)";g.beginPath();g.ellipse(pt.x,pt.y+br*.55,br*1.25,br*.42,0,0,7);g.fill();g.fillStyle="#fff";g.strokeStyle="#111";g.lineWidth=1.5;g.beginPath();g.arc(pt.x,pt.y-z,br,0,7);g.fill();g.stroke();g.fillStyle="#111";for(let i=0;i<5;i++){const a=-Math.PI/2+i*Math.PI*2/5;g.beginPath();g.arc(pt.x+Math.cos(a)*br*.45,pt.y-z+Math.sin(a)*br*.45,br*.13,0,7);g.fill()}}
    function tlProDraw(state){const c=$("touchlinesCanvas");if(!c)return;const m=tlProPitch(c);tlProDrawPitch(m,state);[...state.players].sort((a,b)=>a.y-b.y).forEach(p=>tlProDrawPlayer(m,p,state));tlProDrawBall(m,state)}
    function tlProRenderScorers(state){const el=$("touchlinesScorers");if(!el)return;const goals=state.goalScorers||[];el.classList.toggle("hide",!goals.length);if(!goals.length){el.innerHTML="";return}const key=goals.map(g=>g.key).join("|");if(state.lastScorersKey===key)return;state.lastScorersKey=key;el.innerHTML=`<div class="touchlines-scorers-title">GOALS</div><div class="touchlines-scorers-list">${goals.map(g=>`<div class="touchlines-scorer ${safe(g.side||"")}"><b><span>${safe(g.minute)}'</span><i class="touchlines-ball-icon"></i>${safe(g.scorer)}</b>${g.penalty?`<small><strong class="touchlines-pen-tag">PEN</strong></small>`:g.assist?`<small>A: ${safe(g.assist)}</small>`:""}${g.team?`<em>${safe(g.team)}</em>`:""}</div>`).join("")}</div>`}
    function tlProRenderGoalFlash(state){const el=$("touchlinesGoalFlash"),flash=state.goalFlash;if(!el)return;if(!flash||performance.now()>Number(flash.until||0)){el.classList.add("hide");el.classList.remove("home","away");el.textContent="";return}if(state.lastGoalFlashKey!==flash.key){state.lastGoalFlashKey=flash.key;el.textContent=flash.text||"GOAL!!";el.classList.remove("home","away");if(flash.side)el.classList.add(flash.side)}el.classList.remove("hide")}
    function tlProHud(state){const score=$("touchlinesScore"),clock=$("touchlinesClock"),log=$("touchlinesLog"),poss=$("touchlinesPoss"),shots=$("touchlinesShots"),passes=$("touchlinesPasses"),tackles=$("touchlinesTackles"),label=$("touchlinesEngineLabel");tlProUpdateHeader(state,score);if(clock)clock.textContent=tlProClockText(state);const pos=tlProPossessionPct(state);if(poss)poss.textContent=`${pos.home}-${pos.away}`;if(shots)shots.textContent=`${state.stats.shots.home}/${state.stats.onTarget.home} - ${state.stats.shots.away}/${state.stats.onTarget.away}`;if(passes)passes.textContent=`${state.stats.passes.home} - ${state.stats.passes.away}`;if(tackles)tackles.textContent=`${state.stats.tackles.home} - ${state.stats.tackles.away}`;if(label)label.textContent=`${state.home.formation} v ${state.away.formation}`;tlProUpdatePressure(state);tlProRenderGoalFlash(state);tlProRenderScorers(state);tlProMaybeReporter(state,false);tlProRenderReporter(state);const key=state.events.map(e=>`${e.minute}:${e.text}`).join("|");if(log&&key!==state.lastHudKey){state.lastHudKey=key;log.innerHTML=state.events.map(e=>`<div class="touchlines-log-row ${safe(e.side||"")}"><b>${safe(e.minute)}'</b><span>${safe(e.text)}</span></div>`).join("")||`<div class="touchlines-log-row"><b>0'</b><span>Kickoff</span></div>`}}
    function tlProFastForward(state,progress=0,reason="spectator_join"){
      if(!state||!state.report)return;
      const target=clamp(Number(progress||0)*90,0,88.5);
      if(target<1)return;
      const halfAt=tlProHalfTimeMinute(state);
      const shouldSwitch=target>=halfAt;
      state.halfTimeStarted=shouldSwitch;
      state.halfTime=null;
      state.half=shouldSwitch?2:1;
      if(!!state.sidesSwitched!==shouldSwitch){
        state.sidesSwitched=shouldSwitch;
        state.players.forEach(p=>{p.baseX=clamp(1-Number(p.baseX||p.x),.04,.96);p.x=p.baseX;p.y=clamp(Number(p.baseY||p.y),.06,.94);p.tx=p.x;p.ty=p.y;p.vx=0;p.vy=0;p.recovery=0})
      }
      state.minute=target;state.scriptedGoalActive=null;state.goalHold=null;tlProKickoff(state,state.rng()<.5?"home":"away");
      const timeline=managerSimTimeline(state.report),past=timeline.filter(e=>Number(e.minute||0)<=target),goals=past.filter(e=>e.kind==="goal");
      let home=0,away=0;state.goalScorers=[];
      goals.forEach((e,i)=>{
        if(e.side==="home")home++;else away++;
        const player=tlProFindScriptedPlayer(state,e.side,e.player),scorer=player?.name||e.player||managerSimSidePlayer(state.report,e.side,i);
        const assistPlayer=e.assist?tlProFindScriptedPlayer(state,e.side,e.assist):null,assist=assistPlayer&&assistPlayer.name!==scorer?assistPlayer.name:(tlProNameMatches(e.assist,scorer)?"":(e.assist||""));
        state.goalScorers.push({key:`ff:${e.minute}:${e.side}:${scorer}:${assist}:${e.penalty?1:0}:${i}`,minute:e.minute,side:e.side,scorer,assist:e.penalty?"":assist,penalty:!!e.penalty,team:e.side==="home"?state.home.name:state.away.name});
      });
      state.score.home=home;state.score.away=away;(state.scriptedGoals||[]).forEach(g=>{if(Number(g.minute||0)<=target+.15){g.done=true;g.armed=true;g.shot=true}});
      const textFor=e=>{if(e.kind!=="goal")return String(e.text||"").replace(/^\d+'\s*/,"");const player=tlProFindScriptedPlayer(state,e.side,e.player),scorer=player?.name||e.player||"Player",assistPlayer=e.assist?tlProFindScriptedPlayer(state,e.side,e.assist):null,assist=!e.penalty&&assistPlayer&&assistPlayer.name!==scorer?assistPlayer.name:"";return `GOAL${e.penalty?" (PEN)":""} - ${scorer}${assist?` | A: ${assist}`:""}`};
      state.events=past.slice(-10).reverse().map(e=>({minute:e.minute,text:textFor(e),side:e.side||"",importance:e.kind==="goal"?2:1}));
      const s=state.report.teamStats||{},scale=target/90;["home","away"].forEach(side=>{state.stats.pos[side]=Number(s.possession?.[side]||0)*scale||target*.45;state.stats.passes[side]=Math.round(Number(s.passes?.[side]||s.touches?.[side]||0)*scale*.62);state.stats.shots[side]=Math.round(Number(s.shots?.[side]||0)*scale);state.stats.onTarget[side]=Math.round(Number(s.onTarget?.[side]||s.shots?.[side]||0)*scale*.45);state.stats.tackles[side]=Math.round(Number(s.tackles?.[side]||0)*scale)});
      state.lastHudKey="";state.lastScorersKey="";state.lastReporterMinute=Math.floor(target)-10;state.lastReporterScore=`${state.score.home}-${state.score.away}`;
      tlProMaybeReporter(state,true);
      const syncLog=reason==="server_sync";
      clientDebugLog(syncLog?"tl_playback_resync":"tl_spectator_fast_forward",syncLog?"Live playback resynced":"Spectator joined live match",tlProDebugSnapshot(state,{progress:Number(progress).toFixed(3),targetMinute:Number(target).toFixed(2),reason}),"touchlines",!syncLog)
    }
    function tlProSyncToServerPlayback(state=touchlinesView,fixture=null,force=false){
      if(!state||state.finished||!state.report)return false;
      const f=fixture||state.fixture||{},started=Number(f.playbackStartedAt||0);
      if(started<=0)return false;
      const progress=managerFixturePlaybackProgress(f,null,0),target=clamp(progress*90,0,88.5),drift=target-Number(state.minute||0),now=performance.now();
      if(!force&&Math.abs(drift)<1.35)return false;
      if(!force&&state.lastPlaybackSyncAt&&now-state.lastPlaybackSyncAt<2200)return false;
      state.lastPlaybackSyncAt=now;
      state.fixture={...state.fixture,...f};
      tlProFastForward(state,progress,force?"initial_sync":"server_sync");
      state.lastTs=0;
      return true
    }
    function tlProRenderError(err){const log=$("touchlinesLog");if(log)log.innerHTML=`<div class="touchlines-log-row"><b>ERR</b><span>${safe(err?.message||String(err||"Render error"))}</span></div>`;clientDebugLog("render_error",err?.message||String(err||"Render error"),{stack:err?.stack||"",state:touchlinesView?tlProDebugSnapshot(touchlinesView):null},"touchlines",true);managerSimRunning=false;stopCrowd();syncManagerMenuMusic();tlProShowBackButton();console.error(err)}
    function tlProLoop(ts){const state=touchlinesView;if(!state)return;try{tlProSyncToServerPlayback(state,state.fixture,false);if(!state.lastTs)state.lastTs=ts;const dt=Math.min(.06,(ts-state.lastTs)/1000)*managerMatchSpeedFactor();state.lastTs=ts;tlProTick(state,dt);tlProDraw(state);tlProHud(state);if(!state.finished)state.raf=requestAnimationFrame(tlProLoop)}catch(err){tlProRenderError(err)}}
    async function tlProLoadFixtureDetails(fixture){const load=async side=>{try{const user=fixture?.[side];if(!user)return null;const r=await api("managerTeamDetails",{teamUser:user},{quiet:true});return r?.ok?r.teamDetails:null}catch(e){return null}};const [home,away]=await Promise.all([load("home"),load("away")]);fixture._tlDetails={home:home||{},away:away||{}};return fixture}
    function renderTouchlinesView(fixture){
      consumeManagerAutoStartFor(fixture);
      applyManagerMatchSpeedFromFixture(fixture);
      const home=tlProTeam(fixture,"home"),away=tlProTeam(fixture,"away"),matchType=managerMatchTypeLine({round:fixture?.round,phase:fixture?.phase,playoff:fixture?.playoff,cupName:fixture?.cupName},fixture);
      const statbar=`<div class="touchlines-statbar"><span><b id="touchlinesPoss">50-50</b><small>POS</small></span><span><b id="touchlinesShots">0/0 - 0/0</b><small>SHOTS/OT</small></span><span><b id="touchlinesPasses">0 - 0</b><small>PASSES</small></span><span><b id="touchlinesTackles">0 - 0</b><small>TACKLES</small></span><span><b id="touchlinesEngineLabel">${safe(home.formation)} v ${safe(away.formation)}</b><small>ENGINE</small></span></div>`;
      const speedControls=`<div class="touchlines-speed-controls"><button id="touchlinesSlowDown" type="button">SLOW DOWN</button><b id="touchlinesSpeedValue">${safe(managerMatchSpeedLabel())}</b><button id="touchlinesFastForward" type="button">FAST FORWARD</button></div>`;
      $("managerSimView").innerHTML=`<div class="touchlines-page touchlines-pro"><div class="touchlines-head"><span id="touchlinesHeadLeft" data-side="home">${tlProHeaderTeam(home,"left","home")}</span><strong id="touchlinesScore">0 - 0</strong><span id="touchlinesHeadRight" data-side="away" class="away">${tlProHeaderTeam(away,"right","away")}</span><em id="touchlinesClock">00'</em><small class="touchlines-match-type">${safe(matchType)}</small></div><div class="touchlines-pressure"><div class="touchlines-pressure-head"><span id="touchlinesPressureLeft">${safe(home.name)}</span><b id="touchlinesPressureLabel">EVEN PRESSURE</b><span id="touchlinesPressureRight">${safe(away.name)}</span></div><div id="touchlinesPressureTrack" class="touchlines-pressure-track"><div id="touchlinesPressureFill" class="touchlines-pressure-fill"></div><div id="touchlinesPressureBall" class="touchlines-pressure-ball"></div></div><div id="touchlinesPressureScore" class="touchlines-pressure-score">50 - 50</div></div><div class="touchlines-stage"><canvas id="touchlinesCanvas"></canvas><div id="touchlinesGoalFlash" class="touchlines-goal-flash hide" aria-live="polite"></div></div>${speedControls}${statbar}<div id="touchlinesScorers" class="touchlines-scorers hide"></div><div class="touchlines-bottom"><section class="touchlines-panel"><div class="touchlines-panel-title">EVENTS</div><div id="touchlinesLog" class="touchlines-log"></div></section><section class="touchlines-panel reporter"><div class="touchlines-panel-title">REPORTER</div><div id="touchlinesReporter" class="touchlines-reporter"></div></section></div><div id="touchlinesMatchReport" class="touchlines-match-report hide"></div></div>`;
      const back=$("managerSimBack");
      if(back){back.classList.add("hide");back.textContent="BACK TO LEAGUE"}
      showManagerSection("managerSimPage",true);
      $("managerSimPage")?.classList.remove("touchlines-report-open");
      $("managerSimPage")?.classList.add("touchlines-live");
      resetManagerSimScroll();
      touchlinesView=tlProCreateEngine(fixture);
      bindManagerMatchSpeedControls();
      if(!tlProSyncToServerPlayback(touchlinesView,fixture,true)&&Number(fixture?._liveProgress||0)>0)tlProFastForward(touchlinesView,fixture._liveProgress);
      managerSimRunning=true;
      syncManagerMenuMusic();
      playCrowd();
      try{tlProDraw(touchlinesView);tlProHud(touchlinesView)}catch(err){tlProRenderError(err);return}
      touchlinesView.raf=requestAnimationFrame(tlProLoop)
    }
    function managerSimMatchType(fixture=null,report=null){
      const round=Number.isFinite(Number(report?.roundIndex))?(managerSeason?.rounds||[])[Number(report.roundIndex)]:null;
      const phase=String(round?.phase||fixture?.phase||report?.phase||"league").toLowerCase();
      const roundName=String(round?.round||fixture?.roundLabel||fixture?.round||report?.round||"");
      if(phase==="cup")return round?.cupName||fixture?.cupName||roundName||"Cup match";
      if(phase==="playoff"||round?.playoff||fixture?.playoff)return roundName?`Playoff - ${roundName}`:"Playoff match";
      if(phase==="friendly")return "Friendly match";
      if(phase==="training")return "Training match";
      return `${managerSeason?.divisionName||"League"} match`;
    }
    function managerSimLiveReport(fixture=null){const rows=managerSeason?.liveSimulations||[];if(!fixture||!rows.length)return null;const ri=Number(fixture.roundIndex),fi=Number(fixture.fixtureIndex),h=String(fixture.home||""),a=String(fixture.away||"");for(const live of rows){const lf=live?.fixture||{},report=live?.report||null;if(!report)continue;const lri=Number(lf.roundIndex),lfi=Number(lf.fixtureIndex);if(Number.isInteger(ri)&&Number.isInteger(fi)&&lri===ri&&lfi===fi)return report;if(h&&a&&String(lf.home||"")===h&&String(lf.away||"")===a)return report}return null}
    function managerSimLatestReport(fixture=null){const live=managerSimLiveReport(fixture);if(live)return live;const reports=viewerMatchReports();if(!reports.length)return null;if(fixture){const ri=Number(fixture.roundIndex),fi=Number(fixture.fixtureIndex);if(Number.isInteger(ri)&&Number.isInteger(fi)){const exact=reports.find(r=>Number(r.roundIndex)===ri&&Number(r.fixtureIndex)===fi);if(exact)return exact}const h=String(fixture.home||""),a=String(fixture.away||"");const found=reports.find(r=>String(r.home||"")===h&&String(r.away||"")===a);if(found)return found}return reports[0]}
    function managerSimPressure(report){const s=report?.teamStats||{},val=side=>Number(s.possession?.[side]||0)*0.75+Number(s.touches?.[side]||0)*0.35+Number(s.shots?.[side]||0)*8+Number(s.tackles?.[side]||0)*2.5+Number(report?.score?.[side==="home"?0:1]||0)*5,home=val("home"),away=val("away"),total=Math.max(1,home+away);return Math.max(5,Math.min(95,Math.round(home/total*100)))}
    function managerSimPressureText(homeTeam,awayTeam,pressure){const home=homeTeam?.name||"Home",away=awayTeam?.name||"Away",dist=Math.abs(Number(pressure||50)-50);if(dist<18)return "ZzZz mode";return pressure>50?`${home} pressure ->`:`<- ${away} pressure`}
    function managerSimPressureStyle(pressure){const p=clamp(Number(pressure)||50,5,95),dist=Math.abs(p-50),left=Math.min(p,50),hot=dist>=42?"#b91024":dist>=27?"#f28a18":dist>=18?"#ffdd45":"#26da48",from=p>=50?"#26da48":hot,to=p>=50?hot:"#26da48";return `--pressure-left:${left}%;--pressure-width:${dist}%;--pressure-from:${from};--pressure-to:${to}`}
    function managerSimPlaybackPressure(report,progress=0){
      if(!report)return 50+Math.round(Math.sin(Date.now()/260)*6);
      const minute=clamp(Number(progress||0)*90,0,90),events=managerSimTimeline(report),baseTarget=managerSimPressure(report),baseBias=clamp((baseTarget-50)*.22,-8,8);
      const goalNow=events.find(e=>e.kind==="goal"&&minute>=Number(e.minute||0)&&minute-Number(e.minute||0)<.55);
      if(goalNow){
        const side=goalNow.side==="home"?1:goalNow.side==="away"?-1:0;
        if(side)return side>0?95:5;
      }
      const lastGoal=[...events].filter(e=>e.kind==="goal"&&Number(e.minute||0)<=minute).pop();
      if(lastGoal){
        const sinceGoal=minute-Number(lastGoal.minute||0);
        if(sinceGoal>0&&sinceGoal<4.5)return 50;
        if(sinceGoal>=4.5&&sinceGoal<9){
          const restart=(sinceGoal-4.5)/4.5;
          return clamp(Math.round(50+baseBias*restart+Math.sin(Date.now()/620+minute*.12)*2*restart),42,58);
        }
      }
      const seed=managerSimSeed(report);
      let force=baseBias
        + Math.sin(minute*.29+(seed%31)) * 9
        + Math.sin(minute*.73+(seed%17)) * 4;
      events.forEach(e=>{
        const side=e.side==="home"?1:e.side==="away"?-1:0;
        if(!side)return;
        const eventMinute=Number(e.minute||0);
        if(eventMinute>minute)return;
        const dist=minute-eventMinute,window=e.kind==="goal"?13:e.kind==="pen"?11:7;
        if(dist>window)return;
        if(e.kind==="goal")return;
        const weight=(1-dist/window)*(e.kind==="goal"?31:e.kind==="pen"?25:e.kind==="red"?20:e.kind==="yellow"?13:9);
        force+=side*weight;
      });
      const wobble=Math.sin(Date.now()/520+minute*.18)*3;
      return clamp(Math.round(50+force+wobble),5,95);
    }
    function managerSimSeed(report){return String(report?.id||report?.seasonId||"match").split("").reduce((a,c)=>a+c.charCodeAt(0),0)}
    function managerSimSideName(report,side){return side==="home"?(report?.homeTeam?.name||report?.home||"Home"):(report?.awayTeam?.name||report?.away||"Away")}
    function managerSimSidePlayer(report,side,index=0){const all=(report?.players||[]).filter(p=>p.side===side),shots=all.filter(p=>Number(p.shots||0)>0),pool=shots.length?shots:all;return pool.length?(pool[index%pool.length]?.name||"Player"):"Player"}
    function managerSimSideAssist(report,side,scorer,index=0){const all=(report?.players||[]).filter(p=>p.side===side&&p.name&&p.name!==scorer);if(!all.length)return"";const score=p=>Number(p.passes||0)*2+Number(p.longPasses||0)*2.5+Number(p.widePasses||0)*2.2+Number(p.touches||0)*.5+Number(p.impact||0)*.2;const passers=all.filter(p=>Number(p.passes||0)>0||Number(p.longPasses||0)>0||Number(p.widePasses||0)>0),pool=(passers.length?passers:all).slice().sort((a,b)=>score(b)-score(a)||String(a.name||"").localeCompare(String(b.name||"")));return pool.length?(pool[index%pool.length]?.name||""):""}
    function managerReportGoalEvents(report){return (report?.goalScorers||[]).filter(g=>g&&["home","away"].includes(String(g.side||""))).map((g,i)=>{const side=String(g.side||"home"),minute=clamp(Math.round(Number(g.minute??g.at??0)||0),1,90),player=String(g.scorer||"").trim()||managerSimSidePlayer(report,side,i),penalty=!!g.penalty,assist=penalty?"":String(g.assist||"").trim();return{kind:"goal",side,minute,sort:minute+i*.07,player,assist,penalty,text:`${minute}' ${managerSimSideName(report,side)} ${penalty?"penalty goal":"goal"} - ${player}${assist?` | assist ${assist}`:""}`}})}
    function managerSimTimeline(report){if(!report)return[];const seed=managerSimSeed(report),events=[],score=report.score||[0,0],disc=report.discipline||{},reportGoals=managerReportGoalEvents(report),addGoal=(side,count,off)=>{for(let i=0;i<count;i++){let minute=clamp(Math.round(8+((i+1)/(count+1))*74+(((seed+off+i*11)%9)-4)),2,89),player=managerSimSidePlayer(report,side,i),assist=managerSimSideAssist(report,side,player,i);events.push({kind:"goal",side,minute,sort:minute+i*.07,player,assist,text:`${minute}' ${managerSimSideName(report,side)} goal - ${player}${assist?` | assist ${assist}`:""}`})}},addCount=(kind,side,count,label,base)=>{for(let i=0;i<Math.min(4,Number(count)||0);i++){let minute=clamp(base+i*17+((seed+i*5)%9)-4,6,88),player=managerSimSidePlayer(report,side,minute+i);events.push({kind,side,minute,sort:minute+i*.03,player,label,text:`${minute}' ${label}: ${managerSimSideName(report,side)}`})}};if(reportGoals.length)events.push(...reportGoals);else{addGoal("home",Number(score[0]||0),3);addGoal("away",Number(score[1]||0),17)}addCount("yellow","home",disc.yellows?.home,"Yellow card",24);addCount("yellow","away",disc.yellows?.away,"Yellow card",27);addCount("red","home",disc.reds?.home,"Red card",53);addCount("red","away",disc.reds?.away,"Red card",57);addCount("pen","home",disc.penalties?.home,"Penalty",35);addCount("pen","away",disc.penalties?.away,"Penalty",39);const fkHome=Number(disc.freeKicks?.home||0),fkAway=Number(disc.freeKicks?.away||0);if(fkHome+fkAway>0)events.push({kind:"free",side:fkHome>=fkAway?"home":"away",minute:31,sort:31.5,label:"Free kick",text:`31' Free kicks are building`});const moaner=report.highlights?.moaner;if(moaner)events.push({kind:"arguing",side:moaner.side||"",minute:66,sort:66.2,player:moaner.name||"Player",label:"Dissent",text:`66' Arguing: ${moaner.name||"Player"}`});return events.sort((a,b)=>a.sort-b.sort)}
    function managerSimLiveScore(report,progress=1){if(!report)return[0,0];if(progress>=.995)return[Number(report.score?.[0]||0),Number(report.score?.[1]||0)];let home=0,away=0;managerSimTimeline(report).filter(e=>e.kind==="goal"&&e.minute/90<=progress).forEach(e=>{if(e.side==="home")home++;else away++});return[home,away]}
    function managerSimGoalWhistles(report,prevProgress,progress){if(!report)return;managerSimTimeline(report).filter(e=>e.kind==="goal").forEach(e=>{const at=clamp(Number(e.minute||0)/90,0,1),key=`${report.id||"match"}:${e.side}:${e.minute}:${e.sort}`;if(at>prevProgress&&at<=progress&&!managerSimWhistledGoals.has(key)){managerSimWhistledGoals.add(key);ensureAudio();goalCheerSound();whistleSound()}})}
    function managerSimLog(report,progress=1,pressure=50){if(!report)return `<div class="sim-log-row">Match engine running...</div>`;const rows=managerSimTimeline(report).filter(e=>e.minute/90<=progress).slice(-6).map(e=>e.text);if(!rows.length)rows.push(Math.abs(Number(pressure||50)-50)<18?"ZzZz mode - midfield passing.":"Pressure is building.");if(progress>=.995){const hi=report.highlights||{};if(hi.worst)rows.push(`Underperformer: ${hi.worst.name||"Player"} (${hi.worst.behavior||""})`);if(hi.moaner&&!rows.some(x=>String(x).includes("Arguing")))rows.push(`Arguing: ${hi.moaner.name||"Player"} (${hi.moaner.teamName||""})`)}return rows.map(x=>`<div class="sim-log-row">${safe(x)}</div>`).join("")}
    function managerSimStatusText(state,progress=1,message=""){if(state==="waiting")return message||"Waiting";if(state==="running")return `${Math.max(1,Math.min(90,Math.round(clamp(progress,0,.995)*90)))}'`;return "Full Time"}
    function managerSimEventName(report,e,index=0){const player=e.player||managerSimSidePlayer(report,e.side,index);if(e.kind==="goal"){const assist=e.penalty?"":(e.assist||managerSimSideAssist(report,e.side,player,index));return `<span class="sim-goal-stack"><span class="sim-goal-main"><b>${safe(player)}</b> <span class="sim-ball-icon"></span>${e.penalty?` <span class="sim-event-tag">PEN</span>`:""}</span>${assist?`<small class="sim-assist-line">A: ${safe(assist)}</small>`:""}</span>`}if(e.kind==="yellow")return `<span class="sim-card-icon yellow"></span><b>${safe(player)}</b>`;if(e.kind==="red")return `<span class="sim-card-icon red"></span><b>${safe(player)}</b>`;if(e.kind==="pen")return `<span class="sim-event-tag">PEN</span><b>${safe(managerSimSideName(report,e.side))}</b>`;if(e.kind==="free")return `<b>Free kick</b>`;if(e.kind==="arguing")return `<span class="sim-event-tag">DISSENT</span><b>${safe(player)}</b>`;return safe(e.text||"Event")}
    function managerSimSummaryRows(report,progress=1,state="done"){
      if(!report)return `<div class="sim-summary-row"><span class="sim-summary-minute">--</span><div class="sim-summary-side">Match engine running...</div><b></b><div></div></div>`;
      const cutoff=state==="running"?clamp(Number(progress||0)*90,0,89.5):90,items=managerSimTimeline(report).filter(e=>Number(e.minute||0)<=cutoff);
      if(cutoff>=45)items.push({kind:"marker",minute:45,sort:45.5,label:"HT"});
      if(state!=="running"||progress>=.995)items.push({kind:"marker",minute:90,sort:90.5,label:"FT"});
      items.sort((a,b)=>(a.sort??a.minute)-(b.sort??b.minute));
      let home=0,away=0,rows=[];
      items.forEach((e,i)=>{
        if(e.kind==="goal"){if(e.side==="home")home++;else away++}
        if(e.kind==="marker"){rows.push(`<div class="sim-summary-row marker"><span class="sim-summary-minute">${safe(e.label)}</span><div></div><b>${home} - ${away}</b><div></div></div>`);return}
        const body=managerSimEventName(report,e,i),score=e.kind==="goal"?`${home} - ${away}`:"";
        rows.push(`<div class="sim-summary-row ${safe(e.side||"")} ${safe(e.kind||"")}"><span class="sim-summary-minute">${safe(e.minute)}'</span><div class="sim-summary-side sim-home-event">${e.side==="home"?body:""}</div><b>${safe(score)}</b><div class="sim-summary-side sim-away-event">${e.side==="away"?body:""}</div></div>`);
      });
      if(!rows.length)rows.push(`<div class="sim-summary-row"><span class="sim-summary-minute">${Math.max(1,Math.round(cutoff||1))}'</span><div class="sim-summary-side">Match settling in midfield.</div><b></b><div></div></div>`);
      return rows.join("");
    }
    function managerSimHtml(state="running",fixture=null,report=null,message="Simulating round...",progress=1,pressure=null){
      fixture=fixture||managerSimFixture()||report||{};
      const h=report?reportSideTeam(report,"home"):(fixture.homeTeam||managerSimTeam(fixture.home)),a=report?reportSideTeam(report,"away"):(fixture.awayTeam||managerSimTeam(fixture.away)),p=state==="running"?clamp(Number(progress)||0,0,.995):1,liveScore=report?managerSimLiveScore(report,p):null,score=liveScore?`${safe(liveScore[0])} - ${safe(liveScore[1])}`:(state==="running"?"0 - 0":"v"),press=pressure??(state==="running"?managerSimPlaybackPressure(report,p):(report?managerSimPressure(report):50)),status=managerSimStatusText(state,p,message),matchType=managerSimMatchType(fixture,report);
      return `<div class="sim-summary-page"><div class="sim-scoreboard"><div class="sim-board-team">${teamFlag(h)}<span>${safe(h?.name||fixture.home||"HOME")}</span></div><div class="sim-board-score"><b>${score}</b><span>${safe(status)}</span><small>${safe(matchType)}</small></div><div class="sim-board-team away">${teamFlag(a)}<span>${safe(a?.name||fixture.away||"AWAY")}</span></div></div><div class="sim-tabs"><span>Info</span><span class="active">Summary</span><span>Stats</span><span>Line-ups</span><span>H2H</span></div><div class="sim-momentum-card"><div><b>${safe(managerSimPressureText(h,a,press))}</b><span>${safe(message)}</span></div><div class="sim-pressure-track"><div id="managerSimPressureFill" class="sim-pressure-fill" style="${managerSimPressureStyle(press)}"></div></div></div><div class="sim-summary-table">${managerSimSummaryRows(report,p,state)}</div></div>`;
    }
    function managerSimScrollSnapshot(view){const table=view?.querySelector(".sim-summary-table");return table?{top:table.scrollTop,bottom:table.scrollTop+table.clientHeight>=table.scrollHeight-8}:null}
    function managerSimRestoreScroll(view,keep){const table=view?.querySelector(".sim-summary-table");if(!table||!keep)return;table.scrollTop=keep.bottom?table.scrollHeight:Math.min(keep.top,table.scrollHeight)}
    function renderManagerSimPage(state="running",fixture=null,report=null,message="Simulating round..."){
      fixture=fixture||managerSimFixture()||report||{};
      managerSimRunning=state==="running";
      $("managerSimView").innerHTML=managerSimHtml(state,fixture,report,message,state==="running"?0:1);
      const back=$("managerSimBack");
      if(back){back.classList.toggle("hide",state==="running");back.dataset.roundContinue="0";back.dataset.roundIndex="";back.dataset.roundPhase="";back.textContent=state==="done"?"CONTINUE":"BACK"}
      showManagerSection("managerSimPage",state==="running");
      if(state==="running")resetManagerSimScroll();
      syncManagerMenuMusic();
      if(state==="running"&&!managerSimTimer){const started=performance.now();let prev=0;managerSimTimer=setInterval(()=>{const p=clamp((performance.now()-started)/MANAGER_SIM_PLAYBACK_MS,0,.985),press=managerSimPlaybackPressure(report,p),view=$("managerSimView");managerSimGoalWhistles(report,prev,p);prev=p;if(view){const keep=managerSimScrollSnapshot(view);view.innerHTML=managerSimHtml("running",fixture,report,message,p,press);managerSimRestoreScroll(view,keep)}},260)}
      if(state!=="running")stopManagerSimAnimation();
    }
    async function maybeAutoStartReadyMatch(section=""){
      if((section||currentManagerSection())==="managerSimPage")return false;
      const remembered=managerAutoStartFixture||loadManagerAutoStart();
      if(!remembered||managerSimRunning||managerActionLocked("auto_start_ready")||visibleScreen()!=="manager")return false;
      const meta=managerFindFixtureMeta(remembered)||remembered,fixture={...(meta.fixture||remembered.fixture||{}),round:meta.round,roundLabel:meta.roundLabel||managerRoundTitle(meta),roundIndex:meta.roundIndex,fixtureIndex:meta.fixtureIndex,phase:meta.phase,playoff:meta.playoff};
      if(managerAutoStartConsumed({...meta,fixture})){forgetManagerAutoStart();return false}
      if(!["played","simulating"].includes(String(fixture.status||"")))return false;
      const report=managerSimLatestReport(fixture);
      if(!report)return false;
      markManagerAutoStartConsumed({...meta,fixture});
      forgetManagerAutoStart();
      stopManagerSimAnimation();
      const viewFixture={...fixture,_tlReport:report};
      await tlProLoadFixtureDetails(viewFixture);
      msg("managerMsg","");
      renderTouchlinesView(viewFixture);
      return true;
    }
    async function maybeAutoStartAfterContinue(section=""){
      if((section||currentManagerSection())==="managerSimPage")return false;
      if(managerRoundVotePassive(effectiveRoundVote())){clearStoredAfterContinueStart();return false}
      const remembered=loadAfterContinueStart();
      if(!remembered||managerSimRunning||managerActionLocked("auto_start_after_continue")||visibleScreen()!=="manager")return false;
      if(Date.now()-Number(remembered.createdAt||0)>15*60*1000){clearStoredAfterContinueStart();return false}
      const activeIndex=managerActiveRoundIndex(),afterRoundIndex=Number(remembered.afterRoundIndex);
      if(!Number.isInteger(activeIndex))return false;
      const preview=nextManagerFixturePreview();
      const fixture=nextManagerFixture()||(Number(preview?.roundIndex)===activeIndex?preview:null);
      if(!fixture)return false;
      if(Number.isInteger(afterRoundIndex)&&afterRoundIndex>=0&&Number(fixture.roundIndex)<afterRoundIndex)return false;
      if(Number(fixture.roundIndex)!==activeIndex)return false;
      if(String(fixture.fixture?.status||"")!=="pending")return false;
      clearStoredAfterContinueStart();
      clientDebugLog("manager_auto_start","Starting next match after continue wait",{afterRoundIndex:remembered.afterRoundIndex,roundIndex:fixture.roundIndex,fixtureIndex:fixture.fixtureIndex},"manager",true);
      await playManagerViewedRound();
      return true;
    }
    async function maybeAutoCloseCompletedRound(section=""){
      const vote=managerSeason?.simVote;
      if(!vote?.mineContinuePending||managerAutoContinueBusy||managerSimRunning||visibleScreen()!=="manager"||(section||currentManagerSection())==="managerSimPage")return false;
      const now=Date.now();
      if(now-managerAutoContinueLastAt<2400)return false;
      managerAutoContinueLastAt=now;
      managerAutoContinueBusy=true;
      try{
        const r=await api("managerRoundContinue",managerRoundContinuePayload(vote),{quiet:true});
        if(r.managerSeason)managerSeason=r.managerSeason;
        if(r.managerFinance)managerFinance=r.managerFinance;
        if(r.managerSquad)managerSquad=r.managerSquad;
        if(r.managerMarket)managerMarket=r.managerMarket;
        if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);
        syncManagerActions();
        if(section==="managerTeamPage"&&currentTeamDetailsUser)await openManagerTeam(currentTeamDetailsUser,{record:false});
        else renderManagerSeason();
        if(!section||section==="managerHome")showManagerSection("managerHome",false);
        return true;
      }catch(e){
        clientDebugLog("manager_auto_continue_error",e?.message||String(e||"auto continue failed"),{stack:e?.stack||""},"manager",true);
        return false;
      }finally{
        managerAutoContinueBusy=false;
      }
    }
    function managerWaitNames(r={}){return (r.humanMatchWaiting||r.roundWaiting||effectiveRoundVote()?.waiting||[]).filter(Boolean)}
    function managerWaitText(r={},fallback="Waiting for other managers"){const names=managerWaitNames(r);return names.length?`Waiting for ${names.join(", ")}`:fallback}
    function openManagerLiveMatch(m){stopManagerPoll();setMatch(m);if(m?.status==="ready"){crowdMatchId=m.id;playCrowd()}show("match");pushAppHistory();renderMatch();startPoll()}
    function managerMainViewClick(){const action=String($("managerNextRound")?.dataset.managerSimAction||"");if(action==="continue")return continueManagerRound(managerRoundContinuePayload());if(action==="cpu")return playManagerCpuRound();return playManagerViewedRound()}
    async function playManagerViewedRound(retryStale=false){
      retryStale=retryStale===true;
      if(touchlinesView&&!touchlinesView.finished)return resumeManagerSimAnimation();
      if(managerActionLocked("start_game_viewed"))return;
      if(managerInviteBlocksProgress("managerMsg"))return;
      const section=currentManagerSection(),teamUser=currentTeamDetailsUser;
      const fixture=managerSimFixture();
      if(!fixture)return playManagerCpuRound();
      clearStoredAfterContinueStart();
      stopManagerSimAnimation();
      setManagerBusy(true);msg("managerMsg","");
      try{
        const r=await api("managerNextRound",managerNextRoundPayload(fixture));
        await delay(MANAGER_SIM_LOAD_SETTLE_MS);
        if(handleManagerInjuryBlock(r,"managerMsg")){stopManagerSimAnimation();await refreshManagerSectionAfterUpdate(section,teamUser);return}
        if(!r.ok){const text=r.error==="invite_pending"?managerInviteWaitingMessage(r):r.error==="match_in_progress"?"Finish watched match first":"Could not start game";stopCrowd();renderManagerSimPage("done",fixture,null,text);return msg("managerMsg",text)}
        if(r.match){openManagerLiveMatch(r.match);return}
        managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);syncManagerActions();
        if(r.staleRound){stopCrowd();renderManagerSeason();msg("managerMsg","");if(!retryStale&&nextManagerFixturePreview()){setManagerBusy(false);return playManagerViewedRound(true)}return}
        if(r.simVotePending&&!r.managerFixtureSimulated){if(managerRoundVotePassive(managerSeason?.simVote))clearStoredAfterContinueStart();else rememberManagerAutoStart({fixture,round:fixture.round,roundLabel:fixture.roundLabel,roundIndex:fixture.roundIndex,fixtureIndex:fixture.fixtureIndex,phase:fixture.phase,playoff:fixture.playoff,cupName:fixture.cupName});stopCrowd();await renderManagerAfterStartVote(section,teamUser);msg("managerMsg",managerWaitText(r,"Waiting for other managers"));return}
        const report=managerSimLatestReport(fixture);
        const viewFixture={...fixture,_tlReport:report||null};
        await tlProLoadFixtureDetails(viewFixture);
        msg("managerMsg","");
        renderTouchlinesView(viewFixture)
      }finally{setManagerBusy(false)}
    }
    async function playManagerCpuRound(){
      if(managerActionLocked("start_game_cpu"))return;
      if(managerInviteBlocksProgress("managerMsg"))return;
      const label=managerCpuOnlyActionLabel(),section=currentManagerSection(),teamUser=currentTeamDetailsUser;
      stopManagerSimAnimation();
      setManagerBusy(true);msg("managerMsg",`${label}...`);
      try{
        const r=await api("managerNextRound",managerNextRoundPayload());
        if(handleManagerInjuryBlock(r,"managerMsg")){await refreshManagerSectionAfterUpdate(section,teamUser);return}
        if(!r.ok)return msg("managerMsg",r.error==="invite_pending"?managerInviteWaitingMessage(r):r.error==="match_in_progress"?"Finish watched match first":"Could not update season");
        managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);syncManagerActions();renderManagerSeason();
        if(r.staleRound)return msg("managerMsg","");
        if(r.simVotePending){msg("managerMsg","");return}
        msg("managerMsg",managerSeason?.status==="finished"?"Season finished":`${label} done`);
      }finally{setManagerBusy(false)}
    }
    async function playManagerSeason(messageId="managerMsg",adminOverride=false){
      if(managerActionLocked("sim_season"))return;
      if(!managerSeason)return msg(messageId,"No active manager league");
      if(managerInviteBlocksProgress(messageId))return;
      if(!await askConfirm("SIM SEASON","Simulate the whole season until everything is finished?\nNext season will not start until you press NEXT SEASON.","SIM SEASON","CANCEL",false))return;
      setManagerBusy(true);msg(messageId,"Marking season ready...");
      try{
        const r=await api("managerSimSeason",{simSeasonKey:managerSeason?.simSeasonVote?.key||"",adminOverride:!!adminOverride});
        if(handleManagerInjuryBlock(r,messageId))return;
        if(!r.ok)return msg(messageId,r.error==="invite_pending"?managerInviteWaitingMessage(r):r.error==="match_in_progress"?"Finish watched match first":r.error==="no_season"?"No active manager league":"Could not simulate season");
        managerSeason=r.managerSeason||managerSeason;
        managerFinance=r.managerFinance||managerFinance;
        managerSquad=r.managerSquad||managerSquad;
        managerMarket=r.managerMarket||managerMarket;
        if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);
        syncManagerActions();renderManagerSeason();syncAdminControls();
        if(r.staleSeason)return msg(messageId,"League updated. Check the table.");
        if(r.simSeasonVotePending){const v=managerSeason?.simSeasonVote;return msg(messageId,messageId==="managerMsg"?"":(v?.waiting?.length?`Waiting for ${v.waiting.join(", ")}`:"Waiting for other managers"))}
        msg(messageId,r.seasonSimulated?"Season simulated. Press NEXT SEASON when you are ready.":"Season sim stopped before finish")
      }finally{setManagerBusy(false)}
    }
    async function watchManagerMatch(){if(managerInviteBlocksProgress("managerMsg"))return;ensureAudio();const r=await api("managerWatchMatch");if(handleManagerInjuryBlock(r,"managerMsg"))return;if(!r.ok)return msg("managerMsg",r.error==="invite_pending"?managerInviteWaitingMessage(r):r.error==="current_match"?"Leave current match first":r.error==="no_fixture"?"No match for your user in this league":"Could not open match");if(r.simVotePending&&!r.match){managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;syncManagerActions();renderManagerSeason();return msg("managerMsg","")}openManagerLiveMatch(r.match)}
    async function continueManagerRound(payload=null){
      if(managerActionLocked("round_continue"))return;
      if(managerInviteBlocksProgress("managerMsg"))return;
      stopManagerSimAnimation();
      let autoSimNext=false;
      setManagerBusy(true);msg("managerMsg","");
      try{
        const requestPayload=payload&&!("currentTarget" in payload)&&!("target" in payload)?payload:managerRoundContinuePayload();
        const r=await api("managerRoundContinue",requestPayload);
        if(r.managerSeason)managerSeason=r.managerSeason;
        if(r.managerFinance)managerFinance=r.managerFinance;
        if(r.managerSquad)managerSquad=r.managerSquad;
        if(r.managerMarket)managerMarket=r.managerMarket;
        if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);
        syncManagerActions();renderManagerSeason();showManagerSection("managerHome",false);
        if(!r.ok)return msg("managerMsg",r.error==="invite_pending"?managerInviteWaitingMessage(r):r.error==="no_season"?"No active manager league":r.error==="not_your_season"?"Not your manager league":"Match is not ready to continue");
        if(r.staleRound)return msg("managerMsg","");
        const wait=managerWaitNames(r);
        if(wait.length&&r.managerRoundContinued&&!managerRoundVotePassive(managerSeason?.simVote))rememberAfterContinueStart(managerSeason?.simVote||{roundIndex:requestPayload.roundIndex});
        autoSimNext=!managerRoundVotePassive(managerSeason?.simVote)&&!wait.length&&!!r.managerRoundAdvanced&&!!nextManagerFixturePreview();
        msg("managerMsg",wait.length||autoSimNext?"":"Round ready");
      }finally{setManagerBusy(false)}
      if(autoSimNext)return playManagerViewedRound();
    }
    async function continueManagerSeason(){if(managerInviteBlocksProgress("managerMsg"))return;const r=await api("continueManagerSeason");if(!r.ok){if(r.managerSeason)managerSeason=r.managerSeason;if(r.managerFinance)managerFinance=r.managerFinance;if(r.managerSquad)managerSquad=r.managerSquad;if(r.managerMarket)managerMarket=r.managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave});syncManagerActions();renderManagerSeason();return msg("managerMsg",r.error==="invite_pending"?managerInviteWaitingMessage(r):r.error==="season_year_wait"?`Waiting for ${(r.waitingUsers||[]).join(", ")}`:r.error==="season_not_finished"?"Season is not finished yet":"Could not continue season")}managerSeason=r.managerSeason||null;setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave});managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);syncManagerActions();renderManagerSeason();msg("managerMsg","Next season started")}
    function showAbortManagerConfirm(){managerAbortConfirm=true;renderManagerSeason()}
    async function abortManagerLeague(){const r=await api("abortManagerSeason");if(!r.ok)return msg("managerMsg","Could not abort league");managerAbortConfirm=false;managerSeason=null;managerHasSeason=false;managerCanContinue=false;setManagerTurnAlerts(r.managerTurnAlerts||[]);managerFinance=r.managerFinance||managerFinance;syncManagerActions();goMainMenu(true);msg("menuMsg","League aborted")}
    function lowOfferText(r){const ask=Number(r?.basePrice||0),total=Number(r?.offerTotal??r?.cashPrice??0),gap=Number(r?.marketDivisionGap||0),premium=Number(r?.marketPricePremiumPct||0),extra=gap>0?` Higher-division price +${premium}%.`:"";return ask?`Asking price ${money(ask)}. Your total bid ${money(total)}.${extra}`:"Bid is below asking price."}
    function transferRejectNotice(r){return `<b>BID REJECTED</b>${safe(r?.message||"The selling club rejected the bid.")}${r?.basePrice?`<br>${safe(lowOfferText(r))}`:""}`}
    async function buyManagerPlayer(id,offer={}){const wanted=(managerMarket||[]).find(p=>p.id===id);const r=await api("buyPlayer",{playerId:id,...offer});if(!r.ok){if(r.error==="low_offer"||r.error==="bid_rejected"){managerMarketNotice=r.error==="bid_rejected"?transferRejectNotice(r):`<b>BID REJECTED</b>${safe(lowOfferText(r))}`;renderManagerMarketPage();return msg("managerMsg","Bid rejected")}return msg("managerMsg",r.error==="bench_full"?benchFullText(r):r.error==="no_money"?"Not enough money":r.error==="human_transfer_locked"?"Use Browse and send a deal offer to that manager":r.error==="stale_listing"?"Player is no longer available":r.error==="no_replacement"?"Need a bench player before offering a starter":"Could not buy player")}managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);if(r.status==="human_offer"){managerMarketNotice=`<b>OFFER SENT</b>${safe(r.message||"Waiting for manager approval")}`;renderManagerMarketPage();return msg("managerMsg","Offer sent")}managerMarketNotice=signingNotice(r.boughtPlayer||wanted,r.skillChange);renderManagerSeason();renderManagerMarketPage();msg("managerMsg",`${(r.boughtPlayer||wanted)?.name||"Player"} signed for ${money(r.cashPrice??r.price??r.boughtPlayer?.purchasePrice??0)}${r.offerValue?` + player value ${money(r.offerValue)}`:""}${r.skillChange?.delta?` | skill ${r.skillChange.before}->${r.skillChange.after}`:""}`)}
    async function sellManagerPlayer(id,offer={}){const r=await api("sellPlayer",{playerId:id,...offer});if(!r.ok)return msg("managerMsg",r.error==="no_buyer"?`No buyer at that price${r.chance?` (${r.chance}% chance)`:""}. Lower price and try again.`:r.error==="no_replacement"?"Need a bench player first":r.error==="player_training"?"Player is away on training":"Could not sell player");managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance;managerSquad=r.managerSquad;managerMarket=r.managerMarket||managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);renderManagerSeason();renderManagerSquadPage();msg("managerMsg",r.salePending?`Player listed for ${money(r.salePrice||offer.cashOffer||0)}. CPU bids can take 1-10 matches.`:`Player sold for ${money(r.salePrice||offer.cashOffer||0)}`)}
    function scoutResultById(id){return (managerScoutResults||[]).find(p=>String(p.id||"")===String(id||""))||null}
    function removeScoutResult(id){managerScoutResults=(managerScoutResults||[]).filter(p=>String(p.id||"")!==String(id||""))}
    async function buyScoutMarketPlayer(id,offer={}){const wanted=scoutResultById(id);const r=await api("buyPlayer",{playerId:id,...offer});if(!r.ok){managerScoutNotice=(r.error==="low_offer"||r.error==="bid_rejected")?(r.error==="bid_rejected"?transferRejectNotice(r):`<b>BID REJECTED</b>${safe(lowOfferText(r))}`):`<b>TRANSFER FAILED</b>${safe(r.error==="bench_full"?benchFullText(r):r.error==="no_money"?"Not enough money":r.error==="human_transfer_locked"?"Use Browse and send a deal offer to that manager":r.error==="stale_listing"?"Player is no longer available":r.error==="no_replacement"?"Need a bench player before offering a starter":"Could not buy player")}`;renderManagerScoutBox();return msg("managerMsg",(r.error==="low_offer"||r.error==="bid_rejected")?"Bid rejected":"Could not buy player")}managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);if(r.status==="human_offer"){managerScoutNotice=`<b>OFFER SENT</b>${safe(r.message||"Waiting for manager approval")}`;renderManagerScoutBox();return msg("managerMsg","Offer sent")}removeScoutResult(id);managerScoutNotice=signingNotice(r.boughtPlayer||wanted,r.skillChange);renderManagerSeason();renderManagerScoutBox();msg("managerMsg",`${(r.boughtPlayer||wanted)?.name||"Player"} signed for ${money(r.cashPrice??r.price??r.boughtPlayer?.purchasePrice??0)}`)}
    async function browseScoutTransferBid(teamUser,id,offer={}){const wanted=scoutResultById(id);const r=await api("browseTransferBid",{teamUser,playerId:id,...offer});if(!r.ok){managerScoutNotice=r.error==="low_offer"?`<b>BID REJECTED</b>${safe(lowOfferText(r))}`:`<b>TRANSFER FAILED</b>${safe(r.error==="too_many_offer_players"?`Max ${r.maxPlayers||3} players in one bid`:r.error==="bench_full"?benchFullText(r):r.error==="no_money"?"Not enough money":r.error==="human_transfer_locked"?"That manager is not available for deals":r.error==="no_replacement"?"Need enough bench cover before offering those players":"Could not make bid")}`;renderManagerScoutBox();return msg("managerMsg",r.error==="low_offer"?"Bid rejected":"Could not make bid")}if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);if(r.status==="human_offer"){managerScoutNotice=`<b>OFFER SENT</b>${safe(r.message||"Waiting for manager approval")}`;renderManagerScoutBox();return msg("managerMsg","Offer sent")}if(r.status==="rejected"){managerScoutNotice=`<b>BID REJECTED</b>${safe(r.message||"Club rejected the bid")} ${r.basePrice?`<br>${safe(lowOfferText(r))}`:""}`;renderManagerScoutBox();return msg("managerMsg","Bid rejected")}if(r.status==="counter"){const player=r.player?.name||wanted?.name||"Player",cash=Number(r.price||0),total=Number(r.counterTotal||r.offerTotal||cash),count=Number(r.offerPlayerCount||0),extra=r.offerValue?` including ${count>1?`${count} players`:"player"} value ${money(r.offerValue)}`:"",ok=await askConfirm("TRANSFER COUNTER",`${player}: club wants total ${money(total)}. Cash needed ${money(cash)}${extra}. Accept?`,"ACCEPT","DECLINE",false);if(!ok){managerScoutNotice=`<b>COUNTER DECLINED</b>${safe(player)} stays at ${safe(r.team?.name||wanted?.sourceTeam||"the club")}`;renderManagerScoutBox();return msg("managerMsg","Counter declined")}const a=await api("acceptBrowseTransfer",{offerId:r.offerId});if(!a.ok)return msg("managerMsg",a.error==="bench_full"?benchFullText(a):a.error==="no_money"?"Not enough money for counter offer":a.error==="no_replacement"?"Need enough bench cover before offering those players":"Could not accept counter offer");managerSeason=a.managerSeason||managerSeason;managerFinance=a.managerFinance||managerFinance;managerSquad=a.managerSquad||managerSquad;managerMarket=a.managerMarket||managerMarket;if(a.managerTransferOffers)setManagerTransferOffers(a.managerTransferOffers);removeScoutResult(id);managerScoutNotice=signingNotice(a.boughtPlayer||r.player||wanted,a.skillChange);renderManagerSeason();renderManagerScoutBox();return msg("managerMsg",`${(a.boughtPlayer||r.player||wanted)?.name||"Player"} signed for ${money(a.cashPrice??a.price??0)}`)}if(r.status==="bought"){managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerMarket=r.managerMarket||managerMarket;if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);removeScoutResult(id);managerScoutNotice=signingNotice(r.boughtPlayer||r.player||wanted,r.skillChange);renderManagerSeason();renderManagerScoutBox();return msg("managerMsg",`${(r.boughtPlayer||r.player||wanted)?.name||"Player"} signed for ${money(r.cashPrice??r.price??0)}`)}}
    async function finishBrowseTransfer(r,wanted){managerSeason=r.managerSeason||managerSeason;managerFinance=r.managerFinance||managerFinance;managerSquad=r.managerSquad||managerSquad;managerBrowseNotice=signingNotice(r.boughtPlayer||wanted,r.skillChange);renderManagerSeason();await openManagerBrowseTeam(managerBrowseTeam);const cash=Number(r.cashPrice??r.price??r.boughtPlayer?.purchasePrice??0),count=Number(r.offerPlayerCount||0),playerText=r.offerValue?` + ${count>1?"players":"player"} value ${money(r.offerValue)}`:"";msg("managerMsg",`${(r.boughtPlayer||wanted)?.name||"Player"} signed for ${money(cash)}${playerText}`)}
    async function browseTransferBid(teamUser,id,offer={}){const r=await api("browseTransferBid",{teamUser,playerId:id,...offer});if(!r.ok){if(r.error==="low_offer"){managerBrowseNotice=`<b>BID REJECTED</b>${safe(lowOfferText(r))}`;await openManagerBrowseTeam(teamUser);return msg("managerMsg","Bid rejected")}return msg("managerMsg",r.error==="too_many_offer_players"?`Max ${r.maxPlayers||3} players in one bid`:r.error==="bench_full"?benchFullText(r):r.error==="no_money"?"Not enough money":r.error==="human_transfer_locked"?"That manager is not available for deals":r.error==="no_replacement"?"Need enough bench cover before offering those players":"Could not make bid")}if(r.managerTransferOffers)setManagerTransferOffers(r.managerTransferOffers);if(r.status==="human_offer"){managerBrowseNotice=`<b>OFFER SENT</b>${safe(r.message||"Waiting for manager approval")}`;await openManagerBrowseTeam(teamUser);return msg("managerMsg","Offer sent")}if(r.status==="rejected"){managerBrowseNotice=`<b>BID REJECTED</b>${safe(r.message||"Club rejected the bid")} ${r.basePrice?`<br>${safe(lowOfferText(r))}`:""}`;await openManagerBrowseTeam(teamUser);return msg("managerMsg","Bid rejected")}if(r.status==="counter"){const player=r.player?.name||"Player",cash=Number(r.price||0),total=Number(r.counterTotal||r.offerTotal||cash),count=Number(r.offerPlayerCount||0),extra=r.offerValue?` including ${count>1?`${count} players`:"player"} value ${money(r.offerValue)}`:"",ok=await askConfirm("TRANSFER COUNTER",`${player}: club wants total ${money(total)}. Cash needed ${money(cash)}${extra}. Accept?`,"ACCEPT","DECLINE",false);if(!ok){managerBrowseNotice=`<b>COUNTER DECLINED</b>${safe(player)} stays at ${safe(r.team?.name||"the club")}`;await openManagerBrowseTeam(teamUser);return msg("managerMsg","Counter declined")}const a=await api("acceptBrowseTransfer",{offerId:r.offerId});if(!a.ok)return msg("managerMsg",a.error==="bench_full"?benchFullText(a):a.error==="no_money"?"Not enough money for counter offer":a.error==="no_replacement"?"Need enough bench cover before offering those players":"Could not accept counter offer");return finishBrowseTransfer(a,r.player)}if(r.status==="bought")return finishBrowseTransfer(r,r.boughtPlayer||r.player)}
    async function submitTransferOffer(){if(!transferOffer)return;const offer=transferOfferPayload(),kind=transferOffer.kind,id=transferOffer.player?.id,teamUser=transferOffer.teamUser,offerId=transferOffer.offerId,context=transferOffer.context;closeTransferOffer();if(kind==="counter")return counterManagerDeal(offerId,offer);if(kind==="market")return context==="scout"?buyScoutMarketPlayer(id,offer):buyManagerPlayer(id,offer);if(kind==="sell")return sellManagerPlayer(id,offer);return context==="scout"?browseScoutTransferBid(teamUser,id,offer):browseTransferBid(teamUser,id,offer)}
    function closeOptionsDropdowns(except=""){["optionsSoundDropdown"].forEach(id=>{if(id!==except)$(id)?.classList.add("hide")})}
    function toggleOptionsSoundDropdown(){const box=$("optionsSoundDropdown");if(!box)return;const open=box.classList.contains("hide");closeOptionsDropdowns(open?"optionsSoundDropdown":"");box.classList.toggle("hide",!open);if(open)updateSoundButton()}
    function openOptions(){setRoute("");renderUserTop();updateSoundButton();updateSiteLightButton();managerSaves=[];renderManagerSaves();closeOptionsDropdowns();msg("optionsMsg","");show("optionsPage");pushAppHistory()}
    function showAuthMode(mode){const create=mode==="create";$("loginForm").classList.toggle("hide",create);$("createForm").classList.toggle("hide",!create);$("showCreate").classList.toggle("hide",create);$("showLogin").classList.toggle("hide",!create);msg("authMsg","")}
    $("openLogin").onclick=()=>show("auth");
    $("showLogin").onclick=()=>showAuthMode("login");
    $("showCreate").onclick=()=>showAuthMode("create");
    $("transferBidMinus").onclick=()=>changeTransferBid(-1);
    $("transferBidPlus").onclick=()=>changeTransferBid(1);
    $("transferOfferPlayerButton").onclick=e=>{e.stopPropagation();$("transferOfferPlayerList").classList.toggle("hide")};
    $("transferOfferPlayerList").onclick=e=>{const b=e.target.closest("[data-transfer-offer-player]");if(!b)return;e.stopPropagation();chooseTransferOfferPlayer(b.dataset.transferOfferPlayer||"")};
    $("transferOfferCancel").onclick=closeTransferOffer;
    $("transferOfferSubmit").onclick=submitTransferOffer;
    $("transferOfferModal").onclick=e=>{if(e.target===$("transferOfferModal"))closeTransferOffer()};
    $("loginForm").onsubmit=async e=>{e.preventDefault();const d=Object.fromEntries(new FormData(e.target));const r=await api("login",d);if(!r.ok)return msg("authMsg","Wrong login");msg("authMsg","");await state()};
    $("createForm").onsubmit=async e=>{e.preventDefault();const d=Object.fromEntries(new FormData(e.target));const r=await api("register",d);if(!r.ok)return msg("authMsg",r.error==="user_exists"?"Login name exists":r.error==="bad_username"?"Login name must be 3-24 letters/numbers":r.error==="short_password"?"Password must be at least 3 characters":"Could not create account");msg("authMsg","");await state()};
    $("teamDropdown").onclick=e=>{e.stopPropagation();$("teamDropdownList").classList.toggle("hide")};
    document.addEventListener("scroll",e=>{const menu=managerTeamMenuFromEvent(e);if(menu)rememberManagerTeamMenuScroll(menu);else if(managerTeamMenuOpen)positionManagerTeamMenu()},true);
    document.addEventListener("wheel",e=>{
      const menu=managerTeamMenuFromEvent(e);
      if(!menu)return;
      rememberManagerTeamMenuScroll(menu);
      e.stopPropagation();
      const dy=e.deltaY||0,atTop=menu.scrollTop<=0,atBottom=menu.scrollTop+menu.clientHeight>=menu.scrollHeight-1;
      if((dy<0&&atTop)||(dy>0&&atBottom))e.preventDefault()
    },{capture:true,passive:false});
    document.addEventListener("touchstart",e=>{const menu=managerTeamMenuFromEvent(e);if(menu){managerTeamMenuTouchY=e.touches?.[0]?.clientY||0;rememberManagerTeamMenuScroll(menu)}},{capture:true,passive:true});
    document.addEventListener("touchmove",e=>{
      const menu=managerTeamMenuFromEvent(e);
      if(!menu)return;
      const y=e.touches?.[0]?.clientY||managerTeamMenuTouchY,dy=managerTeamMenuTouchY-y;
      managerTeamMenuTouchY=y;rememberManagerTeamMenuScroll(menu);e.stopPropagation();
      const atTop=menu.scrollTop<=0,atBottom=menu.scrollTop+menu.clientHeight>=menu.scrollHeight-1;
      if((dy<0&&atTop)||(dy>0&&atBottom))e.preventDefault()
    },{capture:true,passive:false});
    document.addEventListener("click",e=>{
      const teamToggle=e.target.closest("[data-manager-team-toggle]");
      if(teamToggle){e.preventDefault();managerTeamMenuOpen=managerTeamMenuOpen===teamToggle.dataset.managerTeamToggle?"":teamToggle.dataset.managerTeamToggle;renderTeamPickerOwners();return}
      const teamPick=e.target.closest("[data-manager-team-id]");
      if(teamPick){e.preventDefault();managerDraftTeams[String(teamPick.dataset.managerTeamUser||"").toLowerCase()]=teamPick.dataset.managerTeamId||"";managerTeamMenuOpen="";renderManagerCreate();return}
      const invitePick=e.target.closest("[data-invite-team-id]");
      if(invitePick){e.preventDefault();const inv=(managerInvites||[]).find(x=>String(x?.id||"")===String(invitePick.dataset.inviteId||""))||{id:invitePick.dataset.inviteId||""},user=String(invitePick.dataset.inviteUser||me?.name||"").toLowerCase();managerInviteDraftTeams[inviteDraftKey(inv,user)]=invitePick.dataset.inviteTeamId||"";managerTeamMenuOpen="";renderTeamPickerOwners();return}
      if(!$("teamPicker").contains(e.target))$("teamDropdownList").classList.add("hide");
      const p=$("transferOfferPlayerPicker");if(p&&!p.contains(e.target))closeTransferOfferPlayerMenu();
      if(managerTeamMenuOpen&&!e.target.closest(".manager-team-picker")){managerTeamMenuOpen="";renderTeamPickerOwners()}
    });
    async function openManagerTurnAlert(button){if(managerInteractionBusy())return;const idx=Number(button?.dataset?.managerTurnIndex||-1),alert=managerTurnAlerts[idx]||{},saveId=alert.saveId||button?.dataset?.managerTurnSave||"",seasonId=alert.seasonId||button?.dataset?.managerTurnSeason||"",managerGameId=alert.managerGameId||button?.dataset?.managerTurnGame||"";closeManagerMenus();const r=await api("managerSwitchTurnAlert",{saveId,seasonId,managerGameId});if(!r.ok){if(saveId)return loadManagerSave(saveId,{skipConfirm:true,message:"Your turn loaded"});return msg("managerMsg","Could not open that save")}me=r.user||me;teamChoices=r.teams||teamChoices;managerInvites=r.managerInvites||[];managerSeason=r.managerSeason||null;setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave,managerPrivateChatAlerts:r.managerPrivateChatAlerts});setManagerTurnAlerts(r.managerTurnAlerts);managerFinance=r.managerFinance||null;managerSquad=r.managerSquad||null;managerMarket=r.managerMarket||[];managerDivisions=r.managerDivisions||[];setManagerTransferOffers(r.managerTransferOffers);setRoute("manager");show("manager");await loadManager(false);replaceAppHistory();msg("managerMsg","Your turn loaded")}
    function openMainMenuFromManager(){msg("managerMsg","");stopManagerSimAnimation();goMainMenu(true)}
    function runManagerAction(v){if(!v||managerInteractionBusy())return;closeManagerMenus();if(v==="mainMenu"){openMainMenuFromManager();return}if(v==="home"){if(resumeManagerSimAnimation())return;renderManagerSeason();showManagerSection("managerHome");return}if(v==="play")watchManagerMatch();if(v==="simulate")playManagerViewedRound();if(v==="simSeason")playManagerSeason();if(v==="continue")return;if(v==="create"){if(!canInviteMoreManagers())return msg("managerMsg",managerSeasonStarted()?"League already started":"Invite already waiting");openManagerCreate()}if(v==="scorers")renderManagerScorersPage(true);if(v==="assists")renderManagerAssistsPage();if(v==="cups")renderManagerCupsPage();if(v==="reports")renderManagerReportsPage();if(v==="chat")renderManagerChatPage();if(v==="fixtures")renderManagerFixturesPage();if(v==="viewTeams")renderManagerViewTeamsPage();if(v==="economy")renderManagerEconomyPage();if(v==="transfers")renderManagerTransfersPage();if(v==="lineup")openManagerTeam(me?.name);if(v==="trophies")renderManagerTrophiesPage();if(v==="statsInfo")renderManagerStatsInfoPage();if(v==="options")openOptions();if(v==="admin")openAdmin();if(v==="abort")showAbortManagerConfirm();if(v==="squad"){renderManagerSquadPage();showManagerSection("managerSquadPage")}if(v==="market"){managerMarketNotice="";renderManagerMarketPage();showManagerSection("managerMarketPage")}if(v==="browse"){managerBrowseNotice="";renderManagerBrowsePage(managerBrowseLevel||managerFinance?.divisionLevel||5)}}
    $("managerActionButton").onclick=e=>{e.stopPropagation();if(managerInteractionBusy())return;setManagerActionMenuOpen($("managerActionList").classList.contains("hide"))};
    $("managerActionList").onclick=e=>{const turn=e.target.closest("[data-manager-turn-index]");if(turn&&!turn.disabled)return openManagerTurnAlert(turn);const b=e.target.closest("[data-manager-action]");if(!b||b.disabled)return;runManagerAction(b.dataset.managerAction)};
    $("managerChatForm").onsubmit=e=>{e.preventDefault();sendManagerChat()};
    $("managerChatUpload").onclick=()=>$("managerChatImageInput")?.click();
    $("managerChatImageInput").onchange=e=>uploadManagerChatImage(e.target.files?.[0]);
    $("managerChatUsers").onclick=toggleManagerChatUsers;
    $("managerChatUsersPanel").onclick=e=>{const league=e.target.closest("[data-manager-chat-league]");if(league)return openManagerLeagueChat();const b=e.target.closest("[data-manager-private-user]");if(!b||b.disabled)return;openManagerPrivateChat(b.dataset.managerPrivateUser)};
    $("managerViewTeamsPageList").onclick=e=>{const b=e.target.closest("[data-manager-view-team]");if(!b||b.disabled)return;renderManagerDivision(b.dataset.managerViewTeam)};
    $("managerUsers").onclick=e=>{const team=e.target.closest("[data-manager-solo-team-id]");if(team&&!team.disabled){chooseManagerSoloTeam(team.dataset.managerSoloTeamId);return}const b=e.target.closest("[data-user]");if(!b||b.disabled)return;toggleManagerUser(b.dataset.user)};
    $("managerUsers").onchange=e=>{const s=e.target.closest("[data-manager-team-user]");if(!s)return;managerDraftTeams[String(s.dataset.managerTeamUser||"").toLowerCase()]=s.value;renderManagerCreate()};
    document.addEventListener("click",e=>{const m=$("managerActionMenu");if(m&&!m.contains(e.target))closeManagerActionMenu()});
    $("teamForm").onsubmit=async e=>{e.preventDefault();const d=Object.fromEntries(new FormData(e.target));if(!d.teamId)return msg("teamMsg","Choose a team");const r=await api("selectTeam",d);if(!r.ok)return msg("teamMsg",r.error==="team_locked"?"This account already has a team":"Choose another team");msg("teamMsg","");await state()};
    async function logout(){stopManagerPoll();await api("logout");setRoute("");me=null;setMatch(null);renderUserTop();appHistoryDepth=0;show("auth");replaceAppHistory()}
    function clearClientManagerState(){stopManagerPoll();setRoute("");setMatch(null);managerSeason=null;managerCreateMode="";managerTeamMenuOpen="";managerDraftTeams={};managerPicked=[];managerHasSeason=false;managerCanContinue=false;managerHasAnySave=false;managerSaves=[];managerInvites=[];managerFinance=null;managerSquad=null;managerMarket=[];managerDivisions=[];setManagerTurnAlerts([]);setManagerTransferOffers({incoming:[],outgoing:[],notices:[]})}
    function hideAdminResetPanels(except=""){[["manager","resetManagerLeaguePanel"],["everything","resetEverythingPanel"]].forEach(([key,id])=>{if(key!==except)$(id)?.classList.add("hide")})}
    function toggleAdminResetPanel(kind){if(!me?.admin)return;const id=kind==="everything"?"resetEverythingPanel":"resetManagerLeaguePanel",panel=$(id);if(!panel)return;const open=panel.classList.contains("hide");hideAdminResetPanels(open?kind:"");panel.classList.toggle("hide",!open);msg("adminMsg","")}
    function handleAdminLoggedOut(message=""){clearClientManagerState();me=null;adminUsers=[];managerUsers=[];teamChoices=[];renderUserTop();syncMenuControls();syncAdminControls();appHistoryDepth=0;show("auth");replaceAppHistory();if(message)msg("authMsg",message)}
    async function resetGameData(){if(!me?.admin)return;if(!await askConfirm("RESET GAME DATA","Accounts and selected teams stay.\nMatches, manager leagues, squads, economy and progress are reset.","RESET","CANCEL"))return;const r=await api("resetGameData");if(!r.ok)return msg("menuMsg","Could not reset game data");clearClientManagerState();await state();msg("menuMsg","Game data reset")}
    async function loadAdminManager(){const r=await api("managerSetup");if(!r.ok){msg("adminMsg","Could not load manager league");return false}managerUsers=r.managerUsers||[];managerSeason=r.managerSeason||null;managerInvites=r.managerInvites||[];managerFinance=r.managerFinance||null;managerSquad=r.managerSquad||null;managerMarket=r.managerMarket||[];managerDivisions=r.managerDivisions||[];setManagerTurnAlerts(r.managerTurnAlerts);setManagerPrivateChatAlerts(r.managerPrivateChatAlerts);setManagerTransferOffers(r.managerTransferOffers);setManagerStateFlags({managerHasSeason:!!managerSeason,managerCanContinue:r.managerCanContinue??!!managerSeason,managerHasAnySave:r.managerHasAnySave,managerPrivateChatAlerts:r.managerPrivateChatAlerts});renderUserTop();syncMenuControls();syncManagerActions();syncAdminControls();return !!managerSeason}
    async function adminSimSeason(){if(!me?.admin)return;if(!managerSeason&&!await loadAdminManager())return msg("adminMsg","No active manager league");if(managerSeason?.status==="finished")return msg("adminMsg","Season already finished");await playManagerSeason("adminMsg",true)}
    function adminUserLine(u){const team=u?.team?.name||"NO TEAM",seen=u?.lastSeen?shortDate(u.lastSeen):"NEVER",created=u?.created?shortDate(u.created):"";return `<div class="admin-user-row"><div><b>${safe(String(u?.name||"").toUpperCase())}</b><small>${safe(team)} | seen ${safe(seen)}${created?` | created ${safe(created)}`:""}</small></div><button class="admin-user-delete" data-admin-delete-user="${safe(u?.name||"")}" type="button" ${u?.canDelete?"":"disabled"} title="Delete user">X</button></div>`}
    function renderAdminUsers(){const box=$("adminUsersPanel");if(!box)return;box.innerHTML=adminUsers.length?adminUsers.map(adminUserLine).join(""):`<div class="manager-meta">No users</div>`;box.classList.remove("hide")}
    async function loadAdminUsers(){if(!me?.admin)return;const r=await api("adminUsers");if(!r.ok)return msg("adminMsg","Could not load users");adminUsers=r.adminUsers||[];renderAdminUsers();msg("adminMsg","")}
    async function toggleAdminUsers(){const panel=$("adminUsersPanel");if(!panel||!me?.admin)return;if(!panel.classList.contains("hide")){panel.classList.add("hide");return}await loadAdminUsers()}
    async function deleteAdminUser(name){name=String(name||"");if(!me?.admin||!name)return;if(!await askConfirm("DELETE USER",`Delete ${name}?\nThis removes the account, active manager references and saves that include this user.`,"DELETE","CANCEL"))return;const r=await api("adminDeleteUser",{user:name});if(!r.ok)return msg("adminMsg",r.error==="bad_user"?"User not found":"Could not delete user");if(r.loggedOut||!r.user)return handleAdminLoggedOut(`Deleted ${name}`);adminUsers=r.adminUsers||[];managerUsers=r.managerUsers||managerUsers;teamChoices=r.teams||teamChoices;setManagerStateFlags(r);managerSeason=null;managerInvites=r.managerInvites||[];renderAdminUsers();renderManagerChatUsersPanel();syncMenuControls();syncManagerActions();msg("adminMsg",`Deleted ${name}${r.deletedSaves?` | saves ${r.deletedSaves}`:""}`)}
    async function openAdmin(){if(!me?.admin)return;stopPoll();stopManagerPoll();stopCrowd();setMatch(null);setRoute("");renderUserTop();msg("adminMsg","");adminUsers=[];$("adminUsersPanel")?.classList.add("hide");hideAdminResetPanels();show("admin");syncAdminControls();pushAppHistory();if(managerHasSeason&&!managerSeason)await loadAdminManager()}
    async function resetManagerLeague(){if(!me?.admin)return;const r=await api("resetManagerLeague");if(!r.ok)return msg("adminMsg","Could not reset manager league");hideAdminResetPanels();clearClientManagerState();teamChoices=r.teams||teamChoices;me=r.user||me;renderUserTop();goMainMenu(true);msg("menuMsg","Manager league reset")}
    async function resetEverything(){if(!me?.admin)return;const r=await api("resetEverything");if(!r.ok)return msg("adminMsg","Could not reset everything");hideAdminResetPanels();handleAdminLoggedOut("Everything reset")}
    $("logout").onclick=$("logoutTeam").onclick=$("appTopLogout").onclick=logout;
    $("adminMenu").onclick=openAdmin;
    $("adminSimSeason").onclick=adminSimSeason;
    $("adminUsersButton").onclick=toggleAdminUsers;
    $("adminUsersPanel").onclick=e=>{const b=e.target.closest("[data-admin-delete-user]");if(!b||b.disabled)return;deleteAdminUser(b.dataset.adminDeleteUser)};
    $("adminBack").onclick=()=>{msg("adminMsg","");goBackOrMenu()};
    $("resetManagerLeague").onclick=()=>toggleAdminResetPanel("manager");
    $("resetEverything").onclick=()=>toggleAdminResetPanel("everything");
    $("confirmResetManagerLeague").onclick=resetManagerLeague;
    $("cancelResetManagerLeague").onclick=()=>hideAdminResetPanels();
    $("confirmResetEverything").onclick=resetEverything;
    $("cancelResetEverything").onclick=()=>hideAdminResetPanels();
    $("resetGameData").onclick=resetGameData;
    $("options").onclick=openOptions;
    $("optionsBack").onclick=()=>{msg("optionsMsg","");goBackOrMenu()};
    $("optionsSoundButton").onclick=toggleOptionsSoundDropdown;
    $("siteLightButton").onclick=cycleSiteLightLevel;
    $("soundToggle").onclick=()=>setSoundEnabled(!soundAllEnabled());
    $("optionsForm").onsubmit=async e=>{e.preventDefault();const d=Object.fromEntries(new FormData(e.target));const r=await api("changePassword",d);msg("optionsMsg",r.ok?"Password saved":r.error==="short_password"?"Password too short":"Wrong current password");if(r.ok)e.target.reset()};
    $("managerSaveButton").onclick=()=>openManagerSaves(true);
    $("managerSavesBack").onclick=()=>{msg("managerSavesMsg","");goBackOrMenu()};
    $("managerMode").onclick=()=>openNewManagerGame({mode:"solo"});
    $("inviteUserMode").onclick=openInviteUserFromMenu;
    $("startNewManagerMode").onclick=()=>openNewManagerGame({mode:"solo"});
    $("managerPowerOff").onclick=openMainMenuFromManager;
    $("managerBack").onclick=()=>{msg("managerMsg","");if(currentManagerSection()==="managerHome"){stopManagerPoll();setRoute("");goMainMenu(true);return}if(currentManagerSection()==="managerTeamPage"){backFromManagerTeam();return}goBackOrMenu()};
    $("cancelManagerCreate").onclick=()=>{if(managerSeason)goBackOrMenu();else goBackOrMenu()};
    $("managerSquadBack").onclick=goBackOrMenu;
    $("managerFullSquadBack").onclick=goBackOrMenu;
    $("managerMarketBack").onclick=goBackOrMenu;
    $("managerEconomyBack").onclick=goBackOrMenu;
    $("managerTransfersBack").onclick=resumeManagerDealReturnOrBack;
    $("managerDealsBack").onclick=resumeManagerDealReturnOrBack;
    $("managerBrowseBack").onclick=goBackOrMenu;
    $("managerBrowseTeamBack").onclick=goBackOrMenu;
    $("transfersSquadSell").onclick=()=>{renderManagerSquadPage();showManagerSection("managerSquadPage")};
    $("transfersMarket").onclick=()=>{managerMarketNotice="";renderManagerMarketPage();showManagerSection("managerMarketPage")};
    $("transfersBrowse").onclick=()=>{managerBrowseNotice="";renderManagerBrowsePage(managerBrowseLevel||managerFinance?.divisionLevel||5)};
    $("transfersDeals").onclick=renderManagerDealsPage;
    $("transfersStaff").onclick=showManagerStaffBox;
    $("transfersScout").onclick=showManagerScoutBox;
    $("managerDivisionBack").onclick=goBackOrMenu;
    $("managerScorersBack").onclick=goBackOrMenu;
    $("managerAssistsBack").onclick=goBackOrMenu;
    $("managerReportsBack").onclick=goBackOrMenu;
    $("managerChatBack").onclick=goBackOrMenu;
    $("managerCupsBack").onclick=goBackOrMenu;
    $("managerSimBack").onclick=closeManagerSimToLeague;
    $("managerFixturesBack").onclick=goBackOrMenu;
    $("managerViewTeamsPageBack").onclick=goBackOrMenu;
    $("managerStatsInfoBack").onclick=goBackOrMenu;
    $("managerTrophiesBack").onclick=goBackOrMenu;
    $("managerTeamBack").onclick=backFromManagerTeam;
    $("startManagerLeague").onclick=startManagerLeague;
    $("trainingDivisionButton").onclick=e=>{e.stopPropagation();closeTrainingDropdowns("division");$("trainingDivisionList").classList.toggle("hide")};
    $("trainingTeamButton").onclick=e=>{e.stopPropagation();closeTrainingDropdowns("team");$("trainingTeamList").classList.toggle("hide")};
    document.addEventListener("click",e=>{if(!$("trainingDivisionPicker").contains(e.target)&&!$("trainingTeamPicker").contains(e.target))closeTrainingDropdowns()});
    if($("speedScenario"))$("speedScenario").onclick=()=>openTraining("speed");
    if($("shootScenario"))$("shootScenario").onclick=()=>openTraining("shoot");
    $("startSpeedTest").onclick=startSpeedRace;
    $("startShootTest").onclick=startShootTest;
    $("clearSpeedTest").onclick=clearTrainingSelection;
    $("trainingBack").onclick=closeTraining;
    $("startMatch").onclick=async()=>{ensureAudio();const r=await api("start");if(!r.ok)return;setMatch(r.match);playCrowd();renderMatch();startPoll()};
    $("skipLineup").onclick=()=>{lineupUntil=performance.now();renderMatch()};
    $("subMatch").onclick=async()=>{ensureAudio();const r=await api("substitute");if(!r.ok){$("subMatch").textContent=r.error==="subs_used"?`BYTEN ${MAX_MATCH_SUBS}/${MAX_MATCH_SUBS}`:"NO SUB";setTimeout(renderMatch,800);return}setMatch(r.match);renderMatch()};
    async function leaveMatchToMenu(){const managerMatch=isManagerMatch();await api("leave");setMatch(null);stopPoll();if(appHistoryDepth>0){history.back();return}await returnFromMatch(managerMatch)}
    $("cancelWait").onclick=leaveMatchToMenu;
    $("toMenu").onclick=async()=>{if(trainingMode){toggleTrainingMenu();return}await leaveMatchToMenu()};
    $("matchMenu").onclick=leaveMatchToMenu;
    $("leaveMatch").onclick=leaveMatchToMenu;
    $("refreshMatch").onclick=state;
    document.querySelectorAll("[data-mode]").forEach(b=>b.onclick=async()=>{ensureAudio();document.querySelectorAll("[data-mode]").forEach(x=>x.classList.remove("green"));b.classList.add("green");await api("tactic",{mode:b.dataset.mode});await state()});
    async function pollState(){if(pollBusy)return;pollBusy=true;try{await state(true)}finally{pollBusy=false}}
    function startPoll(){stopPoll();poll=setInterval(pollState,POLL_MS)}
    function stopPoll(){if(poll)clearInterval(poll);poll=null;pollBusy=false}
    function layout(){const c=$("field"),r=c.getBoundingClientRect(),d=Math.min(2,devicePixelRatio||1);W=Math.max(320,r.width|0);H=Math.max(320,r.height|0);let cw=Math.round(W*d),ch=Math.round(H*d);if(c.width!==cw||c.height!==ch){c.width=cw;c.height=ch}const g=c.getContext("2d");g.setTransform(d,0,0,d,0,0);let port=W/H<.8,ratio=68/105;if(port){let mm=96/25.4,edge=6,sideOut=mm,goalOut=mm,top=Math.max(72,Math.min(92,H*.11)),controlsTop=H-78,hLimit=Math.max(240,(controlsTop-top-goalOut-12)/(1+2.44/105)),w=Math.min(W-2*(edge+sideOut),hLimit*ratio),h=w/ratio;p={x:(W-w)/2,y:top,w,h};return g}let top=Math.max(70,H*.09),bot=Math.max(150,H*.18),side=Math.max(40,W*.04),aw=W-2*side,ah=Math.max(240,H-top-bot),w=Math.min(aw*.55,ah*ratio),h=Math.min(ah,w/ratio),down=Math.min(76,Math.max(54,H*.085));p={x:(W-w)/2,y:top+(ah-h)/2+down,w,h};return g}
    function showIntroNow(ready){if(!ready||!match)return false;const now=performance.now();if(introMatchId!==match.id){introMatchId=match.id;introUntil=now+INTRO_MS;if(crowdMatchId!==match.id){crowdMatchId=match.id;playCrowd()}}return now<introUntil}
    function showLineupNow(ready){if(!ready||!match)return false;const now=performance.now();if(lineupMatchId!==match.id){lineupMatchId=match.id;lineupUntil=now+LINEUP_MS}return now<lineupUntil}
    function introFrame(frame){if(!match||introMatchId!==match.id||performance.now()>=introUntil)return frame;let base=clamp(1-(introUntil-performance.now())/INTRO_MS,0,1),out={ball:frame.ball,units:{home:{},away:{}}},ease=t=>t*t*(3-2*t);["home","away"].forEach(side=>{Object.keys(frame.units[side]||{}).forEach((id,i)=>{let v=frame.units[side][id],targetY=side==="home"?Math.max(v.y,.535):Math.min(v.y,.465),st=ease(clamp((base-i*.016)/.86,0,1)),lane=side==="away"?.055:0,x0=1.18+lane+i*.01,y0=.5,mid={x:.62+lane-(i%4)*.018,y:.5};if(st<.46){let q=ease(st/.46);out.units[side][id]={x:lerp(x0,mid.x,q),y:y0}}else{let q=ease((st-.46)/.54);out.units[side][id]={x:lerp(mid.x,v.x,q),y:lerp(mid.y,targetY,q)}}})});return out}
    function lineupPosition(i,u){const hx=Number(u.homeX??u.x),hy=Number(u.homeY??u.y);if(Number.isFinite(hx)&&Number.isFinite(hy))return{x:clamp(hx,.08,.92),y:clamp(hy,.10,.86)};const base=[[.50,.82],[.18,.66],[.38,.68],[.62,.68],[.82,.66],[.16,.47],[.38,.50],[.62,.50],[.84,.47],[.38,.25],[.62,.25]],roles=["GK","LB","CB","CB","RB","LM","CM","CM","RM","ST","ST"],role=u.slotRole||u.role||"",p=base.find((_,n)=>roles[n]===role)||base[i]||[.5,.5];return{x:p[0],y:p[1]}}
    function renderLineup(){if(!match)return;const home=match.teams.home,away=match.teams.away;$("lineHome").textContent=home.name;$("lineAway").textContent=away.name;const draw=(id,team,units)=>{let flag=lineFlag(team),name=`<div class="line-team-name">${safe(team.name||"TEAM")}</div>`,players=(units||[]).map((u,i)=>{let pos=lineupPosition(i,u),x=pos.x*100,y=pos.y*100;return `<div class="line-player" style="left:${x}%;top:${y}%;--shirt:${safe(team.shirt||"#fff")};--trim:${safe(team.trim||"#111")}"><span class="line-head"></span><span>${safe(u.name||u.id||u.role||"Player")}</span></div>`}).join("");$(id).innerHTML=flag+players+name};draw("lineHomeGrid",home,match.units?.home);draw("lineAwayGrid",away,match.units?.away)}
    function renderMatch(){const waiting=match&&match.status==="waiting",ready=match&&match.status==="ready",active=match&&["ready","active","finished"].includes(match.status),intro=showIntroNow(ready),lineup=!intro&&showLineupNow(ready);syncManagerMenuMusic();maintainCrowd();renderGoalBanner();$("wait").classList.toggle("hide",!waiting);$("hud").classList.toggle("hide",!active);$("controls").classList.toggle("hide",!active||intro||lineup);$("toMenu").classList.add("hide");$("lineup").classList.toggle("hide",!lineup);$("startMatch").classList.toggle("hide",!ready||intro||lineup);if(lineup)renderLineup();if(waiting){$("waitText").textContent="WAITING FOR OPPONENT";drawEmpty();return}if(!active){drawEmpty();return}const home=match.teams.home,away=match.teams.away,rt=match.ratings||{},frame=introFrame(sampleFrame()),side=match.side||"home",subs=match.engine?.subsUsed?.[side]||0;$("homeName").innerHTML=teamLabel(home,rt.home,false);$("awayName").innerHTML=teamLabel(away,rt.away,true);$("scoreScorers").innerHTML=goalScorerHtml(match.engine?.goalScorers||[]);$("matchType").textContent=currentLiveMatchTypeText();$("subMatch").textContent=`BYTEN ${subs}/${MAX_MATCH_SUBS}`;$("subMatch").disabled=subs>=MAX_MATCH_SUBS;$("hs").textContent=match.score[0];$("as").textContent=match.score[1];let total=Math.max(0,Math.min(90*60,Math.floor((match.elapsed||0)*60)));$("time").textContent=String(total/60|0).padStart(2,"0")+":"+String(total%60).padStart(2,"0");$("events").innerHTML=(match.events||[]).slice(-5).map(eventLineHtml).join("");drawField(home,away,frame)}
    function drawEmpty(){const g=layout();g.fillStyle="#050407";g.fillRect(0,0,W,H)}
    function drawGoalFlutter(g,gx,gd,gw){if(!goalFx)return;const age=(performance.now()-goalFx.at)/1000;if(age>2.3){goalFx=null;return}const top=goalFx.net==="top",baseY=top?-gd:p.h,fade=1-age/2.3,amp=gd*(.12+.30*fade),phase=age*20;g.save();g.strokeStyle=`rgba(255,255,255,${.22+.62*fade})`;g.lineWidth=Math.max(1,p.w*.004);for(let i=0;i<=7;i++){let x=gx+gw*i/7,wig=Math.sin(phase+i*.8)*amp;g.beginPath();g.moveTo(x,top?-gd:p.h);g.quadraticCurveTo(x+wig*.42,baseY+(top?gd*.5:-gd*.5),x+wig,top?0:p.h);g.stroke()}for(let j=1;j<=4;j++){let y=top?-gd+gd*j/5:p.h+gd*j/5,wig=Math.sin(phase+j)*amp*.62;g.beginPath();g.moveTo(gx,y);g.quadraticCurveTo(gx+gw*.5,y+wig,gx+gw,y-wig*.35);g.stroke()}g.restore()}
    function visualBallOwner(frame){if(trainingMode)return null;const engineOwner=match?.engine?.owner;if(engineOwner?.side&&engineOwner?.id)return engineOwner;const ball=frame?.ball||match?.ball;if(!match||!ball||(ball.z||0)>.035||match?.engine?.shot)return null;let best=null,bestD=.0009;["home","away"].forEach(side=>{(match.units?.[side]||[]).forEach(u=>{const v=frame?.units?.[side]?.[u.id]||u,dx=(v.x??u.x)-ball.x,dy=(v.y??u.y)-ball.y,d=dx*dx+dy*dy;if(d<bestD){bestD=d;best={side,id:u.id}}})});return best}
    function drawField(home,away,frame){const g=layout(),ball=frame.ball||match.ball||{x:.5,y:.5,z:0},owner=visualBallOwner(frame);g.fillStyle="#050407";g.fillRect(0,0,W,H);g.fillStyle="#1b111f";g.fillRect(0,p.y-42,W,28);g.fillRect(0,p.y+p.h+14,W,28);g.save();g.translate(p.x,p.y);for(let i=0;i<12;i++){g.fillStyle=i%2?"#238143":"#176d35";g.fillRect(0,p.h/12*i,p.w,p.h/12+1)}g.strokeStyle="#f3f0ff";g.lineWidth=Math.max(2,p.w*.006);g.strokeRect(0,0,p.w,p.h);g.beginPath();g.moveTo(0,p.h/2);g.lineTo(p.w,p.h/2);g.stroke();let L=105,FW=68,goal=7.32,goalH=2.44,pen=16.5,box=5.5,spot=11,arc=9.15,cr=p.h*(arc/L);g.beginPath();g.arc(p.w/2,p.h/2,cr,0,7);g.stroke();let bw=p.w*((goal+pen*2)/FW),bh=p.h*(pen/L),sw=p.w*((goal+box*2)/FW),sh=p.h*(box/L),gw=p.w*(goal/FW),gd=Math.max(6,p.h*(goalH/L)),gx=(p.w-gw)/2,pt=p.h*(spot/L),pb=p.h*(1-spot/L),pr=Math.max(1.8,p.w*.006),aa=Math.asin((pen-spot)/arc),post=Math.max(2,p.w*.008);g.strokeRect((p.w-bw)/2,0,bw,bh);g.strokeRect((p.w-bw)/2,p.h-bh,bw,bh);g.strokeRect((p.w-sw)/2,0,sw,sh);g.strokeRect((p.w-sw)/2,p.h-sh,sw,sh);g.beginPath();g.arc(p.w/2,pt,cr,aa,Math.PI-aa);g.stroke();g.beginPath();g.arc(p.w/2,pb,cr,Math.PI+aa,Math.PI*2-aa);g.stroke();g.fillStyle="#f3f0ff";g.beginPath();g.arc(p.w/2,pt,pr,0,7);g.fill();g.beginPath();g.arc(p.w/2,pb,pr,0,7);g.fill();g.fillStyle="rgba(235,235,255,.1)";g.fillRect(gx,-gd,gw,gd);g.fillRect(gx,p.h,gw,gd);g.strokeRect(gx,-gd,gw,gd);g.strokeRect(gx,p.h,gw,gd);g.fillStyle="#f3f0ff";g.fillRect(gx-post/2,-gd,post,gd+post);g.fillRect(gx+gw-post/2,-gd,post,gd+post);g.fillRect(gx-post/2,p.h-post,post,gd+post);g.fillRect(gx+gw-post/2,p.h-post,post,gd+post);g.lineWidth=1;for(let i=1;i<5;i++){let x=gx+gw*i/5;g.beginPath();g.moveTo(x,-gd);g.lineTo(x,0);g.moveTo(x,p.h);g.lineTo(x,p.h+gd);g.stroke()}drawGoalFlutter(g,gx,gd,gw);g.restore();drawPlayers(home,0,match?.units?.home,frame.units.home,owner);drawPlayers(away,1,match?.units?.away,frame.units.away,owner);if(!trainingMode)drawReferee(g,match?.referee,ball);let bx=p.x+p.w*ball.x,by=p.y+p.h*ball.y,bz=(ball.z||0)*p.h*.45,br=Math.max(4,p.w*.014);g.fillStyle="rgba(0,0,0,.32)";g.beginPath();g.ellipse(bx,by,br*(1.1+Math.min(.8,ball.z||0)),br*.42,0,0,7);g.fill();g.fillStyle="#fff";g.strokeStyle="#151515";g.lineWidth=1.5;g.beginPath();g.arc(bx,by-bz,br,0,7);g.fill();g.stroke()}
    const baseDrawField=drawField;
    function drawGoalFrameOverlay(){const g=$("field").getContext("2d");if(!p.w||!p.h)return;const L=105,FW=68,goal=7.32,goalH=2.44,gw=p.w*(goal/FW),gd=Math.max(7,p.h*(goalH/L)),gx=p.x+(p.w-gw)/2,post=Math.max(2.4,p.w*.009),now=performance.now();function one(top){const y=top?p.y:p.y+p.h,dir=top?-1:1,active=goalFx&&((top&&goalFx.net==="top")||(!top&&goalFx.net==="bottom")),age=active?(now-goalFx.at)/1000:9,fade=active?clamp(1-age/2.3,0,1):0,phase=age*22,amp=gd*(.06+.22*fade);g.save();g.lineCap="round";g.lineJoin="round";g.strokeStyle="rgba(235,235,255,.28)";g.lineWidth=Math.max(1,p.w*.003);for(let i=0;i<=8;i++){let x=gx+gw*i/8,wig=active?Math.sin(phase+i*.7)*amp:0;g.beginPath();g.moveTo(x,y);g.quadraticCurveTo(x+wig*.45,y+dir*gd*.52,x+wig*.18,y+dir*gd);g.stroke()}for(let j=1;j<=4;j++){let yy=y+dir*gd*j/4,wig=active?Math.sin(phase+j*.9)*amp*.45:0;g.beginPath();g.moveTo(gx,yy);g.quadraticCurveTo(gx+gw*.5,yy+wig,gx+gw,yy-wig*.35);g.stroke()}g.strokeStyle="#f8f7ff";g.lineWidth=post;g.beginPath();g.moveTo(gx,y);g.lineTo(gx+gw,y);g.moveTo(gx,y);g.lineTo(gx,y+dir*gd);g.moveTo(gx+gw,y);g.lineTo(gx+gw,y+dir*gd);g.stroke();g.strokeStyle="rgba(248,247,255,.72)";g.lineWidth=Math.max(1.4,post*.55);g.beginPath();g.moveTo(gx,y+dir*gd);g.lineTo(gx+gw,y+dir*gd);g.moveTo(gx,y+dir*gd);g.lineTo(gx,y);g.moveTo(gx+gw,y+dir*gd);g.lineTo(gx+gw,y);g.stroke();g.restore()}one(true);one(false)}
    function drawBallPattern(ball){const g=$("field").getContext("2d"),bx=p.x+p.w*ball.x,by=p.y+p.h*ball.y,bz=(ball.z||0)*p.h*.45,br=Math.max(4,p.w*.014),cy=by-bz;g.save();g.lineJoin="round";g.lineCap="round";g.strokeStyle="#111";g.fillStyle="#111";g.lineWidth=Math.max(1,br*.13);g.beginPath();for(let i=0;i<5;i++){let a=-Math.PI/2+i*Math.PI*2/5,r=i%2?br*.28:br*.46;g.lineTo(bx+Math.cos(a)*r,cy+Math.sin(a)*r)}g.closePath();g.fill();for(let i=0;i<5;i++){let a=-Math.PI/2+i*Math.PI*2/5,x=bx+Math.cos(a)*br*.82,y=cy+Math.sin(a)*br*.82;g.beginPath();g.moveTo(bx+Math.cos(a)*br*.38,cy+Math.sin(a)*br*.38);g.lineTo(x,y);g.stroke();g.beginPath();g.arc(x,y,br*.17,0,7);g.fill()}g.strokeStyle="rgba(0,0,0,.42)";g.lineWidth=Math.max(1,br*.09);g.beginPath();g.arc(bx,cy,br*.72,.15,Math.PI*.92);g.stroke();g.restore()}
    function drawBallBoyOverlay(){const r=match?.engine?.restart;if(!r?.type||!r.out||!r.spot||!p.w)return;let start=Number(r.rollUntil||r.startedAt||match.elapsed||0),end=Number(r.deliveryUntil||start),span=Math.max(.1,end-start),t=clamp(((match.elapsed||0)-start)/span,0,1);if(t<=0||t>=1)return;const g=$("field").getContext("2d"),ease=x=>x*x*(3-2*x),q=ease(t),ox=Number(r.out.x??r.spot.x),oy=Number(r.out.y??r.spot.y),tx=Number(r.spot.x??.5),ty=Number(r.spot.y??.5),nearX=lerp(ox,tx,.82),nearY=lerp(oy,ty,.82);let bx,by,bz=0,boyX,boyY;if(q<.72){let n=ease(q/.72);boyX=lerp(ox,nearX,n);boyY=lerp(oy,nearY,n);bx=boyX;by=boyY;bz=.035}else{let n=ease((q-.72)/.28);boyX=nearX;boyY=nearY;bx=lerp(nearX,tx,n);by=lerp(nearY,ty,n);bz=Math.sin(n*Math.PI)*.10}const x=p.x+p.w*boyX,y=p.y+p.h*boyY,s=Math.max(5,Math.min(9,p.w*.021));g.save();g.fillStyle="rgba(0,0,0,.25)";g.beginPath();g.ellipse(x,y+s*.95,s*.75,s*.25,0,0,7);g.fill();g.strokeStyle="#1b0d0a";g.lineCap="round";g.lineWidth=Math.max(1.5,s*.18);g.beginPath();g.moveTo(x-s*.18,y+s*.05);g.lineTo(x-s*.40,y+s*.72);g.moveTo(x+s*.18,y+s*.05);g.lineTo(x+s*.42,y+s*.72);g.stroke();g.fillStyle="#1677d2";g.strokeStyle="#101010";g.lineWidth=Math.max(1,s*.12);g.fillRect(x-s*.42,y-s*.46,s*.84,s*.72);g.strokeRect(x-s*.42,y-s*.46,s*.84,s*.72);g.strokeStyle="#d8a06f";g.lineWidth=Math.max(1.5,s*.16);g.beginPath();g.moveTo(x-s*.42,y-s*.2);g.lineTo(x-s*.76,y+s*.1);g.moveTo(x+s*.42,y-s*.2);g.lineTo(x+s*.76,y+s*.1);g.stroke();g.fillStyle="#d8a06f";g.beginPath();g.arc(x,y-s*.85,s*.28,0,7);g.fill();drawSmallBall(g,bx,by,bz,Math.max(3,p.w*.01));g.restore()}
    function drawSmallBall(g,x,y,z,r){let bx=p.x+p.w*x,by=p.y+p.h*y-(z||0)*p.h*.45;g.fillStyle="#fff";g.strokeStyle="#111";g.lineWidth=1.2;g.beginPath();g.arc(bx,by,r,0,7);g.fill();g.stroke();g.fillStyle="#111";g.beginPath();g.arc(bx,by,r*.32,0,7);g.fill()}
    drawField=function(home,away,frame){baseDrawField(home,away,frame);drawBallBoyOverlay();drawGoalFrameOverlay();let b=frame.ball||match.ball||{x:.5,y:.5,z:0};if(b.x>=-.08&&b.x<=1.08&&b.y>=-.16&&b.y<=1.16)drawBallPattern(b)}
    function drawReferee(g,ref,ball){let tx=ref?.x??.975,ty=ref?.y??clamp((ball?.y||.5)+.03,.04,.96);if(!refView)refView={x:tx,y:ty};refView.x=lerp(refView.x,tx,.18);refView.y=lerp(refView.y,ty,.18);let x=p.x+p.w*refView.x,y=p.y+p.h*refView.y,s=Math.max(6,Math.min(11,p.w*.025));g.save();g.fillStyle="rgba(0,0,0,.3)";g.beginPath();g.ellipse(x,y+s*.78,s*.8,s*.28,0,0,7);g.fill();g.lineCap="round";g.strokeStyle="#111";g.lineWidth=Math.max(2,s*.18);g.beginPath();g.moveTo(x-s*.22,y+s*.18);g.lineTo(x-s*.45,y+s*.9);g.moveTo(x+s*.22,y+s*.18);g.lineTo(x+s*.45,y+s*.9);g.stroke();g.fillStyle="#f0d84e";g.strokeStyle="#111";g.lineWidth=Math.max(1,s*.13);g.fillRect(x-s*.46,y-s*.42,s*.92,s*.78);g.strokeRect(x-s*.46,y-s*.42,s*.92,s*.78);g.strokeStyle="#111";g.lineWidth=Math.max(2,s*.14);g.beginPath();g.moveTo(x-s*.5,y-s*.25);g.lineTo(x-s*.86,y+s*.12);g.moveTo(x+s*.5,y-s*.25);g.lineTo(x+s*.86,y+s*.12);g.stroke();g.fillStyle="#d8a06f";g.beginPath();g.arc(x,y-s*.85,s*.32,0,7);g.fill();g.fillStyle="#111";g.beginPath();g.arc(x,y-s*1.05,s*.34,Math.PI,0);g.fill();if(ref?.card==="yellow"){g.fillStyle="#ffd900";g.strokeStyle="#111";g.lineWidth=1;g.fillRect(x+s*.55,y-s*1.8,s*.34,s*.52);g.strokeRect(x+s*.55,y-s*1.8,s*.34,s*.52)}if(ref?.whistle){g.strokeStyle="#fff";g.lineWidth=Math.max(1,s*.12);g.beginPath();g.arc(x+s*.5,y-s*.92,s*.18,0,7);g.stroke();g.beginPath();g.moveTo(x+s*.66,y-s*.9);g.lineTo(x+s*1.02,y-s*.78);g.stroke()}g.restore()}
    function drawOwnerNumber(g,x,y,s,num){g.save();g.font=Math.max(9,s*.9)+"px Arial";g.textAlign="center";g.textBaseline="middle";g.fillStyle="#ffdd45";g.strokeStyle="#000";g.lineWidth=3;g.strokeText(String(num),x,y-s*2.25);g.fillText(String(num),x,y-s*2.25);g.restore()}
    function playerNum(u,i){return u?.shirtNumber||u?.legacyNumber||String(i+1)}
    function weightScale(w){return w==="light"?.9:w==="heavy"?1.1:1}
    function drawPlayers(team,side,units,sampled,visualOwner=null){const g=$("field").getContext("2d"),shirt=team.shirt||(side?"#11bcc7":"#ff6d10"),trim=team.trim||"#111",s=Math.max(6.3,Math.min(11.7,p.w*.027)),sideName=side?"away":"home",fk=match?.engine?.freeKick,owner=visualOwner||match?.engine?.owner;if(units&&units.length){units.forEach((u,i)=>{let v=sampled&&sampled[u.id]||u,ps=u.shirt||shirt,pt=u.trim||trim,raised=!!(fk?.signal&&fk?.side===sideName&&fk?.kicker===u.id),x=p.x+p.w*v.x,y=p.y+p.h*v.y,ss=s*weightScale(u.weightClass||v.weightClass);drawPlayer(g,x,y,ss,u.role==="GK"?(side?"#48d7ff":"#ffe05d"):ps,pt,side,u.rating,u.role==="GK",i,raised);if(owner?.side===sideName&&String(owner?.id)===String(u.id))drawOwnerNumber(g,x,y,ss,playerNum(u,i))});return}if(trainingMode)return;const base=[[.5,.94,1],[.18,.78,0],[.38,.8,0],[.62,.8,0],[.82,.78,0],[.16,.58,0],[.38,.61,0],[.62,.61,0],[.84,.58,0],[.38,.36,0],[.62,.36,0]];base.forEach((a,i)=>{let x=p.x+p.w*a[0],y=p.y+p.h*(side?1-a[1]:a[1]);drawPlayer(g,x,y,s,a[2]? (side?"#48d7ff":"#ffe05d"):shirt,trim,side,"",!!a[2],i,false)})}
    function drawPlayer(g,x,y,s,shirt,trim,side,rating,keeper,idx,raised=false){const face=-1,walk=match&&match.status==="active"?Math.sin(performance.now()/150+idx*.9)*s*.12:0,skin=["#f0c8a8","#d8a06f","#8f563b"][idx%3],hair=["#24140f","#4d2c17","#111"][idx%3],line=Math.max(1,s*.13),headY=y+face*s*.72,shoulderY=y+face*s*.12,hipY=y-face*s*.42,footY=y-face*s*.95,shoeY=footY-face*Math.abs(walk);g.fillStyle="rgba(0,0,0,.34)";g.beginPath();g.ellipse(x,y+s*.82,s*.88,s*.32,0,0,7);g.fill();g.lineCap="round";g.lineJoin="round";g.strokeStyle=trim;g.lineWidth=Math.max(2,s*.2);g.beginPath();g.moveTo(x-s*.22,hipY);g.lineTo(x-s*.45,shoeY);g.moveTo(x+s*.22,hipY);g.lineTo(x+s*.45,footY+face*Math.abs(walk));g.stroke();g.strokeStyle=shirt;g.lineWidth=Math.max(2,s*.28);g.beginPath();g.moveTo(x-s*.18,hipY-face*s*.04);g.lineTo(x-s*.43,shoeY);g.moveTo(x+s*.18,hipY-face*s*.04);g.lineTo(x+s*.43,footY+face*Math.abs(walk));g.stroke();g.fillStyle=trim;g.fillRect(x-s*.56,hipY-face*s*.1,s*1.12,s*.22);g.fillStyle=shirt;g.strokeStyle=trim;g.lineWidth=line;g.beginPath();g.moveTo(x-s*.68,shoulderY);g.lineTo(x+s*.68,shoulderY);g.lineTo(x+s*.48,hipY);g.lineTo(x-s*.48,hipY);g.closePath();g.fill();g.stroke();g.save();g.beginPath();g.moveTo(x-s*.62,shoulderY);g.lineTo(x+s*.62,shoulderY);g.lineTo(x+s*.42,hipY);g.lineTo(x-s*.42,hipY);g.closePath();g.clip();g.fillStyle=keeper?"rgba(255,255,255,.28)":trim;g.fillRect(x-s*.1,Math.min(shoulderY,hipY),s*.2,Math.abs(hipY-shoulderY));if(!keeper){g.globalAlpha=.5;g.fillRect(x-s*.48,Math.min(shoulderY,hipY)+Math.abs(hipY-shoulderY)*.46,s*.96,s*.16)}g.restore();g.strokeStyle=skin;g.lineWidth=Math.max(2,s*.2);g.beginPath();g.moveTo(x-s*.62,shoulderY+face*s*.02);g.lineTo(x-s*.88,y-face*s*.22);g.moveTo(x+s*.62,shoulderY+face*s*.02);if(raised){g.lineTo(x+s*.72,y+face*s*1.22);g.moveTo(x+s*.72,y+face*s*1.22);g.lineTo(x+s*.66,y+face*s*1.52)}else g.lineTo(x+s*.88,y-face*s*.22);g.stroke();g.fillStyle=skin;g.strokeStyle="#22110c";g.lineWidth=line;g.beginPath();g.ellipse(x,headY,s*.38,s*.46,0,0,7);g.fill();g.stroke();g.fillStyle=hair;g.beginPath();g.ellipse(x,headY-face*s*.24,s*.43,s*.22,0,0,7);g.fill();g.fillStyle=side?"rgba(255,255,255,.55)":"rgba(0,0,0,.3)";g.fillRect(x-s*.24,headY-face*s*.02,s*.13,s*.08);g.fillRect(x+s*.11,headY-face*s*.02,s*.13,s*.08);if(rating){g.font=Math.max(6,s*.68)+"px Arial";g.textAlign="center";g.textBaseline="middle";g.fillStyle="#fff";g.strokeStyle="#000";g.lineWidth=2;g.strokeText(String(rating),x,y-face*s*.03);g.fillText(String(rating),x,y-face*s*.03)}g.lineCap="butt"}
    function loop(){if(!$("match").classList.contains("hide")){if(trainingMode)renderTraining();else if(match)renderMatch()}requestAnimationFrame(loop)}
    addEventListener("resize",()=>{if(managerTeamMenuOpen)positionManagerTeamMenu();if(!$("managerActionList")?.classList.contains("hide"))syncManagerActionMenuGeometry(true);trainingMode?renderTraining():renderMatch()});
    requestAnimationFrame(loop);
    setTimeout(()=>{const screen=visibleScreen();if(screen==="loading"||screen==="manager"&&!me&&!managerSeason)startupError(new Error("startup timeout"))},8000);
    state(true).catch(startupError);
