const $ = s => document.querySelector(s);
const $$ = s => [...document.querySelectorAll(s)];
const rand = (a,b) => Math.floor(Math.random()*(b-a+1))+a;
const clamp = (n,a,b) => Math.max(a,Math.min(b,n));
const money = n => new Intl.NumberFormat('de-DE',{style:'currency',currency:'EUR',maximumFractionDigits:0}).format(n);
const uid = () => (globalThis.crypto && typeof globalThis.crypto.randomUUID === 'function') ? globalThis.crypto.randomUUID() : `fm-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`;

/* Version 1.5.2 - sicherer Offline-Speicher */
let memorySave=null;
function storageSet(value){
  memorySave=value;
  try{globalThis.localStorage.setItem('fmretro-save',value);return true;}catch(err){console.warn('Lokaler Browserspeicher nicht verfügbar; temporärer Speicher wird verwendet.',err);return false;}
}
function storageGet(){
  try{return globalThis.localStorage.getItem('fmretro-save')||memorySave;}catch(err){console.warn('Lokaler Browserspeicher nicht verfügbar; temporärer Speicher wird verwendet.',err);return memorySave;}
}
function storageHas(){return !!storageGet();}

let state = null;
try{Object.defineProperty(globalThis,'state',{configurable:true,get(){return state;},set(v){state=v;}});}catch(_e){}
let view = 'dashboard';
let liveMatch = null;
let liveTimer = null;

function clubStrength(name, idx){
  const elite = ['Reel Madrin','Manchesta Citi','Bavern Münchenau','Liverpol','Arsenel','FC Barceluna','Interna Mailand','Pari Saint-Germand'];
  const strong = ['Borusia Dortmunt','Bayer Leverkuzen','Atlético Madrin','Juventia','AC Mailanda','Napola','Benfika','FC Porta','Sporting CPA','Ajex','PSV Eindhovan','Feyenord','Red Ball Salzberg','Sturm Greiz'];
  if(elite.includes(name)) return rand(86,92);
  if(strong.includes(name)) return rand(80,86);
  return clamp(78-idx*2+rand(-2,3),66,82);
}
function makePlayer(clubRating, position, i){
  const age = rand(18,34);
  const potentialBonus = age < 22 ? rand(2,9) : rand(0,3);
  const rating = clamp(clubRating + rand(-8,5),55,94);
  return { id: uid(), name: `${FIRST_NAMES[rand(0,FIRST_NAMES.length-1)]} ${LAST_NAMES[rand(0,LAST_NAMES.length-1)]}`, position, age, rating, potential: clamp(rating+potentialBonus, rating, 96), value: Math.round((rating**3)*55*(35-age)/20), wage: Math.round(rating*rating*18), fitness: rand(82,100), morale: rand(65,95), contract: rand(1,5), goals:0, assists:0, apps:0 };
}
function makeClub(name, idx){
  const rating = clubStrength(name,idx);
  const squad = [];
  const roles = [...POSITIONS,'TW','IV','RV','LV','DM','ZM','RA','LA','ST','ST','ZM','IV'];
  roles.forEach((p,i)=>squad.push(makePlayer(rating,p,i)));
  const stadiumName=STADIUMS[name]||`${name} Arena`; return { id: uid(), name, rating, squad, budget: rand(12,90)*1e6, balance: rand(30,180)*1e6, stadium:{name:stadiumName, originalName:stadiumName, capacity: rand(17000,65000), condition:rand(70,95), ticketPrice:rand(22,58)}, fans:rand(180000,1800000), played:0,wins:0,draws:0,losses:0,gf:0,ga:0,points:0, form:[] };
}
function buildLeague(countryIndex,leagueIndex){
  const c=COUNTRIES[countryIndex], l=c.leagues[leagueIndex];
  return {country:c.name,name:l.name,clubs:l.clubs.map(makeClub),round:0,fixtures:[],results:[]};
}
function roundRobin(clubs){
  const ids=clubs.map(c=>c.id); if(ids.length%2) ids.push(null); const firstLeg=[]; const a=[...ids];
  for(let r=0;r<a.length-1;r++){
    const games=[]; for(let i=0;i<a.length/2;i++){ const h=a[i],aw=a[a.length-1-i]; if(h&&aw) games.push({home:h,away:aw,played:false}); }
    firstLeg.push(games); a.splice(1,0,a.pop());
  }
  const secondLeg=firstLeg.map(g=>g.map(x=>({home:x.away,away:x.home,played:false})));
  const firstHalf=[...firstLeg,...secondLeg];
  const secondHalf=firstHalf.map(g=>g.map(x=>({home:x.home,away:x.away,played:false})));
  return [...firstHalf,...secondHalf];
}
function ensure36GameSeason(){
  if(!state?.league?.fixtures)return;
  const clubCount=state.league.clubs.length;
  const expectedRounds=36;
  if(clubCount===10&&state.league.fixtures.length===18){
    const extra=state.league.fixtures.map(round=>round.map(f=>({home:f.home,away:f.away,played:false})));
    state.league.fixtures.push(...extra);
  }
  if(clubCount===10&&state.league.fixtures.length!==expectedRounds){
    console.warn(`Unerwartete Saisonlaenge: ${state.league.fixtures.length} statt ${expectedRounds} Spieltage.`);
  }
}
function newGame(ci,li,clubName){
  const league=buildLeague(ci,li); league.fixtures=roundRobin(league.clubs);
  const userClub=league.clubs.find(c=>c.name===clubName);
  state={version:5,formation:'4-4-2',matchSettings:{tactic:'balanced',aggression:'fair'},season:'2026/27',week:1,league,userClubId:userClub.id,selectedXI:userClub.squad.sort((a,b)=>b.rating-a.rating).slice(0,11).map(p=>p.id),news:[`Du wurdest als Manager von ${clubName} vorgestellt.`],international:{qualified:false,groupPoints:0,played:0},transferList:generateTransferList(league.clubs),outgoingOffers:[],lastMatch:null,matchFinanceHistory:[]};
  ensureSponsorState(); generateSponsorOffers(true); save(); render();
}
function generateTransferList(clubs){
  const base=[]; clubs.forEach(c=>c.squad.slice(14).forEach(p=>{if(Math.random()<.45)base.push({...p,fromClub:c.name,asking:Math.round(p.value*rand(90,125)/100)});}));
  return base.slice(0,35);
}
function getUserClub(){return state.league.clubs.find(c=>c.id===state.userClubId)}


const SPONSOR_COMPANIES=['AlpenMobil','NovaTech','KronenBank','RapidNet','VitaPlus','Nordstern Energie','BluePeak','Arena Bau','EuroDrive','GreenGrid','Sportiva','CityConnect','ProWerk','AeroLine','Goldquell','FutureByte','Bergland','PrimeLogistik','UrbanFox','Solaris','Titan Tools','Pulse Media','Globus Reisen','FreshOne','Mondo Foods','Helix Pharma','Vector Systems','RoyalBet','Maxx Telecom','Optima Versicherung'];
const SPONSOR_LABELS={shirt:'Trikotsponsor',board:'Stadionbande',stadium:'Stadionname',merch:'Merchandisingpartner'};
function ensureSponsorState(){
  const c=getUserClub();
  if(!c.stadium.originalName)c.stadium.originalName=c.stadium.name;
  if(!c.fans)c.fans=rand(180000,1800000);
  if(!state.sponsors)state.sponsors={shirt:null,stadium:null,merch:null,boards:Array(20).fill(null),offers:[],history:[],lastIncome:0,lastMerchSales:0};
  if(!Array.isArray(state.sponsors.boards))state.sponsors.boards=Array(20).fill(null);
  while(state.sponsors.boards.length<20)state.sponsors.boards.push(null);
  state.sponsors.boards=state.sponsors.boards.slice(0,20);
  if(!Array.isArray(state.sponsors.offers))state.sponsors.offers=[];
  if(!Array.isArray(state.sponsors.history))state.sponsors.history=[];
}
function clubSuccessScore(){
  const c=getUserClub(),table=sortedTable(),pos=Math.max(1,table.findIndex(x=>x.id===c.id)+1),n=table.length;
  const tableScore=(n-pos)/(Math.max(1,n-1));
  const formScore=c.form.length?c.form.reduce((a,x)=>a+(x==='S'?1:x==='U'?.45:0),0)/c.form.length:.5;
  const strengthScore=clamp((c.rating-65)/28,0,1);
  const internationalBonus=state.international?.qualified?.12:0;
  return clamp(.2+tableScore*.35+formScore*.2+strengthScore*.25+internationalBonus,0,1.15);
}
function sponsorSlotAvailable(type){
  ensureSponsorState();
  if(type==='board')return state.sponsors.boards.some(x=>!x);
  return !state.sponsors[type];
}
function generateSponsorOffers(force=false){
  ensureSponsorState();
  if(!force&&state.week%4!==0)return;
  const score=clubSuccessScore(),c=getUserClub();
  const desired=force?10:rand(3,6);
  const existing=new Set(state.sponsors.offers.map(o=>o.company+o.type));
  const types=['shirt','board','board','board','stadium','merch'];
  for(let i=0;i<desired;i++){
    const type=types[rand(0,types.length-1)];
    if(type!=='board'&&!sponsorSlotAvailable(type))continue;
    const company=SPONSOR_COMPANIES[rand(0,SPONSOR_COMPANIES.length-1)];
    if(existing.has(company+type))continue;
    const scale=.65+score*1.15+(c.fans/1800000)*.3;
    const base={shirt:210000,board:18000,stadium:170000,merch:70000}[type];
    const weekly=Math.round(base*scale*(.8+Math.random()*.45)/1000)*1000;
    const duration=rand(type==='board'?18:36,type==='board'?54:108);
    const signing=Math.round(weekly*rand(3,10)/10000)*10000;
    const royalty=type==='merch'?rand(8,18):0;
    const nameProposal=type==='stadium'?`${company} ${c.stadium.originalName.replace(/^(.*?\s)?(Arena|Stadion)$/i,'Arena')}`:null;
    state.sponsors.offers.push({id:uid(),company,type,weekly,duration,signing,royalty,nameProposal,createdWeek:state.week});
    existing.add(company+type);
  }
  state.sponsors.offers=state.sponsors.offers.slice(-24);
}
function acceptSponsorOffer(id){
  ensureSponsorState();const idx=state.sponsors.offers.findIndex(o=>o.id===id);if(idx<0)return;
  const o=state.sponsors.offers[idx],c=getUserClub();let contract={...o,weeksLeft:o.duration,startWeek:state.week};delete contract.id;
  if(o.type==='board'){
    const slot=state.sponsors.boards.findIndex(x=>!x);if(slot<0)return alert('Alle 20 Werbebanden sind bereits vergeben.');
    contract.slot=slot+1;state.sponsors.boards[slot]=contract;
  }else{
    if(state.sponsors[o.type])return alert('Dieser Sponsorenplatz ist bereits belegt.');
    state.sponsors[o.type]=contract;
    if(o.type==='stadium')c.stadium.name=o.nameProposal;
  }
  c.balance+=o.signing;state.sponsors.history.unshift(`${o.company}: ${SPONSOR_LABELS[o.type]} abgeschlossen (${o.duration} Wochen).`);
  state.news.unshift(`${o.company} wird ${SPONSOR_LABELS[o.type]}. Unterschriftsbonus: ${money(o.signing)}.`);
  state.sponsors.offers.splice(idx,1);save();render();
}
function rejectSponsorOffer(id){ensureSponsorState();const o=state.sponsors.offers.find(x=>x.id===id);state.sponsors.offers=state.sponsors.offers.filter(x=>x.id!==id);if(o)state.news.unshift(`Das Sponsorenangebot von ${o.company} wurde abgelehnt.`);save();render();}
function weeklySponsorIncome(){
  ensureSponsorState();const c=getUserClub(),sp=state.sponsors;let fixed=0;
  const contracts=[sp.shirt,sp.stadium,sp.merch,...sp.boards].filter(Boolean);contracts.forEach(x=>fixed+=Number(x.weekly)||0);
  c.balance+=fixed;sp.lastIncome=fixed;
  if(fixed>0)state.news.unshift(`Sponsoren: ${money(fixed)} feste Einnahmen in dieser Woche.`);
  function tick(key){const x=sp[key];if(!x)return;if(--x.weeksLeft<=0){state.news.unshift(`${x.company}: Vertrag als ${SPONSOR_LABELS[key]} ist ausgelaufen.`);sp[key]=null;if(key==='stadium')c.stadium.name=c.stadium.originalName;}}
  tick('shirt');tick('stadium');tick('merch');
  sp.boards=sp.boards.map(x=>{if(!x)return null;x.weeksLeft--;if(x.weeksLeft<=0){state.news.unshift(`${x.company}: Vertrag für Werbebande ${x.slot} ist ausgelaufen.`);return null;}return x;});
  generateSponsorOffers(false);
}


function ensureMatchFinanceState(){
  if(!Array.isArray(state.matchFinanceHistory))state.matchFinanceHistory=[];
  if(state.lastMatch&&state.lastMatch.attendance===undefined){state.lastMatch.attendance=0;state.lastMatch.ticketIncome=0;state.lastMatch.merchSales=0;state.lastMatch.merchIncome=0;}
}
function estimateAttendance(home,away){
  const table=sortedTable(),pos=Math.max(1,table.findIndex(x=>x.id===home.id)+1),success=1-(pos-1)/Math.max(1,table.length-1);
  const appeal=clamp(.52+success*.22+(away.rating-65)/120+(home.fans/1800000)*.12-(home.stadium.ticketPrice-35)/220,.35,.98);
  return Math.min(home.stadium.capacity,Math.max(1000,Math.round(home.stadium.capacity*appeal*(.9+Math.random()*.16))));
}
function calculateUserMatchFinance(h,a){
  ensureSponsorState();ensureMatchFinanceState();const user=getUserClub(),isHome=h.id===user.id,attendance=estimateAttendance(h,a);
  const ticketIncome=isHome?Math.round(attendance*user.stadium.ticketPrice):0;
  const score=clubSuccessScore(),resultFactor=.9+Math.random()*.25,venueFactor=isHome?1:.58;
  const merchSales=Math.round(user.fans*(.018+score*.018)*venueFactor*resultFactor);
  const merchRate=state.sponsors.merch?state.sponsors.merch.royalty/100:.30;
  const merchIncome=Math.round(merchSales*merchRate);
  return {attendance,ticketIncome,merchSales,merchIncome,isHome};
}

function ensureTransferState(){
  if(!state.outgoingOffers)state.outgoingOffers=[];
  getUserClub().squad.forEach(p=>{
    if(p.transferListed===undefined)p.transferListed=false;
    if(p.askingPrice===undefined)p.askingPrice=Math.round(p.value*1.05);
    if(p.listedWeek===undefined)p.listedWeek=null;
  });
}
function listedPlayers(){ensureTransferState();return getUserClub().squad.filter(p=>p.transferListed);}
function activeOfferFor(playerId){ensureTransferState();return state.outgoingOffers.find(o=>o.playerId===playerId&&o.status==='pending');}
function toggleTransferList(playerId){
  ensureTransferState(); const p=getUserClub().squad.find(x=>x.id===playerId); if(!p)return;
  if(p.transferListed){
    p.transferListed=false;p.listedWeek=null;
    state.outgoingOffers=state.outgoingOffers.filter(o=>o.playerId!==playerId||o.status!=='pending');
    state.news.unshift(`${p.name} wurde von der Transferliste genommen.`);
  }else{
    p.transferListed=true;p.listedWeek=state.week;p.askingPrice=Math.max(p.value,Math.round(p.value*1.08));
    state.news.unshift(`${p.name} wurde auf die Transferliste gesetzt.`);
  }
  save();render();
}
function updateAskingPrice(playerId,value){
  const p=getUserClub().squad.find(x=>x.id===playerId);if(!p)return;
  p.askingPrice=clamp(Math.round(Number(value)||p.value),Math.round(p.value*.5),Math.round(p.value*2.5));save();render();
}
function buyerNeedScore(club,player){
  const same=club.squad.filter(p=>p.position===player.position);
  const avg=same.reduce((s,p)=>s+p.rating,0)/(same.length||1);
  return clamp((player.rating-avg+10)/22,.12,.88);
}
function processOutgoingTransferOffers(){
  ensureTransferState(); const user=getUserClub();
  for(const p of listedPlayers()){
    if(activeOfferFor(p.id))continue;
    const weeksListed=Math.max(0,state.week-(p.listedWeek||state.week));
    const candidates=state.league.clubs.filter(c=>c.id!==user.id&&c.budget>p.value*.65)
      .map(c=>({club:c,score:buyerNeedScore(c,p)*(0.65+Math.random()*.7)}))
      .filter(x=>x.score>.18).sort((a,b)=>b.score-a.score);
    const chance=clamp(.16+weeksListed*.06+(p.rating-70)*.008,.12,.72);
    if(!candidates.length||Math.random()>chance)continue;
    const buyer=candidates[rand(0,Math.min(3,candidates.length-1))].club;
    const ageFactor=p.age<24?1.12:p.age>31?.78:1;
    const contractFactor=.88+Math.min(5,p.contract||2)*.035;
    let amount=Math.round(p.value*ageFactor*contractFactor*(.82+Math.random()*.35));
    amount=Math.min(amount,Math.round(buyer.budget*.72));
    if(amount<Math.round(p.value*.55))continue;
    state.outgoingOffers.push({id:uid(),playerId:p.id,bidderId:buyer.id,amount,week:state.week,status:'pending'});
    state.news.unshift(`${buyer.name} bietet ${money(amount)} für ${p.name}. Deine Entscheidung ist erforderlich.`);
  }
}
function acceptOutgoingOffer(offerId){
  ensureTransferState(); const offer=state.outgoingOffers.find(o=>o.id===offerId&&o.status==='pending');if(!offer)return;
  const user=getUserClub(),buyer=getClub(offer.bidderId),idx=user.squad.findIndex(p=>p.id===offer.playerId);if(idx<0||!buyer)return;
  const player=user.squad[idx];
  if(!confirm(`${buyer.name} bietet ${money(offer.amount)} für ${player.name}. Angebot annehmen?`))return;
  user.squad.splice(idx,1);buyer.squad.push({...player,transferListed:false,listedWeek:null,askingPrice:undefined});
  buyer.budget=Math.max(0,buyer.budget-offer.amount);buyer.balance-=offer.amount;user.balance+=offer.amount;user.budget+=offer.amount;
  offer.status='accepted';state.outgoingOffers.forEach(o=>{if(o.playerId===player.id&&o.id!==offer.id&&o.status==='pending')o.status='expired';});
  state.selectedXI=state.selectedXI.filter(id=>id!==player.id);
  const replacements=[...user.squad].sort((a,b)=>b.rating-a.rating).filter(p=>!state.selectedXI.includes(p.id));
  while(state.selectedXI.length<11&&replacements.length)state.selectedXI.push(replacements.shift().id);
  state.news.unshift(`${player.name} wechselt für ${money(offer.amount)} zu ${buyer.name}.`);save();render();
}
function rejectOutgoingOffer(offerId){
  ensureTransferState();const offer=state.outgoingOffers.find(o=>o.id===offerId&&o.status==='pending');if(!offer)return;
  const p=getUserClub().squad.find(x=>x.id===offer.playerId),buyer=getClub(offer.bidderId);offer.status='rejected';
  if(p&&buyer)state.news.unshift(`Das Angebot von ${buyer.name} über ${money(offer.amount)} für ${p.name} wurde abgelehnt. Er bleibt auf der Transferliste.`);
  save();render();
}

