// ═══════════════════════════════════════════════
// STATE
// ═══════════════════════════════════════════════
const TODAY = new Date().toISOString().slice(0,10);

let D = {
  pkg: null,
  ci: null, co: null,
  cMonth: new Date().getMonth(),
  cYear: new Date().getFullYear(),
  admMonth: new Date().getMonth(),
  admYear: new Date().getFullYear(),
  blocked: new Set(),
  bookings: [],
  icalSrcs: [],
  bkFilter: 'all',
  aTab: 'bookings',
};

const PKGS = [
  {id:'harvest',name:'Olive Harvest Stay',season:'October – November',price:'from €140/person',min:2,desc:'Pick your own olives, pressed the same day. Leave with a tin you made yourself.'},
  {id:'winter',name:'Slow Winter Break',season:'December – March',price:'from €110/person',min:2,desc:'Quiet, cold, completely yours. Fire in the evening, wine from our vines, Sibillini views.'},
  {id:'taste',name:'Taste & Stay',season:'All year',price:'from €190/person',min:2,desc:'Oil tasting, communal farm dinner, two nights in the groves.'},
  {id:'custom',name:'Custom dates',season:'Your choice',price:'Contact for pricing',min:1,desc:'Choose your own dates — we\'ll discuss.'}
];

// ═══════════════════════════════════════════════
// STORAGE
// ═══════════════════════════════════════════════
function LS(k,v){if(v===undefined)return JSON.parse(localStorage.getItem(k)||'null');localStorage.setItem(k,JSON.stringify(v));}

function loadAll(){
  const b=LS('m11_blocked'); D.blocked = b ? new Set(b) : new Set();
  D.bookings = LS('m11_bookings')||[];
  D.icalSrcs = LS('m11_ical')||[];
  // init settings
  const cfg=LS('m11_cfg')||{};
  if(!cfg.rates) cfg.rates={default:150,minNights:2,cleaning:60,deposit:200,seasons:[
    {name:'High Season',from:'07-01',to:'08-31',rate:400,min:7},
    {name:'Olive Harvest',from:'10-01',to:'11-15',rate:180,min:2},
    {name:'Easter',from:'04-01',to:'04-20',rate:200,min:3},
  ]};
  if(!cfg.pw) cfg.pw='montanello';
  D.cfg = cfg;
  LS('m11_cfg',cfg);
}

function save(){
  LS('m11_blocked',[...D.blocked]);
  LS('m11_bookings',D.bookings);
  LS('m11_ical',D.icalSrcs);
  LS('m11_cfg',D.cfg);
}

// ═══════════════════════════════════════════════
// PRICING
// ═══════════════════════════════════════════════
function getRate(dateStr){
  const md = dateStr.slice(5); // MM-DD
  const ss = D.cfg.rates.seasons||[];
  for(const s of ss){
    if(md>=s.from && md<=s.to) return {rate:s.rate,min:s.min||1,name:s.name};
  }
  return {rate:D.cfg.rates.default,min:D.cfg.rates.minNights||1,name:'Standard'};
}

function calcPrice(ci,co){
  if(!ci||!co) return null;
  let total=0, d=new Date(ci);
  const end=new Date(co);
  const breakdown={};
  while(d<end){
    const ds=d.toISOString().slice(0,10);
    const {rate,name}=getRate(ds);
    breakdown[name]=(breakdown[name]||{count:0,rate}); breakdown[name].count++;
    total+=rate;
    d.setDate(d.getDate()+1);
  }
  const nights=Math.round((new Date(co)-new Date(ci))/86400000);
  const cleaning=D.cfg.rates.cleaning||0;
  const deposit=D.cfg.rates.deposit||0;
  return {nights,breakdown,subtotal:total,cleaning,deposit,total:total+cleaning};
}

function checkMinNights(ci,co){
  if(!ci||!co) return true;
  const nights=Math.round((new Date(co)-new Date(ci))/86400000);
  const {min}=getRate(ci);
  return nights>=min;
}

