// Reports view — análise funcional para tomada de decisão
function Reports({ ws, accent, currentMonth }) {
  const txns = ws.transactions || [];
  const recs = ws.receitas || [];

  // ===== 12-month series =====
  const months12 = [];
  for (let i = 11; i >= 0; i--) {
    const d = new Date(currentMonth.year, currentMonth.month - i, 1);
    const y = d.getFullYear(), m = d.getMonth();
    const monthIn = recs.filter(r => { const dd = new Date(r.date); return dd.getFullYear() === y && dd.getMonth() === m; }).reduce((s, r) => s + (Number(r.value) || 0), 0);
    const monthOut = txns.filter(t => { const dd = new Date(t.date); return dd.getFullYear() === y && dd.getMonth() === m; }).reduce((s, t) => s + (Number(t.value) || 0), 0);
    months12.push({ label: monthLabel(m), in: monthIn, out: monthOut, year: y, monthIdx: m });
  }

  // ===== Detecção de despesas fixas (recorrentes em 3+ meses) =====
  const recurMap = {};
  txns.forEach(t => {
    const key = (t.desc || "").trim().toUpperCase();
    if (!key) return;
    const monthKey = new Date(t.date).toISOString().slice(0, 7);
    if (!recurMap[key]) recurMap[key] = { months: new Set(), values: [], lastDate: t.date, category: t.category };
    recurMap[key].months.add(monthKey);
    recurMap[key].values.push(Number(t.value) || 0);
    if (new Date(t.date) > new Date(recurMap[key].lastDate)) recurMap[key].lastDate = t.date;
  });
  const fixedKeys = new Set(Object.entries(recurMap).filter(([_, v]) => v.months.size >= 3).map(([k]) => k));
  const fixedDescs = Object.entries(recurMap)
    .filter(([_, v]) => v.months.size >= 3)
    .map(([desc, v]) => ({ desc, count: v.months.size, avg: v.values.reduce((s, x) => s + x, 0) / v.values.length, total: v.values.reduce((s, x) => s + x, 0), category: v.category }))
    .sort((a, b) => b.avg - a.avg);
  const recurringMonthly = fixedDescs.reduce((s, r) => s + r.avg, 0);

  // Por mês: fixas vs variáveis
  const monthsFixedVar = months12.map(m => {
    const monthTxns = txns.filter(t => {
      const dd = new Date(t.date);
      return dd.getFullYear() === m.year && dd.getMonth() === m.monthIdx;
    });
    const fixed = monthTxns.filter(t => fixedKeys.has((t.desc || "").trim().toUpperCase())).reduce((s, t) => s + (Number(t.value) || 0), 0);
    const variable = monthTxns.reduce((s, t) => s + (Number(t.value) || 0), 0) - fixed;
    return { label: m.label, fixed, variable };
  });

  // ===== Totais e médias =====
  const totalAll = txns.reduce((s, t) => s + (Number(t.value) || 0), 0);
  const totalRec = recs.reduce((s, r) => s + (Number(r.value) || 0), 0);
  const avgMonth = totalAll / 12;
  const avgRec = totalRec / 12;

  // ===== Insights =====
  const cur = months12[months12.length - 1] || { in: 0, out: 0 };
  const prev = months12[months12.length - 2] || { in: 0, out: 0 };
  const outDelta = prev.out > 0 ? ((cur.out - prev.out) / prev.out) * 100 : (cur.out > 0 ? 100 : 0);
  const inDelta  = prev.in  > 0 ? ((cur.in  - prev.in)  / prev.in)  * 100 : (cur.in  > 0 ? 100 : 0);
  const monthsWithData = months12.filter(m => m.in > 0 || m.out > 0);
  const balances = monthsWithData.map(m => ({ ...m, bal: m.in - m.out }));
  const bestMonth = balances.length ? [...balances].sort((a, b) => b.bal - a.bal)[0] : null;
  const worstMonth = balances.length ? [...balances].sort((a, b) => a.bal - b.bal)[0] : null;
  const savingsRate = totalRec > 0 ? ((totalRec - totalAll) / totalRec) * 100 : 0;
  const reserve = Math.max(0, totalRec - totalAll);
  const burnMonths = avgMonth > 0 ? reserve / avgMonth : 0;

  const today = new Date();
  const in30 = new Date(); in30.setDate(in30.getDate() + 30);
  const upcoming = txns
    .filter(t => (t.status === "PENDENTE" || t.status === "AGENDADO") && new Date(t.date) >= today && new Date(t.date) <= in30)
    .sort((a, b) => new Date(a.date) - new Date(b.date))
    .slice(0, 5);

  // ===== Análise de Receitas =====
  const recCount = recs.length;
  const ticketAvg = recCount > 0 ? totalRec / recCount : 0;
  // Receita recorrente (mesmo cliente/origem em 2+ meses)
  const recOriginMap = {};
  recs.forEach(r => {
    const key = (r.client || r.desc || "").trim().toUpperCase();
    if (!key) return;
    const monthKey = new Date(r.date).toISOString().slice(0, 7);
    if (!recOriginMap[key]) recOriginMap[key] = { months: new Set(), values: [], desc: r.client || r.desc };
    recOriginMap[key].months.add(monthKey);
    recOriginMap[key].values.push(r.value);
  });
  const recurringClients = Object.values(recOriginMap).filter(c => c.months.size >= 2);
  const recurringRevTotal = recurringClients.reduce((s, c) => s + c.values.reduce((a, b) => a + (Number(b) || 0), 0), 0);
  const oneTimeRevTotal = totalRec - recurringRevTotal;
  const topClients = Object.values(recOriginMap)
    .map(c => ({ desc: c.desc, total: c.values.reduce((a, b) => a + (Number(b) || 0), 0), count: c.values.length, recurrent: c.months.size >= 2 }))
    .sort((a, b) => b.total - a.total)
    .slice(0, 5);

  // ===== Vitalidade financeira (4 métricas, separadas por tipo de conta) =====
  const isBusiness = ws.type !== "personal";

  // Métricas brutas
  const avgBal = monthsWithData.length > 0
    ? monthsWithData.reduce((s, m) => s + (m.in - m.out), 0) / monthsWithData.length
    : 0;
  const avgIn = monthsWithData.length > 0
    ? monthsWithData.reduce((s, m) => s + m.in, 0) / monthsWithData.length
    : 0;

  // Últimos 3 meses vs 3 anteriores (pra tendência)
  const last3 = months12.slice(-3).filter(m => m.in > 0 || m.out > 0);
  const prev3 = months12.slice(-6, -3).filter(m => m.in > 0 || m.out > 0);
  const avg3Bal = last3.length > 0 ? last3.reduce((s, m) => s + (m.in - m.out), 0) / last3.length : 0;
  const avgPrev3Bal = prev3.length > 0 ? prev3.reduce((s, m) => s + (m.in - m.out), 0) / prev3.length : 0;
  const avg3Out = last3.length > 0 ? last3.reduce((s, m) => s + m.out, 0) / last3.length : avgMonth;
  const trend3m = avgPrev3Bal !== 0 ? ((avg3Bal - avgPrev3Bal) / Math.abs(avgPrev3Bal)) * 100 : 0;

  const reserveMonths = avg3Out > 0 ? reserve / avg3Out : 0;
  const curBal = cur.in - cur.out;
  const fixedShareOfIncome = avgIn > 0 ? (recurringMonthly / avgIn) * 100 : 0;
  const periodMargin = totalRec > 0 ? ((totalRec - totalAll) / totalRec) * 100 : 0;
  const topClientShare = topClients[0] && totalRec > 0 ? (topClients[0].total / totalRec) * 100 : 0;
  const recurringShare = totalRec > 0 ? (recurringRevTotal / totalRec) * 100 : 0;

  const overdueCount = txns.filter(t => t.status === "PENDENTE" && new Date(t.date) < today).length;
  const totalUnpaid = txns.filter(t => t.status === "PENDENTE" || t.status === "AGENDADO").length;
  const totalPaid = txns.filter(t => t.status === "PAGO").length;

  const trendIcon = Math.abs(trend3m) < 5 ? "→" : trend3m > 0 ? "↑" : "↓";

  const vitalityMetrics = isBusiness ? [
    {
      label: "Margem do período",
      value: `${periodMargin.toFixed(1)}%`,
      sub: periodMargin >= 15 ? "Saudável — sobra confortável" : periodMargin >= 5 ? "Apertada, vale revisar custos" : "Negativa — atenção urgente",
      tone: periodMargin >= 15 ? "pos" : periodMargin >= 5 ? "warn" : "neg",
    },
    {
      label: "Caixa em meses",
      value: `${reserveMonths.toFixed(1)}m`,
      sub: avg3Out > 0 ? `Custo médio ${fmtBRL(avg3Out)}/mês` : "Sem dados de custo",
      tone: reserveMonths >= 3 ? "pos" : reserveMonths >= 1 ? "warn" : "neg",
    },
    {
      label: "Concentração de cliente",
      value: topClients[0] ? `${topClientShare.toFixed(0)}%` : "—",
      sub: topClients[0] ? `Topo: ${(topClients[0].desc || "").slice(0, 22)}` : "Sem clientes ainda",
      tone: !topClients[0] ? "neutral" : topClientShare < 30 ? "pos" : topClientShare < 50 ? "warn" : "neg",
    },
    {
      label: "Receita recorrente",
      value: totalRec > 0 ? `${recurringShare.toFixed(0)}%` : "—",
      sub: totalRec > 0 ? `${fmtBRL(recurringRevTotal)} previsíveis` : "Sem receitas ainda",
      tone: totalRec === 0 ? "neutral" : recurringShare >= 50 ? "pos" : recurringShare >= 25 ? "warn" : "neg",
    },
  ] : [
    {
      label: "Sobra do mês",
      value: fmtBRL(curBal),
      sub: avg3Bal !== 0 ? `Média 3 meses: ${fmtBRL(avg3Bal)}` : "Sem histórico suficiente",
      tone: curBal > 0 ? "pos" : curBal < 0 ? "neg" : "neutral",
    },
    {
      label: "Reserva de emergência",
      value: `${reserveMonths.toFixed(1)}m`,
      sub: reserveMonths >= 3 ? "Saudável — meta atingida" : reserveMonths >= 1 ? "Construa até 3 meses" : "Sem reserva real ainda",
      tone: reserveMonths >= 3 ? "pos" : reserveMonths >= 1 ? "warn" : "neg",
    },
    {
      label: "Compromisso fixo",
      value: avgIn > 0 ? `${fixedShareOfIncome.toFixed(0)}%` : "—",
      sub: avgIn > 0 ? `${fmtBRL(recurringMonthly)} já comprometidos/mês` : "Sem renda detectada",
      tone: avgIn === 0 ? "neutral" : fixedShareOfIncome < 50 ? "pos" : fixedShareOfIncome < 70 ? "warn" : "neg",
    },
    {
      label: "Tendência 3 meses",
      value: last3.length === 0 || avgPrev3Bal === 0 ? "—" : `${trendIcon} ${Math.abs(trend3m).toFixed(0)}%`,
      sub: last3.length === 0 ? "Sem dados ainda" : Math.abs(trend3m) < 5 ? "Estável" : trend3m > 0 ? "Sua sobra está melhorando" : "Sua sobra está piorando",
      tone: last3.length === 0 ? "neutral" : trend3m > 5 ? "pos" : Math.abs(trend3m) <= 5 ? "neutral" : "neg",
    },
  ];

  // ===== Sinais (max 3, filtrados pra eliminar ruído) =====
  const allSignals = [];

  // Variação de despesas — só se baseline >= R$ 100 e variação < 200% (evita ruído de mês vazio)
  if (prev.out >= 100 && Math.abs(outDelta) < 200 && Math.abs(outDelta) >= 8) {
    allSignals.push({
      tone: outDelta > 0 ? "warn" : "good",
      title: outDelta > 0
        ? `Despesas subiram ${outDelta.toFixed(0)}% vs ${prev.label}`
        : `Despesas caíram ${Math.abs(outDelta).toFixed(0)}% vs ${prev.label}`,
      sub: `${fmtBRL(prev.out)} → ${fmtBRL(cur.out)}`,
    });
  }

  // Contas a vencer (30d)
  if (upcoming.length > 0) {
    const total = upcoming.reduce((s, u) => s + (Number(u.value) || 0), 0);
    allSignals.push({
      tone: "risk",
      title: `${upcoming.length} contas a vencer em 30 dias`,
      sub: `Total: ${fmtBRL(total)}${upcoming[0] ? ` · próxima: ${(upcoming[0].desc || "").slice(0, 24)}` : ""}`,
    });
  }

  // Atrasados
  if (overdueCount > 0) {
    allSignals.push({
      tone: "risk",
      title: `${overdueCount} pendência${overdueCount > 1 ? "s" : ""} atrasada${overdueCount > 1 ? "s" : ""}`,
      sub: "Vencimento passou e ainda não foi paga",
    });
  }

  // Compromisso fixo alto (PF)
  if (!isBusiness && avgIn > 0 && fixedShareOfIncome >= 60) {
    allSignals.push({
      tone: "warn",
      title: `${fixedShareOfIncome.toFixed(0)}% da sua renda já tem dono`,
      sub: `${fmtBRL(recurringMonthly)} em fixos antes do mês começar`,
    });
  }

  // Reserva curta (PF)
  if (!isBusiness && reserveMonths < 1 && totalRec > 0) {
    allSignals.push({
      tone: "risk",
      title: "Reserva abaixo de 1 mês de gastos",
      sub: `Ideal: 3 meses (~${fmtBRL(avg3Out * 3)})`,
    });
  }

  // Concentração alta (PJ)
  if (isBusiness && topClientShare > 50 && topClients[0]) {
    allSignals.push({
      tone: "warn",
      title: `${topClientShare.toFixed(0)}% da receita vem de 1 cliente`,
      sub: `${(topClients[0].desc || "").slice(0, 32)} é seu cliente mais concentrado`,
    });
  }

  // Vitória positiva (PF) — taxa de economia boa
  if (!isBusiness && savingsRate >= 20) {
    allSignals.push({
      tone: "good",
      title: `Você poupa ${savingsRate.toFixed(0)}% do que entra`,
      sub: "Taxa de economia bem acima da média brasileira",
    });
  }

  const topSignals = allSignals.slice(0, 3);

  // ===== Top subcategorias (gastos agrupados por nome — Uber, Restaurante, Aluguel...) =====
  const subAgg = {};
  txns.forEach(t => {
    const sub = (t.subcategory || "").trim();
    if (!sub) return;
    if (!subAgg[sub]) subAgg[sub] = { total: 0, count: 0, category: t.category || "Outros" };
    subAgg[sub].total += Number(t.value) || 0;
    subAgg[sub].count += 1;
  });
  const topSubcategories = Object.entries(subAgg)
    .map(([name, d]) => ({ name, total: d.total, count: d.count, category: d.category, avg: d.total / d.count }))
    .sort((a, b) => b.total - a.total)
    .slice(0, 12);

  // ===== Análise com IA (cache 24h em localStorage + auto-trigger na 1ª vez) =====
  // Chave isolada por workspace + período. Se ws.key for vazio NÃO cacheamos (evita vazar entre contas).
  const aiCacheKey = ws.key
    ? `ai_diagnosis_${ws.key}_${currentMonth.year}_${currentMonth.month}`
    : null;
  const [aiAnalysis, setAiAnalysis] = React.useState(null);
  const [aiLoading, setAiLoading] = React.useState(false);
  const [aiError, setAiError] = React.useState(null);

  // Limpa caches antigos contaminados (chaves criadas com fallback "x" que vazaram entre contas)
  React.useEffect(() => {
    try {
      Object.keys(localStorage).forEach(k => {
        if (k.startsWith("ai_diagnosis_x_")) localStorage.removeItem(k);
      });
    } catch (e) {}
  }, []);

  // Recarrega o cache do localStorage SEMPRE que a workspace ou o período mudar.
  // Reset prévio garante que o diagnóstico da conta anterior nunca persiste.
  React.useEffect(() => {
    setAiAnalysis(null);
    setAiError(null);
    if (!aiCacheKey) return;
    try {
      const raw = localStorage.getItem(aiCacheKey);
      if (!raw) return;
      const obj = JSON.parse(raw);
      if (Date.now() - obj.ts > 24 * 60 * 60 * 1000) {
        localStorage.removeItem(aiCacheKey);
        return;
      }
      setAiAnalysis(obj.data);
    } catch (e) { /* ignora */ }
  }, [aiCacheKey]);

  const runAiAnalysis = React.useCallback(async () => {
    setAiLoading(true);
    setAiError(null);
    try {
      const summary = buildFinanceSummary({
        ws, txns, recs, months12, totalAll, totalRec, savingsRate,
        reserve, burnMonths, fixedDescs, recurringMonthly,
        topSubcategories, upcoming,
        totalPaid, totalUnpaid, overdueCount,
      });
      const result = await aiAnalyzeFinances(summary, ws);
      const stamped = { ...result, generatedAt: new Date().toISOString() };
      setAiAnalysis(stamped);
      if (aiCacheKey) {
        try { localStorage.setItem(aiCacheKey, JSON.stringify({ ts: Date.now(), data: stamped })); } catch (e) {}
      }
    } catch (e) {
      console.error("[IA Diagnóstico] erro:", e);
      setAiError(e?.message || String(e));
    } finally {
      setAiLoading(false);
    }
  }, [aiCacheKey, ws, txns.length, recs.length, currentMonth.year, currentMonth.month]);

  // Auto-roda na 1ª vez se: tem >=30 lançamentos, IA configurada, sem cache válido
  React.useEffect(() => {
    if (aiAnalysis || aiLoading) return;
    const total = txns.length + recs.length;
    if (total < 30) return;
    let cancelled = false;
    window.db.getAiConfig().then(({ key }) => {
      if (cancelled || !key) return;
      runAiAnalysis();
    });
    return () => { cancelled = true; };
  }, [aiAnalysis, aiLoading, txns.length, recs.length, runAiAnalysis]);

  const clearAiAnalysis = () => {
    setAiAnalysis(null);
    setAiError(null);
    if (aiCacheKey) {
      try { localStorage.removeItem(aiCacheKey); } catch (e) {}
    }
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      {/* Linha 1: Painel de Vitalidade (4 métricas separadas por tipo de conta) */}
      <VitalityPanel metrics={vitalityMetrics} isBusiness={isBusiness} accent={accent} />

      {/* Linha 2: Diagnóstico IA (resposta enxuta + botão analisar/expandir) */}
      <AiDiagnosisCard
        accent={accent}
        analysis={aiAnalysis}
        loading={aiLoading}
        error={aiError}
        onRun={runAiAnalysis}
        onClear={clearAiAnalysis}
      />

      {/* Linha 3: Sinais (max 3) + Insights mecânicos antigos como fallback (extras) */}
      {topSignals.length > 0 && <SignalsPanel signals={topSignals} accent={accent} />}

      {/* Linha 2: KPIs */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14 }}>
        <KPI title="Total despesas (12m)" value={fmtBRL(totalAll)} icon="arrowUp" tone="neg" sub={`média ${fmtBRL(avgMonth)}/mês`} />
        <KPI title="Total receitas (12m)" value={fmtBRL(totalRec)} icon="arrowDown" tone="pos" sub={`média ${fmtBRL(avgRec)}/mês`} />
        <KPI title="Saldo acumulado" value={fmtBRL(totalRec - totalAll)} icon="wallet" tone={totalRec > totalAll ? "pos" : "neg"} sub={`${savingsRate.toFixed(1)}% taxa de economia`} />
        <KPI title="Compromisso fixo/mês" value={fmtBRL(recurringMonthly)} icon="calendar" tone="warn" sub={`${fixedDescs.length} despesas recorrentes`} />
      </div>

      {/* Linha 3: Fluxo de caixa + Destaques */}
      <div style={{ display: "grid", gridTemplateColumns: "1.7fr 1fr", gap: 14, alignItems: "stretch" }}>
        <div className="card" style={{ padding: 18 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14 }}>
            <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Fluxo de caixa · 12 meses</h3>
            <span style={{ fontSize: 11, color: "var(--fg-3)" }}>Receita vs Despesa + Saldo acumulado</span>
          </div>
          <CashflowCombo months={months12} accent={accent} />
        </div>
        <PeriodHighlights
          accent={accent}
          months12={months12}
          bestMonth={bestMonth}
          worstMonth={worstMonth}
          biggestTxn={[...txns].sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))[0]}
          biggestRec={[...recs].sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))[0]}
          recurringMonthly={recurringMonthly}
          outDelta={outDelta}
          inDelta={inDelta}
          totalAll={totalAll}
          totalRec={totalRec}
        />
      </div>

      {/* Linha 4: Fixas vs Variáveis + Análise de receitas */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, alignItems: "start" }}>
        <div className="card" style={{ padding: 18 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 6 }}>
            <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Fixas vs Variáveis</h3>
            <div style={{ display: "flex", gap: 12, fontSize: 11, color: "var(--fg-3)" }}>
              <span style={{ display: "flex", alignItems: "center", gap: 4 }}>
                <span style={{ width: 9, height: 9, background: "var(--fg-1)", opacity: 0.85, borderRadius: 2 }}></span>Fixas
              </span>
              <span style={{ display: "flex", alignItems: "center", gap: 4 }}>
                <span style={{ width: 9, height: 9, background: accent, opacity: 0.6, borderRadius: 2 }}></span>Variáveis
              </span>
            </div>
          </div>
          <div style={{ fontSize: 11.5, color: "var(--fg-3)", marginBottom: 12 }}>
            Compromisso fixo identificado por recorrência (3+ meses)
          </div>
          <StackedBars months={monthsFixedVar} accent={accent} />
          {fixedDescs.length > 0 && (
            <div style={{ marginTop: 14, paddingTop: 14, borderTop: "1px solid var(--border)" }}>
              <div style={{ fontSize: 11.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, marginBottom: 8, fontWeight: 500 }}>Despesas fixas detectadas</div>
              <div style={{ display: "flex", flexDirection: "column", gap: 6, maxHeight: 160, overflow: "auto" }}>
                {fixedDescs.slice(0, 6).map((f, i) => (
                  <div key={i} style={{ display: "flex", justifyContent: "space-between", fontSize: 12, padding: "4px 0" }}>
                    <span style={{ color: "var(--fg-1)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1, marginRight: 8 }}>{f.desc}</span>
                    <span style={{ color: "var(--fg-3)", fontVariantNumeric: "tabular-nums" }}>{f.count}× · </span>
                    <span style={{ color: "var(--fg-1)", fontVariantNumeric: "tabular-nums", fontWeight: 500, marginLeft: 4 }}>{fmtBRL(f.avg)}</span>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>

        <RevenueAnalysis
          accent={accent}
          totalRec={totalRec}
          ticketAvg={ticketAvg}
          recCount={recCount}
          recurringRevTotal={recurringRevTotal}
          oneTimeRevTotal={oneTimeRevTotal}
          topClients={topClients}
          months12={months12}
        />
      </div>

      {/* Linha 5: Top subcategorias — onde você gasta agrupado por nome */}
      {topSubcategories.length > 0 && (
        <SubcategoryPanel items={topSubcategories} accent={accent} totalAll={totalAll} />
      )}
    </div>
  );
}

// ===== Painel: Top subcategorias =====
function SubcategoryPanel({ items, accent, totalAll }) {
  const max = items[0]?.total || 1;
  return (
    <div className="card" style={{ padding: 18 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 4 }}>
        <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Onde você gasta — detalhado</h3>
        <span style={{ fontSize: 11, color: "var(--fg-3)" }}>Top {items.length} subcategorias</span>
      </div>
      <div style={{ fontSize: 11.5, color: "var(--fg-3)", marginBottom: 14 }}>
        Lançamentos agrupados pelo nome do gasto (ex: Uber, Restaurante, Netflix). A IA detecta isso na importação.
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px 24px" }}>
        {items.map((s, i) => {
          const pct = (s.total / max) * 100;
          const sharePct = totalAll > 0 ? (s.total / totalAll) * 100 : 0;
          return (
            <div key={s.name} style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 8 }}>
                <span style={{ fontSize: 13, fontWeight: 500, color: "var(--fg-1)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {s.name}
                </span>
                <span style={{ fontSize: 12.5, fontVariantNumeric: "tabular-nums", color: "var(--fg-1)", fontWeight: 600 }}>
                  {fmtBRL(s.total)}
                </span>
              </div>
              <div style={{ height: 5, background: "var(--surface-2)", borderRadius: 999, overflow: "hidden" }}>
                <div style={{ width: `${pct}%`, height: "100%", background: accent, borderRadius: 999, transition: "width .6s" }} />
              </div>
              <div style={{ fontSize: 10.5, color: "var(--fg-3)", display: "flex", justifyContent: "space-between" }}>
                <span>{s.count}× · média {fmtBRL(s.avg)}{s.category ? ` · ${s.category}` : ""}</span>
                <span>{sharePct.toFixed(1)}% do total</span>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ===== Health Score Card =====
function HealthCard({ score, breakdown, accent, subtitle }) {
  const tone = score >= 75 ? "var(--success)" : score >= 50 ? "var(--warn)" : "var(--danger)";
  const label = score >= 85 ? "Excelente" : score >= 70 ? "Saudável" : score >= 50 ? "Atenção" : score >= 30 ? "Crítico" : "Vermelho";
  const size = 140, stroke = 14, r = (size - stroke) / 2, cx = size / 2, cy = size / 2;
  const C = 2 * Math.PI * r;
  const dash = (score / 100) * C;

  return (
    <div className="card" style={{ padding: 18, display: "flex", flexDirection: "column" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 10 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <span style={{
            width: 28, height: 28, borderRadius: 8,
            background: `color-mix(in oklab, ${accent} 14%, transparent)`,
            color: accent, display: "flex", alignItems: "center", justifyContent: "center"
          }}>
            <Icon name="target" size={15} />
          </span>
          <div>
            <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Health Score</h3>
            <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, marginTop: 2 }}>
              {subtitle || "Saúde financeira"}
            </div>
          </div>
        </div>
      </div>

      <div style={{ display: "flex", alignItems: "center", gap: 18, marginTop: 4 }}>
        <div style={{ position: "relative", width: size, height: size, flexShrink: 0 }}>
          <svg width={size} height={size} style={{ transform: "rotate(-90deg)" }}>
            <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--border)" strokeWidth={stroke} />
            <circle cx={cx} cy={cy} r={r} fill="none" stroke={tone} strokeWidth={stroke}
              strokeDasharray={`${dash} ${C - dash}`} strokeLinecap="round"
              style={{ transition: "stroke-dasharray .8s cubic-bezier(.2,.8,.2,1)" }} />
          </svg>
          <div style={{ position: "absolute", inset: 0, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
            <span style={{ fontSize: 36, fontWeight: 700, color: "var(--fg-1)", lineHeight: 1, fontVariantNumeric: "tabular-nums", letterSpacing: -1 }}>{score}</span>
            <span style={{ fontSize: 10, color: "var(--fg-3)", marginTop: 2, textTransform: "uppercase", letterSpacing: 0.8 }}>de 100</span>
          </div>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: "inline-block", fontSize: 11, fontWeight: 600, color: tone, background: `color-mix(in oklab, ${tone} 12%, transparent)`, padding: "4px 10px", borderRadius: 999, letterSpacing: 0.4, textTransform: "uppercase", marginBottom: 10 }}>{label}</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {breakdown.map((b, i) => {
              const pct = (b.score / b.max) * 100;
              const c = pct >= 75 ? "var(--success)" : pct >= 50 ? "var(--warn)" : "var(--danger)";
              return (
                <div key={i}>
                  <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, marginBottom: 2 }}>
                    <span style={{ color: "var(--fg-2)" }}>{b.label}</span>
                    <span style={{ color: "var(--fg-1)", fontVariantNumeric: "tabular-nums", fontWeight: 500 }}>{b.score}/{b.max}</span>
                  </div>
                  <div style={{ height: 4, background: "var(--surface-2)", borderRadius: 999, overflow: "hidden" }}>
                    <div style={{ width: `${pct}%`, height: "100%", background: c, borderRadius: 999, transition: "width .8s cubic-bezier(.2,.8,.2,1)" }} />
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

// ===== Insights Panel (compactado) =====
function InsightsPanel({ accent, outDelta, inDelta, bestMonth, worstMonth, savingsRate, recurringMonthly, fixedDescs, burnMonths, reserve, upcoming }) {
  const insights = [];

  if (Math.abs(outDelta) > 1) {
    const up = outDelta > 0;
    insights.push({
      icon: up ? "arrowUp" : "arrowDown",
      tone: up ? "neg" : "pos",
      title: `Despesas ${up ? "subiram" : "caíram"} ${Math.abs(outDelta).toFixed(0)}%`,
      sub: "vs. mês anterior",
      metric: `${up ? "+" : "−"}${Math.abs(outDelta).toFixed(1)}%`,
    });
  }
  if (Math.abs(inDelta) > 1) {
    const up = inDelta > 0;
    insights.push({
      icon: up ? "arrowUp" : "arrowDown",
      tone: up ? "pos" : "warn",
      title: `Receitas ${up ? "cresceram" : "recuaram"} ${Math.abs(inDelta).toFixed(0)}%`,
      sub: "vs. mês anterior",
      metric: `${up ? "+" : "−"}${Math.abs(inDelta).toFixed(1)}%`,
    });
  }
  if (reserve > 0 && burnMonths > 0) {
    insights.push({
      icon: "spark",
      tone: burnMonths >= 3 ? "pos" : "warn",
      title: `Reserva cobre ${burnMonths.toFixed(1)} meses`,
      sub: burnMonths >= 6 ? "Excelente fôlego" : burnMonths >= 3 ? "Confortável" : "Recomendado 3+ meses",
      metric: `${burnMonths.toFixed(1)}m`,
    });
  }
  if (upcoming.length > 0) {
    const total = upcoming.reduce((s, u) => s + (Number(u.value) || 0), 0);
    insights.push({
      icon: "calendar",
      tone: "warn",
      title: `${upcoming.length} contas a vencer (30 dias)`,
      sub: `Total ${fmtBRL(total)}`,
      metric: fmtBRL(total),
      list: upcoming.map(u => `${new Date(u.date).toLocaleDateString("pt-BR", { day: "2-digit", month: "short" })} · ${u.desc} · ${fmtBRL(u.value)}`),
    });
  }
  if (bestMonth && worstMonth && bestMonth.label !== worstMonth.label) {
    insights.push({
      icon: "chart",
      tone: "neutral",
      title: `Melhor mês: ${bestMonth.label}`,
      sub: `Pior: ${worstMonth.label} · ${fmtBRL(worstMonth.bal)}`,
      metric: fmtBRL(bestMonth.bal),
    });
  }
  if (savingsRate !== 0) {
    insights.push({
      icon: "wallet",
      tone: savingsRate >= 20 ? "pos" : savingsRate >= 0 ? "warn" : "neg",
      title: savingsRate >= 0 ? `Você poupa ${savingsRate.toFixed(1)}% do que entra` : `Gastando ${Math.abs(savingsRate).toFixed(1)}% acima do que entra`,
      sub: savingsRate >= 20 ? "Saúde financeira ótima" : savingsRate >= 0 ? "Margem apertada" : "Operando no vermelho",
      metric: `${savingsRate >= 0 ? "" : "−"}${Math.abs(savingsRate).toFixed(1)}%`,
    });
  }

  return (
    <div className="card" style={{ padding: 18, display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <span style={{
            width: 28, height: 28, borderRadius: 8,
            background: `color-mix(in oklab, ${accent} 14%, transparent)`,
            color: accent,
            display: "flex", alignItems: "center", justifyContent: "center"
          }}>
            <Icon name="spark" size={15} />
          </span>
          <div>
            <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Insights automáticos</h3>
            <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, marginTop: 2 }}>
              Análise dos últimos 12 meses
            </div>
          </div>
        </div>
        {insights.length > 0 && (
          <span style={{ fontSize: 11, fontWeight: 600, color: accent, background: `color-mix(in oklab, ${accent} 10%, transparent)`, padding: "3px 8px", borderRadius: 999, letterSpacing: 0.4 }}>
            {insights.length} sinais
          </span>
        )}
      </div>
      {insights.length === 0 ? (
        <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-3)", fontSize: 13, padding: "40px 0", textAlign: "center" }}>
          Adicione lançamentos para ver insights gerados automaticamente.
        </div>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 8, flex: 1, overflow: "auto" }}>
          {insights.map((ins, i) => <InsightItem key={i} ins={ins} accent={accent} />)}
        </div>
      )}
    </div>
  );
}

function InsightItem({ ins, accent }) {
  const [open, setOpen] = React.useState(false);
  const toneColor = { pos: "var(--success)", neg: "var(--danger)", warn: "var(--warn)", neutral: accent }[ins.tone] || accent;
  const hasList = ins.list && ins.list.length > 0;
  return (
    <div onClick={() => hasList && setOpen(o => !o)}
      style={{
        position: "relative", padding: "10px 12px 10px 16px", borderRadius: 10,
        background: "var(--surface-2)", cursor: hasList ? "pointer" : "default",
      }}>
      <div style={{ position: "absolute", left: 0, top: 10, bottom: 10, width: 3, background: toneColor }} />
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <span style={{
          width: 22, height: 22, borderRadius: 6,
          background: `color-mix(in oklab, ${toneColor} 14%, transparent)`,
          color: toneColor, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
        }}>
          <Icon name={ins.icon} size={12} />
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-1)", lineHeight: 1.3 }}>{ins.title}</div>
          <div style={{ fontSize: 11, color: "var(--fg-3)", marginTop: 2 }}>{ins.sub}</div>
        </div>
        <div style={{ fontSize: 12.5, fontWeight: 600, color: toneColor, fontVariantNumeric: "tabular-nums", flexShrink: 0 }}>
          {ins.metric}
        </div>
        {hasList && (
          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ color: "var(--fg-3)", transform: open ? "rotate(180deg)" : "none", transition: "transform .15s" }}>
            <polyline points="6 9 12 15 18 9"/>
          </svg>
        )}
      </div>
      {open && hasList && (
        <div style={{ marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--border)", display: "flex", flexDirection: "column", gap: 5 }}>
          {ins.list.map((l, i) => (
            <div key={i} style={{ fontSize: 11.5, color: "var(--fg-2)", display: "flex", gap: 6 }}>
              <span style={{ color: "var(--fg-3)" }}>•</span>
              <span style={{ flex: 1 }}>{l}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ===== Análise de Receitas =====
function RevenueAnalysis({ accent, totalRec, ticketAvg, recCount, recurringRevTotal, oneTimeRevTotal, topClients, months12 }) {
  const recurringPct = totalRec > 0 ? (recurringRevTotal / totalRec) * 100 : 0;
  const lastMonth = months12[months12.length - 1] || { in: 0 };
  const recValues = months12.map(m => m.in);

  return (
    <div className="card" style={{ padding: 18 }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
        <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Análise de receitas</h3>
        <Sparkline values={recValues} accent={accent} width={80} height={22} />
      </div>

      {/* Mini KPIs */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginBottom: 14 }}>
        <div style={{ background: "var(--surface-2)", padding: "10px 12px", borderRadius: 8 }}>
          <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.5, fontWeight: 500 }}>Ticket médio</div>
          <div style={{ fontSize: 18, fontWeight: 600, color: "var(--fg-1)", fontVariantNumeric: "tabular-nums", marginTop: 2 }}>{fmtBRL(ticketAvg)}</div>
          <div style={{ fontSize: 11, color: "var(--fg-3)", marginTop: 2 }}>{recCount} entradas</div>
        </div>
        <div style={{ background: "var(--surface-2)", padding: "10px 12px", borderRadius: 8 }}>
          <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.5, fontWeight: 500 }}>Mês corrente</div>
          <div style={{ fontSize: 18, fontWeight: 600, color: "var(--fg-1)", fontVariantNumeric: "tabular-nums", marginTop: 2 }}>{fmtBRL(lastMonth.in)}</div>
          <div style={{ fontSize: 11, color: "var(--fg-3)", marginTop: 2 }}>recebido</div>
        </div>
      </div>

      {/* Recorrente vs Eventual */}
      {totalRec > 0 && (
        <div style={{ marginBottom: 14 }}>
          <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11.5, color: "var(--fg-3)", marginBottom: 6, textTransform: "uppercase", letterSpacing: 0.5, fontWeight: 500 }}>
            <span>Composição</span>
            <span>{recurringPct.toFixed(0)}% recorrente</span>
          </div>
          <div style={{ display: "flex", height: 10, borderRadius: 999, overflow: "hidden", background: "var(--surface-2)" }}>
            <div style={{ width: `${recurringPct}%`, background: accent, transition: "width .6s" }}>
              <title>Recorrente: {fmtBRL(recurringRevTotal)}</title>
            </div>
            <div style={{ flex: 1, background: `color-mix(in oklab, ${accent} 30%, transparent)` }} />
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11.5, marginTop: 6 }}>
            <span style={{ color: "var(--fg-2)" }}>
              <span style={{ display: "inline-block", width: 8, height: 8, background: accent, borderRadius: 2, marginRight: 6 }}></span>
              Recorrente {fmtBRL(recurringRevTotal)}
            </span>
            <span style={{ color: "var(--fg-2)" }}>
              <span style={{ display: "inline-block", width: 8, height: 8, background: `color-mix(in oklab, ${accent} 30%, transparent)`, borderRadius: 2, marginRight: 6 }}></span>
              Eventual {fmtBRL(oneTimeRevTotal)}
            </span>
          </div>
        </div>
      )}

      {/* Top clientes/origens */}
      {topClients.length > 0 && (
        <div style={{ paddingTop: 14, borderTop: "1px solid var(--border)" }}>
          <div style={{ fontSize: 11.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, marginBottom: 8, fontWeight: 500 }}>Maiores fontes de receita</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {topClients.map((c, i) => {
              const pct = totalRec > 0 ? (c.total / totalRec) * 100 : 0;
              return (
                <div key={i}>
                  <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, marginBottom: 3, alignItems: "center" }}>
                    <span style={{ color: "var(--fg-1)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1, marginRight: 8, display: "flex", alignItems: "center", gap: 6 }}>
                      {c.desc}
                      {c.recurrent && <span style={{ fontSize: 9, padding: "2px 5px", borderRadius: 4, background: `color-mix(in oklab, ${accent} 14%, transparent)`, color: accent, fontWeight: 600, letterSpacing: 0.4, textTransform: "uppercase" }}>Recorrente</span>}
                    </span>
                    <span style={{ color: "var(--fg-1)", fontVariantNumeric: "tabular-nums", fontWeight: 500 }}>{fmtBRL(c.total)}</span>
                  </div>
                  <div style={{ height: 4, background: "var(--surface-2)", borderRadius: 999, overflow: "hidden" }}>
                    <div style={{ width: `${pct}%`, height: "100%", background: accent, opacity: 0.7, borderRadius: 999, transition: "width .6s" }} />
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

function KPI({ title, value, icon, tone, sub }) {
  const toneColor = { pos: "var(--success)", neg: "var(--danger)", warn: "var(--warn)", neutral: "var(--fg-1)" }[tone] || "var(--fg-1)";
  return (
    <div className="card" style={{ padding: 16 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 12 }}>
        <span style={{ fontSize: 11.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, fontWeight: 500 }}>{title}</span>
        <span style={{
          width: 28, height: 28, borderRadius: 8,
          background: `color-mix(in oklab, ${toneColor} 12%, transparent)`,
          color: toneColor,
          display: "flex", alignItems: "center", justifyContent: "center"
        }}>
          <Icon name={icon} size={15} />
        </span>
      </div>
      <div style={{ fontSize: 22, fontWeight: 600, color: "var(--fg-1)", fontVariantNumeric: "tabular-nums", letterSpacing: -0.3, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{value}</div>
      <div style={{ fontSize: 11.5, color: "var(--fg-3)", marginTop: 4 }}>{sub}</div>
    </div>
  );
}

// ===== Destaques do período (acompanha o Fluxo de Caixa) =====
function PeriodHighlights({ accent, months12, bestMonth, worstMonth, biggestTxn, biggestRec, recurringMonthly, outDelta, inDelta, totalAll, totalRec }) {
  // Conta meses com dados pra média e tendência
  const withData = months12.filter(m => m.in > 0 || m.out > 0);
  const avgIn = withData.length > 0 ? withData.reduce((s, m) => s + m.in, 0) / withData.length : 0;
  const avgOut = withData.length > 0 ? withData.reduce((s, m) => s + m.out, 0) / withData.length : 0;
  const avgBal = avgIn - avgOut;

  // Tendência simples: comparar últimos 3 meses vs 3 anteriores
  const last3 = months12.slice(-3);
  const prev3 = months12.slice(-6, -3);
  const last3Out = last3.reduce((s, m) => s + m.out, 0);
  const prev3Out = prev3.reduce((s, m) => s + m.out, 0);
  const trend3m = prev3Out > 0 ? ((last3Out - prev3Out) / prev3Out) * 100 : 0;

  const Row = ({ label, value, sub, tone }) => {
    const c = tone === "pos" ? "var(--success)" : tone === "neg" ? "var(--danger)" : tone === "warn" ? "var(--warn)" : "var(--fg-1)";
    return (
      <div style={{ padding: "10px 0", borderBottom: "1px solid var(--border)" }}>
        <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, fontWeight: 500, marginBottom: 4 }}>{label}</div>
        <div style={{ fontSize: 14, fontWeight: 600, color: c, fontVariantNumeric: "tabular-nums", lineHeight: 1.2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{value}</div>
        {sub && <div style={{ fontSize: 11, color: "var(--fg-3)", marginTop: 3, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{sub}</div>}
      </div>
    );
  };

  return (
    <div className="card" style={{ padding: 18, display: "flex", flexDirection: "column" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
        <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Destaques do período</h3>
        <span style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.5 }}>{withData.length}m com dados</span>
      </div>
      <div style={{ fontSize: 11.5, color: "var(--fg-3)", marginBottom: 6 }}>Resumo dos números que importam</div>

      <div style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "space-between" }}>
        {bestMonth && (
          <Row
            label="Melhor mês"
            value={`${bestMonth.label} · ${fmtBRL(bestMonth.bal)}`}
            sub={`Receita ${fmtBRL(bestMonth.in)} − Despesa ${fmtBRL(bestMonth.out)}`}
            tone="pos"
          />
        )}
        {worstMonth && bestMonth && worstMonth.label !== bestMonth.label && (
          <Row
            label="Pior mês"
            value={`${worstMonth.label} · ${fmtBRL(worstMonth.bal)}`}
            sub={`Receita ${fmtBRL(worstMonth.in)} − Despesa ${fmtBRL(worstMonth.out)}`}
            tone={worstMonth.bal < 0 ? "neg" : "warn"}
          />
        )}
        <Row
          label="Saldo médio mensal"
          value={fmtBRL(avgBal)}
          sub={`Receita média ${fmtBRL(avgIn)} · Despesa média ${fmtBRL(avgOut)}`}
          tone={avgBal >= 0 ? "pos" : "neg"}
        />
        {biggestTxn && (
          <Row
            label="Maior despesa única"
            value={fmtBRL(biggestTxn.value)}
            sub={biggestTxn.desc || "—"}
            tone="warn"
          />
        )}
        {biggestRec && (
          <Row
            label="Maior receita única"
            value={fmtBRL(biggestRec.value)}
            sub={biggestRec.desc || "—"}
            tone="pos"
          />
        )}
        <Row
          label="Tendência de gastos (3m)"
          value={`${trend3m >= 0 ? "↑" : "↓"} ${Math.abs(trend3m).toFixed(0)}%`}
          sub={trend3m >= 5 ? "Subindo nos últimos 3 meses" : trend3m <= -5 ? "Caindo nos últimos 3 meses" : "Estável"}
          tone={trend3m > 5 ? "neg" : trend3m < -5 ? "pos" : "neutral"}
        />
        {recurringMonthly > 0 && (
          <div style={{ padding: "10px 0" }}>
            <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, fontWeight: 500, marginBottom: 4 }}>Compromisso fixo/mês</div>
            <div style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-1)", fontVariantNumeric: "tabular-nums" }}>{fmtBRL(recurringMonthly)}</div>
            <div style={{ fontSize: 11, color: "var(--fg-3)", marginTop: 3 }}>{avgOut > 0 ? `${((recurringMonthly / avgOut) * 100).toFixed(0)}% da despesa média mensal` : ""}</div>
          </div>
        )}
      </div>
    </div>
  );
}

// ============================================================
// ===== Análise com IA (sob demanda) =====
// ============================================================

// Monta um resumo textual compacto da situação financeira do usuário pra mandar pra IA.
function buildFinanceSummary(d) {
  const lines = [];
  const fmt = v => "R$ " + Number(v || 0).toFixed(2).replace(".", ",");
  lines.push(`Tipo de conta: ${d.ws.type === "personal" ? "Pessoal (orçamento doméstico)" : "Empresarial (negócio)"}`);
  lines.push(`Data atual: ${new Date().toLocaleDateString("pt-BR")}`);
  lines.push("");

  lines.push("=== RESUMO ANUAL (12 meses) ===");
  lines.push(`Receita total: ${fmt(d.totalRec)}`);
  lines.push(`Despesa total: ${fmt(d.totalAll)}`);
  lines.push(`Saldo acumulado: ${fmt(d.totalRec - d.totalAll)}`);
  lines.push(`Taxa de economia: ${d.savingsRate.toFixed(1)}%`);
  lines.push(`Reserva (saldo positivo): ${fmt(d.reserve)}`);
  lines.push(`Burn rate: cobre ${d.burnMonths.toFixed(1)} meses de despesas no ritmo atual`);
  lines.push("");

  lines.push("=== MÊS A MÊS ===");
  d.months12.forEach(m => {
    if (m.in === 0 && m.out === 0) return;
    const bal = m.in - m.out;
    lines.push(`${m.label}/${String(m.year).slice(2)}: receita ${fmt(m.in)} | despesa ${fmt(m.out)} | saldo ${bal >= 0 ? "+" : ""}${fmt(bal)}`);
  });
  lines.push("");

  // Despesas por categoria
  const byCat = {};
  d.txns.forEach(t => {
    const c = t.category || "Sem categoria";
    byCat[c] = (byCat[c] || 0) + (Number(t.value) || 0);
  });
  const catSorted = Object.entries(byCat).sort((a, b) => b[1] - a[1]);
  if (catSorted.length > 0) {
    lines.push("=== DESPESAS POR CATEGORIA (12 meses) ===");
    catSorted.forEach(([c, v]) => {
      const pct = d.totalAll > 0 ? (v / d.totalAll) * 100 : 0;
      lines.push(`${c}: ${fmt(v)} (${pct.toFixed(1)}%)`);
    });
    lines.push("");
  }

  // Top subcategorias específicas (Uber, Mercado, Aluguel)
  if (d.topSubcategories && d.topSubcategories.length > 0) {
    lines.push("=== MAIORES DESTAQUES (subcategorias específicas) ===");
    d.topSubcategories.slice(0, 10).forEach(s => {
      lines.push(`${s.name} (${s.category}): ${fmt(s.total)} em ${s.count}× · média ${fmt(s.avg)}`);
    });
    lines.push("");
  }

  if (d.fixedDescs.length > 0) {
    lines.push("=== DESPESAS FIXAS RECORRENTES (3+ meses) ===");
    d.fixedDescs.slice(0, 12).forEach(f => {
      lines.push(`${f.desc}: ${fmt(f.avg)}/mês × ${f.count} meses`);
    });
    lines.push(`Compromisso fixo total/mês: ${fmt(d.recurringMonthly)}`);
    lines.push("");
  }

  lines.push("=== STATUS DE PAGAMENTOS ===");
  lines.push(`Lançamentos pagos: ${d.totalPaid}`);
  lines.push(`Pendentes/agendados: ${d.totalUnpaid}`);
  lines.push(`Atrasados (vencidos sem pagar): ${d.overdueCount}`);
  if (d.upcoming && d.upcoming.length > 0) {
    lines.push("Próximos 30 dias:");
    d.upcoming.forEach(u => {
      lines.push(`  - ${u.date} · ${u.desc} · ${fmt(u.value)} · ${u.status}`);
    });
  }

  return lines.join("\n");
}

// Chama a IA pra analisar o resumo. Devolve { score, label, summary, breakdown[], strengths[], concerns[], periodInsights[], recommendations[] }
async function aiAnalyzeFinances(summary, ws) {
  const isBusiness = ws.type !== "personal";
  const systemMsg = `Você é um analista financeiro brasileiro experiente. Analise os dados de um usuário ${isBusiness ? "empresarial (negócio)" : "pessoal (orçamento doméstico)"} e dê um diagnóstico ENXUTO, HONESTO e ACIONÁVEL.

FORMATO ENXUTO — só 3 blocos:
1. **headline** (1 frase forte): a leitura mais importante da situação. Tom direto, com 1 número específico se possível. Max 22 palavras.
2. **win** (1 ponto positivo): algo concreto que está funcionando, com número. 1 frase curta. Max 18 palavras.
3. **action** (1 próxima ação sugerida): a coisa mais alavancada que o usuário pode fazer agora. Concreta, com valor quando der. 1 frase. Max 22 palavras.
4. **details** (opcional, max 4 itens): contexto extra pra quem clicar "ver mais" — observações sobre meses específicos, categorias, padrões. Cada item: {"period":"...","tone":"pos|neg|neutral","comment":"frase com número"}.

REGRAS DE TOM:
- Sem "diversifique seus investimentos" / sem clichês de coach financeiro
- Sempre cite NÚMEROS reais dos dados
- Honesto: se tá ruim, diz tá ruim — não suaviza
- Se a pessoa tá indo bem, celebra com fato (não vazio)

OUTPUT (JSON estrito, sem markdown, sem texto fora):
{
  "headline": "Frase única resumindo a situação com 1 número.",
  "headlineTone": "good|warn|risk|neutral",
  "win": "1 fato positivo concreto com número.",
  "action": "1 próxima ação acionável com valor.",
  "details": [
    {"period":"out/25","tone":"neg","comment":"ALIMENTAÇÃO subiu 40% vs setembro"}
  ]
}`;

  const userMsg = `DADOS:
${summary}

Devolva o diagnóstico em JSON estrito (formato enxuto).`;

  const text = await window.db.callAi({ system: systemMsg, user: userMsg, maxTokens: 1200 });
  const fenced = text.match(/```(?:json)?\s*([\s\S]+?)\s*```/);
  const jsonStr = fenced ? fenced[1] : (text.match(/\{[\s\S]+\}/)?.[0] || text);
  const parsed = JSON.parse(jsonStr);
  if (typeof parsed.headline !== "string") {
    throw new Error("Resposta da IA em formato inesperado");
  }
  return parsed;
}

// Barra superior com botão pra rodar a análise IA
function AiAnalysisBar({ accent, loading, analysis, error, onRun, onClear }) {
  const ts = analysis?.generatedAt
    ? new Date(analysis.generatedAt).toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" })
    : null;

  return (
    <div className="card" style={{
      padding: "12px 18px", display: "flex", alignItems: "center", justifyContent: "space-between", gap: 14,
      background: analysis ? `color-mix(in oklab, ${accent} 5%, var(--surface-1))` : "var(--surface-1)",
      border: analysis ? `1px solid color-mix(in oklab, ${accent} 30%, transparent)` : "1px solid var(--border)",
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 12, flex: 1, minWidth: 0 }}>
        <span style={{ width: 32, height: 32, borderRadius: 8, background: `color-mix(in oklab, ${accent} 14%, transparent)`, color: accent, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
          <Icon name="spark" size={16} />
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-1)" }}>
            {loading ? "Analisando suas finanças com IA…" : analysis ? "Análise com IA ativa" : "Análise profunda com IA"}
          </div>
          <div style={{ fontSize: 11.5, color: "var(--fg-3)", marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
            {loading ? "Olhando 12 meses de transações, categorias, recorrências e pendências…"
              : analysis ? `${analysis.summary || "Diagnóstico personalizado abaixo."} · gerado às ${ts}`
              : error ? <span style={{ color: "var(--danger)" }}>{error}</span>
              : "A IA olha todas as suas transações e dá um diagnóstico personalizado, com pontos fortes, preocupações e recomendações específicas."}
          </div>
        </div>
      </div>
      <div style={{ display: "flex", gap: 8, flexShrink: 0 }}>
        {analysis && !loading && (
          <button className="btn-ghost" onClick={onClear} style={{ fontSize: 12 }}>
            Voltar para análise simples
          </button>
        )}
        <button
          className="btn-primary"
          onClick={onRun}
          disabled={loading}
          style={{ opacity: loading ? 0.6 : 1, fontSize: 12.5 }}
        >
          <Icon name="spark" size={13} /> {loading ? "Analisando…" : analysis ? "Reanalisar" : "Analisar com IA"}
        </button>
      </div>
    </div>
  );
}

// HealthCard com dados da IA (mesmo visual, mas com comentários por componente)
function HealthCardAi({ analysis, accent, subtitle }) {
  const score = analysis.score || 0;
  const tone = score >= 75 ? "var(--success)" : score >= 50 ? "var(--warn)" : "var(--danger)";
  const label = analysis.label || "—";
  const size = 140, stroke = 14, r = (size - stroke) / 2, cx = size / 2, cy = size / 2;
  const C = 2 * Math.PI * r;
  const dash = (score / 100) * C;
  const breakdown = analysis.breakdown || [];

  return (
    <div className="card" style={{ padding: 18, display: "flex", flexDirection: "column" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 10 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <span style={{ width: 28, height: 28, borderRadius: 8, background: `color-mix(in oklab, ${accent} 14%, transparent)`, color: accent, display: "flex", alignItems: "center", justifyContent: "center" }}>
            <Icon name="target" size={15} />
          </span>
          <div>
            <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Health Score</h3>
            <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, marginTop: 2 }}>
              {subtitle || "Saúde financeira"}
            </div>
          </div>
        </div>
      </div>

      <div style={{ display: "flex", alignItems: "center", gap: 18, marginTop: 4 }}>
        <div style={{ position: "relative", width: size, height: size, flexShrink: 0 }}>
          <svg width={size} height={size} style={{ transform: "rotate(-90deg)" }}>
            <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--border)" strokeWidth={stroke} />
            <circle cx={cx} cy={cy} r={r} fill="none" stroke={tone} strokeWidth={stroke} strokeDasharray={`${dash} ${C - dash}`} strokeLinecap="round" />
          </svg>
          <div style={{ position: "absolute", inset: 0, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
            <span style={{ fontSize: 36, fontWeight: 700, color: "var(--fg-1)", lineHeight: 1, fontVariantNumeric: "tabular-nums", letterSpacing: -1 }}>{score}</span>
            <span style={{ fontSize: 10, color: "var(--fg-3)", marginTop: 2, textTransform: "uppercase", letterSpacing: 0.8 }}>de 100</span>
          </div>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: "inline-block", fontSize: 11, fontWeight: 600, color: tone, background: `color-mix(in oklab, ${tone} 12%, transparent)`, padding: "4px 10px", borderRadius: 999, letterSpacing: 0.4, textTransform: "uppercase", marginBottom: 10 }}>{label}</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            {breakdown.map((b, i) => {
              const pct = (b.score / b.max) * 100;
              const c = pct >= 75 ? "var(--success)" : pct >= 50 ? "var(--warn)" : "var(--danger)";
              return (
                <div key={i}>
                  <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, marginBottom: 2 }}>
                    <span style={{ color: "var(--fg-2)" }}>{b.label}</span>
                    <span style={{ color: "var(--fg-1)", fontVariantNumeric: "tabular-nums", fontWeight: 500 }}>{b.score}/{b.max}</span>
                  </div>
                  <div style={{ height: 4, background: "var(--surface-2)", borderRadius: 999, overflow: "hidden", marginBottom: b.comment ? 3 : 0 }}>
                    <div style={{ width: `${pct}%`, height: "100%", background: c, borderRadius: 999 }} />
                  </div>
                  {b.comment && (
                    <div style={{ fontSize: 10.5, color: "var(--fg-3)", lineHeight: 1.35 }}>{b.comment}</div>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

// Painel de insights com dados da IA (forças, preocupações, períodos, recomendações)
function InsightsPanelAi({ analysis, accent }) {
  const strengths = analysis.strengths || [];
  const concerns = analysis.concerns || [];
  const periodInsights = analysis.periodInsights || [];
  const recommendations = analysis.recommendations || [];

  const Section = ({ title, icon, color, children }) => (
    <div style={{ marginBottom: 14 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, fontWeight: 600, marginBottom: 8 }}>
        <Icon name={icon} size={11} /> {title}
      </div>
      {children}
    </div>
  );

  const Item = ({ children, color }) => (
    <div style={{ display: "flex", gap: 8, fontSize: 12, lineHeight: 1.45, color: "var(--fg-1)", marginBottom: 6 }}>
      <span style={{ width: 4, height: 4, borderRadius: 999, background: color, flexShrink: 0, marginTop: 7 }} />
      <span style={{ flex: 1 }}>{children}</span>
    </div>
  );

  return (
    <div className="card" style={{ padding: 18, display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <span style={{ width: 28, height: 28, borderRadius: 8, background: `color-mix(in oklab, ${accent} 14%, transparent)`, color: accent, display: "flex", alignItems: "center", justifyContent: "center" }}>
            <Icon name="spark" size={15} />
          </span>
          <div>
            <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Diagnóstico IA</h3>
            <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.6, marginTop: 2 }}>
              Análise profunda das transações
            </div>
          </div>
        </div>
      </div>

      <div style={{ flex: 1, overflowY: "auto", paddingRight: 4 }}>
        {strengths.length > 0 && (
          <Section title="Pontos fortes" icon="check" color="var(--success)">
            {strengths.map((s, i) => <Item key={i} color="var(--success)">{s}</Item>)}
          </Section>
        )}
        {concerns.length > 0 && (
          <Section title="Preocupações" icon="arrowUp" color="var(--danger)">
            {concerns.map((c, i) => <Item key={i} color="var(--danger)">{c}</Item>)}
          </Section>
        )}
        {periodInsights.length > 0 && (
          <Section title="Insights por período" icon="calendar" color={accent}>
            {periodInsights.map((p, i) => {
              const tc = p.tone === "pos" ? "var(--success)" : p.tone === "neg" ? "var(--danger)" : "var(--fg-3)";
              return (
                <div key={i} style={{ display: "flex", flexDirection: "column", gap: 2, padding: "8px 10px", background: "var(--surface-2)", borderLeft: `3px solid ${tc}`, borderRadius: 6, marginBottom: 6 }}>
                  <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.5, fontWeight: 600 }}>{p.period}</div>
                  <div style={{ fontSize: 12, color: "var(--fg-1)", lineHeight: 1.4 }}>{p.comment}</div>
                </div>
              );
            })}
          </Section>
        )}
        {recommendations.length > 0 && (
          <Section title="Recomendações" icon="target" color={accent}>
            {recommendations.map((r, i) => <Item key={i} color={accent}>{r}</Item>)}
          </Section>
        )}
      </div>
    </div>
  );
}

// ============================================================
// ===== Painel de Vitalidade (4 métricas tipográficas) =====
// ============================================================
function VitalityPanel({ metrics, isBusiness, accent }) {
  return (
    <div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 10, marginBottom: 10 }}>
        <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>
          Vitalidade {isBusiness ? "do negócio" : "financeira"}
        </h3>
        <span style={{ fontSize: 11, color: "var(--fg-3)" }}>{isBusiness ? "Conta empresarial" : "Conta pessoal"}</span>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12 }}>
        {metrics.map((m, i) => <VitalityCard key={i} metric={m} />)}
      </div>
    </div>
  );
}

function VitalityCard({ metric }) {
  const toneColor = {
    pos: "var(--success)", neg: "var(--danger)", warn: "var(--warn)", neutral: "var(--fg-2)",
  }[metric.tone] || "var(--fg-2)";
  const toneBg = {
    pos: "var(--success-bg)", neg: "var(--danger-bg)", warn: "var(--warn-bg)", neutral: "var(--surface-2)",
  }[metric.tone] || "var(--surface-2)";
  return (
    <div className="card" style={{ padding: 16, position: "relative", overflow: "hidden" }}>
      <div className="eyebrow" style={{ fontSize: 10.5, letterSpacing: "0.16em" }}>{metric.label}</div>
      <div style={{
        fontSize: 22, fontWeight: 600, letterSpacing: "-0.3px",
        color: "var(--fg-1)", marginTop: 10, lineHeight: 1.1, fontVariantNumeric: "tabular-nums",
        overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
      }}>{metric.value}</div>
      <div style={{
        marginTop: 8, padding: "4px 9px", display: "inline-flex", alignItems: "center", gap: 6,
        background: toneBg, borderRadius: 999, fontSize: 11, color: toneColor, fontWeight: 500, lineHeight: 1.3,
      }}>
        <span style={{ width: 6, height: 6, borderRadius: 999, background: toneColor, flexShrink: 0 }} />
        {metric.sub}
      </div>
    </div>
  );
}

// ============================================================
// ===== Painel de Sinais (max 3 chips inteligentes) =====
// ============================================================
function SignalsPanel({ signals, accent }) {
  return (
    <div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 10, marginBottom: 10 }}>
        <h3 style={{ margin: 0, fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Sinais</h3>
        <span style={{ fontSize: 11, color: "var(--fg-3)" }}>{signals.length} {signals.length === 1 ? "alerta" : "alertas"} relevante{signals.length === 1 ? "" : "s"}</span>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: `repeat(${Math.min(signals.length, 3)}, 1fr)`, gap: 12 }}>
        {signals.map((s, i) => {
          const tone = {
            good: { color: "var(--success)", bg: "var(--success-bg)", border: "color-mix(in oklab, var(--success) 28%, transparent)", icon: "check" },
            warn: { color: "var(--warn)",    bg: "var(--warn-bg)",    border: "color-mix(in oklab, var(--warn) 28%, transparent)",    icon: "alert" },
            risk: { color: "var(--danger)",  bg: "var(--danger-bg)",  border: "color-mix(in oklab, var(--danger) 28%, transparent)",  icon: "alert" },
            neutral: { color: "var(--fg-2)", bg: "var(--surface-2)",  border: "var(--border)", icon: "target" },
          }[s.tone || "neutral"];
          return (
            <div key={i} className="card" style={{ padding: 14, borderColor: tone.border, background: `linear-gradient(165deg, ${tone.bg}, transparent), var(--surface-1)` }}>
              <div style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
                <span style={{ width: 28, height: 28, borderRadius: 8, background: tone.bg, color: tone.color, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
                  <Icon name={tone.icon} size={14} />
                </span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-1)", lineHeight: 1.35 }}>{s.title}</div>
                  <div style={{ fontSize: 11, color: "var(--fg-3)", marginTop: 4, lineHeight: 1.4 }}>{s.sub}</div>
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ============================================================
// ===== Card de Diagnóstico IA (resposta enxuta + expand) =====
// ============================================================
function AiDiagnosisCard({ accent, analysis, loading, error, onRun, onClear }) {
  const [expanded, setExpanded] = React.useState(false);
  const ts = analysis?.generatedAt
    ? new Date(analysis.generatedAt).toLocaleString("pt-BR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" })
    : null;

  // Estado vazio (sem análise ainda)
  if (!analysis && !loading) {
    return (
      <div className="card" style={{
        padding: 18,
        display: "flex", alignItems: "center", gap: 14,
        background: `linear-gradient(165deg, color-mix(in oklab, var(--green) 6%, transparent), transparent), var(--surface-1)`,
      }}>
        <span style={{ width: 36, height: 36, borderRadius: 10, background: "var(--green)", color: "var(--green-soft)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, boxShadow: "0 4px 14px color-mix(in oklab, var(--green) 35%, transparent)" }}>
          <Icon name="spark" size={16} />
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: "'Fraunces', Georgia, serif", fontSize: 16, fontWeight: 400, color: "var(--fg-1)", letterSpacing: "-0.01em" }}>
            Diagnóstico com <em style={{ fontStyle: "italic", fontWeight: 300, color: "var(--green)" }}>IA</em>
          </div>
          <div style={{ fontSize: 12, color: "var(--fg-2)", marginTop: 3, lineHeight: 1.4 }}>
            {error
              ? <span style={{ color: "var(--danger)" }}>{error}</span>
              : "A IA olha 12 meses de transações e devolve 1 leitura, 1 vitória e 1 ação concreta."}
          </div>
        </div>
        <button onClick={onRun} className="btn-primary" style={{ flexShrink: 0, fontSize: 12.5 }}>
          <Icon name="spark" size={13} /> Analisar
        </button>
      </div>
    );
  }

  // Loading
  if (loading) {
    return (
      <div className="card" style={{ padding: 18, display: "flex", alignItems: "center", gap: 14 }}>
        <span style={{ width: 36, height: 36, borderRadius: 10, background: "var(--surface-2)", color: "var(--green)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, animation: "spin 1.4s linear infinite" }}>
          <Icon name="spark" size={16} />
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: "'Fraunces', Georgia, serif", fontSize: 16, fontWeight: 400, color: "var(--fg-1)" }}>Analisando suas finanças…</div>
          <div style={{ fontSize: 11.5, color: "var(--fg-3)", marginTop: 3 }}>Lendo 12 meses de lançamentos · pode levar 5–10s</div>
        </div>
        <style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>
      </div>
    );
  }

  // Análise pronta
  const headlineTone = analysis.headlineTone || "neutral";
  const toneColor = { good: "var(--success)", warn: "var(--warn)", risk: "var(--danger)", neutral: "var(--fg-2)" }[headlineTone];

  return (
    <div className="card" style={{
      padding: 22, position: "relative", overflow: "hidden",
      background: `linear-gradient(165deg, color-mix(in oklab, var(--green) 5%, transparent), transparent), var(--surface-1)`,
    }}>
      {/* Header com label IA + ações */}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <span style={{ width: 28, height: 28, borderRadius: 8, background: "var(--green)", color: "var(--green-soft)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
            <Icon name="spark" size={14} />
          </span>
          <div className="eyebrow" style={{ color: "var(--green)" }}>// diagnóstico ia</div>
          {ts && <span style={{ fontSize: 11, color: "var(--fg-3)" }}>{ts}</span>}
        </div>
        <div style={{ display: "flex", gap: 6 }}>
          <button onClick={onRun} className="btn-ghost" style={{ fontSize: 11.5, padding: "6px 12px" }} title="Reanalisar">
            Reanalisar
          </button>
          <button onClick={onClear} className="icon-btn" title="Fechar análise">
            <Icon name="x" size={13} />
          </button>
        </div>
      </div>

      {/* Headline grande em Fraunces */}
      <div style={{
        fontFamily: "'Fraunces', Georgia, serif",
        fontSize: 22, fontWeight: 400, letterSpacing: "-0.02em",
        color: "var(--fg-1)", lineHeight: 1.25,
        borderLeft: `3px solid ${toneColor}`,
        paddingLeft: 14, marginBottom: 16,
      }}>
        {analysis.headline}
      </div>

      {/* Win + Action lado a lado */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: expanded && analysis.details?.length ? 16 : 0 }}>
        {/* Win */}
        {analysis.win && (
          <div style={{ padding: "12px 14px", background: "var(--success-bg)", border: "1px solid color-mix(in oklab, var(--success) 22%, transparent)", borderRadius: 12 }}>
            <div className="eyebrow" style={{ color: "var(--success)", fontSize: 9.5, marginBottom: 5 }}>// vitória</div>
            <div style={{ fontSize: 13, color: "var(--fg-1)", lineHeight: 1.45, fontWeight: 500 }}>{analysis.win}</div>
          </div>
        )}
        {/* Action */}
        {analysis.action && (
          <div style={{ padding: "12px 14px", background: "color-mix(in oklab, var(--green) 6%, var(--surface-1))", border: "1px solid color-mix(in oklab, var(--green) 22%, transparent)", borderRadius: 12 }}>
            <div className="eyebrow" style={{ color: "var(--green)", fontSize: 9.5, marginBottom: 5 }}>// próxima ação</div>
            <div style={{ fontSize: 13, color: "var(--fg-1)", lineHeight: 1.45, fontWeight: 500 }}>{analysis.action}</div>
          </div>
        )}
      </div>

      {/* Detalhes expansíveis */}
      {analysis.details?.length > 0 && (
        <>
          <button
            onClick={() => setExpanded(e => !e)}
            style={{
              fontSize: 11.5, color: "var(--fg-2)", background: "transparent", border: "none", cursor: "pointer",
              padding: "8px 0 0", display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "inherit",
            }}
          >
            {expanded ? "Ocultar detalhes" : `Ver ${analysis.details.length} observa${analysis.details.length === 1 ? "ção" : "ções"} extra${analysis.details.length === 1 ? "" : "s"}`}
            <span style={{ transform: expanded ? "rotate(180deg)" : "none", transition: "transform .2s" }}>▾</span>
          </button>
          {expanded && (
            <div style={{ marginTop: 12, display: "flex", flexDirection: "column", gap: 6 }}>
              {analysis.details.map((d, i) => {
                const tc = d.tone === "pos" ? "var(--success)" : d.tone === "neg" ? "var(--danger)" : "var(--fg-3)";
                return (
                  <div key={i} style={{ display: "flex", gap: 10, padding: "8px 12px", background: "var(--surface-2)", borderLeft: `3px solid ${tc}`, borderRadius: 8 }}>
                    <div className="eyebrow" style={{ fontSize: 9.5, color: "var(--fg-3)", flexShrink: 0, paddingTop: 1, minWidth: 60 }}>{d.period}</div>
                    <div style={{ fontSize: 12, color: "var(--fg-1)", lineHeight: 1.4 }}>{d.comment}</div>
                  </div>
                );
              })}
            </div>
          )}
        </>
      )}
    </div>
  );
}

window.Reports = Reports;