function getClub(id){return state.league.clubs.find(c=>c.id===id)}
function teamPower(club){
  const ids=club.id===state.userClubId?state.selectedXI:club.squad.sort((a,b)=>b.rating-a.rating).slice(0,11).map(p=>p.id);
  const players=ids.map(id=>club.squad.find(p=>p.id===id)).filter(Boolean);
  return players.reduce((s,p)=>s+p.rating*(p.fitness/100)*(0.85+p.morale/500),0)/(players.length||1);
}
function goalsFor(power,opp,home){
  let x=1.2+(power-opp)/16+(home?.25:0)+Math.random()*1.3;
  return clamp(Math.round(x+rand(-1,1)),0,7);
}
function applyMatchResult(f,hg,ag){
  const h=getClub(f.home),a=getClub(f.away);
  [h,a].forEach(c=>c.played++); h.gf+=hg;h.ga+=ag;a.gf+=ag;a.ga+=hg;
  if(hg>ag){h.wins++;h.points+=3;a.losses++;h.form.unshift('S');a.form.unshift('N');}
  else if(hg<ag){a.wins++;a.points+=3;h.losses++;h.form.unshift('N');a.form.unshift('S');}
  else{h.draws++;a.draws++;h.points++;a.points++;h.form.unshift('U');a.form.unshift('U');}
  h.form=h.form.slice(0,5);a.form=a.form.slice(0,5); f.played=true;f.score=[hg,ag];
  if(h.id===state.userClubId||a.id===state.userClubId){
    const user=h.id===state.userClubId?h:a, isHome=h.id===state.userClubId, ug=isHome?hg:ag, og=isHome?ag:hg;
    const finance=(liveMatch&&liveMatch.fixture===f&&liveMatch.finance)?liveMatch.finance:calculateUserMatchFinance(h,a);
    user.balance += finance.ticketIncome+finance.merchIncome;
    state.sponsors.lastMerchSales=finance.merchSales;
    state.lastMatch={home:h.name,away:a.name,score:`${hg}:${ag}`,attendance:finance.attendance,ticketIncome:finance.ticketIncome,merchSales:finance.merchSales,merchIncome:finance.merchIncome,isHome};
    state.matchFinanceHistory.unshift({week:state.week,season:state.season,home:h.name,away:a.name,score:`${hg}:${ag}`,...finance});
    state.matchFinanceHistory=state.matchFinanceHistory.slice(0,20);
    const picked=state.selectedXI.map(id=>user.squad.find(p=>p.id===id)).filter(Boolean); picked.forEach(p=>{p.apps++;p.fitness=clamp(p.fitness-rand(4,12),45,100);p.morale=clamp(p.morale+(ug>og?rand(2,5):ug<og?-rand(2,5):0),30,100)});
    state.news.unshift(`${h.name} ${hg}:${ag} ${a.name}`);
  }
}
function simulateMatch(f){
  const h=getClub(f.home),a=getClub(f.away); const hp=teamPower(h),ap=teamPower(a);
  applyMatchResult(f,goalsFor(hp,ap,true),goalsFor(ap,hp,false));
}
function commentary(type,team,player){
  const lines={
    kickoff:['Der Ball rollt. Beide Teams beginnen konzentriert.'],
    chance:[`${team} kombiniert sich gefährlich nach vorne.`,`${player} kommt zum Abschluss – knapp vorbei!`,`Große Möglichkeit für ${team}, doch der Torwart ist zur Stelle.`],
    goal:[`TOR für ${team}! ${player} trifft nach einem schnellen Angriff.`,`TOOOR! ${player} lässt dem Keeper keine Chance.`,`Der Ball ist drin! ${team} jubelt, Torschütze: ${player}.`],
    card:[`Gelbe Karte für ${player} nach einem taktischen Foul.`,`Der Schiedsrichter verwarnt ${player}.`],
    save:[`Starke Parade! Der Torwart verhindert den Treffer.`,`Glanzreaktion des Keepers – weiter kein Tor.`],
    corner:[`Ecke für ${team}. Der Ball segelt gefährlich in den Strafraum.`,`Druckphase von ${team}: nächster Eckball.`],
    halftime:['Halbzeitpause. Die Trainer geben neue Anweisungen.'],
    final:['Schlusspfiff! Die Partie ist beendet.']
  };
  const arr=lines[type]||lines.chance; return arr[rand(0,arr.length-1)];
}
function randomPlayer(club,attacking=false){
  const pool=club.squad.filter(p=>attacking?['ST','RA','LA','OM','ZM'].includes(p.position):true);
  const use=pool.length?pool:club.squad; return use[rand(0,use.length-1)].name;
}
function startLiveMatch(f,round){
  if(liveMatch)return;
  const h=getClub(f.home),a=getClub(f.away);
  const finance=calculateUserMatchFinance(h,a);
  liveMatch={fixture:f,home:h,away:a,minute:0,homeGoals:0,awayGoals:0,events:[],paused:false,speed:1,finished:false,homePower:teamPower(h)+2,awayPower:teamPower(a),otherFixtures:round.filter(x=>x!==f),finance};
  view='live'; $$('.nav').forEach(x=>x.classList.remove('active')); render();
  addLiveEvent(0,'kickoff',commentary('kickoff')); runLiveTimer();
}
function addLiveEvent(minute,type,text){
  if(!liveMatch)return; liveMatch.events.unshift({minute,type,text});
  const feed=$('#liveFeed'); if(feed){feed.innerHTML=liveFeedHtml();feed.scrollTop=0;}
}
function liveFeedHtml(){return liveMatch.events.map(e=>`<div class="live-line ${e.type}"><span class="live-minute">${e.minute}'</span><span>${esc(e.text)}</span></div>`).join('');}
function runLiveTimer(){
  clearInterval(liveTimer);
  liveTimer=setInterval(()=>{
    if(!liveMatch||liveMatch.paused||liveMatch.finished)return;
    liveMatch.minute++; processLiveMinute(); updateLiveDisplay();
    if(liveMatch.minute>=90)finishLiveMatch();
  },500/Math.max(1,liveMatch?.speed||1));
}
function processLiveMinute(){
  const m=liveMatch.minute;
  if(m===45){addLiveEvent(m,'halftime',commentary('halftime'));return;}
  const total=Math.max(1,liveMatch.homePower+liveMatch.awayPower), homeAttack=Math.random()<liveMatch.homePower/total;
  const team=homeAttack?liveMatch.home:liveMatch.away, player=randomPlayer(team,true), roll=Math.random();
  if(roll<0.028){
    const attack=homeAttack?liveMatch.homePower:liveMatch.awayPower, defence=homeAttack?liveMatch.awayPower:liveMatch.homePower;
    if(Math.random()<clamp(.30+(attack-defence)/120,.18,.48)){
      if(homeAttack)liveMatch.homeGoals++;else liveMatch.awayGoals++;
      const p=team.squad.find(x=>x.name===player);if(p)p.goals++;
      addLiveEvent(m,'goal',commentary('goal',team.name,player));
    }else addLiveEvent(m,'save',commentary('save',team.name,player));
  }else if(roll<0.075)addLiveEvent(m,'chance',commentary('chance',team.name,player));
  else if(roll<0.095)addLiveEvent(m,'corner',commentary('corner',team.name,player));
  else if(roll<0.108)addLiveEvent(m,'yellow',commentary('card',team.name,randomPlayer(team)));
}
function updateLiveDisplay(){
  if(!liveMatch)return;
  const minute=$('#liveMinute'),score=$('#liveScore'),bar=$('#liveProgress');
  if(minute)minute.textContent=liveMatch.minute>=90?'90+':`${liveMatch.minute}'`;
  if(score)score.textContent=`${liveMatch.homeGoals} : ${liveMatch.awayGoals}`;
  if(bar)bar.style.width=`${Math.min(100,liveMatch.minute/90*100)}%`;
}
function finishLiveMatch(){
  if(!liveMatch||liveMatch.finished)return;
  liveMatch.finished=true;clearInterval(liveTimer);addLiveEvent(90,'final',commentary('final'));
  applyMatchResult(liveMatch.fixture,liveMatch.homeGoals,liveMatch.awayGoals);liveMatch.otherFixtures.forEach(simulateMatch);
  state.league.round++;state.week++;
  const user=getUserClub();user.squad.forEach(p=>p.fitness=clamp(p.fitness+rand(2,7),45,100));
  user.balance-=user.squad.reduce((sum,p)=>sum+p.wage,0);if(state.week%4===0)user.balance-=rand(250000,700000);
  processOutgoingTransferOffers();weeklySponsorIncome();save();updateLiveDisplay();render();
}
function nextWeek(){
  if(liveMatch&&liveMatch.finished){clearInterval(liveTimer);liveMatch=null;view='dashboard';}
  if(liveMatch)return;
  const round=state.league.fixtures[state.league.round];if(!round){endSeason();return;}
  const userFixture=round.find(f=>f.home===state.userClubId||f.away===state.userClubId);
  if(userFixture)startLiveMatch(userFixture,round);else{round.forEach(simulateMatch);state.league.round++;state.week++;processOutgoingTransferOffers();weeklySponsorIncome();save();render();}
}
function endSeason(){
  const table=sortedTable(); const pos=table.findIndex(c=>c.id===state.userClubId)+1;
  const user=getUserClub(); user.balance += Math.max(1,table.length-pos+1)*2e6; state.international.qualified=pos<=3;
  state.news.unshift(`Saison beendet: Platz ${pos}. Eine neue Saison wurde gestartet.`);
  state.season=(parseInt(state.season)+1)+'/'+String(parseInt(state.season)+2).slice(-2); state.week=1; state.league.round=0;
  state.league.clubs.forEach(c=>Object.assign(c,{played:0,wins:0,draws:0,losses:0,gf:0,ga:0,points:0,form:[]}));
  state.league.fixtures=roundRobin(state.league.clubs); ensure36GameSeason(); generateSponsorOffers(true); save();render();
}
function sortedTable(){return [...state.league.clubs].sort((a,b)=>b.points-a.points||(b.gf-b.ga)-(a.gf-a.ga)||b.gf-a.gf)}
function save(){if(!state)return;storageSet(JSON.stringify(state));}

function applyLoadedState(loadedState,{saveToBrowser=true}={}){
  if(!loadedState || typeof loadedState!=='object') throw new Error('Ungültiger Spielstand.');
  if(!loadedState.league || !Array.isArray(loadedState.league.clubs)) throw new Error('Die Datei enthält keinen gültigen Football-Manager-Spielstand.');
  state=loadedState;
  liveMatch=null;
  clearInterval(liveTimer);
  ensureTransferState();
  ensure36GameSeason();
  ensureSponsorState();
  ensureMatchFinanceState();
  try{ if(typeof ensureTrainingState==='function')ensureTrainingState(); }catch(_e){}
  try{ if(typeof ensureTacticalState==='function')ensureTacticalState(); }catch(_e){}
  try{ if(typeof ensureHistoryState==='function')ensureHistoryState(); }catch(_e){}
  try{ if(typeof ensureCareerWorldState==='function')ensureCareerWorldState(); }catch(_e){}
  try{ if(typeof ensureContractsState==='function')ensureContractsState(); }catch(_e){}
  if(state.sponsors && Array.isArray(state.sponsors.offers) && !state.sponsors.offers.length) generateSponsorOffers(true);
  if(saveToBrowser) save();
  $('#startScreen').style.display='none';
  render();
}
function load(){
  const raw=storageGet();
  if(raw){
    try{applyLoadedState(JSON.parse(raw),{saveToBrowser:false});}
    catch(err){alert('Spielstand konnte nicht geladen werden: '+err.message);}
  }else alert('Kein Spielstand vorhanden.');
}

function saveFileName(){
  let club='verein';
  try{club=(getUserClub()?.name||club).toLowerCase().replace(/[^a-z0-9äöüß]+/gi,'-').replace(/^-+|-+$/g,'');}catch(_e){}
  const d=new Date();
  const stamp=[d.getFullYear(),String(d.getMonth()+1).padStart(2,'0'),String(d.getDate()).padStart(2,'0')].join('-');
  return `football-manager-retro-${club||'save'}-${stamp}.json`;
}
function buildDiskSave(){
  if(!state) throw new Error('Es ist noch kein Spiel gestartet.');
  return {
    format:'football-manager-retro-save',
    formatVersion:1,
    gameVersion:'4.8.2',
    savedAt:new Date().toISOString(),
    state:state
  };
}
async function saveToDisk(){
  if(!state){alert('Es ist noch kein Spiel gestartet.');return;}
  const data=JSON.stringify(buildDiskSave(),null,2);
  const filename=saveFileName();
  try{
    if(typeof globalThis.showSaveFilePicker==='function' && globalThis.isSecureContext){
      const handle=await globalThis.showSaveFilePicker({
        suggestedName:filename,
        types:[{description:'Football Manager Retro Spielstand',accept:{'application/json':['.json']}}]
      });
      const writable=await handle.createWritable();
      await writable.write(data);
      await writable.close();
      alert('Spielstand wurde auf der Festplatte gespeichert.');
      return;
    }
  }catch(err){
    if(err && err.name==='AbortError') return;
    console.warn('Direktes Speichern nicht möglich, Download-Fallback wird verwendet.',err);
  }
  const blob=new Blob([data],{type:'application/json'});
  const url=URL.createObjectURL(blob);
  const a=document.createElement('a');
  a.href=url;a.download=filename;a.style.display='none';
  document.body.appendChild(a);a.click();a.remove();
  setTimeout(()=>URL.revokeObjectURL(url),1500);
}
async function loadFromDiskFile(file){
  if(!file)return;
  try{
    const text=await file.text();
    const parsed=JSON.parse(text);
    const loaded=(parsed && parsed.format==='football-manager-retro-save' && parsed.state)?parsed.state:parsed;
    applyLoadedState(loaded,{saveToBrowser:true});
    alert('Spielstand von Festplatte geladen.');
  }catch(err){
    console.error(err);
    alert('Die Spielstand-Datei konnte nicht geladen werden: '+(err?.message||err));
  }finally{
    const input=document.getElementById('diskLoadInput');
    if(input)input.value='';
  }
}
function esc(s){return String(s).replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]))}

function dashboard(){const c=getUserClub(); const table=sortedTable(); const pos=table.findIndex(x=>x.id===c.id)+1; const next=state.league.fixtures[state.league.round]?.find(f=>f.home===c.id||f.away===c.id);
return `<div class="grid cols-3"><div class="card"><div class="muted">Verein</div><div class="stat">${esc(c.name)}</div><div>${esc(state.league.name)}</div></div><div class="card"><div class="muted">Tabellenplatz</div><div class="stat">${pos}.</div><div>${c.points} Punkte</div></div><div class="card"><div class="muted">Kontostand</div><div class="stat ${c.balance<0?'bad':'good'}">${money(c.balance)}</div><div>Transferbudget: ${money(c.budget)}</div></div></div>
<div class="card" style="margin-top:16px"><div class="icon-title"><img src="assets/trophy-icon.jpg" alt="Pokal"><h2>Spieltag im Retro-Stil</h2></div><img class="hero-image" src="assets/matchday.jpg" alt="Pixel-Art Fußballspiel im Stadion"><p class="visual-caption">Grafische Spieltagsansicht – Ergebnisse werden weiterhin durch die Simulation berechnet.</p></div>
<div class="grid cols-2" style="margin-top:16px"><div class="card"><h2>Nächstes Spiel</h2>${next?`<div class="stat">${esc(getClub(next.home).name)} – ${esc(getClub(next.away).name)}</div><p class="muted">Spieltag ${state.league.round+1}</p>`:'<p>Saison beendet.</p>'}${state.lastMatch?`<h3>Letztes Ergebnis</h3><p>${esc(state.lastMatch.home)} <b>${state.lastMatch.score}</b> ${esc(state.lastMatch.away)}</p><div class="last-match-finance"><span>👥 ${Number(state.lastMatch.attendance||0).toLocaleString('de-DE')} Zuschauer</span><span>🎟 ${money(state.lastMatch.ticketIncome||0)} Tickets</span><span>🛍 ${money(state.lastMatch.merchSales||0)} Fanartikelverkauf</span><span>💶 ${money(state.lastMatch.merchIncome||0)} Vereinserlös Fanartikel</span></div>`:''}</div><div class="card"><h2>Manager-News</h2>${state.news.slice(0,6).map(n=>`<div class="fixture">${esc(n)}</div>`).join('')}</div></div>
<div class="card sponsor-quick-card" style="margin-top:16px"><div><h2>★ Sponsoren & Vermarktung</h2><p>Trikotsponsor, 20 Werbebanden, Stadionnamensrechte und Fanartikelverkauf verwalten.</p></div><button id="openSponsors" class="primary">Sponsoren öffnen</button></div>
<div class="grid cols-2 retro-gallery"><div class="card"><h3>Trikots</h3><img class="retro-strip" src="assets/kits.jpg" alt="Retro-Trikots"></div><div class="card"><h3>Status & Wetter</h3><img class="retro-strip" src="assets/status-bars.jpg" alt="Fitness- und Formanzeigen"><img class="retro-strip" style="margin-top:8px" src="assets/weather.jpg" alt="Wettersymbole"></div></div>`}
function squad(){ensureTransferState();const c=getUserClub(); return `<div class="card"><h2>Kader – ${esc(c.name)}</h2><p class="muted">Spieler können hier auf die Transferliste gesetzt oder wieder entfernt werden.</p><div class="player-row transfer-header"><span>Pos</span><span>Name</span><span>Alter</span><span>Stärke</span><span>Fitness</span><span>Wert</span><span>Status</span><span>Aktion</span></div>${[...c.squad].sort((a,b)=>b.rating-a.rating).map(p=>`<div class="player-row transfer-row"><span class="badge">${p.position}</span><span>${esc(p.name)}</span><span>${p.age}</span><b>${p.rating}</b><span>${p.fitness}%</span><span>${money(p.value)}</span><span>${p.transferListed?'<span class="listed-label">Transferliste</span>':'—'}</span><span><button data-list-player="${p.id}" class="${p.transferListed?'danger':''}">${p.transferListed?'Entfernen':'Anbieten'}</button></span></div>`).join('')}</div>`}
function lineup(){const c=getUserClub(); const slots=['TW','RV','IV','IV','LV','DM','ZM','ZM','RA','LA','ST']; return `<div class="card"><h2>Aufstellung</h2><p class="muted">Wähle elf Spieler. Fitness und Moral beeinflussen die Matchstärke.</p><div class="lineup-grid">${slots.map((pos,i)=>{const sel=state.selectedXI[i];return `<div class="lineup-slot"><b>${pos}</b><select data-lineup="${i}">${c.squad.map(p=>`<option value="${p.id}" ${p.id===sel?'selected':''}>${esc(p.name)} (${p.position}, ${p.rating})</option>`).join('')}</select></div>`}).join('')}</div></div>`}
function league(){return `<div class="card"><h2>${esc(state.league.name)} – Tabelle</h2><table><thead><tr><th>#</th><th>Verein</th><th>Sp</th><th>S</th><th>U</th><th>N</th><th>Tore</th><th>Diff</th><th>Pkt</th></tr></thead><tbody>${sortedTable().map((c,i)=>`<tr class="${c.id===state.userClubId?'user-team':''}"><td>${i+1}</td><td>${esc(c.name)}</td><td>${c.played}</td><td>${c.wins}</td><td>${c.draws}</td><td>${c.losses}</td><td>${c.gf}:${c.ga}</td><td>${c.gf-c.ga}</td><td><b>${c.points}</b></td></tr>`).join('')}</tbody></table></div>`}
function transfers(){
  ensureTransferState();const c=getUserClub(),pending=state.outgoingOffers.filter(o=>o.status==='pending');
  return `<div class="grid cols-2 transfer-summary"><div class="card"><h2>Einkäufe</h2><p>Transferbudget: <b>${money(c.budget)}</b></p><table><thead><tr><th>Spieler</th><th>Pos</th><th>Stärke</th><th>Verein</th><th>Preis</th><th></th></tr></thead><tbody>${state.transferList.slice(0,20).map((p,i)=>`<tr><td>${esc(p.name)}</td><td>${p.position}</td><td>${p.rating}</td><td>${esc(p.fromClub)}</td><td>${money(p.asking)}</td><td><button data-buy="${i}">Kaufen</button></td></tr>`).join('')}</tbody></table></div>
  <div class="card"><h2>Eingegangene Angebote</h2>${pending.length?pending.map(o=>{const p=c.squad.find(x=>x.id===o.playerId),b=getClub(o.bidderId);return p&&b?`<div class="offer-card"><div><b>${esc(b.name)}</b> bietet für <b>${esc(p.name)}</b></div><div class="offer-price">${money(o.amount)}</div><div class="muted">Marktwert ${money(p.value)} · Forderung ${money(p.askingPrice)}</div><div class="offer-actions"><button data-accept-offer="${o.id}" class="primary">Annehmen</button><button data-reject-offer="${o.id}" class="danger">Ablehnen</button></div></div>`:''}).join(''):'<p class="muted">Momentan liegen keine Angebote vor. Neue Gebote können beim Fortschreiten einer Woche eintreffen.</p>'}</div></div>
  <div class="card" style="margin-top:16px"><h2>Deine Transferliste</h2>${listedPlayers().length?`<table><thead><tr><th>Spieler</th><th>Pos</th><th>Stärke</th><th>Marktwert</th><th>Wunschpreis</th><th>Aktuelles Gebot</th><th></th></tr></thead><tbody>${listedPlayers().map(p=>{const o=activeOfferFor(p.id),b=o?getClub(o.bidderId):null;return `<tr><td>${esc(p.name)}</td><td>${p.position}</td><td>${p.rating}</td><td>${money(p.value)}</td><td><input class="price-input" data-asking-price="${p.id}" type="number" min="${Math.round(p.value*.5)}" max="${Math.round(p.value*2.5)}" step="100000" value="${p.askingPrice}"></td><td>${o&&b?`${esc(b.name)}: <b>${money(o.amount)}</b>`:'Noch keines'}</td><td><button data-list-player="${p.id}" class="danger">Entfernen</button></td></tr>`}).join('')}</tbody></table>`:'<p>Noch kein Spieler wurde auf die Transferliste gesetzt. Das kannst du im Menü „Kader“ erledigen.</p>'}</div>`;
}

