// Calendar views: Dashboard, Today, Week, Month + viz widgets
// Atoms (Pill, Icon, Panel, ApptRow, etc) come from shared.jsx
const { useState, useMemo, useEffect, useRef } = React;

// --- Financial widget --------------------------------------------------------
function FinancialWidget({ appointments, prices }) {
  const now = new Date();
  const ym = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
  const monthAppts = appointments.filter(a => a.date.startsWith(ym));
  const realized = monthAppts.filter(a => a.status === "realizado");
  const projected = monthAppts.filter(a => a.status === "agendado" || a.status === "confirmado");

  const sumOf = (arr) => arr.reduce((acc, a) => acc + (Number(a.price) || prices[a.type] || 0), 0);
  const realRev = sumOf(realized);
  const projRev = sumOf(projected);

  const byType = {};
  realized.forEach(a => {
    byType[a.type] = (byType[a.type] || 0) + (Number(a.price) || prices[a.type] || 0);
  });
  const maxType = Math.max(1, ...Object.values(byType), 1);

  return (
    <div className="finance">
      <div className="finance-totals">
        <div className="finance-cell">
          <div className="dim small">Realizado no mês</div>
          <div className="finance-val">{formatBRL(realRev)}</div>
          <div className="dim small">{realized.length} sessões concluídas</div>
        </div>
        <div className="finance-cell">
          <div className="dim small">Projetado</div>
          <div className="finance-val">{formatBRL(projRev)}</div>
          <div className="dim small">{projected.length} agendados/confirmados</div>
        </div>
        <div className="finance-cell">
          <div className="dim small">Total potencial</div>
          <div className="finance-val">{formatBRL(realRev + projRev)}</div>
          <div className="dim small">se nada cair</div>
        </div>
      </div>
      {Object.keys(byType).length > 0 && (
        <div className="finance-types">
          {Object.entries(byType).map(([t, v]) => (
            <div key={t} className="finance-type-row">
              <div className="finance-type-label">{t}</div>
              <div className="finance-type-track"><div className="finance-type-fill" style={{ width: `${(v / maxType) * 100}%`, background: TYPE_META[t]?.hue }} /></div>
              <div className="finance-type-val tabular">{formatBRL(v)}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// --- Time heatmap (day-of-week × hour) --------------------------------------
function TimeHeatmap({ appointments }) {
  const days = ["Seg","Ter","Qua","Qui","Sex","Sáb","Dom"];
  const hours = [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
  const counts = {};
  appointments.forEach(a => {
    const d = new Date(a.date + "T00:00:00");
    const dow = (d.getDay() + 6) % 7;
    const h = parseInt(a.time.split(":")[0]);
    if (h >= 8 && h <= 19) {
      const k = `${dow}-${h}`;
      counts[k] = (counts[k] || 0) + 1;
    }
  });
  const max = Math.max(1, ...Object.values(counts));

  return (
    <div className="heatmap">
      <div className="heatmap-corner" />
      {hours.map(h => <div key={"h"+h} className="heatmap-hh small dim tabular">{String(h).padStart(2,"0")}</div>)}
      {days.map((day, dow) => (
        <React.Fragment key={day}>
          <div className="heatmap-dd small dim">{day}</div>
          {hours.map(h => {
            const c = counts[`${dow}-${h}`] || 0;
            const alpha = c === 0 ? 0 : 0.15 + (c / max) * 0.75;
            return (
              <div
                key={`${dow}-${h}`}
                className="heatmap-cell"
                title={c > 0 ? `${day} ${h}h — ${c} ${c === 1 ? "atendimento" : "atendimentos"}` : `${day} ${h}h — livre`}
                style={{ background: c === 0 ? "var(--c-surface-2)" : `color-mix(in oklab, var(--c-accent) ${alpha * 100}%, transparent)` }}
              />
            );
          })}
        </React.Fragment>
      ))}
    </div>
  );
}

// --- Lead funnel -------------------------------------------------------------
function LeadFunnel({ people }) {
  const stages = [
    { key: "Lead frio", tone: "default" },
    { key: "Lead quente", tone: "accent" },
    { key: "Avaliando", tone: "warn" },
    { key: "Cliente", tone: "success" },
  ];
  const counts = stages.map(s => ({ ...s, n: people.filter(p => p.tag === s.key).length }));
  const total = counts.reduce((a, b) => a + b.n, 0) || 1;
  const max = Math.max(...counts.map(c => c.n), 1);

  return (
    <div className="funnel">
      {counts.map((s, i) => {
        const prev = i > 0 ? counts[i - 1].n : null;
        const rate = prev && prev > 0 ? Math.round((s.n / prev) * 100) : null;
        const width = (s.n / max) * 100;
        return (
          <div key={s.key} className="funnel-row">
            <div className="funnel-label">{s.key}</div>
            <div className="funnel-bar-wrap">
              <div className="funnel-bar" style={{ width: `${Math.max(8, width)}%` }} />
              <span className="funnel-val tabular">{s.n}</span>
            </div>
            <div className="funnel-rate dim small tabular">
              {rate !== null ? `${rate}%` : `${Math.round((s.n / total) * 100)}% do total`}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// --- Type distribution chart ------------------------------------------------
function TypeChart({ appointments }) {
  const counts = appointments.reduce((acc, a) => { acc[a.type] = (acc[a.type] || 0) + 1; return acc; }, {});
  const max = Math.max(1, ...Object.values(counts));
  return (
    <div className="bar-chart">
      {Object.entries(TYPE_META).map(([t, meta]) => {
        const c = counts[t] || 0;
        const pct = (c / max) * 100;
        return (
          <div key={t} className="bar-row">
            <div className="bar-label">{t}</div>
            <div className="bar-track"><div className="bar-fill" style={{ width: pct + "%", background: meta.hue }} /></div>
            <div className="bar-value tabular">{c}</div>
          </div>
        );
      })}
    </div>
  );
}

// --- Dashboard ---------------------------------------------------------------
function Dashboard({ store, go, openAppt }) {
  const { appointments, tasks, alerts, people, settings } = store.data;
  const todayAppts = appointments.filter(a => a.date === TODAY_ISO).sort((a,b) => a.time.localeCompare(b.time));
  const upcoming = appointments.filter(a => a.date >= TODAY_ISO && a.status !== "realizado" && a.status !== "cancelado").sort((a,b) => (a.date+a.time).localeCompare(b.date+b.time)).slice(0, 5);
  const pendingTasks = tasks.filter(t => t.priority !== "feito");
  const week = weekDates();
  const weekISOs = week.map(fmtISO);
  const weekAppts = appointments.filter(a => weekISOs.includes(a.date));

  const monthRealized = appointments.filter(a => {
    const ym = TODAY_ISO.slice(0,7);
    return a.date.startsWith(ym) && a.status === "realizado";
  });
  const monthRev = monthRealized.reduce((acc, a) => acc + (Number(a.price) || settings.prices[a.type] || 0), 0);

  return (
    <div className="view-wrap">
      <div className="metric-row">
        <Metric label="Atendimentos hoje" value={todayAppts.length} sub={`${todayAppts.filter(a=>a.status==="confirmado").length} confirmados`} accent="indigo" />
        <Metric label="Esta semana" value={weekAppts.length} sub="agendamentos no total" accent="blue" />
        <Metric label="Contatos ativos" value={people.length} sub={`${people.filter(p=>p.tag==="Cliente").length} clientes`} accent="green" />
        <Metric label="Faturamento do mês" value={formatBRL(monthRev)} sub={`${monthRealized.length} sessões concluídas`} accent="amber" mono />
        <Metric label="Alertas" value={alerts.length} sub={`${alerts.filter(a=>a.level==="alta").length} urgentes`} accent="red" />
      </div>

      <div className="grid-2">
        <Panel title="Próximos atendimentos" right={<button className="link" onClick={() => go("semana")}>Ver semana →</button>}>
          {upcoming.length === 0
            ? <EmptyState icon={<Icon name="today" size={28} />} title="Nenhum atendimento próximo" hint="Crie um novo agendamento para começar." />
            : <div className="list">
                {upcoming.map(a => <ApptRow key={a.id} a={a} people={people} compact onOpen={openAppt} />)}
              </div>}
        </Panel>

        <Panel title="Tarefas de hoje" right={<button className="link" onClick={() => go("tarefas")}>Kanban →</button>}>
          <div className="list">
            {pendingTasks.slice(0,6).map(t => (
              <div key={t.id} className="task-row">
                <span className="task-prio" data-prio={t.priority} />
                <div className="task-text">
                  <div className="task-title">{t.title}</div>
                  <div className="task-meta"><span>{t.category}</span>{t.note && <><span>·</span><span className="dim">{t.note}</span></>}</div>
                </div>
                <Pill tone={t.priority === "alta" ? "danger" : t.priority === "andamento" ? "warn" : "default"}>
                  {t.priority === "alta" ? "Alta" : t.priority === "andamento" ? "Em andamento" : "Depois"}
                </Pill>
              </div>
            ))}
          </div>
        </Panel>
      </div>

      <div className="grid-2">
        <Panel title="Financeiro do mês" right={<Pill tone="accent"><Icon name="money" size={11} /> Receita</Pill>}>
          <FinancialWidget appointments={appointments} prices={settings.prices} />
        </Panel>
        <Panel title="Funil de leads">
          <LeadFunnel people={people} />
        </Panel>
      </div>

      <div className="grid-2">
        <Panel title="Heatmap de horários" right={<span className="dim small">onde a agenda costuma encher</span>}>
          <TimeHeatmap appointments={appointments} />
        </Panel>
        <Panel title="Distribuição por tipo">
          <TypeChart appointments={appointments} />
        </Panel>
      </div>

      <Panel title="Alertas pendentes" right={<button className="link" onClick={() => go("alertas")}>Ver todos →</button>}>
        <div className="list">
          {alerts.slice(0,4).map(al => (
            <div key={al.id} className="alert-row">
              <Pill tone={al.level === "alta" ? "danger" : al.level === "média" ? "warn" : "default"}>
                {al.level}
              </Pill>
              <div className="alert-text">
                <div className="alert-title">{al.title}</div>
                <div className="alert-meta dim">{al.when}{al.note ? ` — ${al.note}` : ""}</div>
              </div>
            </div>
          ))}
          {alerts.length === 0 && <EmptyState icon={<Icon name="bell" size={28} />} title="Tudo sob controle" hint="Sem alertas pendentes." />}
        </div>
      </Panel>
    </div>
  );
}

function Metric({ label, value, sub, accent, mono }) {
  return (
    <div className="metric-card">
      <div className={`metric-bar a-${accent}`} />
      <div className="metric-label">{label}</div>
      <div className={`metric-value${mono ? " metric-value-mono" : ""}`}>{value}</div>
      <div className="metric-sub">{sub}</div>
    </div>
  );
}

// --- Hoje --------------------------------------------------------------------
function Today({ store, filters, openAppt, focusDate, setFocusDate }) {
  const { appointments, people } = store.data;
  const dateISO = focusDate || TODAY_ISO;
  const [dragInfo, setDragInfo] = useState(null); // { id, offsetMin }
  const [dropHint, setDropHint] = useState(null); // { top, time }
  const eventsRef = useRef(null);

  const items = appointments
    .filter(a => a.date === dateISO)
    .filter(a => filters.type === "all" || a.type === filters.type)
    .filter(a => filters.status === "all" || a.status === filters.status)
    .filter(a => filters.q ? matches(a, people, filters.q) : true)
    .sort((a,b) => a.time.localeCompare(b.time));

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

  const shift = (n) => {
    const d = new Date(dateISO + "T00:00:00");
    d.setDate(d.getDate() + n);
    setFocusDate(fmtISO(d));
  };

  // Compute minutes from drop position, snapped to 15-min
  const minutesFromY = (clientY) => {
    if (!eventsRef.current) return null;
    const rect = eventsRef.current.getBoundingClientRect();
    const y = clientY - rect.top;
    const totalMin = (y / 56) * 60;
    return Math.max(0, Math.round(totalMin / 15) * 15);
  };

  const minutesToTime = (min) => {
    const h = Math.floor(min / 60) + 7;
    const m = min % 60;
    return `${String(h).padStart(2,"0")}:${String(m).padStart(2,"0")}`;
  };

  const handleDragStart = (e, a) => {
    const [h, m] = a.time.split(":").map(Number);
    const startMin = (h - 7) * 60 + m;
    const rect = e.currentTarget.getBoundingClientRect();
    const offsetMin = ((e.clientY - rect.top) / 56) * 60;
    setDragInfo({ id: a.id, offsetMin, duration: a.duration });
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/plain", a.id);
  };

  const handleDragOver = (e) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
    if (!dragInfo) return;
    const dropMin = minutesFromY(e.clientY);
    if (dropMin === null) return;
    const startMin = Math.max(0, dropMin - Math.round(dragInfo.offsetMin / 15) * 15);
    setDropHint({ top: (startMin / 60) * 56, time: minutesToTime(startMin) });
  };

  const handleDragLeave = () => setDropHint(null);

  const handleDrop = (e) => {
    e.preventDefault();
    if (!dragInfo) return;
    const dropMin = minutesFromY(e.clientY);
    if (dropMin === null) return;
    const startMin = Math.max(0, dropMin - Math.round(dragInfo.offsetMin / 15) * 15);
    const newTime = minutesToTime(startMin);
    const appt = appointments.find(a => a.id === dragInfo.id);
    if (appt && appt.time !== newTime) {
      store.updateAppointment(dragInfo.id, { time: newTime });
    }
    setDragInfo(null);
    setDropHint(null);
  };

  const handleDragEnd = () => { setDragInfo(null); setDropHint(null); };

  const isToday = dateISO === TODAY_ISO;
  const headLabel = new Date(dateISO + "T00:00:00").toLocaleDateString("pt-BR", { weekday: "long", day: "2-digit", month: "long" });

  return (
    <div className="view-wrap">
      <Panel title={(isToday ? "Hoje · " : "") + headLabel.charAt(0).toUpperCase() + headLabel.slice(1)} right={
        <div className="nav-pager">
          <button className="icon-btn" onClick={() => shift(-1)} title="Dia anterior"><Icon name="chevL" size={14} /></button>
          <button className="btn btn-ghost small" onClick={() => setFocusDate(TODAY_ISO)} disabled={isToday}>Hoje</button>
          <button className="icon-btn" onClick={() => shift(1)} title="Próximo dia"><Icon name="chevR" size={14} /></button>
          <span className="nav-sep" />
          <Pill tone="accent">{items.length} atend.</Pill>
        </div>
      }>
        <div className="timeline">
          <div className="timeline-hours">
            {hours.map(h => <div key={h} className="hour-tick"><span>{String(h).padStart(2,"0")}:00</span></div>)}
          </div>
          <div
            className="timeline-events"
            ref={eventsRef}
            onDragOver={handleDragOver}
            onDragLeave={handleDragLeave}
            onDrop={handleDrop}
          >
            {items.length === 0 && <EmptyState icon={<Icon name="today" size={28} />} title="Sem atendimentos neste dia" hint="Use as setas para navegar." />}
            {dropHint && dragInfo && (
              <div className="timeline-drop-hint" style={{ top: dropHint.top, height: (dragInfo.duration / 60) * 56 }}>
                <span className="tabular">{dropHint.time}</span>
              </div>
            )}
            {items.map(a => {
              const [h, m] = a.time.split(":").map(Number);
              const startMin = (h - 7) * 60 + m;
              const top = (startMin / 60) * 56;
              const height = (a.duration / 60) * 56;
              const person = people.find(p => p.id === a.personId);
              const type = TYPE_META[a.type];
              const status = STATUS_META[a.status];
              const hasNotes = !!(a.notes && a.notes.trim());
              const isDragging = dragInfo?.id === a.id;
              return (
                <div
                  key={a.id}
                  className="timeline-event clickable"
                  draggable
                  data-dragging={isDragging ? "1" : undefined}
                  onClick={(e) => { if (!isDragging) openAppt && openAppt(a); }}
                  onDragStart={(e) => handleDragStart(e, a)}
                  onDragEnd={handleDragEnd}
                  style={{ top, height, borderLeftColor: type?.hue || "var(--c-fg-soft)" }}
                  title="Arraste para outro horário ou clique para editar"
                >
                  <div className="te-time tabular">{a.time} <span className="dim">· {a.duration}min</span></div>
                  <div className="te-title">{a.title}{hasNotes && <span className="note-mark inline" title="Possui anotações"><Icon name="note" size={11} /></span>}</div>
                  <div className="te-meta">{person?.name || "—"}<span className="dim"> · </span>{a.type}</div>
                  <div className="te-side">
                    <Pill tone={statusTone(a.status)}><Dot color={status.dot} />{status.label}</Pill>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </Panel>
    </div>
  );
}

// --- Semana (agenda + kanban) -----------------------------------------------
function Week({ store, filters, go, openAppt, weekCursor, setWeekCursor }) {
  const { appointments, people, tasks } = store.data;
  const ref = weekCursor ? new Date(weekCursor + "T00:00:00") : new Date();
  const week = weekDates(ref);
  const dayLabels = ["Seg","Ter","Qua","Qui","Sex","Sáb","Dom"];
  const [dragId, setDragId] = useState(null);
  const [overDay, setOverDay] = useState(null);

  const filtered = appointments
    .filter(a => filters.type === "all" || a.type === filters.type)
    .filter(a => filters.status === "all" || a.status === filters.status)
    .filter(a => filters.q ? matches(a, people, filters.q) : true);

  const shiftWeek = (n) => {
    const start = startOfWeek(ref);
    start.setDate(start.getDate() + 7 * n);
    setWeekCursor(fmtISO(start));
  };

  const onDragStart = (e, id) => {
    setDragId(id);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/plain", id);
  };
  const onDragOver = (e, iso) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
    setOverDay(iso);
  };
  const onDrop = (e, iso) => {
    e.preventDefault();
    const id = dragId || e.dataTransfer.getData("text/plain");
    if (id) {
      const a = appointments.find(x => x.id === id);
      if (a && a.date !== iso) store.updateAppointment(id, { date: iso });
    }
    setDragId(null); setOverDay(null);
  };
  const onDragEnd = () => { setDragId(null); setOverDay(null); };

  const rangeLabel = `${week[0].toLocaleDateString("pt-BR", { day: "2-digit", month: "short" })} — ${week[6].toLocaleDateString("pt-BR", { day: "2-digit", month: "short" })}`;
  const thisWeek = fmtISO(startOfWeek(new Date())) === fmtISO(week[0]);

  return (
    <div className="view-wrap">
      <div className="grid-week">
        <Panel title={`Semana · ${rangeLabel}`} right={
          <div className="nav-pager">
            <button className="icon-btn" onClick={() => shiftWeek(-1)} title="Semana anterior"><Icon name="chevL" size={14} /></button>
            <button className="btn btn-ghost small" onClick={() => setWeekCursor(fmtISO(startOfWeek(new Date())))} disabled={thisWeek}>Atual</button>
            <button className="icon-btn" onClick={() => shiftWeek(1)} title="Próxima semana"><Icon name="chevR" size={14} /></button>
            <span className="nav-sep" />
            <button className="link" onClick={() => go("agendar")}>+ novo</button>
          </div>
        }>
          <div className="week-grid">
            {week.map((d, idx) => {
              const iso = fmtISO(d);
              const items = filtered.filter(a => a.date === iso).sort((a,b) => a.time.localeCompare(b.time));
              const isToday = iso === TODAY_ISO;
              const isOver = overDay === iso;
              return (
                <div
                  key={iso}
                  className="week-day"
                  data-today={isToday ? "1" : undefined}
                  data-over={isOver ? "1" : undefined}
                  onDragOver={e => onDragOver(e, iso)}
                  onDragLeave={() => setOverDay(o => o === iso ? null : o)}
                  onDrop={e => onDrop(e, iso)}
                >
                  <div className="week-day-head">
                    <span className="dim">{dayLabels[idx]}</span>
                    <span className="week-daynum">{d.getDate()}</span>
                  </div>
                  <div className="week-day-body">
                    {items.length === 0 && <div className="week-empty">—</div>}
                    {items.map(a => {
                      const person = people.find(p => p.id === a.personId);
                      const type = TYPE_META[a.type];
                      const hasNotes = !!(a.notes && a.notes.trim());
                      const isDragging = dragId === a.id;
                      return (
                        <div
                          key={a.id}
                          className="week-card clickable"
                          draggable
                          data-dragging={isDragging ? "1" : undefined}
                          onClick={(e) => { if (!isDragging) openAppt && openAppt(a); }}
                          onDragStart={e => onDragStart(e, a.id)}
                          onDragEnd={onDragEnd}
                          style={{ borderLeftColor: type?.hue || "var(--c-fg-soft)" }}
                          title="Arraste para outro dia"
                        >
                          <div className="week-card-time tabular">{a.time}{hasNotes && <span className="note-mark inline"><Icon name="note" size={10} /></span>}</div>
                          <div className="week-card-title">{a.title}</div>
                          {person && <div className="week-card-meta dim">{person.name}</div>}
                        </div>
                      );
                    })}
                  </div>
                </div>
              );
            })}
          </div>
        </Panel>

        <Panel title="Tarefas em execução" right={<button className="link" onClick={() => go("tarefas")}>Kanban →</button>}>
          <KanbanMini tasks={tasks} />
        </Panel>
      </div>
    </div>
  );
}

function KanbanMini({ tasks }) {
  const lanes = [
    { key: "alta", label: "Alta", tone: "danger" },
    { key: "andamento", label: "Em andamento", tone: "warn" },
    { key: "depois", label: "Depois", tone: "default" },
  ];
  return (
    <div className="kanban-mini">
      {lanes.map(l => {
        const items = tasks.filter(t => t.priority === l.key);
        return (
          <div key={l.key} className="kanban-mini-col">
            <div className="kanban-mini-head"><Pill tone={l.tone}>{l.label}</Pill><span className="dim tabular">{items.length}</span></div>
            <div className="kanban-mini-list">
              {items.map(t => (
                <div key={t.id} className="kanban-mini-card">
                  <div>{t.title}</div>
                  <div className="dim">{t.category}</div>
                </div>
              ))}
              {items.length === 0 && <div className="dim small">vazio</div>}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// --- Mês ---------------------------------------------------------------------
function Month({ store, filters, openAppt, go, setFocusDate }) {
  const { appointments } = store.data;
  const [cursor, setCursor] = useState(() => { const d = new Date(); d.setDate(1); return d; });

  const firstDay = new Date(cursor.getFullYear(), cursor.getMonth(), 1);
  const startWeekday = (firstDay.getDay() + 6) % 7;
  const lastDate = new Date(cursor.getFullYear(), cursor.getMonth() + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < startWeekday; i++) cells.push(null);
  for (let d = 1; d <= lastDate; d++) cells.push(d);
  while (cells.length % 7 !== 0) cells.push(null);

  const monthLabel = cursor.toLocaleDateString("pt-BR", { month: "long", year: "numeric" });

  const filtered = appointments
    .filter(a => filters.type === "all" || a.type === filters.type)
    .filter(a => filters.status === "all" || a.status === filters.status);

  const focusDay = (iso) => {
    setFocusDate(iso);
    go("hoje");
  };

  return (
    <div className="view-wrap">
      <Panel title={monthLabel.charAt(0).toUpperCase() + monthLabel.slice(1)} right={
        <div className="nav-pager">
          <button className="icon-btn" onClick={() => setCursor(c => new Date(c.getFullYear(), c.getMonth() - 1, 1))}><Icon name="chevL" size={14} /></button>
          <button className="btn btn-ghost small" onClick={() => { const d = new Date(); d.setDate(1); setCursor(d); }}>Atual</button>
          <button className="icon-btn" onClick={() => setCursor(c => new Date(c.getFullYear(), c.getMonth() + 1, 1))}><Icon name="chevR" size={14} /></button>
        </div>
      }>
        <div className="month-grid">
          {["Seg","Ter","Qua","Qui","Sex","Sáb","Dom"].map(d => <div key={d} className="month-wd">{d}</div>)}
          {cells.map((d, i) => {
            if (d === null) return <div key={i} className="month-cell empty" />;
            const iso = fmtISO(new Date(cursor.getFullYear(), cursor.getMonth(), d));
            const items = filtered.filter(a => a.date === iso);
            const isToday = iso === TODAY_ISO;
            return (
              <div key={i} className="month-cell clickable" data-today={isToday ? "1" : undefined} onClick={() => focusDay(iso)} title="Abrir dia em foco">
                <div className="month-cell-head">
                  <span className="month-daynum">{d}</span>
                  {items.length > 0 && <span className="dim tabular">{items.length}</span>}
                </div>
                <div className="month-cell-body">
                  {items.slice(0,3).map(a => (
                    <div
                      key={a.id}
                      className="month-pill clickable"
                      onClick={(e) => { e.stopPropagation(); openAppt && openAppt(a); }}
                      style={{ background: `color-mix(in oklab, ${TYPE_META[a.type]?.hue || "var(--c-fg-soft)"} 16%, transparent)`, color: TYPE_META[a.type]?.hue || "var(--c-fg)" }}
                    >
                      <span className="tabular">{a.time}</span> {a.title}
                    </div>
                  ))}
                  {items.length > 3 && <div className="dim small">+{items.length - 3} mais</div>}
                </div>
              </div>
            );
          })}
        </div>
      </Panel>
    </div>
  );
}

Object.assign(window, {
  Dashboard, Today, Week, Month,
  FinancialWidget, TimeHeatmap, LeadFunnel, TypeChart, KanbanMini, Metric,
});