// ═══════════════════════════════════════════════
// iCAL
// ═══════════════════════════════════════════════
function parseICal(txt){
  const bl=new Set();
  const lines=txt.replace(/\r\n|\r/g,'\n').split('\n');
  let ev=null;
  for(let raw of lines){
    const l=raw.trim();
    if(l==='BEGIN:VEVENT'){ev={};continue;}
    if(l==='END:VEVENT'){
      if(ev&&ev.s&&ev.e){
        const s=icalD(ev.s),e=icalD(ev.e);
        if(s&&e){const d=new Date(s);while(d<e){bl.add(d.toISOString().slice(0,10));d.setDate(d.getDate()+1);}}
      }
      ev=null;continue;
    }
    if(!ev)continue;
    const ci=l.indexOf(':');if(ci<0)continue;
    const key=l.slice(0,ci).toUpperCase(),val=l.slice(ci+1).trim();
    if(key.startsWith('DTSTART'))ev.s=val;
    else if(key.startsWith('DTEND'))ev.e=val;
  }
  return bl;
}

function icalD(s){
  const d=s.replace(/T.*/,'');
  if(d.length===8) return new Date(+d.slice(0,4),+d.slice(4,6)-1,+d.slice(6,8));
  return null;
}

function importICal(){
  const txt=document.getElementById('ical-txt').value.trim();
  const nm=document.getElementById('ical-nm').value.trim()||'Import';
  if(!txt){alert('Paste iCal content first.');return;}
  const bl=parseICal(txt);
  bl.forEach(d=>D.blocked.add(d));
  D.icalSrcs.push({name:nm,date:new Date().toLocaleString('en-GB'),count:bl.size});
  save();
  document.getElementById('ical-txt').value='';
  document.getElementById('ical-nm').value='';
  alert(`Imported ${bl.size} blocked dates from "${nm}".`);
  renderSync(); renderAdmCal();
}

function exportICal(){
  let c='BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Montanello11//EN\r\n';
  D.bookings.filter(b=>b.status!=='cancelled').forEach(b=>{
    const s=b.ci.replace(/-/g,''),e=b.co.replace(/-/g,'');
    c+=`BEGIN:VEVENT\r\nDTSTART;VALUE=DATE:${s}\r\nDTEND;VALUE=DATE:${e}\r\nSUMMARY:Direct booking - ${b.name}\r\nEND:VEVENT\r\n`;
  });
  c+='END:VCALENDAR';
  const a=document.createElement('a');
  a.href='data:text/calendar;charset=utf-8,'+encodeURIComponent(c);
  a.download='montanello-direct.ics'; a.click();
}

// ═══════════════════════════════════════════════
// EMAIL (EmailJS)
// ═══════════════════════════════════════════════
function ejsCfg(){return D.cfg.emailjs||{};}

async function sendEmail(templateId, params){
  const c=ejsCfg();
  if(!c.serviceId||!c.publicKey||!templateId){
    console.warn('EmailJS not configured — skipping email send.');
    return false;
  }
  try{
    emailjs.init(c.publicKey);
    await emailjs.send(c.serviceId, templateId, params);
    return true;
  }catch(e){ console.error('EmailJS error:',e); return false; }
}

async function notifyAdmin(bk){
  const c=ejsCfg();
  if(!c.templateAdmin) return;
  const p=calcPrice(bk.ci,bk.co)||{};
  await sendEmail(c.templateAdmin,{
    admin_email: c.adminEmail||'montanello11@gmail.com',
    guest_name: bk.name, guest_email: bk.email,
    guest_phone: bk.phone||'—', guests: bk.guests,
    package: bk.pkg, check_in: fmt(bk.ci),
    check_out: fmt(bk.co), nights: bk.nights,
    total: p.total ? '€'+p.total : '—',
    message: bk.note||'—',
  });
}

async function sendConfirmation(bk, payLink){
  const c=ejsCfg();
  if(!c.templateGuest) return;
  const p=calcPrice(bk.ci,bk.co)||{};
  await sendEmail(c.templateGuest,{
    guest_name: bk.name, guest_email: bk.email,
    check_in: fmt(bk.ci), check_out: fmt(bk.co),
    nights: bk.nights, total: p.total ? '€'+p.total : '—',
    deposit: p.deposit ? '€'+p.deposit : '—',
    payment_link: payLink||'—',
    package: bk.pkg,
  });
}

// ═══════════════════════════════════════════════
// CALENDAR RENDER
// ═══════════════════════════════════════════════
function navM(d){
  D.cMonth+=d;
  if(D.cMonth>11){D.cMonth=0;D.cYear++;}
  if(D.cMonth<0){D.cMonth=11;D.cYear--;}
  renderCal();
}

