function ScreenDashboard({ setRoute, openQuotation }) {
  const { BRL, BRLk, PERIODS, ALERT_ROUTE } = window.SCP;

  const [period, setPeriod] = useState('30d');
  const [savingsRange, setSavingsRange] = useState('6m');
  const [shareView, setShareView] = useState('cat');
  const [data, setData] = useState({ quotations: [], orders: [], products: [], receivings: [], categories: [] });
  const [loading, setLoading] = useState(true);
  const [loadErr, setLoadErr] = useState(null);

  useEffect(() => {
    let mounted = true;
    (async () => {
      try {
        const d = await window.scpDb.dashboard.load();
        if (mounted) setData(d);
      } catch (e) {
        if (mounted) setLoadErr(e.message || 'Falha ao carregar dashboard');
      } finally {
        if (mounted) setLoading(false);
      }
    })();
    return () => { mounted = false; };
  }, []);

  const P = PERIODS[period];
  const today = new Date();
  const periodStart = new Date(today.getTime() - P.days * 86400000);

  const inPeriod = (dateStr) => {
    if (!dateStr) return false;
    const d = new Date(dateStr);
    return d >= periodStart && d <= today;
  };

  // ====== KPIs reais ======
  const kpis = useMemo(() => {
    const { quotations, orders, products } = data;
    const cotacoesAbertas = quotations.filter(q => (q.status === 'aberta' || q.status === 'analise') && inPeriod(q.created_at));
    const cotacoesPend = cotacoesAbertas.filter(q => q.status === 'aberta').length;
    const cotacoesAnalise = cotacoesAbertas.filter(q => q.status === 'analise').length;
    const cotacoesNovas = quotations.filter(q => inPeriod(q.created_at)).length;

    const pedidosPeriodo = orders.filter(o => inPeriod(o.emitted_at) && o.status !== 'cancelado');
    const pedidosTotal = pedidosPeriodo.reduce((s, o) => s + Number(o.total || 0), 0);

    const cotacoesFechadasPeriodo = quotations.filter(q => q.status === 'fechada' && inPeriod(q.closed_at));
    const economia = cotacoesFechadasPeriodo.reduce((s, q) => s + Number(q.saving_value || 0), 0);
    const economiaAcum = quotations.filter(q => q.status === 'fechada').reduce((s, q) => s + Number(q.saving_value || 0), 0);

    // ====== Período anterior (mesma duração, anterior ao atual) ======
    const prevStart = new Date(periodStart.getTime() - P.days * 86400000);
    const prevEnd = periodStart;
    const inPrev = (d) => {
      if (!d) return false;
      const x = new Date(d);
      return x >= prevStart && x < prevEnd;
    };
    const pedidosPrevPeriodo = orders.filter(o => inPrev(o.emitted_at) && o.status !== 'cancelado');
    const pedidosPrevTotal = pedidosPrevPeriodo.reduce((s, o) => s + Number(o.total || 0), 0);
    const economiaPrev = quotations.filter(q => q.status === 'fechada' && inPrev(q.closed_at)).reduce((s, q) => s + Number(q.saving_value || 0), 0);

    const pct = (curr, prev) => {
      if (prev === 0 && curr === 0) return null;
      if (prev === 0) return null; // não dá pra comparar
      return ((curr - prev) / prev) * 100;
    };
    const pedidosDelta = pct(pedidosPeriodo.length, pedidosPrevPeriodo.length);
    const economiaDelta = pct(economia, economiaPrev);

    const lowStock = products.filter(p => Number(p.stock) < Number(p.min_stock));
    const criticos = lowStock.length;
    const criticosAbaixo = lowStock.filter(p => Number(p.stock) < Number(p.min_stock) / 2).length;

    return {
      cotacoesAbertas: cotacoesAbertas.length,
      cotacoesPend, cotacoesAnalise, cotacoesNovas,
      pedidos: pedidosPeriodo.length,
      pedidosTotal,
      pedidosDelta,
      economia,
      economiaAcum,
      economiaDelta,
      criticos, criticosAbaixo,
    };
  }, [data, period]);

  // ====== Últimas cotações ======
  const filteredQuotations = useMemo(() => {
    return (data.quotations || [])
      .filter(q => inPeriod(q.created_at))
      .map(q => ({
        ...q,
        items: q.items?.length || 0,
        suppliers: q.invited?.length || 0,
        responded: (q.invited || []).filter(i => i.status === 'respondida').length,
      }));
  }, [data, period]);

  // ====== Active quotation (hero) ======
  const activeQuotation = useMemo(() => {
    return (data.quotations || []).find(q => q.status === 'analise' || q.status === 'aberta');
  }, [data]);

  // Carrega análise IA da cotação ativa (se existir) para popular o orbe + pings
  const [activeAnalysis, setActiveAnalysis] = useState(null);
  useEffect(() => {
    if (!activeQuotation) { setActiveAnalysis(null); return; }
    window.scpDb.ai.getLatestAnalysis(activeQuotation.id).then(setActiveAnalysis).catch(() => {});
  }, [activeQuotation?.id]);

  // Top fornecedores recomendados pela IA — com % de economia por fornecedor
  const aiPings = useMemo(() => {
    if (!activeAnalysis?.recommendation) return [];
    const rec = activeAnalysis.recommendation;
    const supOrders = rec.supplier_orders || {};
    const ids = Object.keys(supOrders).slice(0, 3);
    // Para cada fornecedor, calculamos % média de economia somando economia dos itens dele
    return ids.map(sid => {
      const items = supOrders[sid] || [];
      const supInvited = (activeQuotation?.invited || []).find(i => i.supplier_id === sid);
      const name = supInvited?.supplier?.name || 'Fornecedor';
      const shortName = name.split(' ')[0];
      // Calcula % de economia: precisaria dos preços dos bids - como já temos a recomendação,
      // usamos uma estimativa simples
      const pct = items.length > 0 ? -((rec.savings_pct || 0) / Math.max(1, ids.length)).toFixed(1) : 0;
      return { sid, name, shortName, pct };
    });
  }, [activeAnalysis, activeQuotation]);

  // ====== Savings chart real (agregado por mês) ======
  const savingsData = useMemo(() => {
    const fechadas = (data.quotations || []).filter(q => q.status === 'fechada' && q.closed_at && q.saving_value);
    if (savingsRange === 'ano') {
      const byYear = {};
      fechadas.forEach(q => {
        const y = String(new Date(q.closed_at).getFullYear());
        byYear[y] = (byYear[y] || 0) + Number(q.saving_value);
      });
      const arr = Object.entries(byYear)
        .sort(([a], [b]) => a.localeCompare(b))
        .map(([m, value]) => ({ m, value, quotes: 0 }));
      return arr.length ? arr : [{ m: String(today.getFullYear()), value: 0, quotes: 0 }];
    }
    const months = savingsRange === '12m' ? 12 : 6;
    const byMonth = new Map();
    for (let i = months - 1; i >= 0; i--) {
      const d = new Date(today.getFullYear(), today.getMonth() - i, 1);
      const key = d.toISOString().slice(0, 7);
      const label = d.toLocaleDateString('pt-BR', { month: 'short', year: '2-digit' }).replace('.', '').replace(' de ', '/');
      byMonth.set(key, { m: label, value: 0, quotes: 0 });
    }
    fechadas.forEach(q => {
      const d = new Date(q.closed_at);
      const key = d.toISOString().slice(0, 7);
      if (byMonth.has(key)) {
        const row = byMonth.get(key);
        row.value += Number(q.saving_value);
        row.quotes += 1;
      }
    });
    return Array.from(byMonth.values());
  }, [data, savingsRange]);

  const savingsSub =
    savingsRange === '6m'  ? 'Últimos 6 meses · economia em cotações fechadas' :
    savingsRange === '12m' ? 'Últimos 12 meses · economia em cotações fechadas' :
    'Histórico anual · economia em cotações fechadas';

  // ====== Donut · Categoria ======
  const categoryShare = useMemo(() => {
    const map = {};
    (data.orders || [])
      .filter(o => inPeriod(o.emitted_at) && o.status !== 'cancelado')
      .forEach(o => {
        (o.items || []).forEach(it => {
          const cat = it.product?.cat;
          if (!cat) return;
          map[cat] = (map[cat] || 0) + Number(it.qty) * Number(it.unit_price);
        });
      });
    return Object.entries(map)
      .map(([catKey, value]) => {
        const c = (data.categories || []).find(x => x.key === catKey);
        return { cat: catKey, label: c?.label || catKey, value: Math.round(value), tone: c?.tone || 'fg' };
      })
      .sort((a, b) => b.value - a.value);
  }, [data, period]);

  // ====== Donut · Fornecedor ======
  const supplierShare = useMemo(() => {
    const map = {};
    (data.orders || [])
      .filter(o => inPeriod(o.emitted_at) && o.status !== 'cancelado')
      .forEach(o => {
        const sid = o.supplier?.id;
        if (!sid) return;
        if (!map[sid]) map[sid] = { sid, label: o.supplier.name, value: 0, tone: 'sky' };
        map[sid].value += Number(o.total);
      });
    const arr = Object.values(map).sort((a, b) => b.value - a.value).slice(0, 8);
    const tones = ['emerald','sky','coral','amber','violet','sky','coral','amber'];
    return arr.map((s, i) => ({ ...s, cat: s.sid, value: Math.round(s.value), tone: tones[i % tones.length] }));
  }, [data, period]);

  // ====== Top fornecedores (últimos 90d sempre) ======
  const topSuppliers = useMemo(() => {
    const map = {};
    (data.orders || [])
      .filter(o => o.status === 'entregue' || o.status === 'em_transito' || o.status === 'confirmado')
      .forEach(o => {
        const name = o.supplier?.name;
        if (!name) return;
        map[name] = (map[name] || 0) + 1;
      });
    const arr = Object.entries(map).map(([name, wins]) => ({ name, wins })).sort((a, b) => b.wins - a.wins).slice(0, 10);
    const max = arr[0]?.wins || 1;
    return arr.map(s => ({ ...s, share: Math.round(100 * s.wins / max) }));
  }, [data]);

  // ====== Top produtos ======
  const topProducts = useMemo(() => {
    const map = {};
    (data.orders || []).forEach(o => {
      (o.items || []).forEach(it => {
        const pid = it.product_id;
        if (!pid) return;
        if (!map[pid]) map[pid] = { product_id: pid, name: '', vol: 0, quotes: 0 };
        map[pid].vol += Number(it.qty);
        map[pid].quotes += 1;
      });
    });
    // pega nomes
    Object.values(map).forEach(item => {
      const p = (data.products || []).find(x => x.id === item.product_id);
      item.name = p?.name || '—';
    });
    return Object.values(map).filter(p => p.name !== '—').sort((a, b) => b.quotes - a.quotes).slice(0, 10);
  }, [data]);

  // ====== Alertas gerados ======
  const alerts = useMemo(() => {
    const out = [];
    // Estoque crítico (top 3)
    const crit = (data.products || [])
      .filter(p => Number(p.stock) < Number(p.min_stock))
      .sort((a, b) => (a.stock / Math.max(1, a.min_stock)) - (b.stock / Math.max(1, b.min_stock)))
      .slice(0, 2);
    crit.forEach(p => out.push({
      id: 'stock-' + p.id, kind: 'estoque',
      text: `${p.name} abaixo do mínimo (${p.stock} / ${p.min_stock})`,
      at: 'agora', tone: 'amber',
    }));
    // Recebimentos pendentes com divergência
    const recPend = (data.receivings || []).filter(r => r.status === 'pendente' && r.divergence_count > 0).slice(0, 1);
    recPend.forEach(r => out.push({
      id: 'rec-' + r.id, kind: 'pedido',
      text: `${r.code} pendente com ${r.divergence_count} divergência${r.divergence_count > 1 ? 's' : ''}`,
      at: 'há minutos', tone: 'coral',
    }));
    // Cotações com fornecedores pendentes
    const pendQuotes = (data.quotations || [])
      .filter(q => q.status === 'analise' || q.status === 'aberta')
      .map(q => ({ ...q, pendingCount: (q.invited || []).filter(i => i.status === 'pendente').length }))
      .filter(q => q.pendingCount > 0).slice(0, 1);
    pendQuotes.forEach(q => out.push({
      id: 'q-' + q.id, kind: 'cotacao',
      text: `${q.code} sem resposta de ${q.pendingCount} fornecedor${q.pendingCount > 1 ? 'es' : ''}`,
      at: 'há 1h', tone: 'amber',
    }));
    // IA sugestão na cotação ativa
    if (activeQuotation && activeQuotation.status === 'analise') {
      out.push({
        id: 'ia-' + activeQuotation.id, kind: 'ia',
        text: `IA sugere fechar ${activeQuotation.code} com análise concluída`,
        at: 'há 3h', tone: 'emerald',
      });
    }
    // Pedido em trânsito recente
    const transito = (data.orders || []).filter(o => o.status === 'em_transito').slice(0, 1);
    transito.forEach(o => out.push({
      id: 'o-' + o.id, kind: 'pedido',
      text: `${o.code} em trânsito · entrega prevista ${o.eta ? new Date(o.eta).toLocaleDateString('pt-BR') : 'em breve'}`,
      at: 'há 2h', tone: 'sky',
    }));
    return out.slice(0, 6);
  }, [data, activeQuotation]);

  const handleAlertClick = (alert) => {
    const route = ALERT_ROUTE[alert.kind] || 'dashboard';
    if (route === 'quotationDetail' && activeQuotation) {
      openQuotation(activeQuotation.id);
    } else {
      setRoute(route);
    }
  };

  if (loading) {
    return <div className="scp-screen scp-fade-in" style={{ padding: 80, textAlign: 'center', color: 'var(--fg-3)' }}>
      Carregando dashboard…
    </div>;
  }

  return (
    <div className="scp-screen scp-fade-in">
      {loadErr && (
        <Card style={{ padding: 14, borderColor: 'oklch(0.42 0.10 25 / .55)', background: 'oklch(0.26 0.08 25 / .25)' }}>
          <strong style={{ color: 'oklch(0.88 0.14 25)' }}>Falha ao carregar dashboard:</strong>{' '}
          <span style={{ color: 'var(--fg-2)', fontSize: 13 }}>{loadErr}</span>
        </Card>
      )}
      {/* Period selector bar */}
      <div className="scp-period-bar">
        <div className="scp-period-left">
          <span className="scp-period-eyebrow">Visão geral</span>
          <span className="scp-period-title">Dashboard · {P.sub}</span>
        </div>
        <div className="scp-period-right">
          <div className="scp-tabs">
            {Object.keys(PERIODS).map(k => (
              <button
                key={k}
                className={cls(period === k && 'active')}
                onClick={() => setPeriod(k)}
              >
                {PERIODS[k].label}
              </button>
            ))}
          </div>
        </div>
      </div>

      <div className="scp-dash-grid">
        <Stat
          label="Cotações Abertas"
          value={String(kpis.cotacoesAbertas)}
          delta={kpis.cotacoesNovas > 0 ? `+${kpis.cotacoesNovas} no período` : null}
          deltaTone="emerald"
          icon={<Icon.Quote size={16}/>}
          sub={`${kpis.cotacoesAnalise} em análise · ${kpis.cotacoesPend} aguardando`}
          onClick={() => setRoute('quotations')}
          hint="Ver cotações"
        />
        <Stat
          label="Pedidos"
          value={String(kpis.pedidos)}
          delta={kpis.pedidosDelta != null ? `${kpis.pedidosDelta >= 0 ? '+' : ''}${kpis.pedidosDelta.toFixed(0)}% vs. anterior` : null}
          deltaTone={kpis.pedidosDelta >= 0 ? 'emerald' : 'coral'}
          icon={<Icon.Order size={16}/>}
          sub={`${BRL(kpis.pedidosTotal)} em compras`}
          onClick={() => setRoute('orders')}
          hint="Ver pedidos"
        />
        <Stat
          label="Economia"
          value={BRL(kpis.economia)}
          delta={kpis.economiaDelta != null ? `${kpis.economiaDelta >= 0 ? '+' : ''}${kpis.economiaDelta.toFixed(1)}% vs. anterior` : null}
          deltaTone={kpis.economiaDelta >= 0 ? 'emerald' : 'coral'}
          icon={<Icon.Trend size={16}/>}
          sub={`Acumulado: ${BRL(kpis.economiaAcum)}`}
          onClick={() => setRoute('reports')}
          hint="Ver relatórios"
        />
        <Stat
          label="Estoque Crítico"
          value={`${kpis.criticos} itens`}
          delta={kpis.criticos > 0 ? 'Reposição sugerida' : 'Tudo em dia'}
          deltaTone={kpis.criticos > 0 ? 'amber' : 'emerald'}
          icon={<Icon.Warning size={16}/>}
          sub={`${kpis.criticosAbaixo} abaixo de 50% do mínimo`}
          onClick={() => setRoute('stock')}
          hint="Repor estoque"
        />
      </div>

      {/* Hero: active quotation + IA recommendation */}
      <Card className="scp-hero">
        <div className="scp-hero-left">
          <div className="scp-hero-tag">
            <span className="scp-ai-glow" />
            <Icon.Sparkle size={14}/>
            <span>IA OpenAI · {activeQuotation?.status === 'analise' ? 'Análise concluída' : activeQuotation ? 'Cotação aberta' : 'Sem cotação ativa'}</span>
          </div>
          {activeQuotation ? (() => {
            const itemsCount = activeQuotation.items?.length || 0;
            const supCount = activeQuotation.invited?.length || 0;
            const respCount = (activeQuotation.invited || []).filter(i => i.status === 'respondida').length;
            const deadline = activeQuotation.deadline ? new Date(activeQuotation.deadline).toLocaleString('pt-BR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }).replace(',', ' ·') : '—';
            return <>
              <h2>
                <span className="muted">Cotação ativa</span><br/>
                {activeQuotation.title}
              </h2>
              <p>
                {respCount} de {supCount} fornecedores responderam. A IA sugere o melhor mix por item considerando preço,
                prazo e histórico.
              </p>
              <div className="scp-hero-meta">
                <div><span>Itens</span><strong>{itemsCount}</strong></div>
                <div><span>Fornecedores</span><strong>{respCount}/{supCount}</strong></div>
                <div><span>Prazo</span><strong>{deadline}</strong></div>
                <div><span>Código</span><strong className="emerald">{activeQuotation.code}</strong></div>
              </div>
              <div className="scp-hero-cta">
                <Btn kind="primary" iconRight={<Icon.Arrow size={16}/>} onClick={() => openQuotation(activeQuotation.id)}>Abrir análise IA</Btn>
                <Btn kind="secondary" icon={<Icon.Eye size={16}/>} onClick={() => openQuotation(activeQuotation.id)}>Comparar lances</Btn>
              </div>
            </>;
          })() : (
            <>
              <h2>
                <span className="muted">Cotação ativa</span><br/>
                Nenhuma cotação em andamento
              </h2>
              <p>
                Crie uma nova cotação para começar a economizar com a análise da IA.
              </p>
              <div className="scp-hero-cta">
                <Btn kind="primary" iconRight={<Icon.Arrow size={16}/>} onClick={() => setRoute('newQuotation')}>Nova Cotação</Btn>
              </div>
            </>
          )}
        </div>
        {activeQuotation && (
          <div className="scp-hero-right">
            <div className="scp-ai-orb">
              <svg viewBox="0 0 200 200" width="100%" height="100%">
                <defs>
                  <radialGradient id="orbg" cx="50%" cy="50%" r="50%">
                    <stop offset="0%" stopColor="oklch(0.92 0.14 160)" stopOpacity=".95"/>
                    <stop offset="40%" stopColor="oklch(0.78 0.18 160)" stopOpacity=".60"/>
                    <stop offset="100%" stopColor="oklch(0.40 0.10 160)" stopOpacity="0"/>
                  </radialGradient>
                  <linearGradient id="ring1" x1="0" x2="1">
                    <stop offset="0%" stopColor="oklch(0.78 0.18 160)" stopOpacity="0"/>
                    <stop offset="50%" stopColor="oklch(0.85 0.18 160)"/>
                    <stop offset="100%" stopColor="oklch(0.78 0.18 285)" stopOpacity="0"/>
                  </linearGradient>
                </defs>
                <circle cx="100" cy="100" r="78" fill="url(#orbg)"/>
                <circle cx="100" cy="100" r="56" fill="none" stroke="url(#ring1)" strokeWidth="1.6" strokeDasharray="4 3">
                  <animateTransform attributeName="transform" type="rotate" from="0 100 100" to="360 100 100" dur="14s" repeatCount="indefinite"/>
                </circle>
                <circle cx="100" cy="100" r="40" fill="none" stroke="oklch(0.86 0.18 160 / .35)" strokeDasharray="2 4">
                  <animateTransform attributeName="transform" type="rotate" from="360 100 100" to="0 100 100" dur="22s" repeatCount="indefinite"/>
                </circle>
                <circle cx="100" cy="100" r="28" fill="oklch(0.20 0.04 160 / .8)" stroke="oklch(0.78 0.18 160)" strokeWidth="1.4"/>
                <g fill="white">
                  {activeAnalysis?.recommendation?.savings_value ? (
                    <>
                      <text x="100" y="93" textAnchor="middle" fontSize="9" fontFamily="JetBrains Mono" fill="oklch(0.78 0.12 160)" letterSpacing="0.16em">ECONOMIA</text>
                      <text x="100" y="112" textAnchor="middle" fontSize="14" fontFamily="Manrope" fontWeight="700" fill="oklch(0.94 0.14 160)">{BRLk(activeAnalysis.recommendation.savings_value)}</text>
                    </>
                  ) : (
                    <>
                      <text x="100" y="98" textAnchor="middle" fontSize="9" fontFamily="JetBrains Mono" fill="oklch(0.78 0.12 160)" letterSpacing="0.16em">ANÁLISE</text>
                      <text x="100" y="112" textAnchor="middle" fontSize="11" fontFamily="JetBrains Mono" fill="oklch(0.94 0.14 160)" letterSpacing="0.16em">IA</text>
                    </>
                  )}
                </g>
              </svg>
            </div>
            {aiPings.length > 0 && (
              <div className="scp-ai-pings">
                {aiPings.map((p, i) => (
                  <button
                    key={p.sid}
                    className={`ping ping-${i + 1}`}
                    onClick={() => setRoute('suppliers')}
                    title={`Ver ${p.name}`}
                  >
                    {p.shortName} · {p.pct}%
                  </button>
                ))}
              </div>
            )}
          </div>
        )}
      </Card>

      {/* Savings + Donut */}
      <div className="scp-row scp-row-2-1">
        <Card style={{ padding: 22 }}>
          <SectionHead
            title="Economia mensal · histórico"
            sub={savingsSub}
            right={
              <div className="scp-tabs">
                <button className={cls(savingsRange === '6m'  && 'active')} onClick={() => setSavingsRange('6m')}>6 meses</button>
                <button className={cls(savingsRange === '12m' && 'active')} onClick={() => setSavingsRange('12m')}>12 meses</button>
                <button className={cls(savingsRange === 'ano' && 'active')} onClick={() => setSavingsRange('ano')}>Ano</button>
              </div>
            }
          />
          <SavingsChart data={savingsData} key={savingsRange} />
        </Card>

        <Card style={{ padding: 22 }}>
          <SectionHead
            title={shareView === 'cat' ? 'Compras por categoria' : 'Compras por fornecedor'}
            sub={P.sub}
            right={
              <div className="scp-tabs">
                <button className={cls(shareView === 'cat' && 'active')} onClick={() => setShareView('cat')}>Categoria</button>
                <button className={cls(shareView === 'sup' && 'active')} onClick={() => setShareView('sup')}>Fornecedor</button>
              </div>
            }
          />
          <div style={{ display: 'flex', alignItems: 'center', gap: 18, marginTop: 8 }}>
            <DonutChart
              key={shareView}
              data={shareView === 'cat' ? categoryShare : supplierShare}
              size={186}
              thick={22}
              centerLabel={`Total ${P.short}`}
              onArcClick={() => setRoute(shareView === 'cat' ? 'reports' : 'suppliers')}
            />
            <div className="scp-legend">
              {(shareView === 'cat' ? categoryShare : supplierShare).map(c => (
                <button
                  key={c.cat || c.sid}
                  className="scp-legend-item clickable"
                  onClick={() => setRoute(shareView === 'cat' ? 'reports' : 'suppliers')}
                  title={`Detalhar ${c.label}`}
                >
                  <span className={cls('dot', `tone-${c.tone}`)} />
                  <span className="lbl">{c.label}</span>
                  <span className="val">{BRLk(c.value)}</span>
                </button>
              ))}
            </div>
          </div>
        </Card>
      </div>

      <div className="scp-row scp-row-2-1">
        {/* Recent quotations */}
        <Card style={{ padding: 0, overflow: 'hidden' }}>
          <div style={{ padding: 22, paddingBottom: 0 }}>
            <SectionHead
              title="Últimas cotações"
              sub={`Histórico de cotações · ${P.sub.toLowerCase()}`}
              right={<Btn kind="ghost" size="sm" iconRight={<Icon.Arrow size={14}/>} onClick={() => setRoute('quotations')}>Ver todas</Btn>}
            />
          </div>
          {filteredQuotations.length > 0 ? (
            <table className="scp-table">
              <thead>
                <tr>
                  <th>Cotação</th>
                  <th>Status</th>
                  <th>Itens</th>
                  <th>Resp.</th>
                  <th style={{ textAlign: 'right' }}>Valor</th>
                  <th style={{ textAlign: 'right' }}>Economia</th>
                </tr>
              </thead>
              <tbody>
                {filteredQuotations.slice(0, 6).map(q => {
                  const status = QSTATUS[q.status] || { tone: 'fg', label: q.status };
                  const created = q.created_at ? new Date(q.created_at).toLocaleDateString('pt-BR') : '—';
                  return (
                    <tr key={q.id} className="clickable" onClick={() => openQuotation(q.id)}>
                      <td>
                        <div className="em">{q.title}</div>
                        <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 2 }} className="num">{q.code} · {created}</div>
                      </td>
                      <td><Badge tone={status.tone}>{status.label}</Badge></td>
                      <td className="num">{q.items}</td>
                      <td className="num">{q.responded}/{q.suppliers}</td>
                      <td className="num" style={{ textAlign: 'right' }}>{q.total_value ? BRL(q.total_value) : '—'}</td>
                      <td className="num em" style={{ textAlign: 'right', color: q.saving_value ? 'oklch(0.86 0.14 160)' : 'var(--fg-3)' }}>
                        {q.saving_value ? '↓ ' + BRL(q.saving_value) : '—'}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          ) : (
            <div className="scp-empty">
              <Icon.Quote size={20} />
              <p>Nenhuma cotação criada {P.sub.toLowerCase()}.</p>
              <Btn kind="secondary" size="sm" onClick={() => setRoute('newQuotation')}>Criar cotação</Btn>
            </div>
          )}
        </Card>

        {/* Alerts feed */}
        <Card style={{ padding: 22 }}>
          <SectionHead title="Alertas em tempo real" sub="Cotações, estoque e pedidos" right={<Icon.Lightning size={16}/>} />
          <div className="scp-alerts">
            {alerts.length === 0 && (
              <div className="scp-detail-empty" style={{ padding: 16 }}>Nenhum alerta no momento. Tudo em ordem.</div>
            )}
            {alerts.map(a => (
              <button
                key={a.id}
                className={cls('scp-alert', `tone-${a.tone}`)}
                onClick={() => handleAlertClick(a)}
                title="Abrir contexto"
              >
                <span className="dot" />
                <div className="body">
                  <p>{a.text}</p>
                  <span>{a.at} · {a.kind}</span>
                </div>
                <span className="arrow"><Icon.Arrow size={14} /></span>
              </button>
            ))}
          </div>
        </Card>
      </div>

      <div className="scp-row scp-row-1-1">
        {/* Top suppliers */}
        <Card style={{ padding: 22 }}>
          <SectionHead title="Top fornecedores · cotações vencidas" sub={P.sub} right={<Icon.Crown size={16}/>} />
          <div className="scp-rank">
            {topSuppliers.map((s, i) => (
              <button
                key={s.name}
                className="scp-rank-row clickable"
                onClick={() => setRoute('suppliers')}
                title={`Ver ${s.name}`}
              >
                <span className={cls('rk', i === 0 && 'gold', i === 1 && 'silver', i === 2 && 'bronze')}>{i+1}</span>
                <div className="info">
                  <span className="n">{s.name}</span>
                  <div className="bar"><span style={{ width: s.share + '%' }} /></div>
                </div>
                <span className="v num">{s.wins}<span className="u"> vit.</span></span>
              </button>
            ))}
          </div>
        </Card>

        {/* Top products */}
        <Card style={{ padding: 22 }}>
          <SectionHead title="Produtos mais cotados" sub={`Volume comprado · ${P.sub.toLowerCase()}`} right={<Icon.Trend size={16}/>} />
          <div className="scp-rank">
            {topProducts.map((p, i) => (
              <button
                key={p.name}
                className="scp-rank-row clickable"
                onClick={() => setRoute('products')}
                title={`Ver ${p.name}`}
              >
                <span className="rk">{i+1}</span>
                <div className="info">
                  <span className="n">{p.name}</span>
                  <span className="meta">{p.quotes} cotações · {p.vol} un.</span>
                </div>
                <Sparkline values={[10, 14, 12, 18, 16, 22, p.quotes]} width={70} height={28}/>
              </button>
            ))}
          </div>
        </Card>
      </div>
    </div>
  );
}

(function() {
  if (document.getElementById('scp-dash-css')) return;
  const s = document.createElement('style'); s.id = 'scp-dash-css';
  s.textContent = `
    .scp-screen { padding: 24px 28px 40px; display: flex; flex-direction: column; gap: 18px; max-width: 1480px; }
    .scp-dash-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
    .scp-row { display: grid; gap: 16px; }
    .scp-row-2-1 { grid-template-columns: 1.7fr 1fr; }
    .scp-row-1-1 { grid-template-columns: 1fr 1fr; }

    /* Period selector bar */
    .scp-period-bar {
      display: flex; align-items: center; justify-content: space-between;
      gap: 16px;
      background: var(--surface);
      border: 1px solid var(--border-soft);
      border-radius: var(--radius-lg);
      padding: 12px 18px;
    }
    .scp-period-left { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
    .scp-period-eyebrow { font-size: 10.5px; color: var(--fg-3); text-transform: uppercase; letter-spacing: .14em; font-weight: 700; }
    .scp-period-title { font-size: 14.5px; color: var(--fg); font-weight: 600; letter-spacing: -0.01em; }
    .scp-period-right { display: flex; align-items: center; gap: 10px; }

    .scp-hero {
      padding: 28px;
      display: grid; grid-template-columns: 1.6fr 1fr; gap: 28px;
      background:
        radial-gradient(60% 80% at 100% 0%, oklch(0.30 0.08 160 / .25), transparent 60%),
        radial-gradient(60% 80% at 0% 100%, oklch(0.30 0.07 285 / .15), transparent 60%),
        var(--surface);
      position: relative; overflow: hidden;
    }
    .scp-hero-left .muted { font-size: 12px; color: var(--fg-3); text-transform: uppercase; letter-spacing: .14em; font-weight: 600; }
    .scp-hero-left h2 { font-size: 28px; font-weight: 600; letter-spacing: -0.02em; line-height: 1.15; margin: 6px 0 12px; }
    .scp-hero-left p { color: var(--fg-2); font-size: 14px; line-height: 1.55; margin: 0; max-width: 520px; }
    .scp-hero-left p strong { color: oklch(0.92 0.13 160); font-weight: 600; }
    .scp-hero-meta { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin: 18px 0; padding-top: 18px; border-top: 1px solid var(--border-soft); }
    .scp-hero-meta > div { display: flex; flex-direction: column; gap: 2px; }
    .scp-hero-meta span { font-size: 11px; color: var(--fg-3); text-transform: uppercase; letter-spacing: .08em; font-weight: 600; }
    .scp-hero-meta strong { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; font-feature-settings: "tnum"; }
    .scp-hero-meta strong.emerald { color: oklch(0.92 0.14 160); }
    .scp-hero-cta { display: flex; gap: 8px; }
    .scp-hero-tag {
      display: inline-flex; align-items: center; gap: 7px;
      padding: 5px 10px; border-radius: 999px;
      background: oklch(0.28 0.06 160 / .5); border: 1px solid oklch(0.40 0.08 160 / .55);
      color: oklch(0.92 0.14 160); font-size: 11px; font-weight: 600; letter-spacing: .02em;
      position: relative;
    }
    .scp-ai-glow {
      width: 7px; height: 7px; border-radius: 999px; background: oklch(0.78 0.18 160);
      box-shadow: 0 0 0 0 oklch(0.78 0.18 160 / .55);
      animation: pulse 1.8s ease-out infinite;
    }
    @keyframes pulse { 0% { box-shadow: 0 0 0 0 oklch(0.78 0.18 160 / .55); } 100% { box-shadow: 0 0 0 10px oklch(0.78 0.18 160 / 0); } }

    .scp-hero-right { position: relative; display: grid; place-items: center; }
    .scp-ai-orb { width: 240px; height: 240px; filter: drop-shadow(0 20px 60px oklch(0.40 0.10 160 / .45)); }
    .scp-ai-pings { position: absolute; inset: 0; pointer-events: none; }
    .scp-ai-pings .ping {
      position: absolute; padding: 4px 9px; border-radius: 999px; font-size: 10.5px; font-weight: 600;
      background: oklch(0.20 0.04 160 / .9); border: 1px solid oklch(0.40 0.08 160 / .6);
      color: oklch(0.92 0.13 160); font-family: 'JetBrains Mono', monospace; letter-spacing: -0.01em;
      animation: floaty 4.5s ease-in-out infinite;
      pointer-events: auto; cursor: pointer;
      transition: transform .12s, border-color .15s, background .15s;
    }
    .scp-ai-pings .ping:hover {
      background: oklch(0.28 0.06 160 / .95);
      border-color: oklch(0.55 0.12 160 / .8);
      transform: scale(1.08);
    }
    .ping-1 { top: 8%;  left: 4%;  }
    .ping-2 { top: 44%; right: 0%;  animation-delay: -2.5s; }
    .ping-3 { bottom: 6%; left: 6%;  animation-delay: -1.2s; }
    @keyframes floaty { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }

    /* Legend */
    .scp-legend { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
    .scp-legend-item {
      display: grid; grid-template-columns: 10px 1fr auto; gap: 10px; align-items: center;
      font-size: 12.5px; padding: 6px 8px; border-radius: 8px;
      background: transparent; border: 1px solid transparent;
      text-align: left; transition: background .12s, border-color .12s;
    }
    .scp-legend-item.clickable { cursor: pointer; }
    .scp-legend-item.clickable:hover { background: var(--surface-2); border-color: var(--border-soft); }
    .scp-legend-item .dot { width: 10px; height: 10px; border-radius: 3px; }
    .scp-legend-item .dot.tone-emerald { background: oklch(0.78 0.16 160); }
    .scp-legend-item .dot.tone-coral { background: oklch(0.74 0.18 25); }
    .scp-legend-item .dot.tone-sky { background: oklch(0.78 0.13 230); }
    .scp-legend-item .dot.tone-amber { background: oklch(0.84 0.14 78); }
    .scp-legend-item .dot.tone-violet { background: oklch(0.74 0.14 285); }
    .scp-legend-item .lbl { color: var(--fg-2); }
    .scp-legend-item .val { color: var(--fg); font-family: 'JetBrains Mono', monospace; font-weight: 600; }

    /* Alerts */
    .scp-alerts { display: flex; flex-direction: column; gap: 6px; max-height: 320px; overflow: auto; }
    .scp-alert {
      display: grid; grid-template-columns: 10px 1fr auto; gap: 12px; align-items: flex-start;
      padding: 12px; border-radius: 10px;
      background: var(--surface-2); border: 1px solid var(--border-soft);
      cursor: pointer; text-align: left;
      transition: background .12s, border-color .12s, transform .12s;
    }
    .scp-alert:hover { background: var(--surface-3); border-color: var(--border); transform: translateX(2px); }
    .scp-alert:hover .arrow { opacity: 1; transform: translateX(0); }
    .scp-alert .dot { width: 8px; height: 8px; border-radius: 999px; margin-top: 6px; }
    .scp-alert.tone-emerald .dot { background: oklch(0.78 0.16 160); box-shadow: 0 0 0 4px oklch(0.78 0.16 160 / .15); }
    .scp-alert.tone-amber .dot { background: oklch(0.82 0.14 78); box-shadow: 0 0 0 4px oklch(0.82 0.14 78 / .15); }
    .scp-alert.tone-coral .dot { background: oklch(0.74 0.18 25); box-shadow: 0 0 0 4px oklch(0.74 0.18 25 / .15); }
    .scp-alert .body { min-width: 0; }
    .scp-alert .body p { margin: 0; font-size: 12.5px; line-height: 1.4; color: var(--fg); }
    .scp-alert .body span { font-size: 11px; color: var(--fg-3); margin-top: 4px; display: inline-block; }
    .scp-alert .arrow {
      color: var(--fg-3); margin-top: 4px;
      opacity: 0; transform: translateX(-4px);
      transition: opacity .15s, transform .15s;
    }

    /* Ranking */
    .scp-rank { display: flex; flex-direction: column; gap: 0; }
    .scp-rank-row {
      display: grid; grid-template-columns: 30px 1fr auto; gap: 12px; align-items: center;
      padding: 10px 10px; border-bottom: 1px dashed var(--border-soft);
      background: transparent; border-radius: 8px; text-align: left;
      transition: background .12s, transform .12s;
      width: 100%;
    }
    .scp-rank-row.clickable { cursor: pointer; }
    .scp-rank-row.clickable:hover { background: var(--surface-2); transform: translateX(2px); }
    .scp-rank-row:last-child { border-bottom: 0; }
    .scp-rank-row .rk { width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center; font-size: 12px; font-weight: 700; background: var(--surface-2); color: var(--fg-2); font-family: 'JetBrains Mono', monospace; }
    .scp-rank-row .rk.gold { background: oklch(0.32 0.07 78 / .6); color: oklch(0.92 0.14 78); }
    .scp-rank-row .rk.silver { background: oklch(0.32 0.01 250 / .8); color: oklch(0.88 0.005 250); }
    .scp-rank-row .rk.bronze { background: oklch(0.32 0.07 60 / .55); color: oklch(0.85 0.13 60); }
    .scp-rank-row .info { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
    .scp-rank-row .info .n { font-size: 13px; font-weight: 500; color: var(--fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .scp-rank-row .info .meta { font-size: 11.5px; color: var(--fg-3); }
    .scp-rank-row .info .bar { height: 4px; background: var(--surface-2); border-radius: 999px; overflow: hidden; }
    .scp-rank-row .info .bar > span { display: block; height: 100%; background: linear-gradient(90deg, oklch(0.78 0.16 160), oklch(0.65 0.14 230)); border-radius: 999px; }
    .scp-rank-row .v { font-size: 14px; font-weight: 600; color: var(--fg); font-family: 'JetBrains Mono', monospace; }
    .scp-rank-row .v .u { font-size: 10px; color: var(--fg-3); font-weight: 500; }

    /* Empty state */
    .scp-empty {
      display: flex; flex-direction: column; align-items: center; gap: 10px;
      padding: 36px 22px 32px; color: var(--fg-3); text-align: center;
    }
    .scp-empty p { margin: 0; font-size: 13px; }

    /* responsive squish */
    @media (max-width: 1180px) {
      .scp-dash-grid { grid-template-columns: repeat(2, 1fr); }
      .scp-row-2-1, .scp-row-1-1 { grid-template-columns: 1fr; }
      .scp-hero { grid-template-columns: 1fr; }
    }
  `;
  document.head.appendChild(s);
})();

window.ScreenDashboard = ScreenDashboard;