function sponsors(){
  ensureSponsorState();const c=getUserClub(),sp=state.sponsors,score=Math.round(clubSuccessScore()*100);
  const activeCard=(title,x)=>`<div class="sponsor-contract"><h3>${title}</h3>${x?`<b>${esc(x.company)}</b><div>${money(x.weekly)}/Woche</div><small>${x.weeksLeft} Wochen verbleibend${x.royalty?` · ${x.royalty}% Umsatzbeteiligung`:''}</small>`:'<span class="muted">Noch frei</span>'}</div>`;
  return `<div class="grid cols-3 sponsor-metrics"><div class="card"><div class="muted">Vereinserfolg</div><div class="stat gold">${score}%</div><p>Tabellenplatz, Form, Stärke und internationale Teilnahme bestimmen die Qualität der Angebote.</p></div><div class="card"><div class="muted">Letzte Sponsoreneinnahmen</div><div class="stat good">${money(sp.lastIncome||0)}</div><p>inklusive Fanartikelbeteiligung</p></div><div class="card"><div class="muted">Fanbasis</div><div class="stat">${c.fans.toLocaleString('de-DE')}</div><p>Letzter Fanartikelumsatz: ${money(sp.lastMerchSales||0)}</p></div></div>
  <div class="grid cols-3" style="margin-top:16px">${activeCard('Trikotsponsor',sp.shirt)}${activeCard('Stadionnamensrechte',sp.stadium)}${activeCard('Merchandisingpartner',sp.merch)}</div>
  <div class="card" style="margin-top:16px"><h2>20 Stadion-Werbebanden</h2><div class="board-grid">${sp.boards.map((x,i)=>`<div class="ad-board ${x?'occupied':''}"><span>Bande ${i+1}</span><b>${x?esc(x.company):'FREI'}</b>${x?`<small>${money(x.weekly)}/W · ${x.weeksLeft} W.</small>`:''}</div>`).join('')}</div></div>
  <div class="card" style="margin-top:16px"><h2>Aktuelle Sponsorenangebote</h2>${sp.offers.length?`<table><thead><tr><th>Firma</th><th>Bereich</th><th>Wöchentlich</th><th>Bonus</th><th>Laufzeit</th><th>Details</th><th></th></tr></thead><tbody>${sp.offers.map(o=>`<tr><td><b>${esc(o.company)}</b></td><td>${SPONSOR_LABELS[o.type]}</td><td>${money(o.weekly)}</td><td>${money(o.signing)}</td><td>${o.duration} Wochen</td><td>${o.type==='merch'?`${o.royalty}% Fanartikel-Umsatz`:o.type==='stadium'?esc(o.nameProposal):o.type==='board'?'eine von 20 Banden':'Logo auf Heim- und Auswärtstrikot'}</td><td><div class="offer-actions"><button data-accept-sponsor="${o.id}" class="primary">Annehmen</button><button data-reject-sponsor="${o.id}" class="danger">Ablehnen</button></div></td></tr>`).join('')}</tbody></table>`:'<p class="muted">Momentan liegen keine Angebote vor. Neue Angebote erscheinen in regelmäßigen Abständen und nach Saisonerfolgen.</p>'}</div>`;
}

function finances(){ensureMatchFinanceState();const c=getUserClub(),w=c.squad.reduce((s,p)=>s+p.wage,0),hist=state.matchFinanceHistory.slice(0,10);return `<div class="grid cols-2"><div class="card"><div class="icon-title"><img src="assets/finance-icon.jpg" alt="Finanzen"><h2>Finanzen</h2></div><p>Kontostand</p><div class="stat ${c.balance<0?'bad':'good'}">${money(c.balance)}</div><hr><p>Wöchentliche Gehälter: <b>${money(w)}</b></p><p>Transferbudget: <b>${money(c.budget)}</b></p><p>Stadion-Einnahmen pro Heimspiel: ca. <b>${money(c.stadium.capacity*c.stadium.ticketPrice*.7)}</b></p></div><div class="card"><h2>Topverdiener</h2>${[...c.squad].sort((a,b)=>b.wage-a.wage).slice(0,8).map(p=>`<div class="fixture"><span>${esc(p.name)}</span><b>${money(p.wage)}/Woche</b></div>`).join('')}</div></div><div class="card" style="margin-top:16px"><h2>Spielabrechnungen</h2>${hist.length?`<table><thead><tr><th>Spiel</th><th>Zuschauer</th><th>Tickets</th><th>Fanartikelverkauf</th><th>Fanartikel-Erlös</th></tr></thead><tbody>${hist.map(x=>`<tr><td>${esc(x.home)} ${esc(x.score)} ${esc(x.away)}</td><td>${Number(x.attendance).toLocaleString('de-DE')}</td><td>${money(x.ticketIncome)}</td><td>${money(x.merchSales)}</td><td>${money(x.merchIncome)}</td></tr>`).join('')}</tbody></table>`:'<p class="muted">Noch keine Spielabrechnung vorhanden.</p>'}</div>`}
function stadium(){const c=getUserClub(),s=c.stadium;const stadiumImage=s.capacity<30000?'stadium-small.jpg':s.capacity<55000?'stadium-medium.jpg':'stadium-large.jpg';return `<div class="grid cols-2"><div class="card"><div class="icon-title"><img src="assets/stadium-icon.jpg" alt="Stadion"><h2>${esc(s.name)}</h2></div><img class="stadium-visual" src="assets/${stadiumImage}" alt="Retro-Stadionansicht"><div class="stat">${s.capacity.toLocaleString('de-DE')} Plätze</div><p>Zustand: ${s.condition}%</p><div class="progress"><span style="width:${s.condition}%"></span></div><p>Ticketpreis: ${money(s.ticketPrice)}</p></div><div class="card"><h2>Ausbau</h2><p>Erweitere um 5.000 Plätze.</p><p>Kosten: <b>${money(12e6)}</b></p><button id="upgradeStadium">Ausbauen</button><h3>Ticketpreis</h3><input id="ticketPrice" type="range" min="10" max="100" value="${s.ticketPrice}"><span id="ticketPriceLabel"> ${money(s.ticketPrice)}</span><h3 style="margin-top:22px">Stadionstufen</h3><div class="grid cols-3"><img class="retro-strip" src="assets/stadium-small.jpg" alt="Kleines Stadion"><img class="retro-strip" src="assets/stadium-medium.jpg" alt="Mittleres Stadion"><img class="retro-strip" src="assets/stadium-large.jpg" alt="Großes Stadion"></div></div></div>`}
function international(){const q=state.international.qualified;return `<div class="card"><h2>Internationaler Wettbewerb</h2>${q?`<p class="good"><b>Qualifiziert</b></p><p>Dein Verein nimmt in dieser Saison am International Champions Cup teil.</p>`:`<p>Die besten drei Teams der Liga qualifizieren sich für den internationalen Wettbewerb der nächsten Saison.</p>`}<h3>Europäische Topligen</h3><p class="muted">Das Spiel enthält bereits acht Nationalligen. Weitere Ligen lassen sich in <code>data.js</code> ergänzen.</p></div>`}
function liveView(){
  if(!liveMatch)return `<div class="card"><h2>Kein Live-Spiel aktiv</h2></div>`;
  const l=liveMatch;
  return `<div class="live-match card"><div class="live-top"><span class="viz-badge">LIVE</span><span id="liveMinute" class="live-clock">${l.minute}'</span></div><div class="live-scoreboard"><div><b>${esc(l.home.name)}</b><small>Heim</small></div><div id="liveScore" class="live-score">${l.homeGoals} : ${l.awayGoals}</div><div><b>${esc(l.away.name)}</b><small>Auswärts</small></div></div><div class="grid cols-3 match-finance-live"><div class="metric-box"><span>Zuschauer</span><b>${l.finance.attendance.toLocaleString('de-DE')}</b></div><div class="metric-box"><span>Ticketeinnahmen</span><b>${money(l.finance.ticketIncome)}</b></div><div class="metric-box"><span>Fanartikelverkauf</span><b>${money(l.finance.merchSales)}</b><small>Vereinseinnahme ${money(l.finance.merchIncome)}</small></div></div><div class="progress live-progress"><span id="liveProgress" style="width:${l.minute/90*100}%"></span></div><img class="hero-image live-pitch" src="assets/matchday.jpg" alt="Retro-Spieltagsansicht"><div class="grid cols-2 live-layout"><div class="card live-chat-card"><h2>Live-Ticker</h2><div id="liveFeed" class="live-feed" aria-live="polite">${liveFeedHtml()}</div></div><div class="card"><h2>Spielsteuerung</h2><div id="liveControls" class="live-controls">${l.finished?'<button id="continueAfterMatch" class="primary">Weiter zur Übersicht</button>':`<button id="pauseLive">${l.paused?'Fortsetzen':'Pause'}</button><button data-speed="1" class="${l.speed===1?'primary':''}">1×</button><button data-speed="2" class="${l.speed===2?'primary':''}">2×</button><button data-speed="4" class="${l.speed===4?'primary':''}">4×</button>`}</div><p class="muted">Eine Partie dauert bei 1× ungefähr 45 Sekunden. Der Ticker meldet Chancen, Tore, Karten, Ecken und Paraden.</p><div class="match-stats"><div><span>Heimstärke</span><b>${Math.round(l.homePower)}</b></div><div><span>Auswärtsstärke</span><b>${Math.round(l.awayPower)}</b></div></div></div></div></div>`;
}
function render(){if(!state)return; $('#seasonLabel').textContent=`Saison ${state.season} · Woche ${state.week} · ${state.league.country}`; const map={dashboard,squad,lineup,league,transfers,sponsors,finances,stadium,international,live:liveView}; $('#content').innerHTML=map[view](); bindDynamic();}
function bindDynamic(){
  const openSponsors=$('#openSponsors');if(openSponsors)openSponsors.onclick=()=>{$$('.nav').forEach(x=>x.classList.remove('active'));const n=$('.nav[data-view="sponsors"]');if(n)n.classList.add('active');view='sponsors';render();};
  const pause=$('#pauseLive');if(pause)pause.onclick=()=>{liveMatch.paused=!liveMatch.paused;pause.textContent=liveMatch.paused?'Fortsetzen':'Pause';};
  $$('[data-speed]').forEach(btn=>btn.onclick=()=>{liveMatch.speed=+btn.dataset.speed;runLiveTimer();render();});
  const cont=$('#continueAfterMatch');if(cont)cont.onclick=()=>{liveMatch=null;view='dashboard';$('.nav[data-view="dashboard"]').classList.add('active');render();};
 $$('[data-lineup]').forEach(sel=>sel.onchange=e=>{const i=+e.target.dataset.lineup; state.selectedXI[i]=e.target.value; save();}); $$('[data-buy]').forEach(btn=>btn.onclick=()=>buyPlayer(+btn.dataset.buy)); $$('[data-list-player]').forEach(btn=>btn.onclick=()=>toggleTransferList(btn.dataset.listPlayer)); $$('[data-accept-offer]').forEach(btn=>btn.onclick=()=>acceptOutgoingOffer(btn.dataset.acceptOffer)); $$('[data-reject-offer]').forEach(btn=>btn.onclick=()=>rejectOutgoingOffer(btn.dataset.rejectOffer)); $$('[data-asking-price]').forEach(inp=>inp.onchange=()=>updateAskingPrice(inp.dataset.askingPrice,inp.value)); $$('[data-accept-sponsor]').forEach(btn=>btn.onclick=()=>acceptSponsorOffer(btn.dataset.acceptSponsor)); $$('[data-reject-sponsor]').forEach(btn=>btn.onclick=()=>rejectSponsorOffer(btn.dataset.rejectSponsor)); const up=$('#upgradeStadium');if(up)up.onclick=()=>{const c=getUserClub();if(c.balance<12e6)return alert('Zu wenig Geld.');c.balance-=12e6;c.stadium.capacity+=5000;c.stadium.condition=100;save();render();}; const range=$('#ticketPrice');if(range)range.oninput=e=>{$('#ticketPriceLabel').textContent=' '+money(+e.target.value);getUserClub().stadium.ticketPrice=+e.target.value;save();};}
function buyPlayer(i){const p=state.transferList[i],c=getUserClub();if(!p)return;if(c.budget<p.asking)return alert('Transferbudget zu niedrig.');c.budget-=p.asking;c.balance-=p.asking;c.squad.push({...p,id:uid()});state.transferList.splice(i,1);state.news.unshift(`${p.name} wurde für ${money(p.asking)} verpflichtet.`);save();render();}
function setupStart(){const cs=$('#countrySelect'),ls=$('#leagueSelect'),clubs=$('#clubSelect');COUNTRIES.forEach((c,i)=>cs.add(new Option(c.name,i)));function leagues(){ls.innerHTML='';COUNTRIES[+cs.value].leagues.forEach((l,i)=>ls.add(new Option(l.name,i)));teams();}function teams(){clubs.innerHTML='';COUNTRIES[+cs.value].leagues[+ls.value].clubs.forEach(n=>clubs.add(new Option(n,n)));}cs.onchange=leagues;ls.onchange=teams;leagues();$('#startBtn').onclick=()=>{$('#startScreen').style.display='none';newGame(+cs.value,+ls.value,clubs.value)};}
/* Version 1.3.1 – Formationen, Sortierung, Live-Taktik, Karten und Sperren */
const FORMATIONS={
  '4-4-2':['TW','RV','IV','IV','LV','RM','ZM','ZM','LM','ST','ST'],
  '5-3-2':['TW','RV','IV','IV','IV','LV','ZM','ZM','ZM','ST','ST'],
  '4-3-3':['TW','RV','IV','IV','LV','ZM','ZM','ZM','RA','ST','LA']
};
const POSITION_ORDER={TW:0,RV:1,IV:2,LV:3,DM:4,RM:5,ZM:6,LM:7,OM:8,RA:9,LA:10,ST:11};
let squadSort='position';
let transferSort='position';