function renderMonth(y,m){
  const days=new Date(y,m+1,0).getDate();
  const first=(new Date(y,m,1).getDay()+6)%7;
  const nm=new Date(y,m,1).toLocaleString('en-GB',{month:'long',year:'numeric'});
  let h=`<div><div class="month-name">${nm}</div><div class="dgrid">`;
  ['Mo','Tu','We','Th','Fr','Sa','Su'].forEach(d=>{h+=`<div class="dh">${d}</div>`;});
  for(let i=0;i<first;i++) h+='<div class="d emp"></div>';
  for(let day=1;day<=days;day++){
    const ds=`${y}-${String(m+1).padStart(2,'0')}-${String(day).padStart(2,'0')}`;
    const past=ds<TODAY, bl=D.blocked.has(ds);
    const isSt=ds===D.ci, isEn=ds===D.co;
    const inR=D.ci&&D.co&&ds>D.ci&&ds<D.co;
    let cls='d';
    if(past)cls+=' past';
    else if(bl)cls+=' bl';
    else if(isSt||isEn)cls+=' s1';
    else if(inR)cls+=' rng';
    if(ds===TODAY&&!bl)cls+=' tod';
    h+=`<div class="${cls}" onclick="dayClick('${ds}')">${day}</div>`;
  }
  return h+'</div></div>';
}

function dayClick(d){
  if(d<TODAY||D.blocked.has(d))return;
  if(!D.ci||(D.ci&&D.co)){D.ci=d;D.co=null;}
  else{
    if(d<=D.ci){D.ci=d;renderCal();return;}
    let cur=new Date(D.ci);cur.setDate(cur.getDate()+1);
    while(cur.toISOString().slice(0,10)<d){
      if(D.blocked.has(cur.toISOString().slice(0,10))){D.ci=d;renderCal();return;}
      cur.setDate(cur.getDate()+1);
    }
    D.co=d;
  }
  renderCal(); renderSelBar();
}

function clearDates(){D.ci=null;D.co=null;renderCal();renderSelBar();}

function renderCal(){
  const m2=(D.cMonth+1)%12, y2=D.cMonth===11?D.cYear+1:D.cYear;
  const n1=new Date(D.cYear,D.cMonth).toLocaleString('en-GB',{month:'long'});
  const n2=new Date(y2,m2).toLocaleString('en-GB',{month:'long'});
  document.getElementById('cal-title').textContent=`${n1} – ${n2} ${D.cYear}`;
  document.getElementById('months').innerHTML=renderMonth(D.cYear,D.cMonth)+renderMonth(y2,m2);
}

// ═══════════════════════════════════════════════
// SELECTION BAR + PRICE
// ═══════════════════════════════════════════════
function renderSelBar(){
  const bar=document.getElementById('sel-bar');
  const fw=document.getElementById('form-wrap');
  const dp=document.getElementById('date-prompt');

  if(D.ci&&D.co){
    const p=calcPrice(D.ci,D.co);
    document.getElementById('sel-txt').innerHTML=
      `<strong>${fmt(D.ci)}</strong> &rarr; ${fmt(D.co)}</strong> &nbsp;&middot;&nbsp; ${p.nights} night${p.nights!==1?'s':''}${D.pkg?' &nbsp;&middot;&nbsp; '+D.pkg.name:''}`;
    document.getElementById('sel-price').textContent=`€${p.total} total`;

    // Price breakdown
    let bd=`<div class="price-breakdown">`;
    for(const [name,info] of Object.entries(p.breakdown)){
      bd+=`<div class="pb-row">${name} (${info.count} × €${info.rate})</span>€${info.count*info.rate}</span></div>`;
    }
    if(p.cleaning) bd+=`<div class="pb-row">Cleaning fee</span>€${p.cleaning}</span></div>`;
    bd+=`<div class="pb-row total">Total</span>€${p.total}</span></div>`;
    if(p.deposit) bd+=`<div class="pb-row" style="color:var(--txt3)">Security deposit (held, refundable)</span>€${p.deposit}</span></div>`;
    bd+='</div>';

    if(!checkMinNights(D.ci,D.co)){
      const {min,name}=getRate(D.ci);
      bd=`<div class="notice warn">Minimum stay for ${name} is ${min} nights. Please adjust your dates.</div>`+bd;
    }

    document.getElementById('price-bd').innerHTML=bd;
    bar.style.display='block';
    fw.style.display=checkMinNights(D.ci,D.co)?'block':'none';
    dp.style.display='none';
  } else if(D.ci){
    document.getElementById('sel-txt').innerHTML=`Check-in: ${fmt(D.ci)}</strong> &nbsp;&middot;&nbsp; Now select check-out date`;
    document.getElementById('sel-price').textContent='';
    document.getElementById('price-bd').innerHTML='';
    bar.style.display='block'; fw.style.display='none'; dp.style.display='none';
  } else {
    bar.style.display='none'; fw.style.display='none'; dp.style.display='block';
  }
}

