// Calendário — dinâmico, baseado na data real do sistema

const WEEK_DAYS = ['DOM', 'SEG', 'TER', 'QUA', 'QUI', 'SEX', 'SÁB'];
const WEEK_DAYS_FULL = ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'];
const WEEK_DAYS_SHORT = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'];
const MONTHS_PT = ['Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'];
const EVENT_TYPES = ['meeting','hearing','deadline','internal','signing'];
const EVENT_LABELS = { meeting:'Reunião', hearing:'Audiência', deadline:'Prazo', internal:'Interno', signing:'Assinatura' };

const fmtHour = (iso) => {
  const d = new Date(iso);
  return `${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
};

const getMondayOf = (date) => {
  const d = new Date(date);
  const dow = d.getDay();
  const diff = dow === 0 ? -6 : 1 - dow;
  d.setDate(d.getDate() + diff);
  d.setHours(0,0,0,0);
  return d;
};

const getWeekDays = (monday) => {
  return Array.from({ length: 7 }, (_, i) => {
    const d = new Date(monday);
    d.setDate(monday.getDate() + i);
    return d;
  });
};

// ============================================================
// Modal de compartilhar disponibilidade
// ============================================================
const AvailabilityModal = ({ onClose, allEvents }) => {
  const [selectedWeek, setSelectedWeek] = React.useState('current');
  const [selected, setSelected] = React.useState(new Set());
  const [copied, setCopied] = React.useState(false);

  const monday = React.useMemo(() => {
    const d = getMondayOf(new Date());
    if (selectedWeek === 'next') d.setDate(d.getDate() + 7);
    return d;
  }, [selectedWeek]);

  const weekDays = getWeekDays(monday);
  const hours = Array.from({ length: 10 }, (_, i) => 8 + i); // 08:00–17:00

  const isBusy = (day, hour) => {
    const slotStart = new Date(day); slotStart.setHours(hour, 0, 0, 0);
    const slotEnd   = new Date(day); slotEnd.setHours(hour + 1, 0, 0, 0);
    return allEvents.some(e => {
      if (!e.starts_at || !e.ends_at) return false;
      return new Date(e.starts_at) < slotEnd && new Date(e.ends_at) > slotStart;
    });
  };

  const isPast = (day, hour) => {
    const slotEnd = new Date(day); slotEnd.setHours(hour + 1, 0, 0, 0);
    return slotEnd <= new Date();
  };

  const slotKey = (day, hour) => `${day.toISOString().slice(0,10)}-${hour}`;

  const toggleSlot = (day, hour) => {
    if (isBusy(day, hour) || isPast(day, hour)) return;
    const key = slotKey(day, hour);
    setSelected(prev => {
      const next = new Set(prev);
      next.has(key) ? next.delete(key) : next.add(key);
      return next;
    });
  };

  const generateText = () => {
    if (selected.size === 0) return '';
    const lines = [...selected].sort().map(key => {
      const parts = key.split('-');
      const hour = parseInt(parts[3]);
      const dateStr = parts.slice(0, 3).join('-');
      const d = new Date(dateStr + 'T12:00:00');
      const dayName = WEEK_DAYS_SHORT[d.getDay()];
      const dateLabel = `${String(d.getDate()).padStart(2,'0')}/${String(d.getMonth()+1).padStart(2,'0')}`;
      return `• ${dayName} (${dateLabel}) das ${String(hour).padStart(2,'0')}:00 às ${String(hour+1).padStart(2,'0')}:00`;
    });
    return `Olá! Seguem minhas próximas disponibilidades:\n\n${lines.join('\n')}\n\nAlgum horário funciona pra você?`;
  };

  const text = generateText();

  const copy = () => {
    navigator.clipboard.writeText(text).then(() => {
      setCopied(true); setTimeout(() => setCopied(false), 2000);
    });
  };

  // reset selection when week changes
  React.useEffect(() => { setSelected(new Set()); }, [selectedWeek]);

  const weekLabel = selectedWeek === 'current' ? 'Esta semana' : 'Próxima semana';
  const weekEnd = weekDays[6];
  const weekRange = `${monday.getDate()}/${monday.getMonth()+1} – ${weekEnd.getDate()}/${weekEnd.getMonth()+1}`;

  return (
    <div className="scrim" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{ maxWidth: 600, maxHeight: '88vh', display: 'flex', flexDirection: 'column' }}>
        <div className="modal-head">
          <div style={{ width: 32, height: 32, borderRadius: 4, background: 'var(--octale-navy)', color: '#fff', display: 'grid', placeItems: 'center' }}>
            <Icon name="share2" size={15} />
          </div>
          <div>
            <h2>Compartilhar disponibilidade</h2>
            <div style={{ fontSize: 11, color: 'var(--fg-muted)', marginTop: 1 }}>{weekLabel} · {weekRange}</div>
          </div>
          <button className="x" onClick={onClose}><Icon name="x" size={16} /></button>
        </div>

        <div className="modal-body" style={{ overflowY: 'auto', flex: 1 }}>
          {/* Seletor de semana */}
          <div style={{ display: 'flex', gap: 6, marginBottom: 16 }}>
            <button
              className={`btn sm ${selectedWeek === 'current' ? '' : 'ghost'}`}
              onClick={() => setSelectedWeek('current')}
            >Esta semana</button>
            <button
              className={`btn sm ${selectedWeek === 'next' ? '' : 'ghost'}`}
              onClick={() => setSelectedWeek('next')}
            >Próxima semana</button>
            <div style={{ marginLeft: 'auto', fontSize: 11.5, color: 'var(--fg-muted)', display: 'flex', alignItems: 'center', gap: 10 }}>
              <span style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                <div style={{ width: 10, height: 10, borderRadius: 2, background: 'rgba(23,23,15,.12)', border: '1px solid var(--border)' }} />
                Disponível
              </span>
              <span style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                <div style={{ width: 10, height: 10, borderRadius: 2, background: 'var(--octale-navy)' }} />
                Selecionado
              </span>
              <span style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                <div style={{ width: 10, height: 10, borderRadius: 2, background: 'rgba(194,37,62,.12)' }} />
                Ocupado
              </span>
            </div>
          </div>

          {/* Grid de horários */}
          <div style={{ display: 'grid', gridTemplateColumns: '52px repeat(7, 1fr)', gap: 3 }}>
            {/* Cabeçalho dos dias */}
            <div />
            {weekDays.map(d => (
              <div key={d.toISOString()} style={{ textAlign: 'center', padding: '4px 2px 8px', fontSize: 11, fontWeight: 700, color: 'var(--octale-navy)', lineHeight: 1.3 }}>
                {WEEK_DAYS_SHORT[d.getDay()]}
                <br />
                <span style={{ fontWeight: 400, color: 'var(--fg-muted)', fontSize: 10.5 }}>{d.getDate()}/{d.getMonth()+1}</span>
              </div>
            ))}

            {/* Linhas de horário */}
            {hours.map(h => (
              <React.Fragment key={h}>
                <div style={{ fontSize: 11, color: 'var(--fg-muted)', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', paddingRight: 8, paddingTop: 2 }}>
                  {String(h).padStart(2,'0')}:00
                </div>
                {weekDays.map(d => {
                  const busy   = isBusy(d, h);
                  const past   = isPast(d, h);
                  const key    = slotKey(d, h);
                  const sel    = selected.has(key);
                  const clickable = !busy && !past;
                  return (
                    <div
                      key={key}
                      onClick={() => toggleSlot(d, h)}
                      title={busy ? 'Ocupado' : past ? 'Horário passado' : sel ? 'Clique para desmarcar' : 'Clique para selecionar'}
                      style={{
                        height: 34, borderRadius: 4, border: '1px solid',
                        borderColor: busy ? 'rgba(194,37,62,.25)' : sel ? 'var(--octale-navy)' : 'var(--border)',
                        background: busy ? 'rgba(194,37,62,.08)' : sel ? 'var(--octale-navy)' : past ? 'rgba(0,0,0,.03)' : 'rgba(23,23,15,.04)',
                        cursor: clickable ? 'pointer' : 'default',
                        display: 'flex', alignItems: 'center', justifyContent: 'center',
                        fontSize: 10, fontWeight: 600,
                        color: busy ? '#C2253E' : sel ? '#fff' : 'transparent',
                        transition: 'all .1s',
                        userSelect: 'none',
                      }}
                    >
                      {busy ? 'Ocupado' : sel ? '✓' : ''}
                    </div>
                  );
                })}
              </React.Fragment>
            ))}
          </div>

          {/* Texto gerado */}
          {selected.size > 0 ? (
            <div style={{ marginTop: 20 }}>
              <div style={{ fontWeight: 600, fontSize: 12, marginBottom: 8, color: 'var(--octale-black)', display: 'flex', alignItems: 'center', gap: 8 }}>
                Texto gerado
                <span style={{ fontWeight: 400, color: 'var(--fg-muted)' }}>({selected.size} horário{selected.size !== 1 ? 's' : ''} selecionado{selected.size !== 1 ? 's' : ''})</span>
              </div>
              <textarea
                readOnly
                value={text}
                style={{
                  width: '100%', boxSizing: 'border-box', height: 148,
                  padding: '12px 14px', border: '1px solid var(--border)', borderRadius: 6,
                  fontSize: 12.5, lineHeight: 1.65, resize: 'vertical',
                  fontFamily: 'inherit', background: 'var(--bg)', color: 'var(--octale-black)',
                  outline: 'none',
                }}
              />
            </div>
          ) : (
            <div style={{ marginTop: 16, padding: '12px 16px', background: 'rgba(23,23,15,.04)', borderRadius: 6, fontSize: 12, color: 'var(--fg-muted)', textAlign: 'center' }}>
              Clique nos horários disponíveis para selecioná-los e gerar o texto automaticamente.
            </div>
          )}
        </div>

        <div className="modal-foot">
          <button className="btn ghost sm" onClick={onClose}>Fechar</button>
          {selected.size > 0 && (
            <button className="btn sm" onClick={copy}>
              {copied ? '✓ Copiado!' : <><Icon name="copy" size={12} /> Copiar texto</>}
            </button>
          )}
        </div>
      </div>
    </div>
  );
};

// ============================================================
// Modal de novo evento
// ============================================================
const NewEventModal = ({ onClose, onCreated, onUpdated, clients, cases, users, defaultStart, defaultEnd, roomBusy, editingEvent }) => {
  const isEdit = !!editingEvent;
  const toLocalInput = (iso) => {
    if (!iso) return '';
    const d = new Date(iso);
    const pad = (n) => String(n).padStart(2, '0');
    return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
  };
  const [form, setForm] = React.useState(() => isEdit ? {
    title: editingEvent.title || '',
    type: editingEvent.type || 'meeting',
    starts_at: toLocalInput(editingEvent.starts_at),
    ends_at: toLocalInput(editingEvent.ends_at),
    description: editingEvent.description || '',
    client_id: editingEvent.client_id || '',
    case_id: editingEvent.case_id || '',
    owner_user_id: editingEvent.owner_user_id || '',
    room_reserved: !!editingEvent.room_reserved,
  } : {
    title: '',
    type: 'meeting',
    starts_at: defaultStart || '',
    ends_at: defaultEnd || '',
    description: '',
    client_id: '',
    case_id: '',
    owner_user_id: '',
    room_reserved: false,
  });
  const [guests, setGuests] = React.useState(() => {
    if (isEdit && editingEvent.guests_text) {
      return editingEvent.guests_text.split(',').map(s => s.trim()).filter(Boolean);
    }
    return [];
  });
  const [guestInput, setGuestInput] = React.useState('');
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState('');

  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const filteredCases = cases.filter(c => !form.client_id || c.client_id === form.client_id);

  const addGuest = () => {
    const email = guestInput.trim().toLowerCase();
    if (!email || !email.includes('@') || guests.includes(email)) return;
    setGuests(prev => [...prev, email]);
    setGuestInput('');
  };

  const removeGuest = (email) => setGuests(prev => prev.filter(g => g !== email));

  const onSave = async () => {
    if (!form.title.trim()) { setError('Título é obrigatório.'); return; }
    if (!form.starts_at || !form.ends_at) { setError('Data e hora são obrigatórias.'); return; }
    setSaving(true); setError('');
    try {
      const payload = {
        title: form.title.trim(),
        type: form.type,
        starts_at: new Date(form.starts_at).toISOString(),
        ends_at: new Date(form.ends_at).toISOString(),
        description: form.description || undefined,
        client_id: form.client_id || undefined,
        case_id: form.case_id || undefined,
        owner_user_id: form.owner_user_id || undefined,
        room_reserved: form.room_reserved || undefined,
        guests_text: guests.length > 0 ? guests.join(',') : undefined,
      };
      if (isEdit) {
        const updated = await window.OctaleApi.events.update(editingEvent.id, payload);
        onUpdated && onUpdated(updated);
      } else {
        const created = await window.OctaleApi.events.create(payload);
        onCreated && onCreated(created);
      }
      onClose();
    } catch (e) {
      setError(e.message || (isEdit ? 'Erro ao atualizar evento.' : 'Erro ao criar evento.'));
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="scrim" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{ width: '96vw', maxWidth: 1100, maxHeight: '94vh' }}>
        <div className="modal-head">
          <div style={{ width: 32, height: 32, borderRadius: 4, background: 'var(--octale-navy)', color: '#fff', display: 'grid', placeItems: 'center' }}>
            <Icon name="calendar" size={16} />
          </div>
          <div><h2>{isEdit ? 'Editar evento' : 'Novo evento'}</h2></div>
          <button className="x" onClick={onClose}><Icon name="x" size={16} /></button>
        </div>
        <div className="modal-body" style={{ display: 'grid', gap: 14 }}>
          {error && (
            <div style={{ padding: '8px 12px', background: 'rgba(194,37,62,.08)', border: '1px solid rgba(194,37,62,.2)', borderRadius: 6, color: '#C2253E', fontSize: 12 }}>
              {error}
            </div>
          )}
          <div className="field-w" style={{ gridColumn: '1 / -1' }}>
            <label>Título *</label>
            <input autoFocus value={form.title} onChange={e => set('title', e.target.value)} placeholder="Ex: Reunião com cliente VBH" />
          </div>
          <div className="field-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 12 }}>
            <div className="field-w">
              <label>Tipo</label>
              <select value={form.type} onChange={e => set('type', e.target.value)}>
                {EVENT_TYPES.map(t => <option key={t} value={t}>{EVENT_LABELS[t]}</option>)}
              </select>
            </div>
            <div className="field-w">
              <label>Responsável</label>
              <select value={form.owner_user_id} onChange={e => set('owner_user_id', e.target.value)}>
                <option value="">— Nenhum —</option>
                {users.map(u => <option key={u.id} value={u.id}>{u.name}</option>)}
              </select>
            </div>
            <div className="field-w">
              <label>Início *</label>
              <input type="datetime-local" value={form.starts_at} onChange={e => set('starts_at', e.target.value)} />
            </div>
            <div className="field-w">
              <label>Fim *</label>
              <input type="datetime-local" value={form.ends_at} onChange={e => set('ends_at', e.target.value)} />
            </div>
            <div className="field-w">
              <label>Cliente</label>
              <SearchableSelect value={form.client_id} onChange={e => { set('client_id', e.target.value); set('case_id', ''); }}>
                <option value="">— Nenhum —</option>
                {clients.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
              </SearchableSelect>
            </div>
            <div className="field-w">
              <label>Caso</label>
              <SearchableSelect value={form.case_id} onChange={e => set('case_id', e.target.value)}>
                <option value="">— Nenhum —</option>
                {filteredCases.map(c => <option key={c.id} value={c.id}>{c.number} · {c.title}</option>)}
              </SearchableSelect>
            </div>
          </div>
          <div className="field-w" style={{ gridColumn: '1 / -1' }}>
            <label>Descrição</label>
            <input value={form.description} onChange={e => set('description', e.target.value)} placeholder="Detalhes ou pauta…" />
          </div>

          {/* Convidados */}
          <div className="field-w" style={{ gridColumn: '1 / -1' }}>
            <label>Convidados (e-mail)</label>
            <div style={{ display: 'flex', gap: 6, marginBottom: guests.length > 0 ? 8 : 0 }}>
              <input
                type="email"
                value={guestInput}
                onChange={e => setGuestInput(e.target.value)}
                onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); addGuest(); } }}
                placeholder="email@convidado.com.br"
                style={{ flex: 1, padding: '8px 10px', border: '1px solid var(--border)', borderRadius: 5, fontSize: 12.5, outline: 'none' }}
              />
              <button type="button" className="btn ghost sm" onClick={addGuest} disabled={!guestInput.trim()} style={{ padding: '0 10px', flexShrink: 0 }}>
                <Icon name="plus" size={12} />
              </button>
            </div>
            {guests.length > 0 && (
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
                {guests.map(g => (
                  <span key={g} style={{ display: 'flex', alignItems: 'center', gap: 5, background: 'rgba(23,23,15,.07)', border: '1px solid rgba(23,23,15,.12)', borderRadius: 5, padding: '3px 8px', fontSize: 11.5, color: 'var(--octale-navy)', fontWeight: 500 }}>
                    {g}
                    <button onClick={() => removeGuest(g)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--fg-muted)', padding: 0, lineHeight: 1, fontSize: 14 }}>×</button>
                  </span>
                ))}
              </div>
            )}
            {guests.length > 0 && (
              <div style={{ fontSize: 11, color: 'var(--fg-muted)', marginTop: 6 }}>
                Os convidados serão registrados no evento. Para enviar o convite, compartilhe o texto gerado ou use a integração com Google Calendar.
              </div>
            )}
          </div>

          {/* Reserva de sala */}
          <label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', padding: '10px 14px', borderRadius: 6, border: `1.5px solid ${form.room_reserved ? '#C2253E' : 'var(--border)'}`, background: form.room_reserved ? 'rgba(194,37,62,.05)' : 'transparent', userSelect: 'none' }}>
            <input type="checkbox" checked={form.room_reserved} onChange={e => set('room_reserved', e.target.checked)} style={{ width: 16, height: 16, accentColor: '#C2253E', cursor: 'pointer' }} />
            <div>
              <div style={{ fontWeight: 600, fontSize: 12.5, color: form.room_reserved ? '#C2253E' : 'var(--octale-black)' }}>
                Reservar Sala de Reunião
              </div>
              {roomBusy ? (
                <div style={{ fontSize: 11, color: '#C2253E', marginTop: 2 }}>⚠ Sala já reservada neste período</div>
              ) : (
                <div style={{ fontSize: 11, color: 'var(--fg-muted)', marginTop: 2 }}>Única sala disponível no escritório</div>
              )}
            </div>
          </label>
        </div>
        <div className="modal-foot">
          <button className="btn ghost sm" onClick={onClose}>Cancelar</button>
          <button className="btn sm" onClick={onSave} disabled={saving}>
            {saving ? <><span className="spinner" style={{ width: 12, height: 12, borderWidth: 2, marginRight: 6 }} />Salvando…</> : (isEdit ? 'Salvar alterações' : 'Criar evento')}
          </button>
        </div>
      </div>
    </div>
  );
};

// ============================================================
// Calendar principal
// ============================================================
const Calendar = ({ currentUser }) => {
  const EventToTaskModal = window.EventToTaskModal || null;
  const [mode, setMode] = React.useState('semana');
  const [weekStart, setWeekStart] = React.useState(() => getMondayOf(new Date()));
  const [monthDate, setMonthDate] = React.useState(() => { const d = new Date(); d.setDate(1); return d; });
  const [events, setEvents] = React.useState([]);
  const [googleEvents, setGoogleEvents] = React.useState([]);
  const [tasks, setTasks] = React.useState([]);
  const [allTasksForLookup, setAllTasksForLookup] = React.useState([]); // todas as tarefas, sem filtro de due_date
  const [subtasks, setSubtasks] = React.useState([]);
  const [clients, setClients] = React.useState([]);
  const [cases, setCases] = React.useState([]);
  const [users, setUsers] = React.useState([]);
  const [allTags, setAllTags] = React.useState([]);
  const [selectedTask, setSelectedTask] = React.useState(null);
  const [overflowPopover, setOverflowPopover] = React.useState(null); // { dStr, dayTasks, rect }
  const [draggingTaskId, setDraggingTaskId] = React.useState(null);
  const [dragOverSlot, setDragOverSlot] = React.useState(null); // {dStr, h} | {dStr, h:'header'}
  const [showNew, setShowNew] = React.useState(false);
  const [newEventStart, setNewEventStart] = React.useState('');
  const [newEventEnd, setNewEventEnd] = React.useState('');
  const [showAvailability, setShowAvailability] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const [calFilter, setCalFilter] = React.useState('all');
  const [showIntegration, setShowIntegration] = React.useState(false);
  const [icalUrl, setIcalUrl] = React.useState('');
  const [googleUrls, setGoogleUrls] = React.useState(['']);
  const [googleUrlSaving, setGoogleUrlSaving] = React.useState(false);
  const [googleUrlError, setGoogleUrlError] = React.useState('');
  const [icalCopied, setIcalCopied] = React.useState(false);
  const [selectedEvent, setSelectedEvent] = React.useState(null);
  const [editingEvent, setEditingEvent] = React.useState(null);
  const [taskFromEvent, setTaskFromEvent] = React.useState(null);

  const today = new Date();
  today.setHours(0,0,0,0);
  const todayStr = today.toISOString().slice(0,10);

  React.useEffect(() => {
    Promise.all([
      window.OctaleApi.clients.list(),
      window.OctaleApi.cases.list(),
      window.OctaleApi.users.list(),
      window.OctaleApi.tasks.list(),
      window.OctaleApi.tags.list().catch(() => []),
    ]).then(([cl, cs, us, tk, tg]) => {
      setClients(cl || []);
      setCases(cs || []);
      setUsers(us || []);
      setAllTags(tg || []);
      setAllTasksForLookup(tk || []);
      // Mantém também tarefas concluídas (com prazo) — aparecem riscadas no calendário.
      setTasks((tk || []).filter(t => t.due_date));
    }).catch(() => {});
    // Subtarefas com prazo + responsável (todas as pessoas — calendário é da equipe)
    window.OctaleApi.tasks.subtasksFeed()
      .then(ss => setSubtasks((ss || []).filter(s => s.due_date)))
      .catch(() => {});
    window.OctaleApi.calendar.getGoogleEvents()
      .then(evs => setGoogleEvents(evs || []))
      .catch(e => setGoogleUrlError(e?.message || 'Erro ao carregar agenda do Google.'));
  }, []);

  React.useEffect(() => {
    setLoading(true);
    let from, to;
    if (mode === 'semana') {
      from = new Date(weekStart);
      to = new Date(weekStart); to.setDate(weekStart.getDate() + 6); to.setHours(23,59,59);
    } else if (mode === 'mes') {
      from = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1);
      to = new Date(monthDate.getFullYear(), monthDate.getMonth() + 1, 0, 23, 59, 59);
    } else {
      from = new Date(today);
      to = new Date(today); to.setHours(23,59,59);
    }
    window.OctaleApi.events.list({ from: from.toISOString(), to: to.toISOString() })
      .then(evs => setEvents(evs || []))
      .catch(() => setEvents([]))
      .finally(() => setLoading(false));
  }, [mode, weekStart, monthDate]);

  const openIntegration = async () => {
    setShowIntegration(true);
    setGoogleUrlError('');
    try {
      const [d, savedUrls] = await Promise.all([
        icalUrl ? Promise.resolve(null) : window.OctaleApi.calendar.getIcalUrl().catch(() => null),
        window.OctaleApi.calendar.getGoogleUrls().catch(() => []),
      ]);
      if (d?.icalUrl) setIcalUrl(d.icalUrl);
      if (savedUrls?.length > 0) setGoogleUrls(savedUrls);
    } catch {}
  };

  const saveGoogleUrls = async () => {
    const valid = googleUrls.map(u => u.trim()).filter(Boolean);
    if (valid.length === 0) return;
    setGoogleUrlSaving(true);
    setGoogleUrlError('');
    try {
      await window.OctaleApi.calendar.saveGoogleUrls(valid);
      const evs = await window.OctaleApi.calendar.getGoogleEvents();
      setGoogleEvents(evs || []);
      setShowIntegration(false);
    } catch (e) {
      setGoogleUrlError(e?.message || 'Não foi possível conectar ao Google Calendar. Verifique as URLs e tente novamente.');
    } finally { setGoogleUrlSaving(false); }
  };

  const copyIcal = () => {
    navigator.clipboard.writeText(icalUrl).then(() => { setIcalCopied(true); setTimeout(() => setIcalCopied(false), 2000); });
  };

  // Abre modal de novo evento com data/hora pré-preenchida
  const openNewAt = (dateStr, hour) => {
    const h = String(hour).padStart(2,'0');
    const hEnd = String(Math.min(hour + 1, 18)).padStart(2,'0');
    setNewEventStart(`${dateStr}T${h}:00`);
    setNewEventEnd(`${dateStr}T${hEnd}:00`);
    setShowNew(true);
  };

  const goTodayWeek = () => setWeekStart(getMondayOf(new Date()));
  const prevWeek = () => { const d = new Date(weekStart); d.setDate(d.getDate() - 7); setWeekStart(d); };
  const nextWeek = () => { const d = new Date(weekStart); d.setDate(d.getDate() + 7); setWeekStart(d); };
  const prevMonth = () => setMonthDate(d => new Date(d.getFullYear(), d.getMonth() - 1, 1));
  const nextMonth = () => setMonthDate(d => new Date(d.getFullYear(), d.getMonth() + 1, 1));

  const hours = Array.from({ length: 11 }, (_, i) => 8 + i);

  const getEventStyle = (e) => {
    const start = new Date(e.starts_at);
    const end = new Date(e.ends_at);
    const startHour = start.getHours() + start.getMinutes() / 60;
    const dur = Math.max(0.5, (end - start) / 3600000);
    const top = (startHour - 8) * 56;
    const height = dur * 56 - 4;
    return { top: top + 2, height };
  };

  // Distribui eventos sobrepostos em colunas lado a lado.
  // Retorna array de { leftPct, widthPct } alinhado com o array de entrada.
  const computeEventLayout = (evs) => {
    if (evs.length === 0) return [];
    const sorted = evs
      .map((e, idx) => ({ idx, start: new Date(e.starts_at).getTime(), end: new Date(e.ends_at).getTime() }))
      .sort((a, b) => a.start - b.start);

    const colEnds = [];
    const assignments = [];
    for (const item of sorted) {
      let col = colEnds.findIndex(t => t <= item.start);
      if (col === -1) { col = colEnds.length; colEnds.push(item.end); }
      else colEnds[col] = item.end;
      assignments.push(col);
    }

    const layout = new Array(evs.length);
    for (let i = 0; i < sorted.length; i++) {
      const { start, end, idx } = sorted[i];
      let maxCol = assignments[i];
      for (let j = 0; j < sorted.length; j++) {
        if (i !== j && sorted[j].start < end && sorted[j].end > start) {
          maxCol = Math.max(maxCol, assignments[j]);
        }
      }
      const totalCols = maxCol + 1;
      layout[idx] = { leftPct: assignments[i] / totalCols, widthPct: 1 / totalCols };
    }
    return layout;
  };

  const allEvents = React.useMemo(() => [
    ...events,
    ...googleEvents.map(e => ({ ...e, _google: true })),
  ], [events, googleEvents]);

  const filteredEvents = React.useMemo(() => {
    if (calFilter === 'all') return allEvents;
    const uid = calFilter === 'mine' ? currentUser?.id : calFilter;
    // Eventos do Google pertencem a quem está logado (busca por usuário). Só
    // aparecem na própria agenda — nunca sob o filtro de outra pessoa.
    const isOwnView = uid === currentUser?.id;
    return allEvents.filter(e => e._google ? isOwnView : e.owner_user_id === uid);
  }, [allEvents, calFilter, currentUser]);

  // Itens normalizados: tarefas principais + subtarefas, num formato único para
  // renderização. _kind distingue; _done marca concluída/feita (exibe riscada).
  const taskItems = React.useMemo(() => {
    const mains = tasks.map(t => ({
      ...t,
      _kind: 'task',
      _done: t.kanban_column === 'concluido',
    }));
    const subs = subtasks.map(s => ({
      id: 'sub-' + s.id,
      title: s.title,
      due_date: s.due_date,
      calendar_scheduled_at: null,
      owner_user_id: s.owner_user_id,
      reviewer_user_id: null,
      priority: 'Média',
      _kind: 'subtask',
      _done: !!s.done,
      _parentId: s.task_id,
      _parentTitle: s.parent_title,
    }));
    return [...mains, ...subs];
  }, [tasks, subtasks]);

  const filteredTasks = React.useMemo(() => {
    if (calFilter === 'all') return taskItems;
    const uid = calFilter === 'mine' ? currentUser?.id : calFilter;
    return taskItems.filter(t => t.owner_user_id === uid || t.reviewer_user_id === uid);
  }, [taskItems, calFilter, currentUser]);

  // Tarefas/subtarefas sem horário definido (aparecem no cabeçalho do dia)
  const tasksForDay = (dateStr) =>
    filteredTasks.filter(t => t.due_date && t.due_date.slice(0, 10) === dateStr && !t.calendar_scheduled_at);

  // Tarefas com horário definido via drag (aparecem na grade de horas)
  const scheduledTasksForDay = (dateStr) =>
    filteredTasks.filter(t => t.calendar_scheduled_at &&
      new Date(t.calendar_scheduled_at).toISOString().slice(0, 10) === dateStr);

  // Abre o detalhe — subtarefa abre o card pai (tem o contexto completo).
  // Usa allTasksForLookup (sem filtro de due_date) para garantir que o pai seja encontrado.
  const openTaskItem = (t) => {
    if (t._kind === 'subtask') {
      const parent = allTasksForLookup.find(x => x.id === t._parentId);
      if (parent) setSelectedTask(parent);
    } else {
      setSelectedTask(t);
    }
  };

  // Atualiza due_date e/ou horário de uma tarefa arrastada
  const updateTaskSchedule = async (taskId, dueDate, scheduledAt) => {
    try {
      await window.OctaleApi.tasks.update(taskId, { due_date: dueDate, calendar_scheduled_at: scheduledAt });
      setTasks(prev => prev.map(t => t.id === taskId
        ? { ...t, due_date: dueDate, calendar_scheduled_at: scheduledAt }
        : t));
    } catch {}
  };

  // Atualiza due_date de uma subtarefa arrastada no calendário
  const updateSubtaskSchedule = async (subtaskId, dueDate) => {
    try {
      await window.OctaleApi.tasks.updateSubtask(subtaskId, { due_date: dueDate });
      setSubtasks(prev => prev.map(s => s.id === subtaskId ? { ...s, due_date: dueDate } : s));
    } catch {}
  };

  const eventsForDay = (dateStr) =>
    filteredEvents.filter(e => e.starts_at && e.starts_at.slice(0, 10) === dateStr);

  const todayEvents = eventsForDay(todayStr);
  const weekDays = getWeekDays(weekStart);

  const weekEnd = weekDays[6];
  const sameMonth = weekStart.getMonth() === weekEnd.getMonth();
  const weekLabel = sameMonth
    ? `${weekStart.getDate()}–${weekEnd.getDate()} de ${MONTHS_PT[weekStart.getMonth()]} ${weekStart.getFullYear()}`
    : `${weekStart.getDate()} ${MONTHS_PT[weekStart.getMonth()]} – ${weekEnd.getDate()} ${MONTHS_PT[weekEnd.getMonth()]}`;

  const eventColors = {
    meeting: 'var(--octale-navy)',
    hearing: '#C2253E',
    deadline: 'var(--octale-dark-purple)',
    internal: '#2E6E40',
    signing: 'var(--octale-neon)',
  };
  const eventTextColors = { signing: 'var(--octale-dark-purple)' };

  return (
    <div className="cal">
      {googleUrlError && !showIntegration && (
        <div style={{ margin: '0 0 12px', padding: '10px 14px', background: 'rgba(194,37,62,.06)', border: '1px solid rgba(194,37,62,.2)', borderRadius: 6, fontSize: 12.5, color: '#C2253E', display: 'flex', alignItems: 'center', gap: 10 }}>
          <Icon name="alertTriangle" size={14} />
          <span style={{ flex: 1 }}>{googleUrlError}</span>
          <button className="btn ghost sm" style={{ fontSize: 11, color: '#C2253E' }} onClick={() => { setGoogleUrlError(''); setShowIntegration(true); }}>Reconfigurar</button>
        </div>
      )}
      <div className="cal-head">
        <h1>{MONTHS_PT[mode === 'mes' ? monthDate.getMonth() : weekStart.getMonth()]} {mode === 'mes' ? monthDate.getFullYear() : weekStart.getFullYear()}</h1>
        <button className="btn ghost sm icon" onClick={mode === 'mes' ? prevMonth : prevWeek}><Icon name="chevronLeft" size={14} /></button>
        <button className="btn ghost sm" onClick={() => { goTodayWeek(); setMonthDate(new Date(new Date().getFullYear(), new Date().getMonth(), 1)); }}>Hoje</button>
        <button className="btn ghost sm icon" onClick={mode === 'mes' ? nextMonth : nextWeek}><Icon name="chevronRight" size={14} /></button>
        {mode === 'semana' && <span style={{ fontSize: 12, color: 'var(--fg-muted)', marginLeft: 8 }}>{weekLabel}</span>}
        <div className="ctl">
          {/* Filtro de agenda */}
          <div className="cal-seg" style={{ marginRight: 8 }}>
            <button className={calFilter === 'all' ? 'active' : ''} onClick={() => setCalFilter('all')} title="Todos os eventos">Todos</button>
            <button className={calFilter === 'mine' ? 'active' : ''} onClick={() => setCalFilter('mine')} title="Somente minha agenda">Minha agenda</button>
          </div>
          {users.length > 0 && (
            <select
              value={calFilter === 'all' || calFilter === 'mine' ? '' : calFilter}
              onChange={e => setCalFilter(e.target.value || 'all')}
              style={{ fontSize: 11.5, padding: '3px 6px', borderRadius: 4, border: '1px solid var(--border)', background: 'var(--surface)', color: 'var(--octale-black)', marginRight: 8, cursor: 'pointer' }}
            >
              <option value="">Filtrar por pessoa…</option>
              {users.map(u => (
                <option key={u.id} value={u.id}>{u.name}</option>
              ))}
            </select>
          )}
          <div className="cal-seg">
            <button className={mode === 'dia' ? 'active' : ''} onClick={() => setMode('dia')}>Dia</button>
            <button className={mode === 'semana' ? 'active' : ''} onClick={() => setMode('semana')}>Semana</button>
            <button className={mode === 'mes' ? 'active' : ''} onClick={() => setMode('mes')}>Mês</button>
          </div>
          <button className="btn sm" style={{ marginLeft: 8 }} onClick={() => openNewAt(todayStr, 9)}>
            <Icon name="plus" size={12} /> Novo evento
          </button>
          <button className="btn ghost sm" style={{ marginLeft: 4 }} onClick={() => setShowAvailability(true)} title="Compartilhar disponibilidade">
            <Icon name="share2" size={12} /> Disponibilidade
          </button>
          <button className="btn ghost sm" style={{ marginLeft: 4 }} onClick={openIntegration} title="Integração Google Calendar">
            <Icon name="link" size={12} /> Google
          </button>
        </div>
      </div>

      {/* Modal de disponibilidade */}
      {showAvailability && (
        <AvailabilityModal
          onClose={() => setShowAvailability(false)}
          allEvents={allEvents}
        />
      )}

      {/* Modal de integração Google Calendar */}
      {showIntegration && (
        <div className="scrim" onClick={() => setShowIntegration(false)}>
          <div className="modal" onClick={e => e.stopPropagation()} style={{ maxWidth: 500 }}>
            <div className="modal-head">
              <div style={{ width: 32, height: 32, borderRadius: 4, background: '#4285F4', color: '#fff', display: 'grid', placeItems: 'center' }}>
                <Icon name="calendar" size={16} />
              </div>
              <div><h2>Integração com Google Calendar</h2></div>
              <button className="x" onClick={() => setShowIntegration(false)}><Icon name="x" size={16} /></button>
            </div>
            <div className="modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
              <div style={{ background: 'var(--bg)', border: '1px solid var(--border)', borderRadius: 8, padding: 16 }}>
                <div style={{ fontWeight: 700, fontSize: 13, color: 'var(--octale-black)', marginBottom: 4 }}>PAC → Google Calendar</div>
                <div style={{ fontSize: 12, color: 'var(--fg-muted)', marginBottom: 12, lineHeight: 1.5 }}>
                  Copie o link abaixo e adicione no Google Calendar em <b>Outras agendas → Por URL</b>.
                </div>
                <div style={{ display: 'flex', gap: 8 }}>
                  <input readOnly value={icalUrl || 'Carregando…'}
                    style={{ flex: 1, padding: '8px 10px', border: '1px solid var(--border)', borderRadius: 5, fontSize: 11.5, background: 'var(--surface)', color: 'var(--fg-muted)', outline: 'none' }} />
                  <button className="btn sm" onClick={copyIcal} disabled={!icalUrl}>
                    {icalCopied ? '✓ Copiado!' : 'Copiar'}
                  </button>
                </div>
              </div>
              <div style={{ background: 'var(--bg)', border: '1px solid var(--border)', borderRadius: 8, padding: 16 }}>
                <div style={{ fontWeight: 700, fontSize: 13, color: 'var(--octale-black)', marginBottom: 4 }}>Google Calendar → PAC</div>
                <div style={{ fontSize: 12, color: 'var(--fg-muted)', marginBottom: 12, lineHeight: 1.5 }}>
                  Cole a URL secreta (.ics) de cada agenda. No Google Calendar: <b>Configurações → selecione a agenda → Integrar agenda → Endereço secreto no formato iCal</b>.
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  {googleUrls.map((url, idx) => (
                    <div key={idx} style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
                      <input
                        value={url}
                        onChange={e => setGoogleUrls(prev => prev.map((u, i) => i === idx ? e.target.value : u))}
                        placeholder={`Agenda ${idx + 1} — https://calendar.google.com/calendar/ical/…/basic.ics`}
                        style={{ flex: 1, padding: '8px 10px', border: '1px solid var(--border)', borderRadius: 5, fontSize: 11.5, outline: 'none' }}
                      />
                      {googleUrls.length > 1 && (
                        <button
                          className="btn ghost sm icon"
                          style={{ flexShrink: 0, color: '#C2253E' }}
                          onClick={() => setGoogleUrls(prev => prev.filter((_, i) => i !== idx))}
                          title="Remover agenda"
                        >
                          <Icon name="x" size={14} />
                        </button>
                      )}
                    </div>
                  ))}
                  <div style={{ display: 'flex', gap: 8, marginTop: 4 }}>
                    <button
                      className="btn ghost sm"
                      style={{ fontSize: 11.5 }}
                      onClick={() => setGoogleUrls(prev => [...prev, ''])}
                    >
                      + Adicionar outra agenda
                    </button>
                    <button className="btn sm" style={{ marginLeft: 'auto' }} onClick={saveGoogleUrls} disabled={googleUrlSaving || googleUrls.every(u => !u.trim())}>
                      {googleUrlSaving ? 'Salvando…' : 'Salvar'}
                    </button>
                  </div>
                </div>
                {googleUrlError && (
                  <div style={{ marginTop: 8, fontSize: 11.5, color: '#C2253E', background: 'rgba(194,37,62,.06)', border: '1px solid rgba(194,37,62,.2)', borderRadius: 5, padding: '6px 10px' }}>
                    {googleUrlError}
                  </div>
                )}
                {!googleUrlError && googleEvents.length > 0 && (
                  <div style={{ marginTop: 8, fontSize: 11.5, color: '#2A7F5E', fontWeight: 600 }}>
                    ✓ {googleEvents.length} evento{googleEvents.length !== 1 ? 's' : ''} do Google carregado{googleEvents.length !== 1 ? 's' : ''} ({googleUrls.filter(u => u.trim()).length} agenda{googleUrls.filter(u => u.trim()).length !== 1 ? 's' : ''})
                  </div>
                )}
              </div>
            </div>
            <div className="modal-foot">
              <button className="btn ghost sm" onClick={() => setShowIntegration(false)}>Fechar</button>
            </div>
          </div>
        </div>
      )}

      {/* ====== SEMANA ====== */}
      {mode === 'semana' && (
        <div className="cal-week-wrap">
          <div className="cal-week-grid">
            <div className="cal-col-head" />
            {weekDays.map(d => {
              const dStr = d.toISOString().slice(0,10);
              const isToday = dStr === todayStr;
              const dayTasks = tasksForDay(dStr);
              const roomTaken = eventsForDay(dStr).some(e => e.room_reserved);
              return (
                <div key={dStr}
                  className={`cal-col-head ${isToday ? 'today' : ''} ${d.getDay() === 0 || d.getDay() === 6 ? 'weekend' : ''}`}
                  style={{ flexDirection: 'column', alignItems: 'flex-start', padding: '6px 8px', gap: 2,
                    ...(draggingTaskId && dragOverSlot?.dStr === dStr && dragOverSlot?.h === 'header'
                      ? { background: 'rgba(23,23,15,.10)', outline: '2px dashed rgba(23,23,15,.35)' } : {}) }}
                  onDragOver={e => { if (!draggingTaskId) return; e.preventDefault(); setDragOverSlot({ dStr, h: 'header' }); }}
                  onDragLeave={() => setDragOverSlot(null)}
                  onDrop={e => {
                    e.preventDefault();
                    const tid = e.dataTransfer.getData('task-id');
                    const sid = e.dataTransfer.getData('subtask-id');
                    setDragOverSlot(null); setDraggingTaskId(null);
                    if (tid) updateTaskSchedule(tid, dStr, null);
                    else if (sid) updateSubtaskSchedule(sid, dStr);
                  }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, width: '100%' }}>
                    <span style={{ fontSize: 10, fontWeight: 600, color: 'var(--fg-muted)', textTransform: 'uppercase' }}>{WEEK_DAYS[d.getDay()]}</span>
                    <span className="num">{d.getDate()}</span>
                    {roomTaken && <span style={{ marginLeft: 'auto', fontSize: 10, color: '#C2253E', fontWeight: 700 }} title="Sala reservada">🏠</span>}
                  </div>
                  {dayTasks.slice(0, 2).map(t => {
                    const isSub = t._kind === 'subtask';
                    const chipLabel = isSub
                      ? '↳ ' + (t._parentTitle ? t._parentTitle + ': ' : '') + t.title
                      : '⏰ ' + t.title;
                    const chipTitle = isSub && t._parentTitle
                      ? t._parentTitle + ' → ' + t.title
                      : t.title;
                    return (
                    <div key={t.id}
                      draggable
                      onDragStart={e => {
                        if (isSub) {
                          e.dataTransfer.setData('subtask-id', t.id.replace('sub-', ''));
                        } else {
                          e.dataTransfer.setData('task-id', t.id);
                        }
                        setDraggingTaskId(t.id);
                      }}
                      onDragEnd={() => { setDraggingTaskId(null); setDragOverSlot(null); }}
                      onClick={ev => { ev.stopPropagation(); openTaskItem(t); }}
                      style={{
                        fontSize: 10, background: isSub ? 'rgba(23,23,15,.05)' : 'rgba(23,23,15,.08)', color: 'var(--octale-navy)',
                        borderRadius: 3, padding: '1px 5px', whiteSpace: 'nowrap', overflow: 'hidden',
                        textOverflow: 'ellipsis', maxWidth: '100%', fontWeight: 600,
                        cursor: 'grab', userSelect: 'none',
                        ...(t._done ? { textDecoration: 'line-through', opacity: 0.5 } : {}),
                      }} title={chipTitle}>{chipLabel}</div>
                    );
                  })}
                  {dayTasks.length > 2 && (
                    <div
                      onClick={ev => {
                        ev.stopPropagation();
                        const rect = ev.currentTarget.getBoundingClientRect();
                        setOverflowPopover({ dStr, dayTasks, rect });
                      }}
                      style={{ fontSize: 10, color: 'var(--octale-navy)', fontWeight: 600, cursor: 'pointer', padding: '1px 4px', borderRadius: 3, background: 'rgba(23,23,15,.06)', userSelect: 'none' }}>
                      +{dayTasks.length - 2} tarefa{dayTasks.length - 2 > 1 ? 's' : ''}
                    </div>
                  )}
                </div>
              );
            })}
            <div className="cal-time">
              {hours.map(h => <div className="cal-time-cell" key={h}>{String(h).padStart(2,'0')}:00</div>)}
            </div>
            {weekDays.map(d => {
              const dStr = d.toISOString().slice(0,10);
              const isToday = dStr === todayStr;
              const dayEvs = eventsForDay(dStr);
              const nowMinutes = new Date().getHours() * 60 + new Date().getMinutes();
              const nowTop = (nowMinutes / 60 - 8) * 56;
              return (
                <div key={dStr} className={`cal-day${d.getDay() === 0 || d.getDay() === 6 ? ' weekend' : ''}`}>
                  {hours.map(h => (
                    <div
                      className="cal-day-cell"
                      key={h}
                      onClick={() => openNewAt(dStr, h)}
                      onDragOver={e => { if (!draggingTaskId) return; e.preventDefault(); setDragOverSlot({ dStr, h }); }}
                      onDragLeave={() => setDragOverSlot(null)}
                      onDrop={e => {
                        e.preventDefault();
                        const tid = e.dataTransfer.getData('task-id');
                        const sid = e.dataTransfer.getData('subtask-id');
                        setDragOverSlot(null); setDraggingTaskId(null);
                        if (tid) {
                          const scheduledAt = `${dStr}T${String(h).padStart(2, '0')}:00:00`;
                          updateTaskSchedule(tid, dStr, scheduledAt);
                        } else if (sid) {
                          updateSubtaskSchedule(sid, dStr);
                        }
                      }}
                      style={{
                        cursor: draggingTaskId ? 'copy' : 'pointer',
                        ...(draggingTaskId && dragOverSlot?.dStr === dStr && dragOverSlot?.h === h
                          ? { background: 'rgba(23,23,15,.10)', outline: '2px dashed rgba(23,23,15,.35)' } : {}),
                      }}
                      title={draggingTaskId ? `Agendar tarefa às ${String(h).padStart(2,'0')}:00` : `Criar evento às ${String(h).padStart(2,'0')}:00`}
                    />
                  ))}
                  {/* Tarefas com horário definido via drag */}
                  {scheduledTasksForDay(dStr).map(t => {
                    const sched = new Date(t.calendar_scheduled_at);
                    const top = (sched.getHours() + sched.getMinutes() / 60 - 8) * 56;
                    if (top < 0 || top > 9 * 56) return null;
                    return (
                      <div key={t.id}
                        draggable
                        onDragStart={e => { e.stopPropagation(); e.dataTransfer.setData('task-id', t.id); setDraggingTaskId(t.id); }}
                        onDragEnd={() => { setDraggingTaskId(null); setDragOverSlot(null); }}
                        onClick={ev => { ev.stopPropagation(); openTaskItem(t); }}
                        style={{
                          position: 'absolute', top, left: 2, right: 2, height: 50,
                          borderRadius: 4,
                          background: 'rgba(23,23,15,.11)',
                          border: '1.5px solid rgba(23,23,15,.30)',
                          color: 'var(--octale-navy)',
                          fontSize: 11, fontWeight: 600,
                          padding: '3px 6px',
                          overflow: 'hidden', cursor: 'grab', zIndex: 5,
                          userSelect: 'none',
                          ...(t._done ? { textDecoration: 'line-through', opacity: 0.55 } : {}),
                        }}>
                        <div style={{ fontSize: 11, fontWeight: 700, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                          ⏰ {t.title}
                        </div>
                        <div style={{ fontSize: 9.5, opacity: 0.65 }}>
                          {String(sched.getHours()).padStart(2,'0')}:{String(sched.getMinutes()).padStart(2,'0')}
                        </div>
                      </div>
                    );
                  })}
                  {isToday && nowTop > 0 && <div className="cal-now" style={{ top: nowTop }} />}
                  {(() => {
                    const evLayout = computeEventLayout(dayEvs);
                    return dayEvs.map((e, i) => {
                      const isGoogle = !!e._google;
                      const isRoom = !!e.room_reserved;
                      const { leftPct, widthPct } = evLayout[i] || { leftPct: 0, widthPct: 1 };
                      const colLeft = `calc(${leftPct * 100}% + 2px)`;
                      const colWidth = `calc(${widthPct * 100}% - 4px)`;
                      return (
                        <div key={i} className={`cal-event ${isGoogle ? 'internal' : e.type}`}
                          onClick={ev => { ev.stopPropagation(); setSelectedEvent(e); }}
                          style={{ ...getEventStyle(e), left: colLeft, width: colWidth, right: 'auto', ...(isGoogle ? { opacity: 0.75, borderLeft: '3px solid #4285F4' } : {}) }}>
                          <div style={{ fontWeight: 700, fontSize: 11, lineHeight: 1.25, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                            {isGoogle && <span style={{ fontSize: 9, marginRight: 3, opacity: 0.7 }}>G</span>}
                            {e.title}
                            {isRoom && <span style={{ marginLeft: 4, fontSize: 9, background: 'rgba(255,255,255,.25)', padding: '1px 4px', borderRadius: 3 }}>🏠</span>}
                          </div>
                          <div className="ev-time">{fmtHour(e.starts_at)}</div>
                        </div>
                      );
                    });
                  })()}
                </div>
              );
            })}
          </div>

          {/* Side rail */}
          <div className="cal-side-rail" style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {/* Mini mês */}
            <div className="cal-month-mini">
              <h4>{MONTHS_PT[weekStart.getMonth()]} · {weekStart.getFullYear()}</h4>
              <div className="grid">
                {WEEK_DAYS.map((d, i) => <div key={i} className="dow">{d}</div>)}
                {(() => {
                  const firstDay = new Date(weekStart.getFullYear(), weekStart.getMonth(), 1);
                  const startOffset = firstDay.getDay();
                  const daysInMonth = new Date(weekStart.getFullYear(), weekStart.getMonth() + 1, 0).getDate();
                  const daysInPrev = new Date(weekStart.getFullYear(), weekStart.getMonth(), 0).getDate();
                  return Array.from({ length: 35 }, (_, i) => {
                    const dayNum = i - startOffset + 1;
                    const isOff = dayNum < 1 || dayNum > daysInMonth;
                    const shown = isOff ? (dayNum < 1 ? daysInPrev + dayNum : dayNum - daysInMonth) : dayNum;
                    const thisDate = new Date(weekStart.getFullYear(), weekStart.getMonth(), dayNum);
                    const isToday = !isOff && dayNum === today.getDate() && weekStart.getMonth() === today.getMonth() && weekStart.getFullYear() === today.getFullYear();
                    const hasEv = !isOff && events.some(e => e.starts_at && e.starts_at.slice(0,10) === thisDate.toISOString().slice(0,10));
                    return (
                      <div key={i} className={`d ${isOff ? 'off' : ''} ${isToday ? 'today' : ''} ${hasEv ? 'has' : ''}`}>
                        {shown}
                      </div>
                    );
                  });
                })()}
              </div>
            </div>

            {/* Eventos de hoje */}
            <div className="panel">
              <div className="panel-head">
                <h3>Hoje · {today.getDate()} {MONTHS_PT[today.getMonth()].slice(0,3)}</h3>
                <span style={{ fontSize: 11, color: 'var(--fg-muted)' }}>{todayEvents.length} evento{todayEvents.length !== 1 ? 's' : ''}</span>
              </div>
              {todayEvents.length === 0 ? (
                <div style={{ padding: '12px 14px', fontSize: 12, color: 'var(--fg-muted)' }}>Sem eventos hoje.</div>
              ) : (
                <div className="panel-body tight">
                  {todayEvents.map((e, i) => (
                    <div className="list-row" key={i} style={{ padding: '10px 14px', cursor: 'pointer' }} onClick={() => setSelectedEvent(e)}>
                      <div style={{ width: 3, alignSelf: 'stretch', borderRadius: 999, background: e._google ? '#4285F4' : (eventColors[e.type] || 'var(--octale-navy)') }} />
                      <div className="grow">
                        <div className="ttl" style={{ fontSize: 12.5 }}>{e.title}</div>
                        <div className="meta">{fmtHour(e.starts_at)} · {e._google ? 'Google Calendar' : (EVENT_LABELS[e.type] || e.type)}</div>
                      </div>
                      <span style={{ fontSize: 10, color: 'var(--fg-muted)', background: 'var(--surface)', borderRadius: 4, padding: '2px 6px', border: '1px solid var(--border)', fontWeight: 600, flexShrink: 0 }}>+ tarefa</span>
                    </div>
                  ))}
                </div>
              )}
            </div>

            {/* Prazos próximos */}
            {(() => {
              const deadlines = events.filter(e => e.type === 'deadline');
              if (deadlines.length === 0) return null;
              return (
                <div className="panel" style={{ background: 'var(--octale-navy)', color: '#fff', border: 0 }}>
                  <div style={{ padding: 18 }}>
                    <div className="eyebrow" style={{ color: 'var(--octale-neon)', marginBottom: 6 }}>Prazos da semana</div>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginTop: 8 }}>
                      {deadlines.slice(0, 4).map((e, i) => (
                        <div key={i} style={{ fontSize: 12, color: 'rgba(255,255,255,.85)' }}>
                          {new Date(e.starts_at).toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' })} · {e.title}
                        </div>
                      ))}
                    </div>
                  </div>
                </div>
              );
            })()}
          </div>
        </div>
      )}

      {/* ====== MÊS ====== */}
      {mode === 'mes' && (
        <div className="cal-month-wrap" style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 6, overflow: 'hidden' }}>
          <div className="cal-month-header" style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', borderBottom: '1px solid var(--border)' }}>
            {WEEK_DAYS.map(d => (
              <div key={d} style={{ padding: '10px 12px', fontSize: 11, fontWeight: 700, color: 'var(--octale-navy)', letterSpacing: '.12em', borderRight: '1px solid var(--border)' }}>{d}</div>
            ))}
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)' }}>
            {(() => {
              const firstDay = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1);
              const startOffset = firstDay.getDay();
              const daysInMonth = new Date(monthDate.getFullYear(), monthDate.getMonth() + 1, 0).getDate();
              const daysInPrev = new Date(monthDate.getFullYear(), monthDate.getMonth(), 0).getDate();
              return Array.from({ length: 35 }, (_, i) => {
                const dayNum = i - startOffset + 1;
                const isOff = dayNum < 1 || dayNum > daysInMonth;
                const shown = isOff ? (dayNum < 1 ? daysInPrev + dayNum : dayNum - daysInMonth) : dayNum;
                const thisDate = isOff ? null : new Date(monthDate.getFullYear(), monthDate.getMonth(), dayNum);
                const dStr = thisDate ? thisDate.toISOString().slice(0,10) : null;
                const isToday = dStr === todayStr;
                const dayEvs = dStr ? eventsForDay(dStr) : [];
                const isDropTarget = !isOff && dStr && draggingTaskId && dragOverSlot?.dStr === dStr && dragOverSlot?.h === 'month';
                return (
                  <div
                    key={i}
                    onClick={() => !isOff && dStr && openNewAt(dStr, 9)}
                    onDragOver={e => { if (isOff || !dStr || !draggingTaskId) return; e.preventDefault(); setDragOverSlot({ dStr, h: 'month' }); }}
                    onDragLeave={() => setDragOverSlot(null)}
                    onDrop={e => {
                      if (isOff || !dStr) return;
                      e.preventDefault();
                      const tid = e.dataTransfer.getData('task-id');
                      const sid = e.dataTransfer.getData('subtask-id');
                      setDragOverSlot(null); setDraggingTaskId(null);
                      if (tid) updateTaskSchedule(tid, dStr, null);
                      else if (sid) updateSubtaskSchedule(sid, dStr);
                    }}
                    style={{
                      minHeight: 90, padding: 8,
                      borderRight: '1px solid var(--border)', borderBottom: '1px solid var(--border)',
                      background: isDropTarget ? 'rgba(23,23,15,.10)' : (isToday ? 'rgba(200,255,0,.05)' : '#fff'),
                      ...(isDropTarget ? { outline: '2px dashed rgba(23,23,15,.35)', outlineOffset: -2 } : {}),
                      cursor: !isOff ? (draggingTaskId ? 'copy' : 'pointer') : 'default',
                      overflow: 'hidden', minWidth: 0,
                    }}
                  >
                    <div style={{
                      fontSize: 12, fontWeight: isToday ? 700 : 600,
                      color: isOff ? 'rgba(0,0,0,.25)' : 'var(--octale-black)',
                      display: 'inline-block',
                      background: isToday ? 'var(--octale-navy)' : 'transparent',
                      ...(isToday ? { color: '#fff', padding: '1px 7px', borderRadius: 999 } : {}),
                      marginBottom: 4,
                    }}>{shown}</div>
                    {dayEvs.slice(0, 3).map((e, j) => (
                      <div key={j} onClick={ev => { ev.stopPropagation(); setSelectedEvent(e); }} style={{
                        fontSize: 10.5, padding: '2px 6px', borderRadius: 3, marginBottom: 2,
                        background: eventColors[e.type] || 'var(--octale-navy)',
                        color: eventTextColors[e.type] || '#fff',
                        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', fontWeight: 600,
                      }}>{e.title}</div>
                    ))}
                    {dayEvs.length > 3 && <div style={{ fontSize: 10, color: 'var(--fg-muted)' }}>+{dayEvs.length - 3}</div>}
                    {dStr && (() => {
                      const dayTasks = tasksForDay(dStr);
                      const visible = dayTasks.slice(0, 3);
                      const overflow = dayTasks.length - 3;
                      return (
                        <>
                          {visible.map(t => {
                            const isSub = t._kind === 'subtask';
                            const chipLabel = isSub
                              ? '↳ ' + (t._parentTitle ? t._parentTitle + ': ' : '') + t.title
                              : '⏰ ' + t.title;
                            const chipTitle = isSub && t._parentTitle
                              ? t._parentTitle + ' → ' + t.title
                              : t.title;
                            return (
                              <div key={t.id}
                                draggable
                                onDragStart={ev => {
                                  ev.stopPropagation();
                                  if (isSub) {
                                    ev.dataTransfer.setData('subtask-id', t.id.replace('sub-', ''));
                                  } else {
                                    ev.dataTransfer.setData('task-id', t.id);
                                  }
                                  setDraggingTaskId(t.id);
                                }}
                                onDragEnd={() => { setDraggingTaskId(null); setDragOverSlot(null); }}
                                onClick={ev => { ev.stopPropagation(); openTaskItem(t); }}
                                style={{
                                  fontSize: 10.5, padding: '2px 6px', borderRadius: 3, marginBottom: 2,
                                  background: isSub ? 'rgba(23,23,15,.05)' : 'rgba(23,23,15,.08)', color: 'var(--octale-navy)',
                                  whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', fontWeight: 600,
                                  cursor: 'grab', userSelect: 'none',
                                  ...(t._done ? { textDecoration: 'line-through', opacity: 0.5 } : {}),
                                }} title={chipTitle}>{chipLabel}</div>
                            );
                          })}
                          {overflow > 0 && (
                            <div
                              onClick={ev => {
                                ev.stopPropagation();
                                const rect = ev.currentTarget.getBoundingClientRect();
                                setOverflowPopover({ dStr, dayTasks, rect });
                              }}
                              style={{ fontSize: 10, color: 'var(--octale-navy)', fontWeight: 600, cursor: 'pointer', padding: '1px 5px', borderRadius: 3, background: 'rgba(23,23,15,.06)', userSelect: 'none', marginBottom: 2 }}>
                              +{overflow} tarefa{overflow > 1 ? 's' : ''}
                            </div>
                          )}
                        </>
                      );
                    })()}
                  </div>
                );
              });
            })()}
          </div>
        </div>
      )}

      {/* ====== DIA ====== */}
      {mode === 'dia' && (
        <div className="cal-dia-wrap">
          <div className="cal-week-grid" style={{ gridTemplateColumns: '60px 1fr' }}>
            <div className="cal-col-head" />
            <div className="cal-col-head today" style={{ flexDirection: 'row', alignItems: 'baseline', gap: 12 }}>
              <span className="num">{today.getDate()}</span>
              <span>{WEEK_DAYS_FULL[today.getDay()]} · {MONTHS_PT[today.getMonth()]} {today.getFullYear()}</span>
            </div>
            <div className="cal-time">
              {hours.map(h => <div className="cal-time-cell" key={h}>{String(h).padStart(2,'0')}:00</div>)}
            </div>
            <div className="cal-day">
              {hours.map(h => (
                <div
                  className="cal-day-cell"
                  key={h}
                  onClick={() => openNewAt(todayStr, h)}
                  style={{ cursor: 'pointer' }}
                  title={`Criar evento às ${String(h).padStart(2,'0')}:00`}
                />
              ))}
              {(() => {
                const nowTop = (new Date().getHours() + new Date().getMinutes() / 60 - 8) * 56;
                return nowTop > 0 ? <div className="cal-now" style={{ top: nowTop }} /> : null;
              })()}
              {(() => {
                const evLayout = computeEventLayout(todayEvents);
                return todayEvents.map((e, i) => {
                  const { leftPct, widthPct } = evLayout[i] || { leftPct: 0, widthPct: 1 };
                  const colLeft = `calc(${leftPct * 100}% + 8px)`;
                  const colWidth = `calc(${widthPct * 100}% - 16px)`;
                  return (
                    <div key={i} className={`cal-event ${e.type}`} onClick={ev => { ev.stopPropagation(); setSelectedEvent(e); }} style={{ ...getEventStyle(e), left: colLeft, width: colWidth, right: 'auto' }}>
                      <div style={{ fontWeight: 700, fontSize: 13, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{e.title}</div>
                      <div className="ev-time">{fmtHour(e.starts_at)} — {fmtHour(e.ends_at)}</div>
                      {e.guests_text && (
                        <div style={{ fontSize: 10, marginTop: 2, opacity: 0.8 }}>
                          👥 {e.guests_text.split(',').join(', ')}
                        </div>
                      )}
                    </div>
                  );
                });
              })()}
            </div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div className="panel">
              <div className="panel-head"><h3>Eventos de hoje</h3><span className="count">{todayEvents.length}</span></div>
              {todayEvents.length === 0 ? (
                <div style={{ padding: '16px 14px', fontSize: 12, color: 'var(--fg-muted)' }}>Sem eventos hoje.</div>
              ) : todayEvents.map((e, i) => (
                <div key={i} className="list-row" style={{ padding: '10px 14px' }}>
                  <div style={{ width: 3, alignSelf: 'stretch', borderRadius: 999, background: eventColors[e.type] || 'var(--octale-navy)' }} />
                  <div className="grow">
                    <div className="ttl" style={{ fontSize: 13 }}>{e.title}</div>
                    <div className="meta">{fmtHour(e.starts_at)} – {fmtHour(e.ends_at)} · {EVENT_LABELS[e.type]}</div>
                    {e.description && <div style={{ fontSize: 11, color: 'var(--fg-muted)', marginTop: 2 }}>{e.description}</div>}
                    {e.guests_text && <div style={{ fontSize: 11, color: 'var(--octale-navy)', marginTop: 2 }}>👥 {e.guests_text.split(',').join(', ')}</div>}
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      )}

      {loading && (
        <div style={{ position: 'fixed', bottom: 24, right: 24, background: 'var(--octale-navy)', color: '#fff', borderRadius: 6, padding: '8px 14px', fontSize: 12, display: 'flex', gap: 8, alignItems: 'center', zIndex: 100 }}>
          <span className="spinner" style={{ width: 12, height: 12, borderColor: 'rgba(255,255,255,.2)', borderTopColor: '#fff' }} /> Carregando eventos…
        </div>
      )}

      {(showNew || editingEvent) && (
        <NewEventModal
          onClose={() => { setShowNew(false); setEditingEvent(null); }}
          onCreated={(ev) => setEvents(prev => [...prev, ev])}
          onUpdated={(ev) => setEvents(prev => prev.map(x => x.id === ev.id ? ev : x))}
          clients={clients}
          cases={cases}
          users={users}
          defaultStart={newEventStart}
          defaultEnd={newEventEnd}
          editingEvent={editingEvent}
        />
      )}

      {/* ── Popup de detalhe do evento ── */}
      {selectedEvent && (
        <div className="scrim" onClick={() => setSelectedEvent(null)}>
          <div className="modal" onClick={e => e.stopPropagation()} style={{ maxWidth: 380 }}>
            <div className="modal-head">
              <div style={{ width: 8, alignSelf: 'stretch', borderRadius: 4, background: selectedEvent._google ? '#4285F4' : (eventColors[selectedEvent.type] || 'var(--octale-navy)'), flexShrink: 0 }} />
              <div style={{ flex: 1 }}>
                <h2 style={{ fontSize: 15, lineHeight: 1.3 }}>{selectedEvent.title}</h2>
                <div style={{ fontSize: 11.5, color: 'var(--fg-muted)', marginTop: 3 }}>
                  {selectedEvent.starts_at && fmtHour(selectedEvent.starts_at)}
                  {selectedEvent.ends_at && ` – ${fmtHour(selectedEvent.ends_at)}`}
                  {' · '}{selectedEvent._google ? 'Google Calendar' : (EVENT_LABELS[selectedEvent.type] || selectedEvent.type)}
                </div>
              </div>
              <button className="x" onClick={() => setSelectedEvent(null)}><Icon name="x" size={16} /></button>
            </div>
            {(selectedEvent.description || selectedEvent.guests_text) && (
              <div className="modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {selectedEvent.description && (
                  <p style={{ fontSize: 12.5, color: 'var(--fg-muted)', margin: 0, lineHeight: 1.6 }}>{selectedEvent.description}</p>
                )}
                {selectedEvent.guests_text && (
                  <div style={{ fontSize: 12, color: 'var(--octale-navy)' }}>
                    <Icon name="users" size={11} style={{ marginRight: 4 }} />
                    {selectedEvent.guests_text.split(',').join(', ')}
                  </div>
                )}
              </div>
            )}
            <div className="modal-foot">
              <button className="btn ghost sm" onClick={() => setSelectedEvent(null)}>Fechar</button>
              {!selectedEvent._google && (
                <>
                  <button
                    className="btn ghost sm"
                    style={{ color: '#C2253E' }}
                    onClick={async () => {
                      if (!confirm(`Excluir o evento "${selectedEvent.title}"?`)) return;
                      try {
                        await window.OctaleApi.events.delete(selectedEvent.id);
                        setEvents(prev => prev.filter(x => x.id !== selectedEvent.id));
                        setSelectedEvent(null);
                      } catch (e) {
                        alert(e.message || 'Erro ao excluir evento.');
                      }
                    }}>
                    <Icon name="trash2" size={12} /> Excluir
                  </button>
                  <button className="btn ghost sm" onClick={() => { setEditingEvent(selectedEvent); setSelectedEvent(null); }}>
                    <Icon name="edit2" size={12} /> Editar
                  </button>
                </>
              )}
              <button className="btn sm" onClick={() => { setTaskFromEvent(selectedEvent); setSelectedEvent(null); }}>
                <Icon name="checkSquare" size={12} /> Transformar em tarefa
              </button>
            </div>
          </div>
        </div>
      )}

      {/* ── Modal evento → tarefa ── */}
      {taskFromEvent && EventToTaskModal && (
        <EventToTaskModal
          event={taskFromEvent}
          clients={clients}
          cases={cases}
          users={users}
          onClose={() => setTaskFromEvent(null)}
          onCreated={(t) => { console.log('Tarefa criada:', t.id); }}
        />
      )}

      {/* ── Popover de overflow de tarefas do dia ── */}
      {overflowPopover && (() => {
        const { dStr, dayTasks, rect } = overflowPopover;
        const left = Math.min(rect.left, window.innerWidth - 280);
        const top = rect.bottom + 6;
        return ReactDOM.createPortal(
          <>
            <div onClick={() => setOverflowPopover(null)} style={{ position: 'fixed', inset: 0, zIndex: 498 }} />
            <div style={{
              position: 'fixed', top, left, zIndex: 499,
              background: '#fff', border: '1px solid #e0e0e8', borderRadius: 8,
              boxShadow: '0 8px 32px rgba(0,0,0,.16)',
              minWidth: 240, maxWidth: 320, maxHeight: 360, overflowY: 'auto',
            }}>
              <div style={{ padding: '8px 14px 6px', borderBottom: '1px solid #eeeef5', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                <span style={{ fontSize: 11.5, fontWeight: 700, color: 'var(--octale-navy)' }}>
                  {dayTasks.length} tarefa{dayTasks.length !== 1 ? 's' : ''} · {new Date(dStr + 'T12:00:00').toLocaleDateString('pt-BR', { weekday: 'short', day: '2-digit', month: '2-digit' })}
                </span>
                <button onClick={() => setOverflowPopover(null)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: '#aaa', padding: 0, lineHeight: 0 }}>
                  <Icon name="x" size={13} />
                </button>
              </div>
              {dayTasks.map(t => {
                const isSub = t._kind === 'subtask';
                return (
                  <div
                    key={t.id}
                    onClick={ev => { ev.stopPropagation(); setOverflowPopover(null); openTaskItem(t); }}
                    style={{
                      display: 'flex', flexDirection: 'column', gap: 1,
                      padding: '8px 14px', cursor: 'pointer', borderBottom: '1px solid #f5f5fa',
                      background: '#fff', transition: 'background .1s',
                      ...(t._done ? { opacity: 0.5 } : {}),
                    }}
                    onMouseEnter={e => { e.currentTarget.style.background = 'rgba(23,23,15,.04)'; }}
                    onMouseLeave={e => { e.currentTarget.style.background = '#fff'; }}
                  >
                    {isSub && t._parentTitle && (
                      <span style={{ fontSize: 10, color: 'var(--fg-muted)', fontWeight: 500, lineHeight: 1.3 }}>
                        {t._parentTitle}
                      </span>
                    )}
                    <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--octale-navy)', lineHeight: 1.4, textDecoration: t._done ? 'line-through' : 'none' }}>
                      {isSub ? '↳ ' : '⏰ '}{t.title}
                    </span>
                  </div>
                );
              })}
            </div>
          </>,
          document.body
        );
      })()}

      {/* ── Drawer de detalhe de tarefa (clique no chip do calendário) ── */}
      {selectedTask && (
        <TaskDetailDrawer
          task={selectedTask}
          clients={clients}
          cases={cases}
          users={users}
          clientMap={Object.fromEntries(clients.map(c => [c.id, c]))}
          userMap={Object.fromEntries(users.map(u => [u.id, u]))}
          allTags={allTags}
          cols={typeof DEFAULT_COLS !== 'undefined' ? DEFAULT_COLS : []}
          onClose={() => setSelectedTask(null)}
          onSaved={(updated) => {
            setTasks(prev => prev.map(t => t.id === updated.id ? { ...t, ...updated } : t));
            setSelectedTask(null);
          }}
          onDeleted={(id) => {
            setTasks(prev => prev.filter(t => t.id !== id));
            setSelectedTask(null);
          }}
          onTagsUpdated={() => {}}
        />
      )}
    </div>
  );
};

window.Calendar = Calendar;