function ensureGameSystems(){
  if(!state)return;
  if(!FORMATIONS[state.formation])state.formation='4-4-2';
  if(!state.matchSettings)state.matchSettings={tactic:'balanced',aggression:'fair'};
  state.league.clubs.forEach(c=>c.squad.forEach(p=>{
    if(p.yellowCards===undefined)p.yellowCards=0;
    if(p.redCards===undefined)p.redCards=0;
    if(p.suspensionGames===undefined)p.suspensionGames=0;
  }));
  normalizeLineup();
}
function sortPlayers(list,mode){
  return [...list].sort((a,b)=>mode==='rating'?(b.rating-a.rating)||((POSITION_ORDER[a.position]??99)-(POSITION_ORDER[b.position]??99)):((POSITION_ORDER[a.position]??99)-(POSITION_ORDER[b.position]??99))||(b.rating-a.rating));
}
function normalizeLineup(){
  if(!state)return;
  const c=getUserClub(),slots=FORMATIONS[state.formation]||FORMATIONS['4-4-2'];
  const validIds=new Set(c.squad.map(p=>p.id));
  const picked=[];
  (state.selectedXI||[]).forEach(id=>{const p=c.squad.find(x=>x.id===id);if(validIds.has(id)&&p&&p.suspensionGames<=0&&!picked.includes(id)&&picked.length<slots.length)picked.push(id);});
  const available=sortPlayers(c.squad.filter(p=>!picked.includes(p.id)&&p.suspensionGames<=0),'rating');
  while(picked.length<slots.length&&available.length)picked.push(available.shift().id);
  state.selectedXI=picked.slice(0,slots.length);
}
function lineupGroupAverages(){
  const c=getUserClub(),slots=FORMATIONS[state.formation]||FORMATIONS['4-4-2'];
  const groups={TW:[],ABW:[],MIT:[],ST:[]};
  slots.forEach((slot,i)=>{const p=c.squad.find(x=>x.id===state.selectedXI[i]);if(!p)return;const g=slot==='TW'?'TW':['RV','IV','LV'].includes(slot)?'ABW':['ST','RA','LA'].includes(slot)?'ST':'MIT';groups[g].push(p.rating);});
  const avg=a=>a.length?(a.reduce((s,n)=>s+n,0)/a.length).toFixed(1):'–';
  return {TW:avg(groups.TW),ABW:avg(groups.ABW),MIT:avg(groups.MIT),ST:avg(groups.ST)};
}
function playerOption(p,sel,index){
  const used=(state.selectedXI||[]).some((id,i)=>i!==index&&id===p.id);
  const suspended=p.suspensionGames>0;
  return `<option value="${p.id}" ${p.id===sel?'selected':''} ${(used||suspended)&&p.id!==sel?'disabled':''}>${esc(p.name)} (${p.position}, ${p.rating}${suspended?`, gesperrt ${p.suspensionGames}`:''})</option>`;
}
function lineup(){
  ensureGameSystems();const c=getUserClub(),slots=FORMATIONS[state.formation];
  return `<div class="card"><h2>Aufstellung</h2><div class="lineup-toolbar"><label>Formation<select id="formationSelect"><option value="4-4-2" ${state.formation==='4-4-2'?'selected':''}>4-4-2</option><option value="5-3-2" ${state.formation==='5-3-2'?'selected':''}>5-3-2</option><option value="4-3-3" ${state.formation==='4-3-3'?'selected':''}>4-3-3</option></select></label><span class="muted">Bereits aufgestellte und gesperrte Spieler können nicht doppelt gewählt werden.</span></div><div class="lineup-grid formation-${state.formation.replaceAll('-','')}">${slots.map((pos,i)=>{const sel=state.selectedXI[i];return `<div class="lineup-slot"><b>${pos}</b><select data-lineup="${i}">${sortPlayers(c.squad,'position').map(p=>playerOption(p,sel,i)).join('')}</select></div>`}).join('')}</div></div>`;
}
function squad(){
  ensureTransferState();ensureGameSystems();const c=getUserClub(),players=sortPlayers(c.squad,squadSort);
  return `<div class="card"><div class="section-toolbar"><div><h2>Kader – ${esc(c.name)}</h2><p class="muted">Spieler verwalten, sortieren und auf die Transferliste setzen.</p></div><label>Sortierung<select id="squadSort"><option value="position" ${squadSort==='position'?'selected':''}>Position</option><option value="rating" ${squadSort==='rating'?'selected':''}>Stärke</option></select></label></div><div class="player-row transfer-header"><span>Pos</span><span>Name</span><span>Alter</span><span>Stärke</span><span>Fitness</span><span>Wert</span><span>Status</span><span>Aktion</span></div>${players.map(p=>`<div class="player-row transfer-row"><span class="badge">${p.position}</span><span>${esc(p.name)}${p.suspensionGames>0?` <span class="suspension-label">Gesperrt ${p.suspensionGames}</span>`:''}</span><span>${p.age}</span><b>${p.rating}</b><span>${p.fitness}%</span><span>${money(p.value)}</span><span>${p.transferListed?'<span class="listed-label">Transferliste</span>':'—'}${p.yellowCards?`<small class="card-count"> ${p.yellowCards} Gelbe</small>`:''}</span><span><button data-list-player="${p.id}" class="${p.transferListed?'danger':''}">${p.transferListed?'Entfernen':'Anbieten'}</button></span></div>`).join('')}</div>`;
}
function transfers(){
  ensureTransferState();ensureGameSystems();const c=getUserClub(),pending=state.outgoingOffers.filter(o=>o.status==='pending'),market=sortPlayers(state.transferList,transferSort).slice(0,20),listed=sortPlayers(listedPlayers(),transferSort);
  return `<div class="card transfer-sortbar"><label>Transferlisten sortieren<select id="transferSort"><option value="position" ${transferSort==='position'?'selected':''}>Position</option><option value="rating" ${transferSort==='rating'?'selected':''}>Stärke</option></select></label></div><div class="grid cols-2 transfer-summary"><div class="card"><h2>Einkäufe</h2><p>Transferbudget: <b>${money(c.budget)}</b></p><table><thead><tr><th>Spieler</th><th>Alter</th><th>Pos</th><th>Stärke</th><th>Verein</th><th>Preis</th><th></th></tr></thead><tbody>${market.map(p=>{const realIndex=state.transferList.findIndex(x=>x.id===p.id);return `<tr><td>${esc(p.name)}</td><td>${p.age}</td><td>${p.position}</td><td>${p.rating}</td><td>${esc(p.fromClub)}</td><td>${money(p.asking)}</td><td><button data-buy="${realIndex}">Kaufen</button></td></tr>`}).join('')}</tbody></table></div><div class="card"><h2>Eingegangene Angebote</h2>${pending.length?pending.map(o=>{const p=c.squad.find(x=>x.id===o.playerId),b=getClub(o.bidderId);return p&&b?`<div class="offer-card"><div><b>${esc(b.name)}</b> bietet für <b>${esc(p.name)}</b> (${p.age})</div><div class="offer-price">${money(o.amount)}</div><div class="muted">Marktwert ${money(p.value)} · Forderung ${money(p.askingPrice)}</div><div class="offer-actions"><button data-accept-offer="${o.id}" class="primary">Annehmen</button><button data-reject-offer="${o.id}" class="danger">Ablehnen</button></div></div>`:''}).join(''):'<p class="muted">Momentan liegen keine Angebote vor.</p>'}</div></div><div class="card" style="margin-top:16px"><h2>Deine Transferliste</h2>${listed.length?`<table><thead><tr><th>Spieler</th><th>Alter</th><th>Pos</th><th>Stärke</th><th>Marktwert</th><th>Wunschpreis</th><th>Aktuelles Gebot</th><th></th></tr></thead><tbody>${listed.map(p=>{const o=activeOfferFor(p.id),b=o?getClub(o.bidderId):null;return `<tr><td>${esc(p.name)}</td><td>${p.age}</td><td>${p.position}</td><td>${p.rating}</td><td>${money(p.value)}</td><td><input class="price-input" data-asking-price="${p.id}" type="number" min="${Math.round(p.value*.5)}" max="${Math.round(p.value*2.5)}" step="100000" value="${p.askingPrice}"></td><td>${o&&b?`${esc(b.name)}: <b>${money(o.amount)}</b>`:'Noch keines'}</td><td><button data-list-player="${p.id}" class="danger">Entfernen</button></td></tr>`}).join('')}</tbody></table>`:'<p>Noch kein Spieler wurde auf die Transferliste gesetzt.</p>'}</div>`;
}
function dashboard(){
  ensureGameSystems();const c=getUserClub(),table=sortedTable(),pos=table.findIndex(x=>x.id===c.id)+1,next=state.league.fixtures[state.league.round]?.find(f=>f.home===c.id||f.away===c.id),a=lineupGroupAverages();
  return `<div class="grid cols-3"><div class="card"><div class="muted">Verein</div><div class="stat">${esc(c.name)}</div><div>${esc(state.league.name)}</div></div><div class="card"><div class="muted">Tabellenplatz</div><div class="stat">${pos}.</div><div>${c.points} Punkte</div></div><div class="card"><div class="muted">Kontostand</div><div class="stat ${c.balance<0?'bad':'good'}">${money(c.balance)}</div><div>Transferbudget: ${money(c.budget)}</div></div></div><div class="card lineup-averages"><h2>Durchschnittsstärke der Aufstellung · ${state.formation}</h2><div class="grid cols-4"><div class="metric-box"><span>TW</span><b>${a.TW}</b></div><div class="metric-box"><span>ABW</span><b>${a.ABW}</b></div><div class="metric-box"><span>MIT</span><b>${a.MIT}</b></div><div class="metric-box"><span>ST</span><b>${a.ST}</b></div></div></div><div class="card" style="margin-top:16px"><div class="icon-title"><img src="assets/trophy-icon.jpg" alt="Pokal"><h2>Spieltag im Retro-Stil</h2></div><img class="hero-image" src="assets/matchday.jpg" alt="Pixel-Art Fußballspiel im Stadion"></div><div class="grid cols-2" style="margin-top:16px"><div class="card"><h2>Nächstes Spiel</h2>${next?`<div class="stat">${esc(getClub(next.home).name)} – ${esc(getClub(next.away).name)}</div><p class="muted">Spieltag ${state.league.round+1}</p>`:'<p>Saison beendet.</p>'}${state.lastMatch?`<h3>Letztes Ergebnis</h3><p>${esc(state.lastMatch.home)} <b>${state.lastMatch.score}</b> ${esc(state.lastMatch.away)}</p><div class="last-match-finance"><span>👥 ${Number(state.lastMatch.attendance||0).toLocaleString('de-DE')} Zuschauer</span><span>🎟 ${money(state.lastMatch.ticketIncome||0)} Tickets</span><span>🛍 ${money(state.lastMatch.merchSales||0)} Fanartikelverkauf</span><span>💶 ${money(state.lastMatch.merchIncome||0)} Vereinserlös Fanartikel</span></div>`:''}</div><div class="card"><h2>Manager-News</h2>${state.news.slice(0,6).map(n=>`<div class="fixture">${esc(n)}</div>`).join('')}</div></div><div class="card sponsor-quick-card" style="margin-top:16px"><div><h2>★ Sponsoren & Vermarktung</h2><p>Trikotsponsor, Werbebanden, Stadionname und Fanartikel verwalten.</p></div><button id="openSponsors" class="primary">Sponsoren öffnen</button></div>`;
}
function effectiveUserPower(base){
  const t=liveMatch?.tactic||state.matchSettings.tactic;
  return base*(t==='offensive'?1.07:t==='defensive'?.96:1);
}
function startLiveMatch(f,round){
  if(liveMatch)return;ensureGameSystems();normalizeLineup();
  const h=getClub(f.home),a=getClub(f.away),finance=calculateUserMatchFinance(h,a),userHome=h.id===state.userClubId;
  let hp=teamPower(h)+2,ap=teamPower(a);
  if(userHome)hp=effectiveUserPower(hp);else ap=effectiveUserPower(ap);
  liveMatch={fixture:f,home:h,away:a,minute:0,homeGoals:0,awayGoals:0,events:[],paused:false,speed:1,finished:false,homePower:hp,awayPower:ap,otherFixtures:round.filter(x=>x!==f),finance,tactic:state.matchSettings.tactic,aggression:state.matchSettings.aggression,userHome,yellowHome:0,yellowAway:0,redHome:0,redAway:0};
  document.body.classList.add('match-running');view='live';$$('.nav').forEach(x=>x.classList.remove('active'));render();addLiveEvent(0,'kickoff',commentary('kickoff'));runLiveTimer();
}
function cardPlayer(team,type){
  const eligible=team.squad.filter(p=>p.suspensionGames<=0);if(!eligible.length)return null;const p=eligible[rand(0,eligible.length-1)];
  if(type==='yellow'){p.yellowCards++;if(p.yellowCards>=4){p.yellowCards=0;p.suspensionGames=Math.max(p.suspensionGames,1);state.news.unshift(`${p.name} ist nach vier Gelben Karten für ein Spiel gesperrt.`);}}
  else{p.redCards++;p.suspensionGames=Math.max(p.suspensionGames,1);state.news.unshift(`${p.name} ist nach einer Roten Karte für ein Spiel gesperrt.`);}
  return p;
}
function processLiveMinute(){
  const m=liveMatch.minute;if(m===45){addLiveEvent(m,'halftime',commentary('halftime'));return;}
  const total=Math.max(1,liveMatch.homePower+liveMatch.awayPower),homeAttack=Math.random()<liveMatch.homePower/total,team=homeAttack?liveMatch.home:liveMatch.away,player=randomPlayer(team,true),roll=Math.random();
  const isUser=team.id===state.userClubId,tactic=isUser?liveMatch.tactic:'balanced',agg=isUser?liveMatch.aggression:'fair';
  const goalThreshold=tactic==='offensive'?.034:tactic==='defensive'?.023:.028;
  const chanceThreshold=goalThreshold+(tactic==='offensive'?.057:tactic==='defensive'?.038:.047);
  const cardRate=agg==='hard'?.030:.010,redChance=agg==='hard'?.18:.06;
  if(roll<goalThreshold){const attack=homeAttack?liveMatch.homePower:liveMatch.awayPower,defence=homeAttack?liveMatch.awayPower:liveMatch.homePower;if(Math.random()<clamp(.30+(attack-defence)/120,.18,.48)){if(homeAttack)liveMatch.homeGoals++;else liveMatch.awayGoals++;const p=team.squad.find(x=>x.name===player);if(p)p.goals++;addLiveEvent(m,'goal',commentary('goal',team.name,player));}else addLiveEvent(m,'save',commentary('save',team.name,player));}
  else if(roll<chanceThreshold)addLiveEvent(m,'chance',commentary('chance',team.name,player));
  else if(roll<chanceThreshold+.02)addLiveEvent(m,'corner',commentary('corner',team.name,player));
  else if(roll<chanceThreshold+.02+cardRate){const type=Math.random()<redChance?'red':'yellow',p=cardPlayer(team,type);if(p){if(homeAttack){if(type==='red')liveMatch.redHome++;else liveMatch.yellowHome++;}else{if(type==='red')liveMatch.redAway++;else liveMatch.yellowAway++;}addLiveEvent(m,type,type==='red'?`Rote Karte für ${p.name} (${team.name})!` : commentary('card',team.name,p.name));}}
}
function liveView(){
  if(!liveMatch)return `<div class="card"><h2>Kein Live-Spiel aktiv</h2></div>`;const l=liveMatch;
  return `<div class="live-match card"><div class="live-top"><span class="viz-badge">LIVE</span><span id="liveMinute" class="live-clock">${l.minute}'</span></div><div class="live-scoreboard"><div><b>${esc(l.home.name)}</b><small>Heim · 🟨 ${l.yellowHome} 🟥 ${l.redHome}</small></div><div id="liveScore" class="live-score">${l.homeGoals} : ${l.awayGoals}</div><div><b>${esc(l.away.name)}</b><small>Auswärts · 🟨 ${l.yellowAway} 🟥 ${l.redAway}</small></div></div><div class="grid cols-3 match-finance-live"><div class="metric-box"><span>Zuschauer</span><b>${l.finance.attendance.toLocaleString('de-DE')}</b></div><div class="metric-box"><span>Ticketeinnahmen</span><b>${money(l.finance.ticketIncome)}</b></div><div class="metric-box"><span>Fanartikelverkauf</span><b>${money(l.finance.merchSales)}</b><small>Vereinseinnahme ${money(l.finance.merchIncome)}</small></div></div><div class="progress live-progress"><span id="liveProgress" style="width:${l.minute/90*100}%"></span></div><img class="hero-image live-pitch" src="assets/matchday.jpg" alt="Retro-Spieltagsansicht"><div class="grid cols-2 live-layout"><div class="card live-chat-card"><h2>Live-Ticker</h2><div id="liveFeed" class="live-feed" aria-live="polite">${liveFeedHtml()}</div></div><div class="card"><h2>Spielsteuerung</h2><div id="liveControls" class="live-controls">${l.finished?'<button id="continueAfterMatch" class="primary">Weiter zur Übersicht</button>':`<button id="pauseLive">${l.paused?'Fortsetzen':'Pause'}</button><button data-speed="1" class="${l.speed===1?'primary':''}">1×</button><button data-speed="2" class="${l.speed===2?'primary':''}">2×</button><button data-speed="4" class="${l.speed===4?'primary':''}">4×</button>`}</div>${!l.finished?`<div class="live-tactics"><label>Taktik<select id="liveTactic"><option value="offensive" ${l.tactic==='offensive'?'selected':''}>Offensiv</option><option value="balanced" ${l.tactic==='balanced'?'selected':''}>Ausgeglichen</option><option value="defensive" ${l.tactic==='defensive'?'selected':''}>Defensiv</option></select></label><label>Zweikampf<select id="liveAggression"><option value="fair" ${l.aggression==='fair'?'selected':''}>Fair</option><option value="hard" ${l.aggression==='hard'?'selected':''}>Hart</option></select></label></div>`:''}<p class="muted">Offensiv erhöht Chancen und Risiko. Hartes Spiel erzeugt mehr Karten und mögliche Sperren.</p><div class="match-stats"><div><span>Heimstärke</span><b>${Math.round(l.homePower)}</b></div><div><span>Auswärtsstärke</span><b>${Math.round(l.awayPower)}</b></div></div></div></div></div>`;
}
function finishLiveMatch(){
  if(!liveMatch||liveMatch.finished)return;liveMatch.finished=true;clearInterval(liveTimer);addLiveEvent(90,'final',commentary('final'));applyMatchResult(liveMatch.fixture,liveMatch.homeGoals,liveMatch.awayGoals);liveMatch.otherFixtures.forEach(simulateMatch);state.league.round++;state.week++;
  const user=getUserClub();user.squad.forEach(p=>{p.fitness=clamp(p.fitness+rand(2,7),45,100);if(p.suspensionGames>0&&!state.selectedXI.includes(p.id))p.suspensionGames=Math.max(0,p.suspensionGames-1);});
  user.balance-=user.squad.reduce((sum,p)=>sum+p.wage,0);if(state.week%4===0)user.balance-=rand(250000,700000);processOutgoingTransferOffers();weeklySponsorIncome();save();document.body.classList.remove('match-running');updateLiveDisplay();render();
}
function render(){
  if(!state)return;ensureGameSystems();document.body.classList.toggle('match-running',!!liveMatch&&!liveMatch.finished);$('#seasonLabel').textContent=`Saison ${state.season} · Woche ${state.week} · ${state.league.country} · Version 1.3.1`;const map={dashboard,squad,lineup,league,transfers,sponsors,finances,stadium,international,live:liveView};$('#content').innerHTML=map[view]();bindDynamic();
}
function bindDynamic(){
  const openSponsors=$('#openSponsors');if(openSponsors)openSponsors.onclick=()=>{$$('.nav').forEach(x=>x.classList.remove('active'));const n=$('.nav[data-view="sponsors"]');if(n)n.classList.add('active');view='sponsors';render();};
  const pause=$('#pauseLive');if(pause)pause.onclick=()=>{liveMatch.paused=!liveMatch.paused;pause.textContent=liveMatch.paused?'Fortsetzen':'Pause';};
  $$('[data-speed]').forEach(btn=>btn.onclick=()=>{liveMatch.speed=+btn.dataset.speed;runLiveTimer();render();});
  const cont=$('#continueAfterMatch');if(cont)cont.onclick=()=>{liveMatch=null;document.body.classList.remove('match-running');view='dashboard';$$('.nav').forEach(x=>x.classList.remove('active'));$('.nav[data-view="dashboard"]')?.classList.add('active');render();};
  const formation=$('#formationSelect');if(formation)formation.onchange=e=>{state.formation=e.target.value;normalizeLineup();save();render();};
  const sqSort=$('#squadSort');if(sqSort)sqSort.onchange=e=>{squadSort=e.target.value;render();};
  const trSort=$('#transferSort');if(trSort)trSort.onchange=e=>{transferSort=e.target.value;render();};
  const tactic=$('#liveTactic');if(tactic)tactic.onchange=e=>{liveMatch.tactic=e.target.value;state.matchSettings.tactic=e.target.value;const base=teamPower(liveMatch.userHome?liveMatch.home:liveMatch.away);const adjusted=effectiveUserPower(base);if(liveMatch.userHome)liveMatch.homePower=adjusted+2;else liveMatch.awayPower=adjusted;save();};
  const aggression=$('#liveAggression');if(aggression)aggression.onchange=e=>{liveMatch.aggression=e.target.value;state.matchSettings.aggression=e.target.value;save();};
  $$('[data-lineup]').forEach(sel=>sel.onchange=e=>{const i=+e.target.dataset.lineup,newId=e.target.value;if(state.selectedXI.some((id,j)=>j!==i&&id===newId)){alert('Dieser Spieler ist bereits auf einer anderen Position aufgestellt.');render();return;}const p=getUserClub().squad.find(x=>x.id===newId);if(p?.suspensionGames>0){alert('Dieser Spieler ist gesperrt.');render();return;}state.selectedXI[i]=newId;save();render();});
  $$('[data-buy]').forEach(btn=>btn.onclick=()=>buyPlayer(+btn.dataset.buy));$$('[data-list-player]').forEach(btn=>btn.onclick=()=>toggleTransferList(btn.dataset.listPlayer));$$('[data-accept-offer]').forEach(btn=>btn.onclick=()=>acceptOutgoingOffer(btn.dataset.acceptOffer));$$('[data-reject-offer]').forEach(btn=>btn.onclick=()=>rejectOutgoingOffer(btn.dataset.rejectOffer));$$('[data-asking-price]').forEach(inp=>inp.onchange=()=>updateAskingPrice(inp.dataset.askingPrice,inp.value));$$('[data-accept-sponsor]').forEach(btn=>btn.onclick=()=>acceptSponsorOffer(btn.dataset.acceptSponsor));$$('[data-reject-sponsor]').forEach(btn=>btn.onclick=()=>rejectSponsorOffer(btn.dataset.rejectSponsor));
  const up=$('#upgradeStadium');if(up)up.onclick=()=>{const c=getUserClub();if(c.balance<12e6)return alert('Zu wenig Geld.');c.balance-=12e6;c.stadium.capacity+=5000;c.stadium.condition=100;save();render();};const range=$('#ticketPrice');if(range)range.oninput=e=>{$('#ticketPriceLabel').textContent=' '+money(+e.target.value);getUserClub().stadium.ticketPrice=+e.target.value;save();};
}
function load(){const raw=storageGet();if(raw){state=JSON.parse(raw);liveMatch=null;clearInterval(liveTimer);ensureTransferState();ensure36GameSeason();ensureSponsorState();ensureMatchFinanceState();ensureGameSystems();if(!state.sponsors.offers.length)generateSponsorOffers(true);save();$('#startScreen').style.display='none';render();}else alert('Kein Spielstand vorhanden.');}

function showFatalError(error){
  console.error(error);
  const content=$('#content');
  if(content)content.innerHTML=`<div class="card"><h2>Das Spiel konnte nicht angezeigt werden</h2><p>${esc(error?.message||String(error))}</p><button id="recoverGame" class="primary">Oberfläche neu laden</button></div>`;
  const recover=$('#recoverGame');if(recover)recover.onclick=()=>location.reload();
}
function boot(){
  try{
    setupStart();
    $$('.nav').forEach(b=>b.onclick=()=>{if(liveMatch&&!liveMatch.finished)return;$$('.nav').forEach(x=>x.classList.remove('active'));b.classList.add('active');view=b.dataset.view;render();});
    $('#nextWeekBtn').onclick=nextWeek;
    $('#saveBtn').onclick=()=>{save();alert('Spiel im Browser gespeichert.');};
    $('#loadBtn').onclick=load;
    const diskSaveBtn=$('#diskSaveBtn'); if(diskSaveBtn)diskSaveBtn.onclick=saveToDisk;
    const diskLoadBtn=$('#diskLoadBtn'); if(diskLoadBtn)diskLoadBtn.onclick=()=>$('#diskLoadInput')?.click();
    const diskLoadInput=$('#diskLoadInput'); if(diskLoadInput)diskLoadInput.onchange=e=>loadFromDiskFile(e.target.files?.[0]);
    $('#newBtn').onclick=()=>{if(confirm('Wirklich ein neues Spiel starten?')){liveMatch=null;clearInterval(liveTimer);state=null;view='dashboard';$('#content').innerHTML='';$('#startScreen').style.display='grid';}};
    if(storageHas())load();
  }catch(error){showFatalError(error);}
}
window.addEventListener('error',event=>showFatalError(event.error||new Error(event.message)));
window.__fmBoot=boot;

/* Version 1.4 – Wappen, Momentum, Live-Wechsel, Gastro, Finanzabschluss und dynamischer Transfermarkt */
var selectedClubRosterId = null;

function crestColors(name){
  let h=0;for(let i=0;i<name.length;i++)h=(h*31+name.charCodeAt(i))>>>0;
  const palette=['#b91c1c','#1d4ed8','#047857','#7e22ce','#c2410c','#0f766e','#4338ca','#a21caf'];
  return [palette[h%palette.length],palette[(Math.floor(h/7)+3)%palette.length]];
}
function clubInitials(name){
  const clean=name.replace(/FC |SC |SV |FK |AC |AS |RC |Red Bull |Borussia |Bayer /gi,'').trim();
  const words=clean.split(/\s+/).filter(Boolean);return (words.length>1?words[0][0]+words[words.length-1][0]:clean.slice(0,2)).toUpperCase();
}
function clubCrest(club,size='normal'){
  const name=typeof club==='string'?club:club.name,[a,b]=crestColors(name);
  return `<span class="club-crest ${size}" style="--crest-a:${a};--crest-b:${b}" title="${esc(name)}"><span>${esc(clubInitials(name))}</span></span>`;
}
function clubNameWithCrest(club,size='small'){return `<span class="club-name-crest">${clubCrest(club,size)}<span>${esc(club.name)}</span></span>`;}

function ensureV14State(){
  if(!state)return;ensureGameSystems();ensureTransferState();ensureMatchFinanceState();
  if(!state.dynamicMarketWeek)state.dynamicMarketWeek=state.week;
  if(!state.transferHistory)state.transferHistory=[];
  state.league.clubs.forEach(c=>c.squad.forEach(p=>{if(p.onAiMarket===undefined)p.onAiMarket=false;}));
  if(!selectedClubRosterId)selectedClubRosterId=state.league.clubs.find(c=>c.id!==state.userClubId)?.id||state.userClubId;
}
function ensureMatchFinanceState(){
  if(!Array.isArray(state.matchFinanceHistory))state.matchFinanceHistory=[];
  if(state.lastMatch&&state.lastMatch.gastroIncome===undefined){
    Object.assign(state.lastMatch,{gastroIncome:0,matchCosts:0,netIncome:(state.lastMatch.ticketIncome||0)+(state.lastMatch.merchIncome||0),costItems:[]});
  }
}
function calculateUserMatchFinance(h,a){
  ensureSponsorState();ensureMatchFinanceState();const user=getUserClub(),isHome=h.id===user.id,attendance=estimateAttendance(h,a);
  const ticketIncome=isHome?Math.round(attendance*user.stadium.ticketPrice):0;
  const score=clubSuccessScore(),resultFactor=.9+Math.random()*.25,venueFactor=isHome?1:.58;
  const merchSales=Math.round(user.fans*(.018+score*.018)*venueFactor*resultFactor);
  const merchRate=state.sponsors.merch?state.sponsors.merch.royalty/100:.30;
  const merchIncome=Math.round(merchSales*merchRate);
  const gastroGross=isHome?Math.round(attendance*(7.5+Math.random()*8.5)):0;
  const gastroIncome=Math.round(gastroGross*.58);
  const securityCost=isHome?Math.round(45000+attendance*2.2):Math.round(18000+attendance*.35);
  const stadiumCost=isHome?Math.round(60000+user.stadium.capacity*.72):0;
  const travelCost=isHome?0:Math.round(35000+user.squad.length*1800);
  const matchBonus=Math.round(state.selectedXI.reduce((sum,id)=>{const p=user.squad.find(x=>x.id===id);return sum+(p?p.wage*.08:0)},0));
  const gastroCost=isHome?gastroGross-gastroIncome:0;
  const matchCosts=securityCost+stadiumCost+travelCost+matchBonus+gastroCost;
  const totalRevenue=ticketIncome+merchIncome+gastroGross;
  const netIncome=totalRevenue-matchCosts;
  return {attendance,ticketIncome,merchSales,merchIncome,gastroGross,gastroIncome,gastroCost,securityCost,stadiumCost,travelCost,matchBonus,matchCosts,totalRevenue,netIncome,isHome};
}
function financeBreakdownHtml(f){
  return `<div class="finance-breakdown"><div class="finance-column"><h3>Einnahmen</h3><div><span>Tickets</span><b>${money(f.ticketIncome||0)}</b></div><div><span>Fanartikel-Erlös</span><b>${money(f.merchIncome||0)}</b></div><div><span>Gastronomieverkauf</span><b>${money(f.gastroGross||0)}</b></div><div class="finance-total"><span>Summe Einnahmen</span><b>${money(f.totalRevenue||0)}</b></div></div><div class="finance-column"><h3>Kosten</h3><div><span>Wareneinsatz Gastro</span><b>− ${money(f.gastroCost||0)}</b></div><div><span>Sicherheit</span><b>− ${money(f.securityCost||0)}</b></div><div><span>Stadionbetrieb</span><b>− ${money(f.stadiumCost||0)}</b></div><div><span>Reisekosten</span><b>− ${money(f.travelCost||0)}</b></div><div><span>Spielprämien</span><b>− ${money(f.matchBonus||0)}</b></div><div class="finance-total"><span>Summe Kosten</span><b>− ${money(f.matchCosts||0)}</b></div></div><div class="finance-saldo ${f.netIncome>=0?'positive':'negative'}"><span>Spieltags-Saldo</span><b>${money(f.netIncome||0)}</b><small>bereits im Kontostand verbucht</small></div></div>`;
}