// ═══════════════════════════════════════════════
// PACKAGES
// ═══════════════════════════════════════════════
function renderPkgs(){
  document.getElementById('pkg-grid').innerHTML=PKGS.map(p=>
    `<div class="pkg${D.pkg?.id===p.id?' on':''}" onclick="selPkg('${p.id}')">
      <div class="pkg-name">${p.name}</div>
      <div class="pkg-season">${p.season}</div>
      <div class="pkg-price">${p.price}</div>
      <div class="pkg-desc">${p.desc}</div>
    </div>`).join('');
}
function selPkg(id){D.pkg=PKGS.find(p=>p.id===id)||null;renderPkgs();}

// ═══════════════════════════════════════════════
// BOOKING SUBMIT
// ═══════════════════════════════════════════════
async function submitRequest(){
  const name=document.getElementById('fn').value.trim();
  const email=document.getElementById('fe').value.trim();
  if(!name||!email){alert('Please enter your name and email.');return;}
  if(!D.ci||!D.co){alert('Please select your dates.');return;}
  if(!checkMinNights(D.ci,D.co)){alert('Please check minimum night requirements.');return;}

  const p=calcPrice(D.ci,D.co);
  const bk={
    id:Date.now(), name, email,
    phone:document.getElementById('fp').value,
    guests:document.getElementById('fg2').value,
    pkg:D.pkg?D.pkg.name:'Custom dates',
    ci:D.ci, co:D.co, nights:p.nights,
    total:p.total, deposit:p.deposit,
    note:document.getElementById('fm').value,
    status:'pending',
    created:new Date().toISOString()
  };

  D.bookings.push(bk);
  save();

  // Send notification to admin
  await notifyAdmin(bk);

  document.getElementById('guest-email-confirm').textContent=email;
  document.getElementById('bform').style.display='none';
  document.getElementById('bsuccess').style.display='block';
}

function resetForm(){
  D.ci=null;D.co=null;D.pkg=null;
  ['fn','fe','fp','fm'].forEach(id=>document.getElementById(id).value='');
  document.getElementById('bform').style.display='block';
  document.getElementById('bsuccess').style.display='none';
  renderPkgs(); renderCal(); renderSelBar();
}

// ═══════════════════════════════════════════════
// ADMIN — LOGIN
// ═══════════════════════════════════════════════
function admLogin(){
  const pw=document.getElementById('adm-pw').value;
  if(pw===(D.cfg.pw||'montanello')){
    document.getElementById('adm-login').style.display='none';
    document.getElementById('adm-content').style.display='block';
    renderAdm();
  }else alert('Incorrect password.');
}

// ═══════════════════════════════════════════════
// ADMIN — RENDER
// ═══════════════════════════════════════════════
function renderAdm(){
  renderStats();
  renderBookings();
  renderAdmCal();
  renderRates();
  renderSync();
  renderSetup();
}

function renderStats(){
  const pending=D.bookings.filter(b=>b.status==='pending').length;
  const confirmed=D.bookings.filter(b=>b.status==='confirmed'||b.status==='paid').length;
  const rev=D.bookings.filter(b=>b.status==='paid').reduce((s,b)=>s+(b.total||0),0);
  document.getElementById('stats').innerHTML=`
    <div class="stat"><div class="stat-n">${pending}</div><div class="stat-l">Pending requests</div></div>
    <div class="stat"><div class="stat-n">${confirmed}</div><div class="stat-l">Confirmed stays</div></div>
    <div class="stat"><div class="stat-n">€${rev}</div><div class="stat-l">Revenue collected</div></div>`;
}

