/* ============================================================
   CALENDARIO — visite commerciali, stile Teams/Outlook.
   Desktop: vista Mese e Settimana con drag&drop.
   Mobile: vista Mese (compatta) e Giorno.
   Commerciale vede le sue; admin/backoffice tutte + filtro.
   Ogni visita collegata a un'opportunità. Promemoria configurabile.
   ============================================================ */

const GIORNI = ['Lun','Mar','Mer','Gio','Ven','Sab','Dom'];
const MESI = ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno','Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'];

// helper date
const startOfDay = (d) => { const x=new Date(d); x.setHours(0,0,0,0); return x; };
const sameDay = (a,b) => startOfDay(a).getTime()===startOfDay(b).getTime();
const addDays = (d,n) => { const x=new Date(d); x.setDate(x.getDate()+n); return x; };
const startOfWeek = (d) => { const x=startOfDay(d); const g=(x.getDay()+6)%7; return addDays(x,-g); }; // lunedì
const startOfMonth = (d) => { const x=startOfDay(d); x.setDate(1); return x; };
const ymd = (d) => { const x=new Date(d); return x.getFullYear()+'-'+String(x.getMonth()+1).padStart(2,'0')+'-'+String(x.getDate()).padStart(2,'0'); };
// ora attuale nel fuso italiano (Europe/Rome)
const nowItaly = () => {
  const s = new Date().toLocaleString('en-US', { timeZone:'Europe/Rome' });
  return new Date(s);
};
// colore stabile per commerciale (per distinguerli nel calendario manager)
const COMM_COLORS = ['#c0392b','#2980b9','#27ae60','#8e44ad','#d68910','#16a085','#c2185b','#5d6d7e'];
const commColor = (id) => { if(!id) return '#7f8c8d'; let h=0; const s=String(id); for(let i=0;i<s.length;i++) h=(h*31+s.charCodeAt(i))>>>0; return COMM_COLORS[h%COMM_COLORS.length]; };
// solo il primo nome (per risparmiare spazio nelle celle strette)
const firstName = (full) => { if(!full||full==='—') return full; return String(full).trim().split(/\s+/)[0]; };