function addDynamicTransferPlayers(){
  ensureV14State();
  const user=getUserClub();
  state.transferList=state.transferList.filter(p=>state.league.clubs.some(c=>c.id===p.fromClubId||c.name===p.fromClub));
  state.league.clubs.filter(c=>c.id!==user.id).forEach(c=>{
    const possible=c.squad.filter(p=>!state.transferList.some(x=>x.sourcePlayerId===p.id));
    if(possible.length>15&&Math.random()<.34){
      const p=possible[rand(0,possible.length-1)];
      const asking=Math.round(p.value*(.92+Math.random()*.38));
      state.transferList.push({...p,id:uid(),sourcePlayerId:p.id,fromClubId:c.id,fromClub:c.name,asking});p.onAiMarket=true;
      state.news.unshift(`${c.name} hat ${p.name} (${p.position}, ${p.rating}) auf den Transfermarkt gesetzt.`);
    }
  });
  while(state.transferList.length>55)state.transferList.shift();state.dynamicMarketWeek=state.week;
}
function buyPlayer(i){
  ensureV14State();const market=state.transferList[i],user=getUserClub();if(!market)return;
  if(user.budget<market.asking||user.balance<market.asking)return alert('Transferbudget oder Kontostand zu niedrig.');
  const seller=market.fromClubId?getClub(market.fromClubId):state.league.clubs.find(c=>c.name===market.fromClub);
  let player=null;
  if(seller&&market.sourcePlayerId){const ix=seller.squad.findIndex(p=>p.id===market.sourcePlayerId);if(ix>=0)player=seller.squad.splice(ix,1)[0];}
  if(!player)player={...market,id:uid()};
  player.transferListed=false;player.onAiMarket=false;user.squad.push(player);user.budget-=market.asking;user.balance-=market.asking;
  if(seller){seller.balance+=market.asking;seller.budget+=Math.round(market.asking*.75);}
  state.transferHistory.unshift({week:state.week,player:player.name,from:market.fromClub,to:user.name,amount:market.asking});
  state.transferList.splice(i,1);state.news.unshift(`${player.name} kommt für ${money(market.asking)} von ${market.fromClub}.`);save();render();
}
function poachPlayer(clubId,playerId){
  ensureV14State();const seller=getClub(clubId),user=getUserClub(),p=seller?.squad.find(x=>x.id===playerId);if(!seller||!p)return;
  const samePos=seller.squad.filter(x=>x.position===p.position).length;
  const premium=samePos<=2?1.55:p.age<24?1.38:1.22;
  const price=Math.round(p.value*premium/100000)*100000;
  if(!confirm(`${seller.name} verlangt voraussichtlich ${money(price)} für ${p.name}. Angebot abgeben?`))return;
  if(user.budget<price||user.balance<price)return alert('Transferbudget oder Kontostand zu niedrig.');
  const acceptance=clamp(.42+(premium-1.2)*.5+(samePos-2)*.12,.25,.88);
  if(Math.random()>acceptance){state.news.unshift(`${seller.name} lehnt dein Angebot für ${p.name} ab.`);alert('Der Verein hat das Angebot abgelehnt.');save();render();return;}
  seller.squad=seller.squad.filter(x=>x.id!==p.id);user.squad.push({...p,onAiMarket:false});user.balance-=price;user.budget-=price;seller.balance+=price;seller.budget+=Math.round(price*.75);
  state.transferList=state.transferList.filter(x=>x.sourcePlayerId!==p.id);state.transferHistory.unshift({week:state.week,player:p.name,from:seller.name,to:user.name,amount:price});state.news.unshift(`${p.name} wurde für ${money(price)} von ${seller.name} abgeworben.`);save();render();
}
function otherSquadsHtml(){
  const clubs=state.league.clubs.filter(c=>c.id!==state.userClubId),club=getClub(selectedClubRosterId)||clubs[0];if(!club)return '';
  const players=sortPlayers(club.squad,transferSort);
  return `<div class="card other-squads"><div class="section-toolbar"><div><h2>Kader anderer Vereine</h2><p class="muted">Spieler beobachten und direkt ein Transferangebot abgeben.</p></div><label>Verein<select id="otherClubSelect">${clubs.map(c=>`<option value="${c.id}" ${c.id===club.id?'selected':''}>${esc(c.name)}</option>`).join('')}</select></label></div><div class="roster-club-head">${clubCrest(club,'large')}<div><b>${esc(club.name)}</b><span>Vereinsstärke ${club.rating} · ${club.squad.length} Spieler</span></div></div><table><thead><tr><th>Spieler</th><th>Alter</th><th>Pos</th><th>Stärke</th><th>Marktwert</th><th></th></tr></thead><tbody>${players.map(p=>`<tr><td>${esc(p.name)}</td><td>${p.age}</td><td>${p.position}</td><td><b>${p.rating}</b></td><td>${money(p.value)}</td><td><button data-poach-club="${club.id}" data-poach-player="${p.id}">Angebot</button></td></tr>`).join('')}</tbody></table></div>`;
}
function transfers(){
  ensureV14State();const c=getUserClub(),pending=state.outgoingOffers.filter(o=>o.status==='pending'),market=sortPlayers(state.transferList,transferSort).slice(0,30),listed=sortPlayers(listedPlayers(),transferSort);
  return `<div class="card transfer-sortbar"><label>Transferlisten sortieren<select id="transferSort"><option value="position" ${transferSort==='position'?'selected':''}>Position</option><option value="rating" ${transferSort==='rating'?'selected':''}>Stärke</option></select></label></div><div class="grid cols-2 transfer-summary"><div class="card"><h2>Dynamischer Transfermarkt</h2><p>Budget: <b>${money(c.budget)}</b> · Neue Spieler können jede Woche angeboten werden.</p><table><thead><tr><th>Spieler</th><th>Alter</th><th>Pos</th><th>Stärke</th><th>Verein</th><th>Preis</th><th></th></tr></thead><tbody>${market.map(p=>{const realIndex=state.transferList.findIndex(x=>x.id===p.id);const source=state.league.clubs.find(x=>x.id===p.fromClubId)||{name:p.fromClub};return `<tr><td>${esc(p.name)}</td><td>${p.age}</td><td>${p.position}</td><td>${p.rating}</td><td>${clubNameWithCrest(source,'tiny')}</td><td>${money(p.asking)}</td><td><button data-buy="${realIndex}">Kaufen</button></td></tr>`}).join('')}</tbody></table></div><div class="card"><h2>Eingegangene Angebote</h2>${pending.length?pending.map(o=>{const p=c.squad.find(x=>x.id===o.playerId),b=getClub(o.bidderId);return p&&b?`<div class="offer-card"><div>${clubNameWithCrest(b,'tiny')} bietet für <b>${esc(p.name)}</b> (${p.age})</div><div class="offer-price">${money(o.amount)}</div><div class="offer-actions"><button data-accept-offer="${o.id}" class="primary">Annehmen</button><button data-reject-offer="${o.id}" class="danger">Ablehnen</button></div></div>`:''}).join(''):'<p class="muted">Momentan liegen keine Angebote vor.</p>'}</div></div><div class="card" style="margin-top:16px"><h2>Deine Transferliste</h2>${listed.length?`<table><thead><tr><th>Spieler</th><th>Alter</th><th>Pos</th><th>Stärke</th><th>Marktwert</th><th>Wunschpreis</th><th>Gebot</th><th></th></tr></thead><tbody>${listed.map(p=>{const o=activeOfferFor(p.id),b=o?getClub(o.bidderId):null;return `<tr><td>${esc(p.name)}</td><td>${p.age}</td><td>${p.position}</td><td>${p.rating}</td><td>${money(p.value)}</td><td><input class="price-input" data-asking-price="${p.id}" type="number" step="100000" value="${p.askingPrice}"></td><td>${o&&b?`${esc(b.name)}: <b>${money(o.amount)}</b>`:'Noch keines'}</td><td><button data-list-player="${p.id}" class="danger">Entfernen</button></td></tr>`}).join('')}</tbody></table>`:'<p>Noch kein Spieler gelistet.</p>'}</div>${otherSquadsHtml()}`;
}

function eventMomentum(type,homeEvent){
  const values={goal:18,chance:8,corner:5,save:3,yellow:-2,red:-10,sub:1,tactic:2};const v=values[type]||0;return homeEvent?v:-v;
}
function currentMomentum(){
  if(!liveMatch)return 50;let value=50+(liveMatch.homePower-liveMatch.awayPower)*1.6;
  liveMatch.events.slice(0,12).forEach((e,i)=>{value+=(e.momentum||0)*Math.max(.25,1-i/14);});return clamp(Math.round(value),6,94);
}
function addLiveEvent(minute,type,text,clubId=null,playerId=null){
  if(!liveMatch)return;const homeEvent=clubId===liveMatch.home.id;liveMatch.events.unshift({minute,type,text,clubId,playerId,momentum:eventMomentum(type,homeEvent)});
  const feed=$('#liveFeed');if(feed){feed.innerHTML=liveFeedHtml();feed.scrollTop=0;}updateLiveDisplay();
}
function liveFeedHtml(){return liveMatch.events.map(e=>{const club=e.clubId?getClub(e.clubId):null;return `<div class="live-line ${e.type}"><span class="live-minute">${e.minute}'</span>${club?clubCrest(club,'tiny'):clubCrest('Spiel','tiny')}<span>${esc(e.text)}</span></div>`}).join('');}
function liveUserClub(){return liveMatch.userHome?liveMatch.home:liveMatch.away;}
function liveBench(){const c=liveUserClub();return c.squad.filter(p=>!liveMatch.userXI.includes(p.id)&&p.suspensionGames<=0);}
function substituteLive(outId,inId){
  if(!liveMatch||liveMatch.finished||liveMatch.substitutions>=3)return;const c=liveUserClub(),ix=liveMatch.userXI.indexOf(outId),incoming=c.squad.find(p=>p.id===inId),outgoing=c.squad.find(p=>p.id===outId);if(ix<0||!incoming||!outgoing||liveMatch.userXI.includes(inId))return;
  liveMatch.userXI[ix]=inId;liveMatch.substitutions++;incoming.fitness=clamp(incoming.fitness-2,40,100);const base=liveMatch.userXI.map(id=>c.squad.find(p=>p.id===id)).filter(Boolean).reduce((s,p)=>s+p.rating*(p.fitness/100),0)/11;const adjusted=effectiveUserPower(base);if(liveMatch.userHome)liveMatch.homePower=adjusted+2;else liveMatch.awayPower=adjusted;
  addLiveEvent(liveMatch.minute,'sub',`${incoming.name} kommt für ${outgoing.name}.`,c.id,incoming.id);render();
}
function changeLiveFormation(value){
  if(!liveMatch||!FORMATIONS[value])return;liveMatch.formation=value;state.formation=value;const c=liveUserClub();const slots=FORMATIONS[value],picked=[];
  liveMatch.userXI.forEach(id=>{if(c.squad.some(p=>p.id===id)&&!picked.includes(id)&&picked.length<11)picked.push(id);});sortPlayers(c.squad.filter(p=>!picked.includes(p.id)&&p.suspensionGames<=0),'rating').forEach(p=>{if(picked.length<11)picked.push(p.id);});liveMatch.userXI=picked.slice(0,slots.length);state.selectedXI=[...liveMatch.userXI];
  addLiveEvent(liveMatch.minute,'tactic',`Formation auf ${value} umgestellt.`,c.id);save();render();
}
function startLiveMatch(f,round){
  if(liveMatch)return;ensureV14State();const h=getClub(f.home),a=getClub(f.away),userHome=h.id===state.userClubId,finance=calculateUserMatchFinance(h,a);
  liveMatch={fixture:f,home:h,away:a,minute:0,homeGoals:0,awayGoals:0,events:[],paused:false,speed:1,finished:false,homePower:teamPower(h)+2,awayPower:teamPower(a),otherFixtures:round.filter(x=>x!==f),finance,userHome,tactic:state.matchSettings.tactic||'balanced',aggression:state.matchSettings.aggression||'fair',yellowHome:0,yellowAway:0,redHome:0,redAway:0,userXI:[...state.selectedXI],substitutions:0,formation:state.formation};
  view='live';$$('.nav').forEach(x=>x.classList.remove('active'));render();addLiveEvent(0,'kickoff',commentary('kickoff'));runLiveTimer();
}
function processLiveMinute(){
  const m=liveMatch.minute;if(m===45){addLiveEvent(m,'halftime',commentary('halftime'));return;}
  const total=Math.max(1,liveMatch.homePower+liveMatch.awayPower),homeAttack=Math.random()<liveMatch.homePower/total,team=homeAttack?liveMatch.home:liveMatch.away,playerName=randomPlayer(team,true),player=team.squad.find(x=>x.name===playerName),roll=Math.random();
  const isUser=team.id===state.userClubId,tactic=isUser?liveMatch.tactic:'balanced',agg=isUser?liveMatch.aggression:'fair';const goalThreshold=tactic==='offensive'?.034:tactic==='defensive'?.023:.028,chanceThreshold=goalThreshold+(tactic==='offensive'?.057:tactic==='defensive'?.038:.047),cardRate=agg==='hard'?.030:.010,redChance=agg==='hard'?.18:.06;
  if(roll<goalThreshold){const attack=homeAttack?liveMatch.homePower:liveMatch.awayPower,defence=homeAttack?liveMatch.awayPower:liveMatch.homePower;if(Math.random()<clamp(.30+(attack-defence)/120,.18,.48)){if(homeAttack)liveMatch.homeGoals++;else liveMatch.awayGoals++;if(player)player.goals++;addLiveEvent(m,'goal',commentary('goal',team.name,playerName),team.id,player?.id);}else addLiveEvent(m,'save',commentary('save',team.name,playerName),team.id,player?.id);}
  else if(roll<chanceThreshold)addLiveEvent(m,'chance',commentary('chance',team.name,playerName),team.id,player?.id);
  else if(roll<chanceThreshold+.02)addLiveEvent(m,'corner',commentary('corner',team.name,playerName),team.id,player?.id);
  else if(roll<chanceThreshold+.02+cardRate){const type=Math.random()<redChance?'red':'yellow',p=cardPlayer(team,type);if(p){if(homeAttack){type==='red'?liveMatch.redHome++:liveMatch.yellowHome++;}else{type==='red'?liveMatch.redAway++:liveMatch.yellowAway++;}addLiveEvent(m,type,type==='red'?`Rote Karte für ${p.name} (${team.name})!`:commentary('card',team.name,p.name),team.id,p.id);}}
}
function updateLiveDisplay(){
  if(!liveMatch)return;const minute=$('#liveMinute'),score=$('#liveScore'),bar=$('#liveProgress'),ball=$('#momentumBall'),label=$('#momentumLabel');if(minute)minute.textContent=liveMatch.minute>=90?'90+':`${liveMatch.minute}'`;if(score)score.textContent=`${liveMatch.homeGoals} : ${liveMatch.awayGoals}`;if(bar)bar.style.width=`${Math.min(100,liveMatch.minute/90*100)}%`;const momentum=currentMomentum();if(ball)ball.style.left=`calc(${momentum}% - 14px)`;if(label)label.textContent=momentum>57?`${liveMatch.home.name} macht Druck`:momentum<43?`${liveMatch.away.name} macht Druck`:'Ausgeglichenes Spiel';
}
function liveView(){
  if(!liveMatch)return `<div class="card"><h2>Kein Live-Spiel aktiv</h2></div>`;const l=liveMatch,user=liveUserClub(),bench=liveBench(),xi=user.squad.filter(p=>l.userXI.includes(p.id));
  const financeFinished=l.finished?`<div class="card match-final-finance"><h2>Finanzabschluss nach dem Spiel</h2>${financeBreakdownHtml(l.finance)}</div>`:'';
  return `<div class="live-match card"><div class="live-top"><span class="viz-badge">LIVE</span><span id="liveMinute" class="live-clock">${l.minute}'</span></div><div class="live-scoreboard"><div>${clubCrest(l.home,'large')}<b>${esc(l.home.name)}</b><small>Heim · 🟨 ${l.yellowHome} 🟥 ${l.redHome}</small></div><div id="liveScore" class="live-score">${l.homeGoals} : ${l.awayGoals}</div><div>${clubCrest(l.away,'large')}<b>${esc(l.away.name)}</b><small>Auswärts · 🟨 ${l.yellowAway} 🟥 ${l.redAway}</small></div></div><div class="grid cols-4 match-finance-live"><div class="metric-box"><span>Zuschauer</span><b>${l.finance.attendance.toLocaleString('de-DE')}</b></div><div class="metric-box"><span>Tickets</span><b>${money(l.finance.ticketIncome)}</b></div><div class="metric-box"><span>Fanartikel</span><b>${money(l.finance.merchIncome)}</b></div><div class="metric-box"><span>Gastronomie</span><b>${money(l.finance.gastroGross)}</b></div></div><div class="progress live-progress"><span id="liveProgress" style="width:${l.minute/90*100}%"></span></div><div class="momentum-panel"><div class="momentum-teams"><span>${clubCrest(l.home,'tiny')} ${esc(l.home.name)}</span><b id="momentumLabel">Spielmomentum</b><span>${esc(l.away.name)} ${clubCrest(l.away,'tiny')}</span></div><div class="momentum-track"><span class="center-line"></span><span id="momentumBall" class="momentum-ball" style="left:calc(${currentMomentum()}% - 14px)">⚽</span></div></div><div class="grid cols-2 live-layout"><div class="card live-chat-card"><h2>Live-Ticker</h2><div id="liveFeed" class="live-feed" aria-live="polite">${liveFeedHtml()}</div></div><div class="card"><h2>Spielsteuerung</h2><div id="liveControls" class="live-controls">${l.finished?'<button id="continueAfterMatch" class="primary">Abrechnung bestätigen & weiter</button>':`<button id="pauseLive">${l.paused?'Fortsetzen':'Pause'}</button><button data-speed="1">1×</button><button data-speed="2">2×</button><button data-speed="4">4×</button>`}</div>${!l.finished?`<div class="live-tactics"><label>Taktik<select id="liveTactic"><option value="offensive" ${l.tactic==='offensive'?'selected':''}>Offensiv</option><option value="balanced" ${l.tactic==='balanced'?'selected':''}>Ausgeglichen</option><option value="defensive" ${l.tactic==='defensive'?'selected':''}>Defensiv</option></select></label><label>Zweikampf<select id="liveAggression"><option value="fair" ${l.aggression==='fair'?'selected':''}>Fair</option><option value="hard" ${l.aggression==='hard'?'selected':''}>Hart</option></select></label><label>Formation<select id="liveFormation">${Object.keys(FORMATIONS).map(f=>`<option value="${f}" ${l.formation===f?'selected':''}>${f}</option>`).join('')}</select></label></div><div class="substitution-box"><h3>Spielerwechsel (${l.substitutions}/3)</h3><label>Raus<select id="subOut">${xi.map(p=>`<option value="${p.id}">${esc(p.name)} (${p.position}, ${p.rating})</option>`).join('')}</select></label><label>Rein<select id="subIn">${bench.map(p=>`<option value="${p.id}">${esc(p.name)} (${p.position}, ${p.rating})</option>`).join('')}</select></label><button id="makeSub" ${l.substitutions>=3?'disabled':''}>Wechsel durchführen</button></div>`:''}</div></div>${financeFinished}</div>`;
}
function applyMatchResult(f,hg,ag){
  const h=getClub(f.home),a=getClub(f.away);[h,a].forEach(c=>c.played++);h.gf+=hg;h.ga+=ag;a.gf+=ag;a.ga+=hg;if(hg>ag){h.wins++;h.points+=3;a.losses++;h.form.unshift('S');a.form.unshift('N');}else if(hg<ag){a.wins++;a.points+=3;h.losses++;h.form.unshift('N');a.form.unshift('S');}else{h.draws++;a.draws++;h.points++;a.points++;h.form.unshift('U');a.form.unshift('U');}h.form=h.form.slice(0,5);a.form=a.form.slice(0,5);f.played=true;f.score=[hg,ag];
  if(h.id===state.userClubId||a.id===state.userClubId){const user=h.id===state.userClubId?h:a,isHome=h.id===state.userClubId,ug=isHome?hg:ag,og=isHome?ag:hg,finance=(liveMatch&&liveMatch.fixture===f&&liveMatch.finance)?liveMatch.finance:calculateUserMatchFinance(h,a);user.balance+=finance.netIncome;state.sponsors.lastMerchSales=finance.merchSales;state.lastMatch={home:h.name,away:a.name,score:`${hg}:${ag}`,...finance};state.matchFinanceHistory.unshift({week:state.week,season:state.season,home:h.name,away:a.name,score:`${hg}:${ag}`,...finance});state.matchFinanceHistory=state.matchFinanceHistory.slice(0,30);const ids=liveMatch?.userXI||state.selectedXI,picked=ids.map(id=>user.squad.find(p=>p.id===id)).filter(Boolean);picked.forEach(p=>{p.apps++;p.fitness=clamp(p.fitness-rand(4,12),45,100);p.morale=clamp(p.morale+(ug>og?rand(2,5):ug<og?-rand(2,5):0),30,100)});state.selectedXI=[...ids];state.news.unshift(`${h.name} ${hg}:${ag} ${a.name} · Spieltags-Saldo ${money(finance.netIncome)}`);}
}
function finishLiveMatch(){
  if(!liveMatch||liveMatch.finished)return;liveMatch.finished=true;clearInterval(liveTimer);addLiveEvent(90,'final',commentary('final'));applyMatchResult(liveMatch.fixture,liveMatch.homeGoals,liveMatch.awayGoals);liveMatch.otherFixtures.forEach(simulateMatch);state.league.round++;state.week++;const user=getUserClub();user.squad.forEach(p=>{p.fitness=clamp(p.fitness+rand(2,7),45,100);if(p.suspensionGames>0&&!state.selectedXI.includes(p.id))p.suspensionGames=Math.max(0,p.suspensionGames-1);});user.balance-=user.squad.reduce((sum,p)=>sum+p.wage,0);if(state.week%4===0)user.balance-=rand(250000,700000);processOutgoingTransferOffers();addDynamicTransferPlayers();weeklySponsorIncome();save();document.body.classList.remove('match-running');updateLiveDisplay();render();
}
function finances(){
  ensureV14State();const c=getUserClub(),w=c.squad.reduce((s,p)=>s+p.wage,0),hist=state.matchFinanceHistory.slice(0,12);return `<div class="grid cols-2"><div class="card"><h2>Finanzen</h2><div class="stat ${c.balance<0?'bad':'good'}">${money(c.balance)}</div><p>Wöchentliche Gehälter: <b>${money(w)}</b></p><p>Transferbudget: <b>${money(c.budget)}</b></p></div><div class="card"><h2>Letzter Spieltag</h2>${state.lastMatch?financeBreakdownHtml(state.lastMatch):'<p class="muted">Noch keine Abrechnung.</p>'}</div></div><div class="card" style="margin-top:16px"><h2>Spielabrechnungen</h2>${hist.length?`<table><thead><tr><th>Spiel</th><th>Zuschauer</th><th>Tickets</th><th>Fanartikel</th><th>Gastro</th><th>Kosten</th><th>Saldo</th></tr></thead><tbody>${hist.map(x=>`<tr><td>${esc(x.home)} ${esc(x.score)} ${esc(x.away)}</td><td>${Number(x.attendance).toLocaleString('de-DE')}</td><td>${money(x.ticketIncome)}</td><td>${money(x.merchIncome)}</td><td>${money(x.gastroGross||0)}</td><td>− ${money(x.matchCosts||0)}</td><td class="${x.netIncome>=0?'good':'bad'}"><b>${money(x.netIncome||0)}</b></td></tr>`).join('')}</tbody></table>`:'<p>Noch keine Spiele.</p>'}</div>`;
}
function league(){const table=sortedTable();return `<div class="card"><h2>${esc(state.league.name)}</h2><table><thead><tr><th>#</th><th>Verein</th><th>Sp</th><th>S</th><th>U</th><th>N</th><th>Tore</th><th>Diff.</th><th>Pkt.</th></tr></thead><tbody>${table.map((c,i)=>`<tr class="${c.id===state.userClubId?'highlight':''}"><td>${i+1}</td><td>${clubNameWithCrest(c,'tiny')}</td><td>${c.played}</td><td>${c.wins}</td><td>${c.draws}</td><td>${c.losses}</td><td>${c.gf}:${c.ga}</td><td>${c.gf-c.ga}</td><td><b>${c.points}</b></td></tr>`).join('')}</tbody></table></div>`;}
function dashboard(){
  ensureV14State();const c=getUserClub(),table=sortedTable(),pos=table.findIndex(x=>x.id===c.id)+1,next=state.league.fixtures[state.league.round]?.find(f=>f.home===c.id||f.away===c.id),a=lineupGroupAverages();return `<div class="grid cols-3"><div class="card club-dashboard">${clubCrest(c,'large')}<div><div class="muted">Verein</div><div class="stat">${esc(c.name)}</div><div>${esc(state.league.name)}</div></div></div><div class="card"><div class="muted">Tabellenplatz</div><div class="stat">${pos}.</div><div>${c.points} Punkte</div></div><div class="card"><div class="muted">Kontostand</div><div class="stat ${c.balance<0?'bad':'good'}">${money(c.balance)}</div><div>Transferbudget: ${money(c.budget)}</div></div></div><div class="card lineup-averages"><h2>Durchschnittsstärke · ${state.formation}</h2><div class="grid cols-4"><div class="metric-box"><span>TW</span><b>${a.TW}</b></div><div class="metric-box"><span>ABW</span><b>${a.ABW}</b></div><div class="metric-box"><span>MIT</span><b>${a.MIT}</b></div><div class="metric-box"><span>ST</span><b>${a.ST}</b></div></div></div><div class="grid cols-2" style="margin-top:16px"><div class="card"><h2>Nächstes Spiel</h2>${next?`<div class="next-fixture-crests"><div>${clubCrest(getClub(next.home),'large')}<b>${esc(getClub(next.home).name)}</b></div><span>–</span><div>${clubCrest(getClub(next.away),'large')}<b>${esc(getClub(next.away).name)}</b></div></div><p>Spieltag ${state.league.round+1}</p>`:'<p>Saison beendet.</p>'}</div><div class="card"><h2>Letzte Abrechnung</h2>${state.lastMatch?`<p>${esc(state.lastMatch.home)} <b>${state.lastMatch.score}</b> ${esc(state.lastMatch.away)}</p><p>Zuschauer: <b>${Number(state.lastMatch.attendance).toLocaleString('de-DE')}</b></p><p>Gastro: <b>${money(state.lastMatch.gastroGross||0)}</b> · Saldo: <b class="${state.lastMatch.netIncome>=0?'good':'bad'}">${money(state.lastMatch.netIncome||0)}</b></p>`:'<p>Noch kein Spiel.</p>'}</div></div><div class="card" style="margin-top:16px"><h2>Vereinsnachrichten</h2>${state.news.slice(0,8).map(n=>`<div class="news">${esc(n)}</div>`).join('')}</div>`;
}
function render(){if(!state)return;ensureV14State();document.body.classList.toggle('match-running',!!liveMatch&&!liveMatch.finished);$('#seasonLabel').textContent=`Saison ${state.season} · Woche ${state.week} · ${state.league.country} · Version 1.4`;const map={dashboard,squad,lineup,league,transfers,sponsors,finances,stadium,international,live:liveView};$('#content').innerHTML=map[view]();bindDynamic();updateLiveDisplay();}
function bindDynamic(){
  const openSponsors=$('#openSponsors');if(openSponsors)openSponsors.onclick=()=>{view='sponsors';render();};const pause=$('#pauseLive');if(pause)pause.onclick=()=>{liveMatch.paused=!liveMatch.paused;render();};$$('[data-speed]').forEach(btn=>btn.onclick=()=>{liveMatch.speed=+btn.dataset.speed;runLiveTimer();render();});const cont=$('#continueAfterMatch');if(cont)cont.onclick=()=>{liveMatch=null;view='dashboard';render();};
  const formation=$('#formationSelect');if(formation)formation.onchange=e=>{state.formation=e.target.value;normalizeLineup();save();render();};const liveFormation=$('#liveFormation');if(liveFormation)liveFormation.onchange=e=>changeLiveFormation(e.target.value);const sqSort=$('#squadSort');if(sqSort)sqSort.onchange=e=>{squadSort=e.target.value;render();};const trSort=$('#transferSort');if(trSort)trSort.onchange=e=>{transferSort=e.target.value;render();};const otherClub=$('#otherClubSelect');if(otherClub)otherClub.onchange=e=>{selectedClubRosterId=e.target.value;render();};
  const tactic=$('#liveTactic');if(tactic)tactic.onchange=e=>{liveMatch.tactic=e.target.value;state.matchSettings.tactic=e.target.value;save();};const aggression=$('#liveAggression');if(aggression)aggression.onchange=e=>{liveMatch.aggression=e.target.value;state.matchSettings.aggression=e.target.value;save();};const sub=$('#makeSub');if(sub)sub.onclick=()=>substituteLive($('#subOut').value,$('#subIn').value);
  $$('[data-lineup]').forEach(sel=>sel.onchange=e=>{const i=+e.target.dataset.lineup,newId=e.target.value;if(state.selectedXI.some((id,j)=>j!==i&&id===newId))return alert('Spieler bereits aufgestellt.');state.selectedXI[i]=newId;save();render();});$$('[data-buy]').forEach(btn=>btn.onclick=()=>buyPlayer(+btn.dataset.buy));$$('[data-poach-player]').forEach(btn=>btn.onclick=()=>poachPlayer(btn.dataset.poachClub,btn.dataset.poachPlayer));$$('[data-list-player]').forEach(btn=>btn.onclick=()=>toggleTransferList(btn.dataset.listPlayer));$$('[data-accept-offer]').forEach(btn=>btn.onclick=()=>acceptOutgoingOffer(btn.dataset.acceptOffer));$$('[data-reject-offer]').forEach(btn=>btn.onclick=()=>rejectOutgoingOffer(btn.dataset.rejectOffer));$$('[data-asking-price]').forEach(inp=>inp.onchange=()=>updateAskingPrice(inp.dataset.askingPrice,inp.value));$$('[data-accept-sponsor]').forEach(btn=>btn.onclick=()=>acceptSponsorOffer(btn.dataset.acceptSponsor));$$('[data-reject-sponsor]').forEach(btn=>btn.onclick=()=>rejectSponsorOffer(btn.dataset.rejectSponsor));const up=$('#upgradeStadium');if(up)up.onclick=()=>{const c=getUserClub();if(c.balance<12e6)return alert('Zu wenig Geld.');c.balance-=12e6;c.stadium.capacity+=5000;c.stadium.condition=100;save();render();};const range=$('#ticketPrice');if(range)range.oninput=e=>{getUserClub().stadium.ticketPrice=+e.target.value;$('#ticketPriceLabel').textContent=' '+money(+e.target.value);save();};
}
function load(){const raw=storageGet();if(raw){state=JSON.parse(raw);liveMatch=null;clearInterval(liveTimer);ensure36GameSeason();ensureSponsorState();ensureV14State();if(!state.sponsors.offers.length)generateSponsorOffers(true);save();$('#startScreen').style.display='none';render();}else alert('Kein Spielstand vorhanden.');}