function setFilter(f){
  D.bkFilter=f;
  ['all','pending','confirmed','paid'].forEach(x=>{
    document.getElementById('bf-'+x)?.classList.toggle('on',x===f);
  });
  renderBookings();
}

function renderBookings(){
  const list=document.getElementById('bk-list');
  const empty=document.getElementById('bk-empty');
  let bks=D.bookings.slice().reverse();
  if(D.bkFilter!=='all') bks=bks.filter(b=>b.status===D.bkFilter);
  if(!bks.length){list.innerHTML='';empty.style.display='block';return;}
  empty.style.display='none';
  list.innerHTML=bks.map(b=>{
    const p=calcPrice(b.ci,b.co)||{};
    const actions=[];
    if(b.status==='pending'){
      actions.push(`<button class="btn sm success" onclick="confirmBk(${b.id})">✓ Confirm + send payment link</button>`);
      actions.push(`<button class="btn sm danger" onclick="rejectBk(${b.id})">✕ Reject</button>`);
    }
    if(b.status==='confirmed') actions.push(`<button class="btn sm success" onclick="markPaid(${b.id})">€ Mark as paid</button>`);
    if(b.status!=='cancelled') actions.push(`<button class="btn sm danger" onclick="cancelBk(${b.id})">Cancel</button>`);
    return `<div class="bk-card">
      <div style="display:flex;justify-content:space-between;align-items:flex-start;gap:.5rem">
        
          <div class="bk-name">${b.name}</div>
          <div class="bk-dates">📅 ${fmt(b.ci)} &rarr; ${fmt(b.co)} &nbsp;&middot;&nbsp; ${b.nights} nights</div>
          <div class="bk-meta">📦 ${b.pkg} &nbsp;&middot;&nbsp; 👥 ${b.guests} guests &nbsp;&middot;&nbsp; ✉️ ${b.email}${b.phone?' &nbsp;&middot;&nbsp; 📞 '+b.phone:''}</div>
          <div class="bk-meta">💶 €${b.total||'—'}${b.deposit?' + €'+b.deposit+' deposit':''}</div>
          ${b.note?`<div class="bk-meta" style="font-style:italic;margin-top:.15rem">"${b.note}"</div>`:''}
        </div>
        <span class="badge b-${b.status}">${b.status}</span>
      </div>
      <div class="bk-actions">${actions.join('')}</div>
    </div>`;
  }).join('');
}

async function confirmBk(id){
  const bk=D.bookings.find(b=>b.id===id);
  if(!bk)return;
  const defLink=D.cfg.stripeLink||'';
  const link=prompt(`Paste the Stripe Payment Link for this booking (€${bk.total}):\n\nGuest: ${bk.name}\nDates: ${fmt(bk.ci)} – ${fmt(bk.co)}\nTotal: €${bk.total}`,defLink);
  if(link===null)return; // cancelled
  bk.status='confirmed';
  bk.payLink=link;
  // Block dates
  const d=new Date(bk.ci);
  while(d.toISOString().slice(0,10)<bk.co){D.blocked.add(d.toISOString().slice(0,10));d.setDate(d.getDate()+1);}
  save();
  await sendConfirmation(bk,link);
  alert(`Booking confirmed. Confirmation email sent to ${bk.email}${link?' with payment link':''}. ${ejsCfg().templateGuest?'':'(EmailJS not configured — email not sent)'}`);
  renderAdm(); renderCal();
}

async function rejectBk(id){
  const bk=D.bookings.find(b=>b.id===id);
  if(!bk)return;
  if(!confirm(`Reject booking from ${bk.name}?`))return;
  bk.status='cancelled';
  save();
  alert('Booking rejected. Consider sending a manual email to the guest.');
  renderAdm();
}

function markPaid(id){
  const bk=D.bookings.find(b=>b.id===id);
  if(!bk)return;
  bk.status='paid'; save(); renderAdm(); renderStats();
}

function cancelBk(id){
  const bk=D.bookings.find(b=>b.id===id);
  if(!bk||!confirm(`Cancel ${bk.name}'s booking? This will unblock their dates.`))return;
  bk.status='cancelled';
  const d=new Date(bk.ci);
  while(d.toISOString().slice(0,10)<bk.co){D.blocked.delete(d.toISOString().slice(0,10));d.setDate(d.getDate()+1);}
  save(); renderAdm(); renderCal(); renderAdmCal();
}