function Calendario({ role, currentUser, users, clienti, opportunities, stages, bookings, onOpenOpportunity, toast }) {
  const vp = useViewport();
  const isManager = role==='admin' || role==='backoffice';
  const [visits, setVisits] = useState([]);
  const [loading, setLoading] = useState(true);
  const [editing, setEditing] = useState(undefined);
  const [commFilter, setCommFilter] = useState('all');
  const [showReminderPref, setShowReminderPref] = useState(false);
  const [cursor, setCursor] = useState(startOfDay(new Date())); // data di riferimento
  const [mode, setMode] = useState(vp.isMobile ? 'month' : 'month'); // month | week | day
  const [selectedDay, setSelectedDay] = useState(startOfDay(new Date()));
  const [dragVisit, setDragVisit] = useState(null);

  const load = async () => {
    setLoading(true);
    try { setVisits(await window.DataAPI.listVisits() || []); }
    catch(e){ console.error(e); }
    finally { setLoading(false); }
  };
  useEffect(()=>{ load(); }, []);
  useEffect(()=>{ window.__calToast = toast; return ()=>{ delete window.__calToast; }; }, [toast]);

  const commName = (id) => (users||[]).find(u=>u.id===id)?.nome || '—';

  let shown = visits.slice();
  if (isManager && commFilter!=='all') shown = shown.filter(v=>v.commerciale_id===commFilter);

  const visitsOn = (day) => shown.filter(v => sameDay(new Date(v.data_visita), day))
    .sort((a,b)=> new Date(a.data_visita)-new Date(b.data_visita));

  // salvataggio (create/update)
  const saveVisit = async (v) => {
    // controllo conflitto: stesso commerciale, orari sovrapposti
    const s = new Date(v.data_visita).getTime();
    const e = s + (v.durata_min||30)*60000;
    const conflict = visits.some(x => {
      if (x.id===v.id) return false;
      if (x.commerciale_id !== v.commerciale_id) return false;
      if (x.stato==='annullata') return false;
      const xs = new Date(x.data_visita).getTime(); const xe = xs + (x.durata_min||30)*60000;
      return s < xe && e > xs;
    });
    if (conflict) { toast('Conflitto: questo commerciale ha già una visita in quell\'orario'); return; }
    try {
      const saved = await window.DataAPI.saveVisit(v);
      if (!v.id && saved) {
        window.LogAPI?.logEvent('visit.scheduled', {
          entity_type:'visit', entity_id: saved.id, title:'Visita programmata',
          description:`${saved.cliente} · ${new Date(saved.data_visita).toLocaleDateString('it-IT')}`,
          metadata:{ cliente: saved.cliente, commerciale_id: saved.commerciale_id, data_visita: saved.data_visita },
        });
      }
      toast(v.id?'Visita aggiornata':'Visita programmata');
      setEditing(undefined); load();
    } catch(e){ console.error('saveVisit', e); toast('Errore: '+(e?.message||'')); }
  };
  const removeVisit = async (v) => {
    try { await window.DataAPI.deleteVisit(v.id); toast('Visita eliminata'); setEditing(undefined); load(); }
    catch(e){ console.error(e); toast('Errore'); }
  };

  // sposta visita a nuovo giorno (drag&drop) mantenendo l'ora
  const moveVisitToDay = async (visit, day) => {
    const old = new Date(visit.data_visita);
    const nd = new Date(day); nd.setHours(old.getHours(), old.getMinutes(), 0, 0);
    if (sameDay(old, nd)) return;
    setVisits(prev => prev.map(v => v.id===visit.id ? { ...v, data_visita: nd.toISOString() } : v));
    try { await window.DataAPI.saveVisit({ ...visit, data_visita: nd.toISOString() }); toast('Visita spostata'); }
    catch(e){ console.error(e); toast('Errore spostamento'); load(); }
  };
  // sposta visita a giorno+ora+minuti (week view, granularità 15min)
  const moveVisitToSlot = async (visit, day, hour, minute=0) => {
    const nd = new Date(day); nd.setHours(hour, minute, 0, 0);
    setVisits(prev => prev.map(v => v.id===visit.id ? { ...v, data_visita: nd.toISOString() } : v));
    try { await window.DataAPI.saveVisit({ ...visit, data_visita: nd.toISOString() }); toast('Visita spostata'); }
    catch(e){ console.error(e); toast('Errore spostamento'); load(); }
  };

  // navigazione
  const prev = () => setCursor(c => mode==='month' ? startOfMonth(addDays(startOfMonth(c),-1)) : mode==='week' ? addDays(c,-7) : addDays(c,-1));
  const next = () => setCursor(c => mode==='month' ? startOfMonth(addDays(startOfMonth(c),32)) : mode==='week' ? addDays(c,7) : addDays(c,1));
  const goToday = () => { const t=startOfDay(new Date()); setCursor(t); setSelectedDay(t); };

  const title = () => {
    if (mode==='month') return `${MESI[cursor.getMonth()]} ${cursor.getFullYear()}`;
    if (mode==='week') { const s=startOfWeek(cursor), e=addDays(s,6); return `${s.getDate()} ${MESI[s.getMonth()].slice(0,3)} – ${e.getDate()} ${MESI[e.getMonth()].slice(0,3)} ${e.getFullYear()}`; }
    return cursor.toLocaleDateString('it-IT',{weekday:'long',day:'numeric',month:'long'});
  };

  const openNewAt = (day, hour, minute=0) => {
    const d = new Date(day); if (hour!=null) d.setHours(hour,minute,0,0); else d.setHours(9,0,0,0);
    setEditing({ _prefillDate: d });
  };

  const modes = vp.isMobile ? [['month','Mese'],['day','Giorno']] : [['month','Mese'],['week','Settimana']];

  return (
    <div className="scroll" style={{ flex:1, minWidth:0, overflowY:'auto', overflowX:'hidden', display:'flex', flexDirection:'column' }}>
      {/* header */}
      <div style={{ padding: vp.isMobile?'12px 12px 10px':'16px 30px 12px', borderBottom:'1px solid var(--line)', background:'var(--surface)', position:'sticky', top:0, zIndex:15 }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap:10, flexWrap:'wrap', marginBottom:10 }}>
          <h1 style={{ margin:0, fontFamily:'var(--font-display)', fontSize: vp.isMobile?18:22, fontWeight:800, letterSpacing:'-.01em' }}>Calendario</h1>
          <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
            <Btn variant="ghost" size={vp.isMobile?'sm':'md'} icon="bell" onClick={()=>setShowReminderPref(true)}>{vp.isMobile?'':'Promemoria'}</Btn>
            <Btn icon="plus" size={vp.isMobile?'sm':'md'} onClick={()=>openNewAt(selectedDay)}>{vp.isMobile?'':'Nuova visita'}</Btn>
          </div>
        </div>
        <div style={{ display:'flex', alignItems:'center', gap:10, flexWrap:'wrap' }}>
          {/* nav */}
          <div style={{ display:'flex', alignItems:'center', gap:4 }}>
            <button onClick={prev} style={navBtn}><Icon name="chevLeft" size={18} /></button>
            <button onClick={goToday} style={{ ...navBtn, width:'auto', padding:'0 12px', fontSize:12.5, fontWeight:700 }}>Oggi</button>
            <button onClick={next} style={navBtn}><Icon name="chevRight" size={18} /></button>
          </div>
          <div style={{ fontSize: vp.isMobile?14:16, fontWeight:800, fontFamily:'var(--font-display)', textTransform:'capitalize', minWidth:0, flex:'1 1 auto' }}>{title()}</div>
          {/* mode toggle */}
          <div style={{ display:'flex', background:'var(--surface-2)', borderRadius:'var(--r-md)', padding:3, gap:2 }}>
            {modes.map(([m,label]) => (
              <button key={m} onClick={()=>setMode(m)}
                style={{ padding:'6px 12px', borderRadius:'calc(var(--r-md) - 2px)', fontSize:12.5, fontWeight:700,
                  background: mode===m?'var(--surface)':'transparent', color: mode===m?'var(--ink)':'var(--ink-3)',
                  boxShadow: mode===m?'var(--sh-1)':'none' }}>{label}</button>
            ))}
          </div>
          {isManager && (
            <div style={{ position:'relative' }}>
              <select value={commFilter} onChange={e=>setCommFilter(e.target.value)}
                style={{ appearance:'none', padding:'8px 30px 8px 12px', fontSize:12.5, fontWeight:600, borderRadius:'var(--r-md)', border:'1.5px solid var(--line)', background:'var(--surface)', color:'var(--ink-2)', cursor:'pointer' }}>
                <option value="all">Tutti</option>
                {(users||[]).map(u=><option key={u.id} value={u.id}>{u.nome}</option>)}
              </select>
              <Icon name="chevDown" size={14} style={{ position:'absolute', right:9, top:'50%', transform:'translateY(-50%)', color:'var(--ink-3)', pointerEvents:'none' }} />
            </div>
          )}
        </div>
      </div>

      {/* body */}
      <div style={{ flex:1, padding: vp.isMobile?'10px':'16px 30px 30px', minHeight:0 }}>
        {loading ? <div style={{ padding:'50px', textAlign:'center', color:'var(--ink-3)' }}>Caricamento…</div>
          : mode==='month' ? <MonthView cursor={cursor} vp={vp} visitsOn={visitsOn} commName={commName} isManager={isManager}
              selectedDay={selectedDay} setSelectedDay={setSelectedDay} onEditVisit={setEditing} onNewAt={openNewAt}
              dragVisit={dragVisit} setDragVisit={setDragVisit} moveVisitToDay={moveVisitToDay} onOpenOpportunity={onOpenOpportunity} opportunities={opportunities} />
          : mode==='week' ? <WeekView cursor={cursor} visitsOn={visitsOn} commName={commName} isManager={isManager}
              onEditVisit={setEditing} onNewAt={openNewAt} dragVisit={dragVisit} setDragVisit={setDragVisit} moveVisitToSlot={moveVisitToSlot} allVisits={shown} />
          : <DayView day={cursor} visitsOn={visitsOn} commName={commName} isManager={isManager} onEditVisit={setEditing} onNewAt={openNewAt} />}
      </div>

      {editing !== undefined && (
        <VisitModal visit={editing && editing._prefillDate ? null : editing}
          prefillDate={editing && editing._prefillDate ? editing._prefillDate : null}
          role={role} currentUser={currentUser} users={users} clienti={clienti}
          opportunities={opportunities} stages={stages} bookings={bookings}
          onClose={()=>setEditing(undefined)} onSave={saveVisit} onDelete={removeVisit} />
      )}
      {showReminderPref && <ReminderPrefModal currentUser={currentUser} onClose={()=>setShowReminderPref(false)} toast={toast} />}
    </div>
  );
}