function stadium(){
  const c=getUserClub(),s=c.stadium,stadiumImage=s.capacity<30000?'stadium-small.jpg':s.capacity<55000?'stadium-medium.jpg':'stadium-large.jpg';
  const expectedAttendance=Math.round(s.capacity*.72),expectedGastro=Math.round(expectedAttendance*11.5),clubGastro=Math.round(expectedGastro*.58);
  return `<div class="grid cols-2"><div class="card"><div class="icon-title"><img src="assets/stadium-icon.jpg" alt="Stadion"><h2>${esc(s.name)}</h2></div><img class="stadium-visual" src="assets/${stadiumImage}" alt="Retro-Stadionansicht"><div class="stat">${s.capacity.toLocaleString('de-DE')} Plätze</div><p>Zustand: ${s.condition}%</p><div class="progress"><span style="width:${s.condition}%"></span></div><p>Ticketpreis: ${money(s.ticketPrice)}</p></div><div class="card"><h2>Stadion & Gastronomie</h2><p>Erwartete Zuschauer: <b>${expectedAttendance.toLocaleString('de-DE')}</b></p><p>Geschätzter Gastroverkauf: <b>${money(expectedGastro)}</b></p><p>Erwarteter Gastrodeckungsbeitrag: <b>${money(clubGastro)}</b></p><p class="muted">Der tatsächliche Umsatz hängt bei jedem Heimspiel von Zuschauerzahl und Nachfrage ab.</p><hr><p>Ausbau um 5.000 Plätze: <b>${money(12e6)}</b></p><button id="upgradeStadium">Ausbauen</button><h3>Ticketpreis</h3><input id="ticketPrice" type="range" min="10" max="100" value="${s.ticketPrice}"><span id="ticketPriceLabel"> ${money(s.ticketPrice)}</span></div></div>`;
}
function league(){
  const table=sortedTable(),recent=state.league.results?.slice(-8)||[],nextRound=state.league.fixtures[state.league.round]||[];
  return `<div class="card"><h2>${esc(state.league.name)}</h2><table><thead><tr><th>#</th><th>Verein</th><th>Sp</th><th>S</th><th>U</th><th>N</th><th>Tore</th><th>Diff.</th><th>Pkt.</th></tr></thead><tbody>${table.map((c,i)=>`<tr class="${c.id===state.userClubId?'highlight':''}"><td>${i+1}</td><td>${clubNameWithCrest(c,'tiny')}</td><td>${c.played}</td><td>${c.wins}</td><td>${c.draws}</td><td>${c.losses}</td><td>${c.gf}:${c.ga}</td><td>${c.gf-c.ga}</td><td><b>${c.points}</b></td></tr>`).join('')}</tbody></table></div><div class="card" style="margin-top:16px"><h2>Nächste Spiele · Spieltag ${state.league.round+1}</h2>${nextRound.map(f=>{const h=getClub(f.home),a=getClub(f.away);return `<div class="fixture crest-fixture"><span>${clubNameWithCrest(h,'tiny')}</span><b>${f.played?`${f.score[0]} : ${f.score[1]}`:'–'}</b><span>${clubNameWithCrest(a,'tiny')}</span></div>`}).join('')||'<p>Saison beendet.</p>'}</div>`;
}

/* Version 1.5 – Training, Trainingslager, Verletzungen, Spezialtaktik und Transferbudget */
const TRAINING_FOCUS_LABELS={general:'Allgemein',attack:'Sturm',midfield:'Mittelfeld',defence:'Verteidigung',goalkeeper:'Torwart'};
const SPECIAL_TRAINING_LABELS={none:'Keines',penalties:'Elfmeter',freekicks:'Freistöße',offside:'Abseitsfalle'};
function ensureV15State(){
  if(!state)return;ensureV14State();
  if(!state.training)state.training={focus:'general',special:'none',intensity:'normal',campCooldown:0,lastReport:'Noch kein Training ausgewertet.',campHistory:[]};
  if(!state.matchSettings.special)state.matchSettings.special='none';
  state.league.clubs.forEach(c=>{
    if(c.offsideTrap===undefined)c.offsideTrap=rand(55,78);
    c.squad.forEach(p=>{
      if(p.penalties===undefined)p.penalties=clamp(p.rating+rand(-12,10),35,95);
      if(p.freeKicks===undefined)p.freeKicks=clamp(p.rating+rand(-15,9),30,94);
      if(p.injuryGames===undefined)p.injuryGames=0;
      if(p.injuryName===undefined)p.injuryName='';
    });
  });
}
function positionGroup(p){
  if(p.position==='TW')return 'goalkeeper';
  if(['ST','RA','LA'].includes(p.position))return 'attack';
  if(['ZM','DM'].includes(p.position))return 'midfield';
  return 'defence';
}
function isPlayerAvailable(p){return (p.suspensionGames||0)<=0&&(p.injuryGames||0)<=0;}
function trainingPotentialChance(p,bonus=0){return clamp(.06+(p.potential-p.rating)*.018+(24-p.age)*.005+bonus,.02,.48);}
function runWeeklyTraining(){
  ensureV15State();const c=getUserClub(),t=state.training;let improved=0,specialImproved=0,injuries=0;
  c.squad.forEach(p=>{
    if(p.injuryGames>0){p.injuryGames--;if(p.injuryGames===0){p.injuryName='';state.news.unshift(`${p.name} ist wieder fit.`);}return;}
    const group=positionGroup(p),focused=t.focus==='general'||t.focus===group;
    const intensityBonus=t.intensity==='high'?.035:t.intensity==='light'?-.02:0;
    if(focused&&p.rating<p.potential&&Math.random()<trainingPotentialChance(p,intensityBonus)){p.rating++;p.value=Math.round(p.value*1.035);improved++;}
    if(t.special==='penalties'&&Math.random()<.28){p.penalties=clamp(p.penalties+rand(1,2),30,99);specialImproved++;}
    if(t.special==='freekicks'&&['ST','RA','LA','ZM'].includes(p.position)&&Math.random()<.28){p.freeKicks=clamp(p.freeKicks+rand(1,2),30,99);specialImproved++;}
    p.fitness=clamp(p.fitness+(t.intensity==='light'?rand(4,8):t.intensity==='high'?rand(-2,3):rand(1,5)),40,100);
    const injuryChance=t.intensity==='high'?.006:t.intensity==='light'?.0015:.003;
    if(Math.random()<injuryChance){p.injuryGames=rand(1,3);p.injuryName=['Zerrung','Prellung','leichte Muskelverletzung'][rand(0,2)];injuries++;state.news.unshift(`${p.name} fällt mit ${p.injuryName} für ${p.injuryGames} Spiel(e) aus.`);}
  });
  if(t.special==='offside'&&Math.random()<.55){c.offsideTrap=clamp(c.offsideTrap+rand(1,2),35,99);specialImproved++;}
  if(t.campCooldown>0)t.campCooldown--;
  t.lastReport=`${improved} Spieler mit Stärke-Fortschritt, ${specialImproved} Spezialwerte verbessert${injuries?`, ${injuries} leichte Verletzung(en)`:''}.`;
}
function startTrainingCamp(){
  ensureV15State();const c=getUserClub(),t=state.training,cost=2500000;
  if(t.campCooldown>0)return alert(`Ein neues Trainingslager ist erst in ${t.campCooldown} Wochen möglich.`);
  if(c.balance<cost)return alert('Für das Trainingslager fehlen 2,5 Mio. Euro.');
  c.balance-=cost;let gains=0;c.squad.forEach(p=>{p.fitness=clamp(p.fitness+rand(5,12),40,100);p.morale=clamp(p.morale+rand(4,10),30,100);if(p.rating<p.potential&&Math.random()<trainingPotentialChance(p,.18)){p.rating++;gains++;}});
  c.offsideTrap=clamp(c.offsideTrap+rand(1,3),35,99);t.campCooldown=12;t.campHistory.unshift({week:state.week,gains,cost});t.lastReport=`Trainingslager abgeschlossen: ${gains} Spieler verbesserten ihre Stärke.`;state.news.unshift(`Trainingslager beendet: ${gains} Spieler entwickelten sich weiter.`);save();render();
}
function training(){
  ensureV15State();const c=getUserClub(),t=state.training,injured=c.squad.filter(p=>p.injuryGames>0);
  return `<div class="budget-banner"><div><b>Trainingszentrum</b><div class="muted">Wöchentliche Entwicklung und taktische Spezialisierung</div></div><div>Kontostand: <b>${money(c.balance)}</b></div></div><div class="training-grid"><div class="card"><h2>Trainingsplan</h2><label>Schwerpunkt<select id="trainingFocus">${Object.entries(TRAINING_FOCUS_LABELS).map(([v,l])=>`<option value="${v}" ${t.focus===v?'selected':''}>${l}</option>`).join('')}</select></label><label>Intensität<select id="trainingIntensity"><option value="light" ${t.intensity==='light'?'selected':''}>Leicht</option><option value="normal" ${t.intensity==='normal'?'selected':''}>Normal</option><option value="high" ${t.intensity==='high'?'selected':''}>Hoch</option></select></label><label>Spezialtraining<select id="specialTraining">${Object.entries(SPECIAL_TRAINING_LABELS).map(([v,l])=>`<option value="${v}" ${t.special===v?'selected':''}>${l}</option>`).join('')}</select></label><p class="muted">Hohe Intensität steigert die Entwicklungschance, erhöht aber das weiterhin geringe Verletzungsrisiko leicht.</p><div class="training-status"><span class="attribute-chip">Letzter Bericht: ${esc(t.lastReport)}</span></div></div><div class="card camp-card"><h2>Trainingslager</h2><p>Kosten: <b>${money(2500000)}</b></p><p>Verbessert Fitness, Moral und mit erhöhter Chance die Spielerstärke.</p><p>Nächste Möglichkeit: <b>${t.campCooldown?`in ${t.campCooldown} Wochen`:'sofort'}</b></p><button id="startCamp" ${t.campCooldown?'disabled':''}>Trainingslager durchführen</button></div></div><div class="card" style="margin-top:16px"><h2>Taktische Stärken</h2><div class="tactic-strengths"><div><span>Elfmeter</span><b>${Math.round(c.squad.reduce((s,p)=>s+p.penalties,0)/c.squad.length)}</b></div><div><span>Freistöße</span><b>${Math.round(c.squad.reduce((s,p)=>s+p.freeKicks,0)/c.squad.length)}</b></div><div><span>Abseitsfalle</span><b>${c.offsideTrap}</b></div></div></div><div class="card" style="margin-top:16px"><h2>Verletzte Spieler</h2>${injured.length?injured.map(p=>`<div class="news injured">${esc(p.name)} · ${esc(p.injuryName)} · noch ${p.injuryGames} Spiel(e)</div>`).join(''):'<p class="fit-status">Derzeit ist der gesamte Kader einsatzfähig.</p>'}</div>`;
}
function v15PlayerDetails(p){return `<div class="attribute-list"><span class="attribute-chip">11m ${p.penalties}</span><span class="attribute-chip">FS ${p.freeKicks}</span>${p.injuryGames?`<span class="attribute-chip injured">${esc(p.injuryName)} (${p.injuryGames})</span>`:''}</div>`;}
const _v14Squad=squad;
squad=function(){ensureV15State();const html=_v14Squad();return html.replaceAll('</span><span><button data-list-player=',`</span><span>${''}</span><span><button data-list-player=`).replace('<h2>Kader –','<h2>Kader –').replace('</div></div>','</div></div>');};
const _v14Transfers=transfers;
transfers=function(){ensureV15State();const c=getUserClub();return `<div class="budget-banner"><div><b>Transferbudget</b><div class="stat">${money(c.budget)}</div></div><div>Kontostand: <b>${money(c.balance)}</b></div></div>`+_v14Transfers();};
const _v14Lineup=lineup;
lineup=function(){ensureV15State();return _v14Lineup().replace(/<option value="([^"]+)"/g,(m,id)=>{const p=getUserClub().squad.find(x=>x.id===id);return `<option value="${id}" ${p&&!isPlayerAvailable(p)?'disabled':''}`;});};
const _v14LiveView=liveView;
liveView=function(){ensureV15State();let html=_v14LiveView();if(!liveMatch||liveMatch.finished)return html;const c=getUserClub();const avgPen=Math.round(c.squad.reduce((s,p)=>s+p.penalties,0)/c.squad.length),avgFs=Math.round(c.squad.reduce((s,p)=>s+p.freeKicks,0)/c.squad.length);html=html.replace('</div><div class="substitution-box">',`<label>Spezialtaktik<select id="liveSpecial"><option value="none" ${liveMatch.special==='none'?'selected':''}>Keine</option><option value="penalties" ${liveMatch.special==='penalties'?'selected':''}>Elfmeter (${avgPen})</option><option value="freekicks" ${liveMatch.special==='freekicks'?'selected':''}>Freistöße (${avgFs})</option><option value="offside" ${liveMatch.special==='offside'?'selected':''}>Abseitsfalle (${c.offsideTrap})</option></select></label></div><div class="substitution-box">`);return html;};
const _v14StartLiveMatch=startLiveMatch;
startLiveMatch=function(f,round){ensureV15State();_v14StartLiveMatch(f,round);if(liveMatch){liveMatch.special=state.matchSettings.special||'none';}};
const _v14EffectiveUserPower=effectiveUserPower;
effectiveUserPower=function(base){ensureV15State();let v=_v14EffectiveUserPower(base);const special=liveMatch?.special||state.matchSettings.special;if(special==='offside')v+=(getUserClub().offsideTrap-65)/18;if(special==='freekicks')v+=.8;if(special==='penalties')v+=.4;return v;};
const _v14ProcessLiveMinute=processLiveMinute;
processLiveMinute=function(){if(!liveMatch)return;const beforeH=liveMatch.homeGoals,beforeA=liveMatch.awayGoals;_v14ProcessLiveMinute();const user=liveUserClub(),special=liveMatch.special;if(special==='freekicks'&&Math.random()<.005){const taker=[...user.squad].sort((a,b)=>b.freeKicks-a.freeKicks)[0];if(taker&&Math.random()<taker.freeKicks/190){if(liveMatch.userHome)liveMatch.homeGoals++;else liveMatch.awayGoals++;addLiveEvent(liveMatch.minute,'goal',`Direkter Freistoß von ${taker.name}!`,user.id,taker.id);}}if(special==='offside'&&Math.random()<.012)addLiveEvent(liveMatch.minute,'tactic',`${user.name} lässt den Gegner mit der Abseitsfalle auflaufen.`,user.id);};
const _v14FinishLiveMatch=finishLiveMatch;
finishLiveMatch=function(){if(!liveMatch||liveMatch.finished)return;_v14FinishLiveMatch();runWeeklyTraining();save();render();};
const _v14NextWeek=nextWeek;
nextWeek=function(){ensureV15State();if(!liveMatch){getUserClub().squad.forEach(p=>{if(p.injuryGames>0&&p.injuryGames<0)p.injuryGames=0;});}_v14NextWeek();};
const _v14Render=render;
render=function(){if(!state)return;ensureV15State();document.body.classList.toggle('match-running',!!liveMatch&&!liveMatch.finished);$('#seasonLabel').textContent=`Saison ${state.season} · Woche ${state.week} · ${state.league.country} · Version 1.5.3`;const map={dashboard,squad,lineup,league,transfers,training,sponsors,finances,stadium,international,live:liveView};$('#content').innerHTML=map[view]();bindDynamic();updateLiveDisplay();};
const _v14BindDynamic=bindDynamic;
bindDynamic=function(){_v14BindDynamic();const tf=$('#trainingFocus');if(tf)tf.onchange=e=>{state.training.focus=e.target.value;save();render();};const ti=$('#trainingIntensity');if(ti)ti.onchange=e=>{state.training.intensity=e.target.value;save();render();};const st=$('#specialTraining');if(st)st.onchange=e=>{state.training.special=e.target.value;save();render();};const camp=$('#startCamp');if(camp)camp.onclick=startTrainingCamp;const liveSpecial=$('#liveSpecial');if(liveSpecial)liveSpecial.onchange=e=>{liveMatch.special=e.target.value;state.matchSettings.special=e.target.value;save();};};
const _v14Load=load;
load=function(){_v14Load();if(state){ensureV15State();save();render();}};