// ═══════════════════════════════════════════════
// ADMIN CALENDAR
// ═══════════════════════════════════════════════
function admNavM(d){
  D.admMonth+=d;
  if(D.admMonth>11){D.admMonth=0;D.admYear++;}
  if(D.admMonth<0){D.admMonth=11;D.admYear--;}
  renderAdmCal();
}
function admJump(){
  const v=document.getElementById('adm-jump').value;
  if(!v)return;
  D.admYear=+v.slice(0,4); D.admMonth=+v.slice(5,7)-1;
  renderAdmCal();
}

function renderAdmCal(){
  const y=D.admYear,m=D.admMonth;
  const title=new Date(y,m,1).toLocaleString('en-GB',{month:'long',year:'numeric'});
  document.getElementById('adm-cal-title').textContent=title;
  const days=new Date(y,m+1,0).getDate();
  const first=(new Date(y,m,1).getDay()+6)%7;

  // Days that have bookings
  const bkDays=new Set();
  D.bookings.filter(b=>b.status!=='cancelled').forEach(b=>{
    const d=new Date(b.ci);
    while(d.toISOString().slice(0,10)<b.co){bkDays.add(d.toISOString().slice(0,10));d.setDate(d.getDate()+1);}
  });

  let h='';
  ['Mo','Tu','We','Th','Fr','Sa','Su'].forEach(d=>{h+=`<div class="ac-head">${d}</div>`;});
  for(let i=0;i<first;i++) h+='<div class="ac-day ac-emp"></div>';
  for(let day=1;day<=days;day++){
    const ds=`${y}-${String(m+1).padStart(2,'0')}-${String(day).padStart(2,'0')}`;
    const past=ds<TODAY, bl=D.blocked.has(ds), bk=bkDays.has(ds);
    let cls='ac-day';
    if(past)cls+=' ac-past';
    else if(bl)cls+=' ac-bl';
    if(bk&&!past)cls+=' ac-bk';
    h+=`<div class="${cls}" onclick="admDayClick('${ds}')" title="${bl?'Blocked':'Available'}">${day}</div>`;
  }
  document.getElementById('adm-cal').innerHTML=h;
  document.getElementById('bl-count').textContent=D.blocked.size;
  document.getElementById('bk-count').textContent=D.bookings.filter(b=>b.status!=='cancelled').length;
}

function admDayClick(d){
  if(d<TODAY)return;
  if(D.blocked.has(d)) D.blocked.delete(d);
  else D.blocked.add(d);
  save(); renderAdmCal();
}

function clearAllBlocked(){
  if(!confirm('Clear all manual date blocks? Booking-blocked dates remain.'))return;
  D.blocked=new Set();
  D.bookings.filter(b=>b.status!=='cancelled').forEach(b=>{
    const d=new Date(b.ci);
    while(d.toISOString().slice(0,10)<b.co){D.blocked.add(d.toISOString().slice(0,10));d.setDate(d.getDate()+1);}
  });
  save(); renderAdmCal(); renderCal();
}

// ═══════════════════════════════════════════════
// RATES
// ═══════════════════════════════════════════════
function renderRates(){
  const r=D.cfg.rates;
  document.getElementById('r-default').value=r.default||150;
  document.getElementById('r-minnights').value=r.minNights||2;
  document.getElementById('r-cleaning').value=r.cleaning||0;
  document.getElementById('r-deposit').value=r.deposit||0;
  renderSeasons();
}

function saveBaseRates(){
  D.cfg.rates.default=+document.getElementById('r-default').value||150;
  D.cfg.rates.minNights=+document.getElementById('r-minnights').value||2;
  D.cfg.rates.cleaning=+document.getElementById('r-cleaning').value||0;
  D.cfg.rates.deposit=+document.getElementById('r-deposit').value||0;
  save(); alert('Base rates saved.');
}