const navBtn = { width:34, height:34, borderRadius:'var(--r-md)', border:'1.5px solid var(--line)', display:'flex', alignItems:'center', justifyContent:'center', color:'var(--ink-2)', background:'var(--surface)' };

/* ---------- VISTA MESE ---------- */
function MonthView({ cursor, vp, visitsOn, commName, isManager, selectedDay, setSelectedDay, onEditVisit, onNewAt, dragVisit, setDragVisit, moveVisitToDay, onOpenOpportunity, opportunities }) {
  const first = startOfWeek(startOfMonth(cursor));
  const weeks = [];
  let d = first;
  for (let w=0; w<6; w++) { const row=[]; for(let i=0;i<7;i++){ row.push(d); d=addDays(d,1); } weeks.push(row); }
  const inMonth = (day) => day.getMonth()===cursor.getMonth();
  const today = startOfDay(new Date());
  const [overDay, setOverDay] = useState(null);

  if (vp.isMobile) {
    // mobile: griglia compatta con puntini, tap giorno → lista sotto
    const dayVisits = visitsOn(selectedDay);
    return (
      <div>
        <div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', gap:2, marginBottom:4 }}>
          {GIORNI.map(g=><div key={g} style={{ textAlign:'center', fontSize:10.5, fontWeight:800, color:'var(--ink-4)', padding:'4px 0' }}>{g}</div>)}
        </div>
        <div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', gap:2 }}>
          {weeks.flat().map((day,i)=>{
            const vs = visitsOn(day); const sel = sameDay(day,selectedDay); const isToday = sameDay(day,today);
            const isPast = startOfDay(day) < today;
            return (
              <button key={i} onClick={()=>setSelectedDay(startOfDay(day))}
                style={{ aspectRatio:'1', display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:3,
                  borderRadius:'var(--r-md)', border: sel?'1.5px solid var(--red)':'1.5px solid transparent',
                  background: sel?'var(--red-tint)':isToday?'rgba(192,57,43,0.06)':'transparent', opacity: inMonth(day)?(isPast&&!isToday?0.6:1):0.35 }}>
                <span style={{ fontSize:13, fontWeight: isToday?800:600, color: isToday?'#fff':'var(--ink)',
                  background: isToday?'var(--red)':'transparent', width:22, height:22, borderRadius:99, display:'flex', alignItems:'center', justifyContent:'center' }}>{day.getDate()}</span>
                {vs.length>0 && <span style={{ display:'flex', gap:2 }}>{vs.slice(0,3).map((v,j)=><span key={j} style={{ width:4, height:4, borderRadius:99, background: isManager?commColor(v.commerciale_id):'var(--red)' }} />)}</span>}
              </button>
            );
          })}
        </div>
        {/* lista giorno selezionato */}
        <div style={{ marginTop:16 }}>
          <div style={{ fontSize:13, fontWeight:800, marginBottom:10, textTransform:'capitalize' }}>{selectedDay.toLocaleDateString('it-IT',{weekday:'long',day:'numeric',month:'long'})}</div>
          {dayVisits.length===0 ? (
            <button onClick={()=>onNewAt(selectedDay)} style={{ width:'100%', padding:'16px', borderRadius:'var(--r-md)', border:'1.5px dashed var(--line)', color:'var(--ink-4)', fontSize:13, fontWeight:600 }}>+ Aggiungi visita</button>
          ) : (
            <div style={{ display:'flex', flexDirection:'column', gap:8 }}>
              {dayVisits.map(v=><VisitPill key={v.id} v={v} commName={commName} isManager={isManager} onClick={()=>onEditVisit(v)} full />)}
            </div>
          )}
        </div>
      </div>
    );
  }

  // desktop: griglia mese con drag&drop
  const todayMonth = startOfDay(new Date());
  return (
    <div style={{ display:'flex', flexDirection:'column', height:'100%', border:'1px solid var(--line)', borderRadius:'var(--r-lg)', overflow:'hidden', background:'var(--surface)' }}>
      <div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', borderBottom:'1px solid var(--line)' }}>
        {GIORNI.map(g=><div key={g} style={{ textAlign:'center', fontSize:11.5, fontWeight:800, color:'var(--ink-3)', padding:'8px 0', textTransform:'uppercase', letterSpacing:'.03em' }}>{g}</div>)}
      </div>
      <div style={{ display:'grid', gridTemplateRows:`repeat(${weeks.length},1fr)`, flex:1 }}>
        {weeks.map((week,wi)=>(
          <div key={wi} style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', borderBottom: wi<weeks.length-1?'1px solid var(--line-2)':'none' }}>
            {week.map((day,di)=>{
              const vs = visitsOn(day); const isToday = sameDay(day,todayMonth); const isOver = overDay && sameDay(overDay,day);
              const isPast = startOfDay(day) < todayMonth; const outMonth = !inMonth(day);
              return (
                <div key={di}
                  onDragOver={(e)=>{ e.preventDefault(); if(!overDay||!sameDay(overDay,day)) setOverDay(startOfDay(day)); }}
                  onDrop={(e)=>{ e.preventDefault(); if(dragVisit) moveVisitToDay(dragVisit, day); setDragVisit(null); setOverDay(null); }}
                  onDoubleClick={()=>onNewAt(day)}
                  style={{ borderRight: di<6?'1px solid var(--line-2)':'none', padding:'5px 5px 3px', minHeight:0, display:'flex', flexDirection:'column', gap:3,
                    background: isOver?'var(--red-tint)':isToday?'rgba(192,57,43,0.04)':outMonth?'var(--surface-2)':'transparent',
                    opacity: outMonth?0.5:isPast?0.72:1, cursor:'default', overflow:'hidden' }}>
                  <div style={{ display:'flex', justifyContent: isToday?'flex-start':'flex-end', alignItems:'center' }}>
                    {isToday && <span style={{ fontSize:9.5, fontWeight:800, color:'var(--red)', textTransform:'uppercase', letterSpacing:'.04em', marginRight:'auto' }}>Oggi</span>}
                    <span style={{ fontSize:12, fontWeight: isToday?800:600, color: isToday?'#fff':'var(--ink-2)',
                      background: isToday?'var(--red)':'transparent', width:20, height:20, borderRadius:99, display:'flex', alignItems:'center', justifyContent:'center' }}>{day.getDate()}</span>
                  </div>
                  <div style={{ display:'flex', flexDirection:'column', gap:2, overflow:'hidden' }}>
                    {vs.slice(0,3).map(v=>{
                      const done = v.stato==='completata'; const annull = v.stato==='annullata';
                      const col = isManager ? commColor(v.commerciale_id) : 'var(--red)';
                      return (
                        <div key={v.id} draggable onDragStart={()=>setDragVisit(v)} onDragEnd={()=>{setDragVisit(null);setOverDay(null);}}
                          onClick={(e)=>{ e.stopPropagation(); onEditVisit(v); }}
                          title={isManager && v.commerciale_id ? `${v.cliente} · ${commName(v.commerciale_id)}` : v.cliente}
                          style={{ display:'flex', alignItems:'center', gap:5, fontSize:11, fontWeight:700, padding:'2px 6px 2px 5px', borderRadius:5, cursor:'grab',
                            background: done?'var(--line-2)':'var(--surface)', border:'1px solid var(--line)', borderLeft:'3px solid '+(done?'var(--ink-4)':col),
                            whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis', opacity: (dragVisit&&dragVisit.id===v.id)?0.4:(annull?0.6:1),
                            textDecoration: annull?'line-through':'none' }}>
                          <span style={{ fontSize:9.5, fontWeight:800, color:'var(--ink-4)', flexShrink:0 }}>{new Date(v.data_visita).toLocaleTimeString('it-IT',{hour:'2-digit',minute:'2-digit'})}</span>
                          <span style={{ overflow:'hidden', textOverflow:'ellipsis', color: done?'var(--ink-3)':'var(--ink)', flexShrink:1 }}>{v.cliente}</span>
                          {isManager && v.commerciale_id && (
                            <span style={{ display:'flex', alignItems:'center', gap:3, marginLeft:'auto', flexShrink:0, maxWidth:'45%' }}>
                              <span style={{ fontSize:9.5, fontWeight:700, color:col, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{firstName(commName(v.commerciale_id))}</span>
                              <span style={{ width:7, height:7, borderRadius:99, background:col, flexShrink:0 }} />
                            </span>
                          )}
                        </div>
                      );
                    })}
                    {vs.length>3 && <div style={{ fontSize:10.5, color:'var(--ink-4)', fontWeight:700, paddingLeft:6 }}>+{vs.length-3} altre</div>}
                  </div>
                </div>
              );
            })}
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---------- VISTA SETTIMANA ---------- */
function WeekView({ cursor, visitsOn, commName, isManager, onEditVisit, onNewAt, dragVisit, setDragVisit, moveVisitToSlot, allVisits }) {
  const start = startOfWeek(cursor);
  const days = Array.from({length:7},(_,i)=>addDays(start,i));
  const HOUR_H = 72; // più alta: 18px per quarto d'ora
  const QUARTER_H = HOUR_H/4;
  const H_START = 7, H_END = 20;
  const hours = Array.from({length:H_END-H_START},(_,i)=>i+H_START);
  const today = startOfDay(new Date());
  const [now, setNow] = useState(nowItaly());
  const [dropHint, setDropHint] = useState(null); // { day, minutes } posizione durante il drag
  useEffect(()=>{ const t=setInterval(()=>setNow(nowItaly()), 60000); return ()=>clearInterval(t); }, []);

  const yOf = (date) => { const d=new Date(date); return (d.getHours()-H_START)*HOUR_H + (d.getMinutes()/60)*HOUR_H; };
  const nowInRange = now.getHours()>=H_START && now.getHours()<H_END;

  // calcola i minuti (arrotondati a 15) dalla posizione Y del mouse dentro una colonna
  const minutesFromY = (e, colEl) => {
    const rect = colEl.getBoundingClientRect();
    const y = e.clientY - rect.top;
    const totalMin = Math.max(0, Math.min((H_END-H_START)*60 - 15, (y/HOUR_H)*60));
    const snapped = Math.round(totalMin/15)*15;
    return snapped; // minuti dall'inizio (H_START)
  };
  const minToTime = (min) => { const h=H_START+Math.floor(min/60); const m=min%60; return { h, m }; };

  // verifica conflitto: stesso commerciale, stesso giorno, orari sovrapposti
  const hasConflict = (visit, day, startMin, durMin=60) => {
    const s = new Date(day); s.setHours(H_START,0,0,0); s.setMinutes(s.getMinutes()+startMin);
    const e = new Date(s.getTime()+durMin*60000);
    return (allVisits||[]).some(v => {
      if (v.id===visit.id) return false;
      if (v.commerciale_id !== visit.commerciale_id) return false;
      if (v.stato==='annullata') return false;
      const vs = new Date(v.data_visita); const ve = new Date(vs.getTime()+(v.durata_min||30)*60000);
      return s < ve && e > vs; // sovrapposizione
    });
  };

  const handleDrop = (e, day, colEl) => {
    e.preventDefault();
    if (!dragVisit) { setDropHint(null); return; }
    const min = minutesFromY(e, colEl);
    const dur = dragVisit.durata_min || 30;
    if (hasConflict(dragVisit, day, min, dur)) {
      setDropHint(null); setDragVisit(null);
      window.__calToast && window.__calToast('Conflitto: il commerciale ha già una visita in quell\'orario');
      return;
    }
    const { h, m } = minToTime(min);
    moveVisitToSlot(dragVisit, day, h, m);
    setDropHint(null); setDragVisit(null);
  };

  return (
    <div style={{ border:'1px solid var(--line)', borderRadius:'var(--r-lg)', overflow:'hidden', background:'var(--surface)', height:'100%', display:'flex', flexDirection:'column' }}>
      {/* header giorni */}
      <div style={{ display:'grid', gridTemplateColumns:'56px repeat(7,1fr)', borderBottom:'1px solid var(--line)', flexShrink:0 }}>
        <div />
        {days.map((d,i)=>{
          const isToday=sameDay(d,today); const isPast=startOfDay(d)<today;
          return (
            <div key={i} style={{ textAlign:'center', padding:'8px 0 7px', borderLeft:'1px solid var(--line-2)',
              background: isToday?'var(--red-tint)':'transparent', opacity: isPast?0.6:1 }}>
              <div style={{ fontSize:10.5, fontWeight:700, color: isToday?'var(--red)':'var(--ink-4)', textTransform:'uppercase' }}>{GIORNI[i]}</div>
              <div style={{ fontSize:16, fontWeight: isToday?800:600, color: isToday?'#fff':'var(--ink)', background: isToday?'var(--red)':'transparent',
                width:28, height:28, borderRadius:99, display:'flex', alignItems:'center', justifyContent:'center', margin:'3px auto 0' }}>{d.getDate()}</div>
            </div>
          );
        })}
      </div>
      {/* griglia orari */}
      <div className="scroll" style={{ flex:1, overflowY:'auto' }}>
        <div style={{ display:'grid', gridTemplateColumns:'56px repeat(7,1fr)', position:'relative' }}>
          {/* colonna orari */}
          <div>
            {hours.map(h=>(
              <div key={h} style={{ height:HOUR_H, fontSize:10.5, color:'var(--ink-4)', fontWeight:600, textAlign:'right', padding:'0 8px 0 0', position:'relative', top:-6 }}>{String(h).padStart(2,'0')}:00</div>
            ))}
          </div>
          {/* colonne giorni */}
          {days.map((d,di)=>{
            const isToday=sameDay(d,today); const isPast=startOfDay(d)<today;
            const dayVisits = visitsOn(d);
            // raggruppa gli eventi che si sovrappongono per affiancarli in colonne
            const positioned = layoutVisits(dayVisits);
            const showHint = dropHint && sameDay(dropHint.day, d);
            return (
              <div key={di} ref={el=>{ if(el) el.__isCol=true; }}
                onDragOver={(e)=>{ e.preventDefault(); const min=minutesFromY(e, e.currentTarget); setDropHint({ day:d, minutes:min }); }}
                onDragLeave={(e)=>{ if(e.currentTarget===e.target) setDropHint(null); }}
                onDrop={(e)=>handleDrop(e, d, e.currentTarget)}
                onDoubleClick={(e)=>{ const min=minutesFromY(e, e.currentTarget); const {h,m}=minToTime(min); onNewAt(d,h,m); }}
                style={{ position:'relative', borderLeft:'1px solid var(--line-2)', background: isToday?'rgba(192,57,43,0.03)':'transparent', height:hours.length*HOUR_H }}>
                {/* righe ore + quarti */}
                {hours.map((h,hi)=>(
                  <div key={h} style={{ position:'absolute', top:hi*HOUR_H, left:0, right:0, height:HOUR_H, borderTop:'1px solid var(--line-2)', opacity: isPast?0.55:1 }}>
                    {/* linee quarti (sottili) */}
                    <div style={{ position:'absolute', top:QUARTER_H, left:0, right:0, borderTop:'1px dotted var(--line-2)', opacity:0.5 }} />
                    <div style={{ position:'absolute', top:QUARTER_H*2, left:0, right:0, borderTop:'1px dotted var(--line-2)', opacity:0.7 }} />
                    <div style={{ position:'absolute', top:QUARTER_H*3, left:0, right:0, borderTop:'1px dotted var(--line-2)', opacity:0.5 }} />
                  </div>
                ))}
                {/* guida tratteggiata dove cadrà l'evento (snap 15min) */}
                {showHint && (
                  <div style={{ position:'absolute', left:2, right:2, top:(dropHint.minutes/60)*HOUR_H, height:(( dragVisit?.durata_min||30)/60)*HOUR_H, zIndex:6, pointerEvents:'none',
                    border:'2px dashed var(--red)', borderRadius:6, background:'rgba(192,57,43,0.08)' }}>
                    <div style={{ position:'absolute', top:-9, left:4, fontSize:9.5, fontWeight:800, color:'var(--red)', background:'var(--surface)', padding:'0 4px', borderRadius:3 }}>
                      {String(minToTime(dropHint.minutes).h).padStart(2,'0')}:{String(minToTime(dropHint.minutes).m).padStart(2,'0')}
                    </div>
                  </div>
                )}
                {/* eventi posizionati (con affiancamento) */}
                {positioned.map(({ v, col, cols })=>{
                  const top = yOf(v.data_visita);
                  const dur = v.durata_min || 30;
                  const height = Math.max(QUARTER_H-2, (dur/60)*HOUR_H - 2);
                  const done = v.stato==='completata'; const annull = v.stato==='annullata';
                  const color = isManager ? commColor(v.commerciale_id) : 'var(--red)';
                  const widthPct = 100/cols;
                  const compact = height < 42; // blocco basso (es. 30 min) → tutto su una riga
                  const ora = new Date(v.data_visita).toLocaleTimeString('it-IT',{hour:'2-digit',minute:'2-digit'});
                  const commLabel = isManager && v.commerciale_id ? commName(v.commerciale_id) : null;
                  return (
                    <div key={v.id} draggable onDragStart={()=>setDragVisit(v)} onDragEnd={()=>{setDragVisit(null);setDropHint(null);}}
                      onClick={(e)=>{ e.stopPropagation(); onEditVisit(v); }}
                      title={`${ora} · ${v.cliente}${v.titolo?' · '+v.titolo:''}${commLabel?' · '+commLabel:''}`}
                      style={{ position:'absolute', top, left:`calc(${col*widthPct}% + 2px)`, width:`calc(${widthPct}% - 4px)`, height, zIndex:3, cursor:'grab',
                        background: done?'var(--line-2)':annull?'var(--surface-2)':'var(--surface)',
                        borderLeft:'3px solid '+(done?'var(--ink-4)':color),
                        border:'1px solid var(--line)', borderLeftWidth:3, borderRadius:6, boxShadow:'var(--sh-1)', padding: compact?'2px 5px':'3px 6px', overflow:'hidden',
                        opacity: (dragVisit&&dragVisit.id===v.id)?0.35:(annull?0.6:1), textDecoration: annull?'line-through':'none',
                        display:'flex', flexDirection:'column', justifyContent: compact?'center':'flex-start' }}>
                      {compact ? (
                        /* riga unica: pallino comm + orario + cliente + nome comm */
                        <div style={{ display:'flex', alignItems:'center', gap:4, minWidth:0 }}>
                          {commLabel && <span style={{ width:6, height:6, borderRadius:99, background:color, flexShrink:0 }} />}
                          <span style={{ fontSize:10, fontWeight:800, color: done?'var(--ink-4)':color, flexShrink:0 }}>{ora}</span>
                          <span style={{ fontSize:10.5, fontWeight:700, color: done?'var(--ink-3)':'var(--ink)', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{v.cliente}</span>
                          {commLabel && <span style={{ fontSize:9.5, fontWeight:700, color, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis', flexShrink:1 }}>· {commLabel}</span>}
                        </div>
                      ) : (
                        <>
                          <div style={{ fontSize:10.5, fontWeight:800, color: done?'var(--ink-3)':'var(--ink)', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis', lineHeight:1.25 }}>
                            <span style={{ color: done?'var(--ink-4)':color }}>{ora}</span> {v.cliente}
                          </div>
                          {height>52 && <div style={{ fontSize:9.5, color:'var(--ink-3)', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{v.titolo||'Visita'}</div>}
                          {commLabel && (
                            <div style={{ display:'flex', alignItems:'center', gap:3, marginTop:1 }}>
                              <span style={{ width:6, height:6, borderRadius:99, background:color, flexShrink:0 }} />
                              <span style={{ fontSize:9, fontWeight:700, color, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{commLabel}</span>
                            </div>
                          )}
                        </>
                      )}
                    </div>
                  );
                })}
                {/* linea "adesso" */}
                {isToday && nowInRange && (
                  <div style={{ position:'absolute', left:0, right:0, top:yOf(now), height:0, zIndex:5, pointerEvents:'none' }}>
                    <div style={{ position:'absolute', left:-4, top:-4, width:8, height:8, borderRadius:99, background:'var(--red)' }} />
                    <div style={{ height:2, background:'var(--red)' }} />
                  </div>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// affianca in colonne gli eventi che si sovrappongono temporalmente
function layoutVisits(visits) {
  const sorted = visits.slice().sort((a,b)=>new Date(a.data_visita)-new Date(b.data_visita));
  const result = [];
  // trova gruppi di sovrapposizione
  let cluster = [];
  let clusterEnd = null;
  const flush = () => {
    if (!cluster.length) return;
    const cols = cluster.length;
    cluster.forEach((v,idx)=>result.push({ v, col:idx, cols }));
    cluster = []; clusterEnd = null;
  };
  for (const v of sorted) {
    const s = new Date(v.data_visita).getTime();
    const e = s + (v.durata_min||30)*60000;
    if (clusterEnd!==null && s < clusterEnd) {
      cluster.push(v); clusterEnd = Math.max(clusterEnd, e);
    } else {
      flush(); cluster=[v]; clusterEnd=e;
    }
  }
  flush();
  return result;
}

/* ---------- VISTA GIORNO (mobile) ---------- */
function DayView({ day, visitsOn, commName, isManager, onEditVisit, onNewAt }) {
  const H_START=7, H_END=20, HOUR_H=52;
  const hours = Array.from({length:H_END-H_START},(_,i)=>i+H_START);
  const vs = visitsOn(day);
  const today = startOfDay(new Date());
  const isToday = sameDay(day, today);
  const [now, setNow] = useState(nowItaly());
  useEffect(()=>{ const t=setInterval(()=>setNow(nowItaly()),60000); return ()=>clearInterval(t); },[]);
  const yOf = (date)=>{ const d=new Date(date); return (d.getHours()-H_START)*HOUR_H + (d.getMinutes()/60)*HOUR_H; };
  const nowInRange = now.getHours()>=H_START && now.getHours()<H_END;

  return (
    <div style={{ border:'1px solid var(--line)', borderRadius:'var(--r-lg)', overflow:'hidden', background:'var(--surface)', position:'relative' }}>
      {hours.map(h=>{
        const slot = vs.filter(v=>new Date(v.data_visita).getHours()===h);
        return (
          <div key={h} onClick={()=>slot.length===0 && onNewAt(day,h)} style={{ display:'flex', gap:10, padding:'6px 12px', borderTop:'1px solid var(--line-2)', minHeight:HOUR_H }}>
            <div style={{ fontSize:11, color:'var(--ink-4)', fontWeight:600, width:44, flexShrink:0, paddingTop:4 }}>{String(h).padStart(2,'0')}:00</div>
            <div style={{ flex:1, display:'flex', flexDirection:'column', gap:4 }}>
              {slot.map(v=><VisitPill key={v.id} v={v} commName={commName} isManager={isManager} onClick={()=>onEditVisit(v)} full />)}
            </div>
          </div>
        );
      })}
      {isToday && nowInRange && (
        <div style={{ position:'absolute', left:56, right:0, top:yOf(now), height:0, zIndex:5, pointerEvents:'none' }}>
          <div style={{ position:'absolute', left:-4, top:-4, width:8, height:8, borderRadius:99, background:'var(--red)' }} />
          <div style={{ height:2, background:'var(--red)' }} />
        </div>
      )}
    </div>
  );
}

function VisitPill({ v, commName, isManager, onClick, full }) {
  const d = new Date(v.data_visita);
  const done = v.stato==='completata'; const annull = v.stato==='annullata';
  const col = isManager ? commColor(v.commerciale_id) : 'var(--red)';
  return (
    <button onClick={onClick} style={{ display:'flex', alignItems:'center', gap:10, width: full?'100%':'auto', textAlign:'left',
      padding:'10px 12px', borderRadius:'var(--r-md)', background:'var(--surface)', border:'1px solid var(--line)', borderLeft:'3px solid '+(done?'var(--ink-4)':col),
      boxShadow:'var(--sh-1)', opacity: annull?0.6:1, textDecoration: annull?'line-through':'none' }}>
      <div style={{ fontSize:12, fontWeight:800, color: done?'var(--ink-3)':col, flexShrink:0, minWidth:42 }}>{d.toLocaleTimeString('it-IT',{hour:'2-digit',minute:'2-digit'})}</div>
      <div style={{ flex:1, minWidth:0 }}>
        <div style={{ fontSize:13.5, fontWeight:700, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{v.cliente}</div>
        <div style={{ fontSize:11.5, color:'var(--ink-3)', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>
          {v.titolo||'Visita'}
          {isManager && v.commerciale_id ? <><span style={{ margin:'0 4px' }}>·</span><span style={{ color:col, fontWeight:700 }}>{commName(v.commerciale_id)}</span></> : ''}
        </div>
      </div>
      {done && <Icon name="check" size={15} style={{ color:'var(--st-disponibile)', flexShrink:0 }} />}
    </button>
  );
}

/* ---------- MODAL crea/modifica visita ---------- */
function VisitModal({ visit, prefillDate, prefillCliente, prefillOppId, role, currentUser, users, clienti, opportunities, stages, bookings, onClose, onSave, onDelete }) {
  const isNew = !visit;
  const isManager = role==='admin' || role==='backoffice';
  const bookingsForOpp = (o) => (bookings||[]).filter(b => (o.bookingIds||[]).includes(b.id));
  const initDate = visit?.data_visita ? new Date(visit.data_visita) : (prefillDate || new Date());
  const [clienteName, setClienteName] = useState(visit?.cliente || prefillCliente?.nome || '');
  const [clienteId, setClienteId] = useState(visit?.cliente_id || prefillCliente?.id || null);
  const [oppId, setOppId] = useState(visit?.opportunity_id || prefillOppId || '');
  const [commId, setCommId] = useState(visit?.commerciale_id || currentUser?.id || '');
  const [dataVisita, setDataVisita] = useState(new Date(initDate.getTime()-initDate.getTimezoneOffset()*60000).toISOString().slice(0,16));
  const [titolo, setTitolo] = useState(visit?.titolo || '');
  const [durata, setDurata] = useState(visit?.durata_min || 30);
  const [note, setNote] = useState(visit?.note || '');
  const [stato, setStato] = useState(visit?.stato || 'programmata');
  const [esito, setEsito] = useState(visit?.esito || '');
  const [results, setResults] = useState([]);
  const [showRes, setShowRes] = useState(false);
  const timer = useRef(null);

  const clienteOpps = (opportunities||[]).filter(o =>
    o.id===oppId || (  // includi sempre quella preselezionata
    (o.esito||'aperta')==='aperta' &&
    ((clienteId && o.cliente_id===clienteId) || (clienteName.trim() && (o.cliente||'').toLowerCase()===clienteName.trim().toLowerCase())))
  );

  const onClienteChange = (val) => {
    setClienteName(val); setClienteId(null); setOppId('');
    if (!val.trim() || val.trim().length<2) { setResults([]); setShowRes(false); return; }
    setShowRes(true);
    if (timer.current) clearTimeout(timer.current);
    timer.current = setTimeout(async ()=>{ try { setResults(await window.DataAPI.searchClienti(val)||[]); } catch(e){ setResults([]); } }, 280);
  };
  const pickCliente = (c) => { setClienteName(c.ragione_sociale); setClienteId(c.id); setResults([]); setShowRes(false); };

  const valid = clienteName.trim().length>=2 && dataVisita;
  const submit = () => {
    if (!valid) return;
    onSave({
      ...(visit||{}), id: visit?.id,
      cliente: clienteName.trim(), cliente_id: clienteId || null,
      opportunity_id: oppId || null, commerciale_id: commId || currentUser?.id || null,
      data_visita: new Date(dataVisita).toISOString(),
      durata_min: Math.max(30, durata||30),
      titolo: titolo.trim() || null, note: note.trim() || null,
      stato, esito: esito.trim() || null,
      created_by: visit?.created_by || currentUser?.id || null,
    });
  };

  return (
    <ModalShell onClose={onClose} width={480} title={isNew?'Nuova visita':'Modifica visita'} subtitle={isNew?'Programma una visita cliente':clienteName}>
      <div style={{ display:'flex', flexDirection:'column', gap:14, maxHeight:'70vh', overflowY:'auto' }} className="scroll">
        <div style={{ position:'relative' }}>
          <Field label="Cliente" required>
            <input value={clienteName} onChange={e=>onClienteChange(e.target.value)} placeholder="Cerca cliente…" style={inputStyle} autoFocus={isNew} />
          </Field>
          {showRes && results.length>0 && (
            <div style={{ position:'absolute', top:'100%', left:0, right:0, zIndex:30, background:'var(--surface)', border:'1px solid var(--line)', borderRadius:'var(--r-md)', boxShadow:'var(--sh-2)', maxHeight:180, overflowY:'auto', marginTop:2 }}>
              {results.map(c=><button key={c.id} onClick={()=>pickCliente(c)} style={{ display:'block', width:'100%', textAlign:'left', padding:'9px 13px', fontSize:13.5, borderBottom:'1px solid var(--line-2)' }}>{c.ragione_sociale}</button>)}
            </div>
          )}
        </div>

        <Field label="Opportunità collegata">
          <div style={{ position:'relative' }}>
            <select value={oppId} onChange={e=>setOppId(e.target.value)} style={{ ...inputStyle, appearance:'none', paddingRight:34 }}>
              <option value="">— Nessuna —</option>
              {clienteOpps.map(o => {
                const st=(stages||[]).find(s=>s.id===o.stage_id);
                const nMacch = (o.bookingIds||[]).length;
                const nDes = (o.desiredIds||[]).length;
                const created = o.created_at ? new Date(o.created_at).toLocaleDateString('it-IT',{day:'2-digit',month:'2-digit',year:'2-digit'}) : '';
                // etichetta ricca per distinguere opportunità dello stesso cliente
                const parts = [st?st.nome:'Opportunità'];
                if (nMacch) parts.push(`${nMacch} macch.`);
                if (nDes) parts.push(`${nDes} desid.`);
                if (created) parts.push(`dal ${created}`);
                return <option key={o.id} value={o.id}>{parts.join(' · ')}</option>;
              })}
            </select>
            <Icon name="chevDown" size={16} style={{ position:'absolute', right:12, top:'50%', transform:'translateY(-50%)', color:'var(--ink-3)', pointerEvents:'none' }} />
          </div>
          {clienteName.trim() && clienteOpps.length===0 && <div style={{ fontSize:11, color:'var(--ink-4)', marginTop:5 }}>Nessuna opportunità aperta per questo cliente</div>}
          {oppId && (() => {
            // riepilogo dell'opportunità selezionata (macchine collegate) per confermare la scelta
            const o = clienteOpps.find(x=>x.id===oppId);
            if (!o) return null;
            const machineLabels = (bookingsForOpp(o)||[]).map(b=>b.prodLabel).filter(Boolean);
            if (machineLabels.length===0) return <div style={{ fontSize:11, color:'var(--ink-4)', marginTop:6 }}>Nessuna macchina collegata a questa opportunità</div>;
            return <div style={{ fontSize:11, color:'var(--ink-3)', marginTop:6, lineHeight:1.4 }}>Macchine: {machineLabels.join(', ')}</div>;
          })()}
        </Field>

        <Field label="Data e ora" required>
          <input type="datetime-local" value={dataVisita} onChange={e=>setDataVisita(e.target.value)} style={inputStyle} />
        </Field>
        <Field label="Durata">
          <div style={{ position:'relative' }}>
            <select value={durata} onChange={e=>setDurata(parseInt(e.target.value))} style={{ ...inputStyle, appearance:'none', paddingRight:34 }}>
              <option value={30}>30 minuti</option>
              <option value={45}>45 minuti</option>
              <option value={60}>1 ora</option>
              <option value={90}>1 ora e 30</option>
              <option value={120}>2 ore</option>
              <option value={180}>3 ore</option>
              <option value={240}>4 ore</option>
            </select>
            <Icon name="chevDown" size={16} style={{ position:'absolute', right:12, top:'50%', transform:'translateY(-50%)', color:'var(--ink-3)', pointerEvents:'none' }} />
          </div>
        </Field>
        <Field label="Titolo / motivo">
          <input value={titolo} onChange={e=>setTitolo(e.target.value)} placeholder="es. Sopralluogo, presentazione…" style={inputStyle} />
        </Field>
        {isManager && (
          <Field label="Commerciale">
            <div style={{ position:'relative' }}>
              <select value={commId} onChange={e=>setCommId(e.target.value)} style={{ ...inputStyle, appearance:'none', paddingRight:34 }}>
                {(users||[]).map(u=><option key={u.id} value={u.id}>{u.nome}</option>)}
              </select>
              <Icon name="chevDown" size={16} style={{ position:'absolute', right:12, top:'50%', transform:'translateY(-50%)', color:'var(--ink-3)', pointerEvents:'none' }} />
            </div>
          </Field>
        )}
        <Field label="Note">
          <textarea value={note} onChange={e=>setNote(e.target.value)} placeholder="Dettagli della visita…" style={{ ...inputStyle, minHeight:60, resize:'vertical', fontFamily:'inherit' }} />
        </Field>
        {!isNew && (
          <>
            <Field label="Stato">
              <div style={{ position:'relative' }}>
                <select value={stato} onChange={e=>setStato(e.target.value)} style={{ ...inputStyle, appearance:'none', paddingRight:34 }}>
                  <option value="programmata">Programmata</option>
                  <option value="completata">Completata</option>
                  <option value="annullata">Annullata</option>
                </select>
                <Icon name="chevDown" size={16} style={{ position:'absolute', right:12, top:'50%', transform:'translateY(-50%)', color:'var(--ink-3)', pointerEvents:'none' }} />
              </div>
            </Field>
            {stato==='completata' && (
              <Field label="Esito della visita">
                <textarea value={esito} onChange={e=>setEsito(e.target.value)} placeholder="Com'è andata…" style={{ ...inputStyle, minHeight:50, resize:'vertical', fontFamily:'inherit' }} />
              </Field>
            )}
          </>
        )}
      </div>
      <div style={{ display:'flex', gap:12, marginTop:20 }}>
        {!isNew && <Btn variant="ghost" icon="trash" onClick={()=>onDelete(visit)} style={{ color:'var(--red)' }}>Elimina</Btn>}
        <Btn variant="ghost" full onClick={onClose}>Annulla</Btn>
        <Btn full icon="check" onClick={submit} disabled={!valid}>{isNew?'Programma':'Salva'}</Btn>
      </div>
    </ModalShell>
  );
}

/* ---------- MODAL promemoria (riepilogo giornaliero) ---------- */
function ReminderPrefModal({ currentUser, onClose, toast }) {
  // visit_reminder_minutes usato come flag: >0 = riepilogo attivo, 0 = disattivato
  const [attivo, setAttivo] = useState((currentUser?.visit_reminder_minutes ?? 1440) > 0);
  const [saving, setSaving] = useState(false);
  const save = async () => {
    setSaving(true);
    const val = attivo ? 1440 : 0;
    try { await window.DataAPI.updateReminderPref(currentUser.id, val); if (currentUser) currentUser.visit_reminder_minutes = val; toast('Preferenza salvata'); onClose(); }
    catch(e){ console.error(e); toast('Errore'); setSaving(false); }
  };
  return (
    <ModalShell onClose={onClose} width={420} title="Promemoria visite" subtitle="Riepilogo giornaliero via email">
      <div style={{ fontSize:13.5, color:'var(--ink-2)', lineHeight:1.5, marginBottom:18 }}>
        Ogni giorno riceverai <b>una sola email</b> con l'elenco di tutte le visite in programma per il giorno successivo, così hai il quadro completo di dove andare senza essere sommerso di notifiche.
      </div>
      <button onClick={()=>setAttivo(a=>!a)}
        style={{ display:'flex', alignItems:'center', justifyContent:'space-between', width:'100%', padding:'14px 16px', borderRadius:'var(--r-md)',
          border:'1.5px solid '+(attivo?'var(--red)':'var(--line)'), background: attivo?'var(--red-tint)':'var(--surface)' }}>
        <div style={{ textAlign:'left' }}>
          <div style={{ fontSize:14, fontWeight:800, color: attivo?'var(--red)':'var(--ink-2)' }}>Riepilogo giornaliero</div>
          <div style={{ fontSize:12, color:'var(--ink-3)', marginTop:2 }}>{attivo?'Attivo — riceverai la mail':'Disattivato'}</div>
        </div>
        {/* toggle */}
        <div style={{ width:44, height:26, borderRadius:99, background: attivo?'var(--red)':'var(--line-2)', position:'relative', flexShrink:0, transition:'.15s' }}>
          <div style={{ position:'absolute', top:3, left: attivo?21:3, width:20, height:20, borderRadius:99, background:'#fff', transition:'.15s', boxShadow:'0 1px 3px rgba(0,0,0,.2)' }} />
        </div>
      </button>
      <div style={{ display:'flex', gap:12, marginTop:20 }}>
        <Btn variant="ghost" full onClick={onClose}>Annulla</Btn>
        <Btn full icon="check" onClick={save} disabled={saving}>Salva</Btn>
      </div>
    </ModalShell>
  );
}

Object.assign(window, { Calendario, VisitModal, ReminderPrefModal });