/* Version 1.5.1 – Verfügbarkeits- und Kaderdarstellungskorrekturen */
function crestFileName(name){return name.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/ß/g,'ss').replace(/[^a-z0-9]+/g,'-').replace(/^-|-$/g,'');}
clubCrest=function(club,size='normal'){
  const name=typeof club==='string'?club:club.name,[a,b]=crestColors(name),slug=crestFileName(name);
  return `<span class="club-crest ${size}" style="--crest-a:${a};--crest-b:${b}" title="${esc(name)}"><img src="assets/club-crests/${slug}.png" alt="" onerror="this.style.display='none';this.nextElementSibling.style.display='grid'"><span style="display:none">${esc(clubInitials(name))}</span></span>`;
};
normalizeLineup=function(){
  if(!state)return;const c=getUserClub(),slots=FORMATIONS[state.formation]||FORMATIONS['4-4-2'],picked=[];
  (state.selectedXI||[]).forEach(id=>{const p=c.squad.find(x=>x.id===id);if(p&&isPlayerAvailable(p)&&!picked.includes(id)&&picked.length<slots.length)picked.push(id);});
  sortPlayers(c.squad.filter(p=>!picked.includes(p.id)&&isPlayerAvailable(p)),'rating').forEach(p=>{if(picked.length<slots.length)picked.push(p.id);});state.selectedXI=picked.slice(0,slots.length);
};
liveBench=function(){const c=liveUserClub();return c.squad.filter(p=>!liveMatch.userXI.includes(p.id)&&isPlayerAvailable(p));};
const _v15ChangeLiveFormation=changeLiveFormation;
changeLiveFormation=function(value){if(!liveMatch||!FORMATIONS[value])return;const c=liveUserClub();liveMatch.userXI=liveMatch.userXI.filter(id=>{const p=c.squad.find(x=>x.id===id);return p&&isPlayerAvailable(p);});_v15ChangeLiveFormation(value);};
squad=function(){
  ensureV15State();const c=getUserClub(),players=sortPlayers(c.squad,squadSort);
  return `<div class="card"><div class="section-toolbar"><div><h2>Kader – ${esc(c.name)}</h2><p class="muted">Stärke, Spezialwerte, Verletzungen und Transferstatus.</p></div><label>Sortierung<select id="squadSort"><option value="position" ${squadSort==='position'?'selected':''}>Position</option><option value="rating" ${squadSort==='rating'?'selected':''}>Stärke</option></select></label></div><table><thead><tr><th>Pos</th><th>Spieler</th><th>Alter</th><th>Stärke</th><th>Fitness</th><th>11m</th><th>Freistoß</th><th>Status</th><th>Wert</th><th></th></tr></thead><tbody>${players.map(p=>`<tr><td><span class="badge">${p.position}</span></td><td>${esc(p.name)}</td><td>${p.age}</td><td><b>${p.rating}</b></td><td>${p.fitness}%</td><td>${p.penalties}</td><td>${p.freeKicks}</td><td>${p.injuryGames?`<span class="injured">${esc(p.injuryName)} · ${p.injuryGames}</span>`:p.suspensionGames?`<span class="suspension-label">Gesperrt ${p.suspensionGames}</span>`:p.transferListed?'<span class="listed-label">Transferliste</span>':'Fit'}</td><td>${money(p.value)}</td><td><button data-list-player="${p.id}" class="${p.transferListed?'danger':''}">${p.transferListed?'Entfernen':'Anbieten'}</button></td></tr>`).join('')}</tbody></table></div>`;
};

/* Version 1.6 – aktuelle Ligen 2026/27 und österreichischer Auf-/Abstieg */
function createLeagueSchedule(clubs){
  const ids=clubs.map(c=>c.id);if(ids.length%2)ids.push(null);const first=[],rot=[...ids];
  for(let r=0;r<rot.length-1;r++){
    const games=[];for(let i=0;i<rot.length/2;i++){const h=rot[i],a=rot[rot.length-1-i];if(h&&a)games.push({home:h,away:a,played:false});}
    first.push(games);rot.splice(1,0,rot.pop());
  }
  const second=first.map(g=>g.map(x=>({home:x.away,away:x.home,played:false})));
  const double=[...first,...second];
  return clubs.length===10?[...double,...double.map(g=>g.map(x=>({home:x.home,away:x.away,played:false})))]:double;
}
roundRobin=createLeagueSchedule;
ensure36GameSeason=function(){
  if(!state?.league?.fixtures)return;
  const expected=state.league.clubs.length===10?36:(state.league.clubs.length-1)*2;
  if(state.league.fixtures.length!==expected)state.league.fixtures=createLeagueSchedule(state.league.clubs);
};
function resetLeagueSeason(league){
  league.round=0;league.results=[];
  league.clubs.forEach(c=>Object.assign(c,{played:0,wins:0,draws:0,losses:0,gf:0,ga:0,points:0,form:[]}));
  league.fixtures=createLeagueSchedule(league.clubs);
}
function leagueClub(league,id){return league.clubs.find(c=>c.id===id);}
function leaguePower(club){
  const players=[...club.squad].sort((a,b)=>b.rating-a.rating).slice(0,11);
  return players.reduce((s,p)=>s+p.rating*(p.fitness/100)*(0.85+p.morale/500),0)/(players.length||1);
}
function applySilentResult(league,f,hg,ag){
  const h=leagueClub(league,f.home),a=leagueClub(league,f.away);if(!h||!a)return;
  [h,a].forEach(c=>c.played++);h.gf+=hg;h.ga+=ag;a.gf+=ag;a.ga+=hg;
  if(hg>ag){h.wins++;h.points+=3;a.losses++;h.form.unshift('S');a.form.unshift('N');}
  else if(hg<ag){a.wins++;a.points+=3;h.losses++;h.form.unshift('N');a.form.unshift('S');}
  else{h.draws++;a.draws++;h.points++;a.points++;h.form.unshift('U');a.form.unshift('U');}
  h.form=h.form.slice(0,5);a.form=a.form.slice(0,5);f.played=true;f.score=[hg,ag];
}
function simulateSilentFixture(league,f){
  const h=leagueClub(league,f.home),a=leagueClub(league,f.away);if(!h||!a||f.played)return;
  const hp=leaguePower(h),ap=leaguePower(a);applySilentResult(league,f,goalsFor(hp,ap,true),goalsFor(ap,hp,false));
}
function simulateOtherLeagueRound(){
  const league=state?.austrianOtherLeague;if(!league)return;
  const round=league.fixtures[league.round];if(!round)return;
  round.forEach(f=>simulateSilentFixture(league,f));league.round++;
}
function completeSilentLeague(league){
  if(!league)return;
  while(league.round<league.fixtures.length){(league.fixtures[league.round]||[]).forEach(f=>simulateSilentFixture(league,f));league.round++;}
}
function sortAnyLeague(league){return [...league.clubs].sort((a,b)=>b.points-a.points||(b.gf-b.ga)-(a.gf-a.ga)||b.gf-a.gf);}
const _v153NewGame=newGame;
newGame=function(ci,li,clubName){
  _v153NewGame(ci,li,clubName);
  state.version=6;
  if(COUNTRIES[ci].name==='Österreich'){
    const otherIndex=li===0?1:0;state.austrianOtherLeague=buildLeague(ci,otherIndex);state.austrianOtherLeague.fixtures=createLeagueSchedule(state.austrianOtherLeague.clubs);
    state.leagueTier=li===0?1:2;
    state.news.unshift(state.leagueTier===1?'Der Tabellenletzte steigt am Saisonende in die 2. Liga ab.':'Der Meister der 2. Liga steigt am Saisonende in die Bundesliga auf.');
  }else{delete state.austrianOtherLeague;delete state.leagueTier;}
  state.league.fixtures=createLeagueSchedule(state.league.clubs);save();render();
};
function processAustrianPromotionRelegation(){
  if(state.league.country!=='Österreich'||!state.austrianOtherLeague)return null;
  const top=state.league.name==='Bundesliga'?state.league:state.austrianOtherLeague;
  const second=state.league.name==='2. Liga'?state.league:state.austrianOtherLeague;
  completeSilentLeague(top);completeSilentLeague(second);
  const relegated=sortAnyLeague(top).at(-1),promoted=sortAnyLeague(second)[0];
  top.clubs=top.clubs.filter(c=>c.id!==relegated.id);second.clubs=second.clubs.filter(c=>c.id!==promoted.id);
  top.clubs.push(promoted);second.clubs.push(relegated);
  let message=`${relegated.name} steigt in die 2. Liga ab. ${promoted.name} steigt in die Bundesliga auf.`;
  if(state.userClubId===relegated.id){state.league=second;state.austrianOtherLeague=top;state.leagueTier=2;message=`ABSTIEG: ${relegated.name} spielt nächste Saison in der 2. Liga. ${promoted.name} steigt auf.`;}
  else if(state.userClubId===promoted.id){state.league=top;state.austrianOtherLeague=second;state.leagueTier=1;message=`AUFSTIEG: ${promoted.name} spielt nächste Saison in der Bundesliga. ${relegated.name} steigt ab.`;}
  return message;
}
endSeason=function(){
  const table=sortedTable(),pos=table.findIndex(c=>c.id===state.userClubId)+1,user=getUserClub();
  user.balance+=Math.max(1,table.length-pos+1)*2e6;state.international.qualified=state.leagueTier===2?false:pos<=3;
  const movement=processAustrianPromotionRelegation();
  state.season=(parseInt(state.season)+1)+'/'+String(parseInt(state.season)+2).slice(-2);state.week=1;
  resetLeagueSeason(state.league);if(state.austrianOtherLeague)resetLeagueSeason(state.austrianOtherLeague);
  state.transferList=generateTransferList(state.league.clubs);state.outgoingOffers=[];
  const current=getUserClub();state.selectedXI=[...current.squad].sort((a,b)=>b.rating-a.rating).filter(isPlayerAvailable).slice(0,11).map(p=>p.id);
  state.news.unshift(movement||`Saison beendet: Platz ${pos}. Eine neue Saison wurde gestartet.`);generateSponsorOffers(true);save();render();
};
const _v153Finish=finishLiveMatch;
finishLiveMatch=function(){const before=state?.week||0;_v153Finish();if(state&&state.week>before){simulateOtherLeagueRound();save();render();}};
const _v153Next=nextWeek;
nextWeek=function(){const before=state?.week||0;_v153Next();if(state&&state.week>before){simulateOtherLeagueRound();save();render();}};
const _v153Load2=load;
load=function(){_v153Load2();if(state){state.version=6;if(state.league?.country==='Österreich'&&!state.austrianOtherLeague){const currentIndex=state.league.name==='2. Liga'?1:0,otherIndex=currentIndex===0?1:0;state.austrianOtherLeague=buildLeague(0,otherIndex);state.austrianOtherLeague.fixtures=createLeagueSchedule(state.austrianOtherLeague.clubs);state.leagueTier=currentIndex+1;}ensure36GameSeason();save();render();}};
const _v153LeagueView=league;
league=function(){
  let html=_v153LeagueView();
  const marker=state.league.country==='Österreich'?(state.league.name==='Bundesliga'?'<p class="muted">Der 12. Platz steigt am Saisonende direkt in die 2. Liga ab.</p>':'<p class="muted">Der Meister steigt am Saisonende direkt in die Bundesliga auf.</p>'):'';
  html=html.replace(`<h2>${esc(state.league.name)}</h2>`,`<h2>${esc(state.league.name)}</h2>${marker}`);
  if(state.austrianOtherLeague){const other=state.austrianOtherLeague,t=sortAnyLeague(other);html+=`<div class="card" style="margin-top:16px"><h2>${esc(other.name)} · Parallelbewerb</h2><table><thead><tr><th>#</th><th>Verein</th><th>Sp</th><th>Diff.</th><th>Pkt.</th></tr></thead><tbody>${t.map((c,i)=>`<tr><td>${i+1}</td><td>${clubNameWithCrest(c,'tiny')}</td><td>${c.played}</td><td>${c.gf-c.ga}</td><td><b>${c.points}</b></td></tr>`).join('')}</tbody></table></div>`;}
  return html;
};
const _v153Render2=render;
render=function(){_v153Render2();if(state)$('#seasonLabel').textContent=`Saison ${state.season} · Woche ${state.week} · ${state.league.country} · ${state.league.name} · Version 1.6`;};