function renderSeasons(){
  const ss=D.cfg.rates.seasons||[];
  document.getElementById('seasons-list').innerHTML=ss.length===0?'<p style="color:var(--txt3);font-size:.8rem">No seasons defined.</p>':
    ss.map((s,i)=>`
    <div class="season-row" id="sr-${i}">
      <input value="${s.name}" oninput="updSeason(${i},'name',this.value)" placeholder="Season name" style="font-size:.8rem">
      <div style="display:flex;gap:.3rem">
        <input value="${s.from}" oninput="updSeason(${i},'from',this.value)" placeholder="07-01" style="width:70px;font-size:.8rem">
        <span style="align-self:center;color:var(--txt3)">–</span>
        <input value="${s.to}" oninput="updSeason(${i},'to',this.value)" placeholder="08-31" style="width:70px;font-size:.8rem">
      </div>
      <input type="number" value="${s.rate}" oninput="updSeason(${i},'rate',+this.value)" placeholder="Rate €" style="font-size:.8rem">
      <input type="number" value="${s.min||1}" oninput="updSeason(${i},'min',+this.value)" placeholder="Min" style="font-size:.8rem">
      <button class="btn danger sm" onclick="delSeason(${i})" style="padding:4px 7px">✕</button>
    </div>`).join('');
}

function updSeason(i,k,v){if(D.cfg.rates.seasons[i])D.cfg.rates.seasons[i][k]=v;}
function addSeason(){D.cfg.rates.seasons.push({name:'New Season',from:'01-01',to:'01-31',rate:150,min:2});renderSeasons();}
function delSeason(i){D.cfg.rates.seasons.splice(i,1);renderSeasons();}
function saveSeasons(){save();alert('Seasons saved.');}

// ═══════════════════════════════════════════════
// SYNC
// ═══════════════════════════════════════════════
function renderSync(){
  const srcs=document.getElementById('ical-srcs');
  srcs.innerHTML=D.icalSrcs.length
    ?'<div style="font-size:.72rem;color:var(--txt3);margin-bottom:.3rem">Imported:</div>'+
      D.icalSrcs.map(s=>`<span class="chip">📅 ${s.name} · ${s.count} dates · ${s.date}</span>`).join('')
    :'';
}

// ═══════════════════════════════════════════════
// SETUP
// ═══════════════════════════════════════════════
function renderSetup(){
  const c=D.cfg.emailjs||{};
  document.getElementById('ej-sid').value=c.serviceId||'';
  document.getElementById('ej-pub').value=c.publicKey||'';
  document.getElementById('ej-tadm').value=c.templateAdmin||'';
  document.getElementById('ej-tguest').value=c.templateGuest||'';
  document.getElementById('ej-email').value=c.adminEmail||'';
  document.getElementById('stripe-link').value=D.cfg.stripeLink||'';
}

function saveEmailJS(){
  D.cfg.emailjs={
    serviceId:document.getElementById('ej-sid').value.trim(),
    publicKey:document.getElementById('ej-pub').value.trim(),
    templateAdmin:document.getElementById('ej-tadm').value.trim(),
    templateGuest:document.getElementById('ej-tguest').value.trim(),
    adminEmail:document.getElementById('ej-email').value.trim(),
  };
  save(); alert('Email settings saved.');
}

function saveStripe(){
  D.cfg.stripeLink=document.getElementById('stripe-link').value.trim();
  save(); alert('Stripe link saved.');
}

function changePw(){
  const p1=document.getElementById('new-pw').value;
  const p2=document.getElementById('new-pw2').value;
  if(!p1){alert('Enter a password.');return;}
  if(p1!==p2){alert('Passwords do not match.');return;}
  D.cfg.pw=p1; save(); alert('Password changed.');
}

// ═══════════════════════════════════════════════
// TABS
// ═══════════════════════════════════════════════
function setTab(t){
  document.getElementById('pane-book').style.display=t==='book'?'block':'none';
  document.getElementById('pane-admin').style.display=t==='admin'?'block':'none';
  document.getElementById('tb-book').classList.toggle('on',t==='book');
  document.getElementById('tb-admin').classList.toggle('on',t==='admin');
}

function setATab(t){
  D.aTab=t;
  ['bookings','calendar','rates','sync','setup'].forEach(x=>{
    document.getElementById('at-'+x)?.classList.toggle('on',x===t);
    document.getElementById('ap-'+x).style.display=x===t?'block':'none';
  });
}

// ═══════════════════════════════════════════════
// HELPERS
// ═══════════════════════════════════════════════
function fmt(d){
  if(!d)return'';
  return new Date(d+'T12:00').toLocaleDateString('en-GB',{day:'numeric',month:'short',year:'numeric'});
}

// ═══════════════════════════════════════════════
// INIT
// ═══════════════════════════════════════════════
loadAll();
renderPkgs();
renderCal();
renderSelBar();