/* Version 2.0 – Jugend, Scouting, Personal, Infrastruktur, Verträge, Medien, Europa und Langzeitkarriere */
const V20_ROLES=['Cheftrainer','Co-Trainer','Torwarttrainer','Athletiktrainer','Physiotherapeut','Scout'];
const V20_ECONOMY=['Normal','Fußballboom','Schwache Konjunktur','Sponsorenboom','Hohe Energiepreise'];
const V20_FACILITIES={vip:'VIP-Logen',business:'Business-Seats',parking:'Parkplätze',fanshop:'Fanshop',museum:'Vereinsmuseum',gastro:'Gastronomie',solar:'Solaranlage',floodlights:'Flutlicht',training:'Trainingszentrum',academy:'Jugendakademie'};
const V20_ATTRS=['technique','passing','shooting','heading','pace','stamina','tackling','positioning','vision','mentality','leadership','aggression','corners'];
let v20ScoutCountry='Österreich';
function v20BaseAttr(p,key){
  const bias={TW:{positioning:5,mentality:3},IV:{tackling:6,heading:5,positioning:4},RV:{pace:4,passing:2},LV:{pace:4,passing:2},DM:{tackling:4,passing:3},ZM:{passing:5,vision:5,technique:3},RA:{pace:5,technique:4},LA:{pace:5,technique:4},ST:{shooting:6,heading:3}};
  return clamp(p.rating+rand(-10,6)+(bias[p.position]?.[key]||0),35,99);
}
function ensureV20State(){
  if(!state)return; ensureV15State();
  state.version=20;
  const c=getUserClub();
  state.v20 ||= {weekProcessed:0,economy:'Normal',economyWeeks:0,fanMood:'Zufrieden',boardConfidence:70,media:[],hallOfFame:[],records:{bestPosition:null,biggestWin:'–',topScorer:'–',seasons:0,trophies:0},loans:[],taxReserve:0,insurance:true,staff:[],academy:[],scoutReports:[],scoutAssignment:null,facilities:{vip:0,business:0,parking:1,fanshop:1,museum:0,gastro:1,solar:0,floodlights:1,training:1,academy:1},europe:{competition:null,round:0,points:0,played:0,fixtures:[],history:[]},nationalCallups:[],boardObjective:'Obere Tabellenhälfte'};
  const v=state.v20;
  V20_ROLES.forEach((role,i)=>{if(!v.staff.some(x=>x.role===role))v.staff.push({id:uid(),role,name:`${FIRST_NAMES[(i*3)%FIRST_NAMES.length]} ${LAST_NAMES[(i*5+2)%LAST_NAMES.length]}`,rating:rand(52,72),wage:rand(9000,26000),employed:true});});
  state.league.clubs.forEach(club=>club.squad.forEach(p=>{
    V20_ATTRS.forEach(k=>{if(p[k]===undefined)p[k]=v20BaseAttr(p,k)});
    if(p.agent===undefined)p.agent=`Agentur ${LAST_NAMES[rand(0,LAST_NAMES.length-1)]}`;
    if(p.signingBonus===undefined)p.signingBonus=Math.round(p.wage*rand(8,20));
    if(p.releaseClause===undefined)p.releaseClause=Math.round(p.value*rand(140,260)/100);
    if(p.loyalty===undefined)p.loyalty=rand(45,90);
    if(p.loanListed===undefined)p.loanListed=false;
  }));
  if(!v.academy.length){for(let i=0;i<10;i++)v.academy.push(v20Youth());}
  if(!v.media.length)v.media.unshift({week:state.week,title:'Neue Ära',text:`${c.name} startet mit erweiterten Vereinsstrukturen in die Saison.`,choice:null});
  if(!v.europe.competition&&state.international?.qualified)v20StartEurope();
}
function v20Youth(){
  const pos=POSITIONS[rand(0,POSITIONS.length-1)],rating=rand(42,66);return {id:uid(),name:`${FIRST_NAMES[rand(0,FIRST_NAMES.length-1)]} ${LAST_NAMES[rand(0,LAST_NAMES.length-1)]}`,position:pos,age:rand(15,18),rating,potential:clamp(rating+rand(12,28),60,94),morale:rand(65,90),country:['Österreich','Deutschland','Kroatien','Serbien','Slowenien','Tschechien'][rand(0,5)]};
}
function v20StaffBonus(role){const x=state.v20.staff.find(s=>s.role===role&&s.employed);return x?x.rating:40;}
function v20LeaguePosition(){const t=sortedTable();return t.findIndex(x=>x.id===state.userClubId)+1;}
function v20EconomyFactor(){return {'Normal':1,'Fußballboom':1.12,'Schwache Konjunktur':.86,'Sponsorenboom':1.08,'Hohe Energiepreise':.94}[state.v20.economy]||1;}
function v20StartEurope(){
  const e=state.v20.europe;e.competition='Europapokal';e.round=0;e.points=0;e.played=0;e.fixtures=['Sporting CPA','Ajex','AS Monako','Bayer Leverkuzen','FC Porta','Olympique Lyonaa'].map((n,i)=>({opponent:n,home:i%2===0,played:false,score:null}));
  state.news.unshift('Die Auslosung für den Europapokal wurde durchgeführt.');
}
function v20ProcessWeek(){
  ensureV20State();const v=state.v20,c=getUserClub();if(v.weekProcessed===state.week)return;v.weekProcessed=state.week;
  const staffWages=v.staff.filter(x=>x.employed).reduce((s,x)=>s+x.wage,0);c.balance-=staffWages;
  v.loans.forEach(l=>{const interest=Math.round(l.remaining*l.rate/5200);l.remaining+=interest;c.balance-=interest;});
  const academyBoost=(v.facilities.academy+v20StaffBonus('Co-Trainer')/50)*.12;
  v.academy.forEach(y=>{if(Math.random()<.38){y.rating=clamp(y.rating+Math.max(1,Math.round(academyBoost)),35,y.potential);}});
  if(Math.random()<.12&&v.academy.length<18)v.academy.push(v20Youth());
  if(v.scoutAssignment){v.scoutAssignment.weeks--;if(v.scoutAssignment.weeks<=0){const count=1+Math.floor(v20StaffBonus('Scout')/30);for(let i=0;i<count;i++){const p=v20Youth();p.age=rand(17,25);p.rating=rand(55,78);p.potential=clamp(p.rating+rand(4,18),p.rating,94);p.country=v.scoutAssignment.country;v.scoutReports.unshift(p);}state.news.unshift(`Scoutingbericht aus ${v.scoutAssignment.country} ist eingetroffen.`);v.scoutAssignment=null;}}
  if(Math.random()<.08){v.economy=V20_ECONOMY[rand(0,V20_ECONOMY.length-1)];v.economyWeeks=rand(5,10);state.news.unshift(`Wirtschaftslage: ${v.economy}.`);}else if(v.economyWeeks>0){v.economyWeeks--;if(v.economyWeeks===0)v.economy='Normal';}
  const lm=state.lastMatch;if(lm){const [hg,ag]=(lm.score||'0:0').split(':').map(Number),home=lm.home===c.name,won=home?hg>ag:ag>hg,lost=home?hg<ag:ag<hg;v.fanMood=won?'Begeistert':lost?'Unruhig':'Zufrieden';v.boardConfidence=clamp(v.boardConfidence+(won?3:lost?-3:0),0,100);}
  if(state.week%6===0){const candidates=c.squad.filter(p=>p.contract<=1);if(candidates.length)state.news.unshift(`${candidates.length} Spielerverträge laufen bald aus.`);}
  if(state.week%12===0)c.squad.forEach(p=>{p.contract=Math.max(.1,p.contract-.25);});
  if(Math.random()<.15){const stars=[...c.squad].sort((a,b)=>b.rating-a.rating).slice(0,5),p=stars[rand(0,stars.length-1)];v.nationalCallups.unshift({week:state.week,player:p.name,country:['Österreich','Deutschland','Italien','England','Frankreich'][rand(0,4)]});p.morale=clamp(p.morale+3,0,100);state.news.unshift(`${p.name} wurde für die Nationalmannschaft nominiert.`);}
  if(v.europe.competition&&state.week%5===0)v20PlayEurope();
  v.media.unshift({week:state.week,title:lm?`${lm.home} ${lm.score} ${lm.away}`:'Vereinswoche',text:`Fans: ${v.fanMood}. Vorstand: ${v.boardConfidence}%. Wirtschaft: ${v.economy}.`,choice:null});v.media=v.media.slice(0,30);
  c.balance+=Math.round((v.facilities.solar*18000+v.facilities.fanshop*35000+v.facilities.museum*12000)*v20EconomyFactor());
}
function v20PlayEurope(){const e=state.v20.europe,f=e.fixtures.find(x=>!x.played);if(!f)return;const user=teamPower(getUserClub()),opp=rand(75,90),ug=goalsFor(user,opp,f.home),og=goalsFor(opp,user,!f.home);f.played=true;f.score=`${ug}:${og}`;e.played++;if(ug>og)e.points+=3;else if(ug===og)e.points++;getUserClub().balance+=ug>og?1800000:ug===og?700000:250000;e.history.unshift(`${f.home?'Heim':'Auswärts'} gegen ${f.opponent}: ${f.score}`);if(e.played===e.fixtures.length){if(e.points>=10){state.v20.records.trophies++;getUserClub().balance+=8000000;state.news.unshift('Europapokal gewonnen!');}else state.news.unshift(`Europapokal beendet: ${e.points} Punkte.`);e.competition=null;}}
function v20PlayerRows(players,actions=''){return players.map(p=>`<tr><td>${p.position}</td><td>${esc(p.name)}</td><td>${p.age}</td><td><b>${p.rating}</b></td><td>${p.potential||p.rating}</td><td>${p.contract||'–'}</td><td>${money(p.wage||0)}</td><td>${actions?actions.replaceAll('{id}',p.id):''}</td></tr>`).join('');}
function academy(){ensureV20State();const v=state.v20;return `<div class="grid cols-2"><div class="card"><h2>Jugendakademie · Stufe ${v.facilities.academy}</h2><p class="muted">Talente entwickeln sich wöchentlich. Bessere Akademie und Trainer erhöhen den Fortschritt.</p><table><thead><tr><th>Pos</th><th>Name</th><th>Alter</th><th>Stärke</th><th>Pot.</th><th></th></tr></thead><tbody>${v.academy.map(p=>`<tr><td>${p.position}</td><td>${esc(p.name)}</td><td>${p.age}</td><td>${p.rating}</td><td><b>${p.potential}</b></td><td><button data-promote-youth="${p.id}">Hochziehen</button></td></tr>`).join('')}</tbody></table></div><div class="card"><h2>Scouting</h2><label>Region<select id="scoutCountry">${['Österreich','Deutschland','England','Italien','Frankreich','Spanien','Südamerika','Skandinavien'].map(x=>`<option ${x===v20ScoutCountry?'selected':''}>${x}</option>`).join('')}</select></label><p>${v.scoutAssignment?`Scout unterwegs in ${esc(v.scoutAssignment.country)} · noch ${v.scoutAssignment.weeks} Wochen`:'Kein Auftrag aktiv.'}</p><button id="startScout" ${v.scoutAssignment?'disabled':''}>Scouting starten · ${money(250000)}</button><h3>Berichte</h3>${v.scoutReports.length?`<table><thead><tr><th>Pos</th><th>Name</th><th>Alter</th><th>Stärke</th><th>Pot.</th><th></th></tr></thead><tbody>${v.scoutReports.map(p=>`<tr><td>${p.position}</td><td>${esc(p.name)}</td><td>${p.age}</td><td>${p.rating}</td><td>${p.potential}</td><td><button data-sign-scout="${p.id}">Verpflichten</button></td></tr>`).join('')}</tbody></table>`:'<p class="muted">Noch keine Berichte.</p>'}</div></div>`;}
function staff(){ensureV20State();return `<div class="card"><h2>Trainer- und Betreuerteam</h2><table><thead><tr><th>Rolle</th><th>Name</th><th>Qualität</th><th>Gehalt/Woche</th><th>Status</th><th></th></tr></thead><tbody>${state.v20.staff.map(s=>`<tr><td>${s.role}</td><td>${esc(s.name)}</td><td><b>${s.rating}</b></td><td>${money(s.wage)}</td><td>${s.employed?'Angestellt':'Frei'}</td><td><button data-upgrade-staff="${s.id}">${s.employed?'Fortbildung':'Einstellen'} · ${money(s.employed?500000:1000000)}</button></td></tr>`).join('')}</tbody></table><p class="muted">Cheftrainer verbessert Entwicklung, Torwarttrainer die TW-Werte, Athletiktrainer Fitness und Physiotherapeut reduziert Verletzungsdauer.</p></div>`;}
function v20Stadium(){const base=stadium(),v=state.v20.facilities;return base+`<div class="card" style="margin-top:16px"><h2>Vereinsinfrastruktur</h2><div class="facility-grid">${Object.entries(V20_FACILITIES).map(([k,n])=>`<div class="facility-item"><b>${n}</b><span>Stufe ${v[k]||0}/5</span><small>Kosten ${money((v[k]+1)*1500000)}</small><button data-facility="${k}" ${(v[k]||0)>=5?'disabled':''}>Ausbauen</button></div>`).join('')}</div></div>`;}
function v20Finances(){const base=finances(),v=state.v20,c=getUserClub(),debt=v.loans.reduce((s,l)=>s+l.remaining,0);return `<div class="grid cols-3"><div class="metric-card"><span>Wirtschaft</span><div class="viz-stat-value">${v.economy}</div></div><div class="metric-card"><span>Kredite</span><div class="viz-stat-value">${money(debt)}</div></div><div class="metric-card"><span>Versicherung</span><div class="viz-stat-value">${v.insurance?'Aktiv':'Aus'}</div></div></div>${base}<div class="card" style="margin-top:16px"><h2>Bank & Absicherung</h2><button data-loan="5000000">5 Mio. Kredit</button> <button data-loan="15000000">15 Mio. Kredit</button> <button id="repayLoan" ${debt<=0?'disabled':''}>5 Mio. tilgen</button> <button id="toggleInsurance">Versicherung ${v.insurance?'kündigen':'abschließen'}</button><p>Kontostand nach Maßnahmen: <b>${money(c.balance)}</b></p></div>`;}
function v20Transfers(){ensureV20State();const c=getUserClub(),base=transfers();return `<div class="card transfer-budget-banner"><span>Verfügbares Transferbudget</span><b>${money(c.budget)}</b></div>${base}<div class="card" style="margin-top:16px"><h2>Verträge & Leihen</h2><table><thead><tr><th>Spieler</th><th>Vertrag</th><th>Gehalt</th><th>Klausel</th><th>Berater</th><th></th></tr></thead><tbody>${c.squad.map(p=>`<tr><td>${esc(p.name)}</td><td>${p.contract.toFixed? p.contract.toFixed(1):p.contract} J.</td><td>${money(p.wage)}</td><td>${money(p.releaseClause)}</td><td>${esc(p.agent)}</td><td><button data-renew="${p.id}">Verlängern</button> <button data-loan-list="${p.id}">${p.loanListed?'Leihe stoppen':'Zur Leihe'}</button></td></tr>`).join('')}</tbody></table></div>`;}
function board(){ensureV20State();const v=state.v20,pos=v20LeaguePosition();return `<div class="grid cols-2"><div class="card"><h2>Vorstand</h2><div class="stat">${v.boardConfidence}% Vertrauen</div><div class="progress"><span style="width:${v.boardConfidence}%"></span></div><p>Saisonziel: <b>${v.boardObjective}</b></p><p>Aktueller Platz: <b>${pos}</b></p><p>Fanstimmung: <b>${v.fanMood}</b></p>${v.boardConfidence<25?'<p class="bad"><b>Entlassungsgefahr!</b></p>':''}</div><div class="card"><h2>Presse & Zeitung</h2>${v.media.slice(0,8).map(m=>`<article class="news-article"><small>Woche ${m.week}</small><h3>${esc(m.title)}</h3><p>${esc(m.text)}</p></article>`).join('')}</div></div>`;}
function records(){ensureV20State();const v=state.v20,c=getUserClub(),top=[...c.squad].sort((a,b)=>b.goals-a.goals)[0];return `<div class="grid cols-3"><div class="metric-card"><span>Saisonen</span><div class="viz-stat-value">${v.records.seasons}</div></div><div class="metric-card"><span>Trophäen</span><div class="viz-stat-value">${v.records.trophies}</div></div><div class="metric-card"><span>Aktueller Torjäger</span><div class="viz-stat-value">${top?esc(top.name):'–'}</div><small>${top?.goals||0} Tore</small></div></div><div class="card"><h2>Hall of Fame</h2>${v.hallOfFame.length?v.hallOfFame.map(x=>`<div class="fixture"><span>${esc(x.name)}</span><b>${esc(x.reason)}</b></div>`).join(''):'<p class="muted">Noch keine Legenden aufgenommen.</p>'}<h2>Nationalmannschaften</h2>${v.nationalCallups.slice(0,10).map(x=>`<div class="fixture"><span>${esc(x.player)}</span><b>${esc(x.country)}</b></div>`).join('')||'<p class="muted">Noch keine Nominierungen.</p>'}</div>`;}
function v20International(){ensureV20State();const e=state.v20.europe;return `<div class="card"><h2>Europa & Nationalteams</h2>${e.competition?`<p class="good"><b>${e.competition}</b> · ${e.points} Punkte aus ${e.played} Spielen</p><table><thead><tr><th>Gegner</th><th>Ort</th><th>Ergebnis</th></tr></thead><tbody>${e.fixtures.map(f=>`<tr><td>${esc(f.opponent)}</td><td>${f.home?'Heim':'Auswärts'}</td><td>${f.score||'–'}</td></tr>`).join('')}</tbody></table>`:'<p>Aktuell kein europäischer Wettbewerb. Qualifikation über die Liga.</p>'}<h3>Nationalteam-Nominierungen</h3>${state.v20.nationalCallups.slice(0,8).map(x=>`<p>${esc(x.player)} · ${esc(x.country)}</p>`).join('')||'<p class="muted">Keine aktuellen Nominierungen.</p>'}</div>`;}
function v20Dashboard(){const base=dashboard(),v=state.v20;return `<div class="grid cols-4"><div class="metric-card"><span>Vorstand</span><div class="viz-stat-value">${v.boardConfidence}%</div></div><div class="metric-card"><span>Fans</span><div class="viz-stat-value">${v.fanMood}</div></div><div class="metric-card"><span>Wirtschaft</span><div class="viz-stat-value">${v.economy}</div></div><div class="metric-card"><span>Jugendtalente</span><div class="viz-stat-value">${v.academy.length}</div></div></div>${base}`;}
function v20Bind(){
  const c=getUserClub(),v=state.v20;
  $$('[data-promote-youth]').forEach(b=>b.onclick=()=>{const i=v.academy.findIndex(x=>x.id===b.dataset.promoteYouth),y=v.academy[i];if(!y)return;const p=makePlayer(c.rating,y.position,0);Object.assign(p,{name:y.name,age:y.age,rating:y.rating,potential:y.potential,value:Math.round(y.rating**3*20),wage:Math.round(y.rating*y.rating*8)});c.squad.push(p);v.academy.splice(i,1);state.news.unshift(`${p.name} wurde aus der Jugend hochgezogen.`);save();render();});
  const sc=$('#scoutCountry');if(sc)sc.onchange=e=>v20ScoutCountry=e.target.value;
  const ss=$('#startScout');if(ss)ss.onclick=()=>{if(c.balance<250000)return alert('Zu wenig Geld.');c.balance-=250000;v.scoutAssignment={country:v20ScoutCountry,weeks:rand(2,4)};save();render();};
  $$('[data-sign-scout]').forEach(b=>b.onclick=()=>{const i=v.scoutReports.findIndex(x=>x.id===b.dataset.signScout),r=v.scoutReports[i],cost=Math.round(r.rating**3*45);if(c.budget<cost)return alert('Transferbudget reicht nicht.');const p=makePlayer(c.rating,r.position,0);Object.assign(p,{name:r.name,age:r.age,rating:r.rating,potential:r.potential,value:cost});c.squad.push(p);c.budget-=cost;c.balance-=cost;v.scoutReports.splice(i,1);save();render();});
  $$('[data-upgrade-staff]').forEach(b=>b.onclick=()=>{const s=v.staff.find(x=>x.id===b.dataset.upgradeStaff),cost=s.employed?500000:1000000;if(c.balance<cost)return alert('Zu wenig Geld.');c.balance-=cost;s.employed=true;s.rating=clamp(s.rating+rand(2,5),0,95);s.wage=Math.round(s.wage*1.06);save();render();});
  $$('[data-facility]').forEach(b=>b.onclick=()=>{const k=b.dataset.facility,cost=(v.facilities[k]+1)*1500000;if(c.balance<cost)return alert('Zu wenig Geld.');c.balance-=cost;v.facilities[k]++;if(k==='gastro')c.stadium.gastroLevel=v.facilities[k];if(k==='training')state.training.intensity='normal';save();render();});
  $$('[data-loan]').forEach(b=>b.onclick=()=>{const amount=+b.dataset.loan;c.balance+=amount;v.loans.push({id:uid(),remaining:amount,rate:6.5});save();render();});
  const repay=$('#repayLoan');if(repay)repay.onclick=()=>{const l=v.loans.find(x=>x.remaining>0);if(!l||c.balance<5000000)return alert('Tilgung nicht möglich.');const x=Math.min(5000000,l.remaining);l.remaining-=x;c.balance-=x;v.loans=v.loans.filter(x=>x.remaining>1000);save();render();};
  const ins=$('#toggleInsurance');if(ins)ins.onclick=()=>{v.insurance=!v.insurance;save();render();};
  $$('[data-renew]').forEach(b=>b.onclick=()=>{const p=c.squad.find(x=>x.id===b.dataset.renew),cost=p.signingBonus;if(c.balance<cost)return alert('Zu wenig Geld für Handgeld.');c.balance-=cost;p.contract=rand(3,5);p.wage=Math.round(p.wage*1.1);p.releaseClause=Math.round(p.value*2);p.loyalty=clamp(p.loyalty+8,0,100);save();render();});
  $$('[data-loan-list]').forEach(b=>b.onclick=()=>{const p=c.squad.find(x=>x.id===b.dataset.loanList);p.loanListed=!p.loanListed;state.news.unshift(`${p.name} ${p.loanListed?'steht nun zur Leihe bereit':'wurde von der Leihliste genommen'}.`);save();render();});
}
const v20OldBind=bindDynamic;
bindDynamic=function(){v20OldBind();if(state){ensureV20State();v20Bind();}};
const v20OldNext=nextWeek;
nextWeek=function(){const before=state?.week||0;v20OldNext();if(state&&state.week>before){v20ProcessWeek();save();render();}};
const v20OldFinish=finishLiveMatch;
finishLiveMatch=function(){const before=state?.week||0;v20OldFinish();if(state&&state.week>before){v20ProcessWeek();save();render();}};
const v20OldEnd=endSeason;
endSeason=function(){if(state){ensureV20State();const c=getUserClub(),top=[...c.squad].sort((a,b)=>b.goals-a.goals)[0];state.v20.records.seasons++;if(top&&top.goals>12)state.v20.hallOfFame.unshift({name:top.name,reason:`${top.goals} Saisontore ${state.season}`});}v20OldEnd();if(state){ensureV20State();if(state.international.qualified)v20StartEurope();state.v20.weekProcessed=0;save();render();}};
const v20OldLoad=load;
load=function(){v20OldLoad();if(state){ensureV20State();save();render();}};
const v20OldNewGame=newGame;
newGame=function(ci,li,clubName){v20OldNewGame(ci,li,clubName);ensureV20State();state.v20.weekProcessed=0;save();render();};
render=function(){
  if(!state)return;ensureV20State();document.body.classList.toggle('match-running',!!liveMatch&&!liveMatch.finished);
  $('#seasonLabel').textContent=`Saison ${state.season} · Woche ${state.week} · ${state.league.country} · ${state.league.name} · Version 2.0`;
  const map={dashboard:v20Dashboard,squad,lineup,league,transfers:v20Transfers,training,academy,staff,sponsors,finances:v20Finances,stadium:v20Stadium,board,records,international:v20International,live:liveView};
  const fn=map[view]||v20Dashboard;$('#content').innerHTML=fn();bindDynamic();updateLiveDisplay();
};

if(window.__fmBoot)window.__fmBoot();
