// ═══════════════════════════════════════════════════════
// BAUKO CRM — Frota (crm-frota-v1.jsx)
// ═══════════════════════════════════════════════════════
/* global React, CRM_DATA, CRM_API */

const useFrotaState    = React.useState;
const useFrotaEffect   = React.useEffect;
const useFrotaMemo     = React.useMemo;

// ─── Constants ────────────────────────────────────────
const _F_ANO_ATUAL  = new Date().getFullYear();
const _F_THRESH_H   = 8000;
const _F_THRESH_ANO = _F_ANO_ATUAL - 10;   // ex: 2015 em 2025

// ─── Helpers ──────────────────────────────────────────
function _fFmtH(h) {
  var n = parseFloat(h) || 0;
  return n > 0 ? n.toLocaleString('pt-BR') + 'h' : '—';
}
function _fIsKom(m)  { return (m.id || '').startsWith('KOM-'); }
function _fIsCand(m, thH, thAno) {
  var h   = parseFloat(m.horimetro) || 0;
  var ano = parseInt(m.ano) || 0;
  return h > thH || (ano > 1990 && ano <= thAno);
}
function _fCli(id) {
  return (CRM_DATA.clientes || []).find(function(c) { return c.id === id; }) || null;
}
function _fAbrirFrota(clienteId, onNav) {
  if (!onNav) return;
  onNav('clientes');
  setTimeout(function() {
    try { window.dispatchEvent(new CustomEvent('crm_open_cliente', { detail: { id: clienteId, tab: 'frota' } })); }
    catch(e) {}
  }, 120);
}
function _fVendedorNome(id) {
  var u = (CRM_DATA.usuarios || []).find(function(u) { return u.id === id; });
  return u ? (u.nome || '').split(' ')[0] : '';
}

// ─── Paleta padrão p/ charts (mesma do Market Share, alinhada ao CRM) ─────
const _F_PALETA = [
  '#007c44', '#3370b7', '#8a5a00', '#dc2626', '#7c3aed',
  '#0891b2', '#65a30d', '#d97706', '#7c2d12', '#1e40af',
  '#be185d', '#15803d', '#92400e', '#1e3a8a', '#581c87',
];

// ─── Botão de download PNG para um chart (canvas) ─────────────────────────
// Usa toDataURL() do canvas. Funciona pra Chart.js. Encontra o primeiro
// <canvas> dentro do panel pai e baixa.
function FrotaExportBtn({ filename }) {
  function baixar() {
    try {
      // Encontra o canvas no panel mais próximo
      var btn    = arguments && arguments[0] && arguments[0].currentTarget;
      var panel  = btn && btn.closest('.panel');
      var canvas = panel && panel.querySelector('canvas');
      if (!canvas) {
        // Fallback: tenta html2canvas se algum dia for adicionado
        window.CRM_TOAST('Este card não tem chart pra exportar.', 'warn');
        return;
      }
      // Cria background branco antes de exportar (canvas Chart.js é transparente)
      var dataUrl = (function() {
        try {
          var w = canvas.width, h = canvas.height;
          var off = document.createElement('canvas');
          off.width = w; off.height = h;
          var ctx = off.getContext('2d');
          ctx.fillStyle = '#ffffff';
          ctx.fillRect(0, 0, w, h);
          ctx.drawImage(canvas, 0, 0);
          return off.toDataURL('image/png');
        } catch(e) {
          return canvas.toDataURL('image/png');
        }
      })();
      var a = document.createElement('a');
      a.href = dataUrl;
      var data = new Date().toISOString().slice(0,10);
      a.download = (filename || 'frota-chart') + '-' + data + '.png';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    } catch(e) {
      console.warn('[FrotaExportBtn] erro ao exportar:', e);
    }
  }
  return (
    <button onClick={baixar}
      title="Baixar este card em PNG"
      style={{
        background: 'transparent', border: 'none', cursor: 'pointer',
        color: 'var(--tx-3)', padding: 4, display: 'inline-flex', alignItems: 'center',
        borderRadius: 'var(--r-xs)', opacity: 0.6, transition: 'opacity 120ms',
      }}
      onMouseEnter={function(e){ e.currentTarget.style.opacity = 1; e.currentTarget.style.color = 'var(--grn)'; }}
      onMouseLeave={function(e){ e.currentTarget.style.opacity = 0.6; e.currentTarget.style.color = 'var(--tx-3)'; }}>
      <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
        <polyline points="7 10 12 15 17 10"/>
        <line x1="12" y1="15" x2="12" y2="3"/>
      </svg>
    </button>
  );
}

// Registra o plugin datalabels uma única vez. Idempotente.
function _ensureChartPlugins() {
  if (window.__BAUKO_CHART_PLUGINS_REGISTERED) return;
  if (window.Chart && window.ChartDataLabels) {
    window.Chart.register(window.ChartDataLabels);
    // Default off — opt-in por dataset/chart pra evitar poluição visual
    window.Chart.defaults.set('plugins.datalabels', { display: false });
    window.__BAUKO_CHART_PLUGINS_REGISTERED = true;
  }
}

// ─── Wrapper genérico Chart.js — cria/destroi o gráfico no canvas ─────────
// Recria quando data, type ou options mudam (JSON.stringify como dep stable).
// onElementClick(label, index) é chamado ao clicar em um elemento (cross-filter).
// activeLabel: realça o pedaço/barra correspondente quando esse label está ativo.
function FrotaChart({ type, data, options, onElementClick, activeLabel, height }) {
  var canvasRef = React.useRef(null);
  var chartRef  = React.useRef(null);

  React.useEffect(function() {
    if (!canvasRef.current || !window.Chart) return;
    _ensureChartPlugins();
    if (chartRef.current) { try { chartRef.current.destroy(); } catch(e) {} chartRef.current = null; }

    var ctx = canvasRef.current.getContext('2d');
    var opts = Object.assign({
      responsive:          true,
      maintainAspectRatio: false,
      plugins: { legend: { display: true, position: 'bottom', labels: { font: { size: 10 } } } },
    }, options || {});

    if (typeof onElementClick === 'function') {
      opts.onClick = function(evt, elements) {
        if (!elements || !elements.length) return;
        var el = elements[0];
        var lbl = data && data.labels && data.labels[el.index];
        if (lbl != null) onElementClick(lbl, el.index);
      };
      opts.onHover = function(evt, elements) {
        if (evt && evt.native && evt.native.target) {
          evt.native.target.style.cursor = (elements && elements.length) ? 'pointer' : 'default';
        }
      };
    }

    chartRef.current = new window.Chart(ctx, { type: type, data: data, options: opts });
    return function() {
      if (chartRef.current) { try { chartRef.current.destroy(); } catch(e) {} chartRef.current = null; }
    };
  }, [type, JSON.stringify(data), JSON.stringify(options), activeLabel]);

  return (
    <div style={{ position: 'relative', height: height || 280 }}>
      {!window.Chart && (
        <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center',
                      justifyContent: 'center', color: 'var(--tx-3)', font: '400 12px/1 var(--ff-body)' }}>
          Carregando gráfico…
        </div>
      )}
      <canvas ref={canvasRef}></canvas>
    </div>
  );
}

// ─── Badge Komtrax ────────────────────────────────────
function FrotaKomBadge() {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center',
                   padding: '1px 5px', borderRadius: 4, fontSize: 9, fontWeight: 700,
                   background: '#dbeafe', color: '#1d4ed8', letterSpacing: '.04em',
                   verticalAlign: 'middle', marginLeft: 4, lineHeight: '14px' }}>
      KOM
    </span>
  );
}

// ─── Barra CSS proporcional ────────────────────────────
function FrotaBar({ pct, color, height }) {
  return (
    <div style={{ flex: 1, height: height || 7, background: 'var(--border)',
                  borderRadius: 999, overflow: 'hidden' }}>
      <div style={{ height: '100%', width: Math.min(pct, 100) + '%',
                    background: color || 'var(--grn)', borderRadius: 999,
                    transition: 'width .3s' }} />
    </div>
  );
}
function FrotaBarRow({ label, n, total, color }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
      <span style={{ width: 130, font: '500 12px/1 var(--ff-body)', color: 'var(--tx)',
                     overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                     flexShrink: 0 }} title={label}>{label}</span>
      <FrotaBar pct={total > 0 ? n / total * 100 : 0} color={color} />
      <span style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)', minWidth: 32,
                     textAlign: 'right', flexShrink: 0 }}>{n}</span>
    </div>
  );
}

// ─── Centroides aproximados das 27 UFs (lat, lng) para o mapa Brasil ─────
const _UF_COORDS = {
  AC: [-9.97, -67.81], AL: [-9.57, -36.78], AP:  [0.04, -51.06],
  AM: [-3.07, -61.66], BA: [-12.97, -41.45], CE: [-3.71, -38.54],
  DF: [-15.83, -47.86], ES: [-19.18, -40.34], GO: [-15.83, -49.32],
  MA: [-2.55, -44.30], MT: [-12.64, -55.41], MS: [-20.51, -54.54],
  MG: [-18.10, -44.38], PA: [-3.79, -52.48], PB: [-7.06, -35.55],
  PR: [-24.89, -51.55], PE: [-8.28, -35.07], PI: [-7.71, -42.72],
  RJ: [-22.84, -43.15], RN: [-5.40, -36.95], RS: [-30.17, -53.50],
  RO: [-10.83, -63.34], RR: [1.99, -61.33], SC: [-27.45, -50.95],
  SP: [-22.19, -48.79], SE: [-10.57, -37.45], TO: [-9.46, -48.26],
};

// ─── Mapa Brasil com bolhas proporcionais ao volume por UF ────────────────
function FrotaMapaBrasil({ porUF, onSelectUF }) {
  var mapRef       = React.useRef(null);
  var mapInst      = React.useRef(null);
  var layerGroup   = React.useRef(null);

  React.useEffect(function() {
    if (!mapRef.current || !window.L) return;
    if (mapInst.current) { try { mapInst.current.remove(); } catch(e){} mapInst.current = null; }
    mapInst.current = window.L.map(mapRef.current, {
      center: [-14, -52],   // centro do Brasil
      zoom:   4,
      scrollWheelZoom: false,
      zoomControl: true,
      attributionControl: false,
    });
    window.L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
      maxZoom: 8, minZoom: 3,
    }).addTo(mapInst.current);
    layerGroup.current = window.L.layerGroup().addTo(mapInst.current);
    return function() {
      if (mapInst.current) { try { mapInst.current.remove(); } catch(e){} mapInst.current = null; }
    };
  }, []);

  React.useEffect(function() {
    if (!layerGroup.current || !window.L) return;
    layerGroup.current.clearLayers();
    var max = Math.max.apply(null, porUF.map(function(x){ return x[1]; }).concat([1]));
    porUF.forEach(function(x) {
      var uf = x[0], n = x[1];
      var coord = _UF_COORDS[uf];
      if (!coord || n <= 0) return;
      // Raio proporcional a sqrt(n) pra área refletir contagem
      var raio = Math.max(8, Math.sqrt(n / max) * 36);
      var marker = window.L.circleMarker(coord, {
        radius:    raio,
        color:     '#15803d',
        fillColor: 'var(--grn,#007c44)',
        fillOpacity: 0.55,
        weight:    2,
      });
      marker.bindTooltip(
        '<strong>' + uf + '</strong>: ' + n.toLocaleString('pt-BR') + ' máquina' + (n>1?'s':''),
        { permanent: false, direction: 'top', className: 'leaflet-tooltip' }
      );
      marker.on('click', function() { if (onSelectUF) onSelectUF(uf); });
      // Label da UF dentro do círculo (se grande o suficiente)
      if (raio >= 16) {
        var icon = window.L.divIcon({
          className: '',
          html: '<div style="font:600 11px/1 system-ui;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.4)">' + uf + '</div>',
          iconSize: [30, 14], iconAnchor: [15, 7],
        });
        window.L.marker(coord, { icon: icon, interactive: false }).addTo(layerGroup.current);
      }
      marker.addTo(layerGroup.current);
    });
  }, [JSON.stringify(porUF)]);

  return (
    <div ref={mapRef} style={{ height: 380, borderRadius: 'var(--r-sm)', overflow: 'hidden' }} />
  );
}

// ─── AnomaliasBloco — lista expansível de máquinas com dados suspeitos ────
function AnomaliasBloco({ anomalias, cliIdx, onNav }) {
  var [aberto, setAberto] = React.useState(false);
  var n = anomalias.length;
  // Contagem por tipo de razão (para badge resumo)
  var porTipo = {};
  anomalias.forEach(function(a) {
    a.razoes.forEach(function(r) {
      var k = r.split(' ')[0]; // primeira palavra como chave
      porTipo[k] = (porTipo[k] || 0) + 1;
    });
  });
  return (
    <div className="panel" style={{ border: '1px solid #fcd34d' }}>
      <div className="panel__hd" style={{ background: 'var(--warn-050, #fef3c7)', borderBottom: '1px solid #fcd34d' }}>
        <h3 style={{ color: '#92400e' }}>🚨 {n} máquina{n>1?'s':''} com dados suspeitos</h3>
        <button onClick={function(){ setAberto(function(v){ return !v; }); }}
          style={{ padding: '4px 12px', background: 'transparent', border: '1px solid #fcd34d',
                   color: '#92400e', borderRadius: 'var(--r-sm)', cursor: 'pointer',
                   font: '500 12px/1 var(--ff-body)' }}>
          {aberto ? '▾ Recolher' : '▸ Detalhar'}
        </button>
      </div>
      {!aberto && (
        <div className="panel__body">
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
            {Object.keys(porTipo).slice(0, 6).map(function(k) {
              return (
                <span key={k} style={{
                  font: '400 11px/1 var(--ff-body)', color: '#92400e',
                  background: '#fffbeb', border: '1px solid #fde68a',
                  padding: '5px 10px', borderRadius: 999,
                }}>
                  {k} <strong>{porTipo[k]}</strong>
                </span>
              );
            })}
          </div>
        </div>
      )}
      {aberto && (
        <div className="dt-wrap">
          <table className="dt">
            <thead><tr><th>ID</th><th>Cliente</th><th>Fab / Modelo</th><th>Ano</th><th>SMR</th><th>Problemas</th></tr></thead>
            <tbody>
              {anomalias.slice(0, 50).map(function(a, i) {
                var m = a.m;
                var cli = m.cliente_id ? cliIdx[m.cliente_id] : null;
                return (
                  <tr key={m._spId || m.id || i}>
                    <td style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>{m.id}</td>
                    <td style={{ font: '500 12px/1.3 var(--ff-body)', maxWidth: 180, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {cli ? (
                        <span style={{ color: 'var(--grn)', cursor: 'pointer' }}
                          onClick={function(){ _fAbrirFrota(m.cliente_id, onNav); }}>
                          {cli.razao}
                        </span>
                      ) : <span style={{ color: 'var(--tx-3)' }}>— órfã</span>}
                    </td>
                    <td style={{ font: '400 12px/1 var(--ff-body)' }}>
                      {[m.fabricante, m.modelo].filter(Boolean).join(' ') || <span style={{ color: 'var(--tx-3)' }}>—</span>}
                    </td>
                    <td style={{ font: '400 12px/1 var(--ff-mono)' }}>{m.ano || '—'}</td>
                    <td style={{ font: '400 12px/1 var(--ff-mono)' }}>{m.horimetro ? parseFloat(m.horimetro).toLocaleString('pt-BR') + 'h' : '—'}</td>
                    <td style={{ font: '400 11px/1.4 var(--ff-body)', color: '#92400e' }}>
                      {a.razoes.join(' · ')}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
          {anomalias.length > 50 && (
            <div style={{ padding: '8px 14px', font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)', textAlign: 'center' }}>
              … e mais {anomalias.length - 50} máquina(s). Mostrando 50 primeiras.
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// ABA 1 — Dashboard (interativo, Chart.js + cross-filter)
// ═══════════════════════════════════════════════════════
function FrotaDashboard({ frota, frotaSemFiltro, clientes, cliIdx, oportunidades, filtros, setF, limparFiltros, nFiltrosAtivos, onNav, onSetAba }) {
  // Toggle: clicar num pedaço/barra adiciona filtro. Clicar de novo no mesmo valor remove.
  function toggle(campo, valor) {
    setF(campo, filtros[campo] === valor ? '' : valor);
  }

  // G12: empty state — filtros zeraram resultado
  if (nFiltrosAtivos > 0 && frota.length === 0) {
    return (
      <div style={{
        padding: '60px 24px', textAlign: 'center',
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 'var(--r-lg)', boxShadow: 'var(--shadow-1)',
      }}>
        <div style={{ fontSize: 48, marginBottom: 16 }}>🔍</div>
        <div style={{ font: '500 16px/1.3 var(--ff-body)', color: 'var(--tx)', marginBottom: 8 }}>
          Nenhuma máquina bate com os filtros aplicados.
        </div>
        <div style={{ font: '400 13px/1.5 var(--ff-body)', color: 'var(--tx-3)', marginBottom: 20, maxWidth: 440, margin: '0 auto 20px' }}>
          {nFiltrosAtivos} filtro{nFiltrosAtivos>1?'s':''} ativo{nFiltrosAtivos>1?'s':''} reduziu o resultado a zero.
          Limpe um ou todos os filtros para ver os dados de novo.
        </div>
        <button onClick={limparFiltros} className="btn btn-primary"
          style={{ fontSize: 13, padding: '8px 18px' }}>
          <i data-lucide="filter-x" style={{ width: 13, height: 13 }}></i>
          Limpar todos os filtros
        </button>
      </div>
    );
  }

  // ── KPIs ─────────────────────────────────────────────────────────────────
  var totalMaq = frota.length;
  var clientesComFrota = useFrotaMemo(function() {
    return new Set(frota.map(function(m) { return m.cliente_id; }).filter(Boolean)).size;
  }, [frota]);
  var pctCob = clientes.length ? Math.round(clientesComFrota / clientes.length * 100) : 0;

  var idadeInfo = useFrotaMemo(function() {
    var comAno = frota.filter(function(m) { return m.ano && parseInt(m.ano) > 1990; });
    if (!comAno.length) return { media: null, n: 0 };
    var soma = comAno.reduce(function(acc, m) { return acc + (_F_ANO_ATUAL - parseInt(m.ano)); }, 0);
    return { media: (soma / comAno.length).toFixed(1), n: comAno.length };
  }, [frota]);

  var horiMed = useFrotaMemo(function() {
    var comH = frota.filter(function(m) { return (parseFloat(m.horimetro) || 0) > 0; });
    if (!comH.length) return null;
    var soma = comH.reduce(function(acc, m) { return acc + parseFloat(m.horimetro); }, 0);
    return Math.round(soma / comH.length);
  }, [frota]);

  var candidatos = useFrotaMemo(function() {
    return frota.filter(function(m) { return _fIsCand(m, _F_THRESH_H, _F_THRESH_ANO); });
  }, [frota]);
  var pctCand = frota.length ? Math.round(candidatos.length / frota.length * 100) : 0;

  // ── Distribuição por fabricante (donut) ──────────────────────────────────
  var dataFab = useFrotaMemo(function() {
    var acc = {};
    frota.forEach(function(m) { var f = m.fabricante || 'Outro'; acc[f] = (acc[f] || 0) + 1; });
    var sorted = Object.entries(acc).sort(function(a, b) { return b[1] - a[1]; });
    return {
      labels:   sorted.map(function(x){ return x[0]; }),
      datasets: [{
        data:            sorted.map(function(x){ return x[1]; }),
        backgroundColor: sorted.map(function(_, i) { return _F_PALETA[i % _F_PALETA.length]; }),
        borderWidth:     2,
        borderColor:     '#fff',
      }],
    };
  }, [frota]);

  // ── Top 10 modelos (barras horizontais) ──────────────────────────────────
  var dataModelos = useFrotaMemo(function() {
    var acc = {};
    frota.forEach(function(m) { if (m.modelo) acc[m.modelo] = (acc[m.modelo] || 0) + 1; });
    var sorted = Object.entries(acc).sort(function(a, b) { return b[1] - a[1]; }).slice(0, 10);
    return {
      labels:   sorted.map(function(x){ return x[0]; }),
      datasets: [{
        label:           'Máquinas',
        data:            sorted.map(function(x){ return x[1]; }),
        backgroundColor: sorted.map(function(x){ return x[0] === filtros.modelo ? '#dc2626' : 'var(--grn,#007c44)'; }),
        borderRadius:    4,
      }],
    };
  }, [frota, filtros.modelo]);

  // ── Por UF (barras horizontais) ──────────────────────────────────────────
  var dataUF = useFrotaMemo(function() {
    var acc = {};
    frota.forEach(function(m) {
      var c = cliIdx[m.cliente_id];
      var uf = c && c.uf ? c.uf.toUpperCase() : '—';
      acc[uf] = (acc[uf] || 0) + 1;
    });
    var sorted = Object.entries(acc).sort(function(a, b) { return b[1] - a[1]; });
    return {
      labels:   sorted.map(function(x){ return x[0]; }),
      datasets: [{
        label:           'Máquinas',
        data:            sorted.map(function(x){ return x[1]; }),
        backgroundColor: sorted.map(function(x){ return x[0] === filtros.uf ? '#dc2626' : '#3370b7'; }),
        borderRadius:    4,
      }],
    };
  }, [frota, filtros.uf, cliIdx]);

  // ── Distribuição etária (faixas) ─────────────────────────────────────────
  var dataAnos = useFrotaMemo(function() {
    var faixas = [
      { label: '< 5 anos',  cor: '#16a34a', test: function(a){ return a >= _F_ANO_ATUAL - 4; } },
      { label: '5–10 anos', cor: '#d97706', test: function(a){ return a >= _F_THRESH_ANO + 1 && a < _F_ANO_ATUAL - 4; } },
      { label: '> 10 anos', cor: '#dc2626', test: function(a){ return a > 1990 && a <= _F_THRESH_ANO; } },
      { label: 'Sem data',  cor: '#9ca3af', test: function(a){ return !a || a <= 1990; } },
    ];
    var counts = faixas.map(function(f) {
      return frota.filter(function(m) { return f.test(parseInt(m.ano)); }).length;
    });
    return {
      labels:   faixas.map(function(f){ return f.label; }),
      datasets: [{
        label:           'Máquinas',
        data:            counts,
        backgroundColor: faixas.map(function(f){ return f.cor; }),
        borderRadius:    4,
      }],
    };
  }, [frota]);

  // ── Distribuição horímetro (buckets) ─────────────────────────────────────
  var dataHori = useFrotaMemo(function() {
    var buckets = [
      { label: '0 – 2k',     test: function(h){ return h > 0    && h < 2000;  }, cor: '#16a34a' },
      { label: '2k – 5k',    test: function(h){ return h >= 2000 && h < 5000;  }, cor: '#3370b7' },
      { label: '5k – 10k',   test: function(h){ return h >= 5000 && h < 10000; }, cor: '#d97706' },
      { label: '10k – 15k',  test: function(h){ return h >= 10000 && h < 15000;}, cor: '#dc2626' },
      { label: '> 15k',      test: function(h){ return h >= 15000; },              cor: '#7c2d12' },
      { label: 'Sem dado',   test: function(h){ return !h || h <= 0; },           cor: '#9ca3af' },
    ];
    var counts = buckets.map(function(b) {
      return frota.filter(function(m) { return b.test(parseFloat(m.horimetro) || 0); }).length;
    });
    return {
      labels:   buckets.map(function(b){ return b.label; }),
      datasets: [{
        label:           'Máquinas',
        data:            counts,
        backgroundColor: buckets.map(function(b){ return b.cor; }),
        borderRadius:    4,
      }],
    };
  }, [frota]);

  // ── Top 10 clientes (lista) ──────────────────────────────────────────────
  var top10 = useFrotaMemo(function() {
    var cnt = {};
    frota.forEach(function(m) { if (m.cliente_id) cnt[m.cliente_id] = (cnt[m.cliente_id] || 0) + 1; });
    return Object.entries(cnt)
      .sort(function(a, b) { return b[1] - a[1]; })
      .slice(0, 10)
      .map(function(x) { return { cli: cliIdx[x[0]] || _fCli(x[0]), id: x[0], n: x[1] }; })
      .filter(function(x) { return !!x.cli; });
  }, [frota, cliIdx]);
  var maxTop = top10[0] ? top10[0].n : 1;

  // ── Renovação ────────────────────────────────────────────────────────────
  var opAtivaSet = useFrotaMemo(function() {
    var ativas = ['prospeccao', 'qualificacao', 'proposta', 'negociacao'];
    return new Set((oportunidades || [])
      .filter(function(o) { return ativas.indexOf(o.etapa) > -1; })
      .map(function(o) { return o.cliente_id; }));
  }, [oportunidades]);
  var cliCandids = useFrotaMemo(function() {
    return [...new Set(candidatos.map(function(m) { return m.cliente_id; }).filter(Boolean))];
  }, [candidatos]);
  var cliSemOp = cliCandids.filter(function(id) { return !opAtivaSet.has(id); });

  // ── G6: FORECAST de renovação em 6/12 meses ─────────────────────────────
  // Premissa: 500h/ano de uso médio (~250h em 6m). Idade soma 0.5 ano em 6m.
  // Margem de horímetro: 250h pra entrar em 6m, 500h pra 12m.
  // Margem de idade: 0.5 ano pra 6m, 1 ano pra 12m.
  var forecast = useFrotaMemo(function() {
    function cand(m, hMargem, anoMargem) {
      var h   = parseFloat(m.horimetro) || 0;
      var ano = parseInt(m.ano) || 0;
      return (h + hMargem) > _F_THRESH_H || (ano > 1990 && ano <= _F_THRESH_ANO + anoMargem);
    }
    var em6  = frota.filter(function(m){ return cand(m, 250, 0); }).length;  // já entra a 250h ou 0.5ano
    var em12 = frota.filter(function(m){ return cand(m, 500, 1); }).length;
    return {
      hoje:  candidatos.length,
      em6m:  em6,
      em12m: em12,
      pctHoje:  totalMaq ? (candidatos.length / totalMaq * 100) : 0,
      pct6m:    totalMaq ? (em6 / totalMaq * 100) : 0,
      pct12m:   totalMaq ? (em12 / totalMaq * 100) : 0,
    };
  }, [frota, candidatos, totalMaq]);

  // ── G3: Histograma por ANO completo (1990-atual) ─────────────────────────
  var dataAnoCompleto = useFrotaMemo(function() {
    var anoMin = 2000, anoMax = _F_ANO_ATUAL;
    var bucket = {};
    for (var y = anoMin; y <= anoMax; y++) bucket[y] = 0;
    frota.forEach(function(m) {
      var a = parseInt(m.ano) || 0;
      if (a >= anoMin && a <= anoMax) bucket[a]++;
    });
    var labels = Object.keys(bucket).map(function(y){ return parseInt(y); });
    var counts = labels.map(function(y){ return bucket[y]; });
    var cores  = labels.map(function(y) {
      if (y >= _F_ANO_ATUAL - 4) return '#16a34a';                    // < 5 anos: verde
      if (y >= _F_THRESH_ANO + 1) return '#d97706';                   // 5-10: amarelo
      return '#dc2626';                                                // > 10: vermelho
    });
    return {
      labels: labels,
      datasets: [{ label: 'Máquinas', data: counts, backgroundColor: cores, borderRadius: 2 }],
    };
  }, [frota]);

  // ── G4: Matrix UF × Fabricante (stacked bar) ─────────────────────────────
  var dataUFFab = useFrotaMemo(function() {
    // Top 8 UFs (por contagem) × Top 5 fabricantes
    var topFabs = dataFab.labels.slice(0, 5);
    var ufCount = {};
    frota.forEach(function(m) {
      var c = cliIdx[m.cliente_id];
      var uf = c && c.uf ? c.uf.toUpperCase() : '—';
      var f  = m.fabricante || 'Outro';
      if (!ufCount[uf]) ufCount[uf] = { _total: 0 };
      ufCount[uf][f] = (ufCount[uf][f] || 0) + 1;
      ufCount[uf]._total++;
    });
    var ufs = Object.keys(ufCount)
      .filter(function(u){ return u !== '—'; })
      .sort(function(a,b){ return ufCount[b]._total - ufCount[a]._total; })
      .slice(0, 8);
    var datasets = topFabs.map(function(fab, i) {
      return {
        label:           fab,
        data:            ufs.map(function(u){ return (ufCount[u] && ufCount[u][fab]) || 0; }),
        backgroundColor: _F_PALETA[i % _F_PALETA.length],
        borderRadius:    2,
        stack:           'fab',
      };
    });
    return { labels: ufs, datasets: datasets };
  }, [frota, cliIdx, dataFab]);

  // ── G10: ANOMALIAS — máquinas com dados suspeitos ────────────────────────
  // Critérios:
  //   - Horímetro > 30.000 (improvável)
  //   - Horímetro < 100 sendo máquina antiga (> 5 anos)
  //   - Ano fora de faixa válida (não 0/null, mas < 1990 ou > anoAtual)
  //   - Sem fabricante NEM modelo
  var anomalias = useFrotaMemo(function() {
    var lista = [];
    frota.forEach(function(m) {
      var h   = parseFloat(m.horimetro) || 0;
      var ano = parseInt(m.ano) || 0;
      var razoes = [];
      if (h > 30000) razoes.push('horímetro implausível (' + h.toLocaleString('pt-BR') + 'h)');
      if (h > 0 && h < 100 && ano > 0 && ano < _F_ANO_ATUAL - 5)
        razoes.push('horímetro baixo p/ idade (' + h + 'h em ' + (_F_ANO_ATUAL - ano) + ' anos)');
      if (ano > 0 && ano < 1990) razoes.push('ano inválido (' + ano + ')');
      if (ano > _F_ANO_ATUAL) razoes.push('ano futuro (' + ano + ')');
      if (!m.fabricante && !m.modelo) razoes.push('sem fabricante nem modelo');
      if (razoes.length) lista.push({ m: m, razoes: razoes });
    });
    return lista;
  }, [frota]);

  // Datalabels — usado em todos os charts pra mostrar valor + % onde fizer sentido
  // Total da série usado pra calcular %
  function _dlBarV() {
    return {
      display:  true,
      anchor:   'end',
      align:    'top',
      offset:   2,
      color:    'var(--tx-2,#404040)',
      font:     { size: 10, weight: '600' },
      formatter: function(value, ctx) {
        if (!value) return '';
        var total = (ctx.dataset.data || []).reduce(function(a, b){ return a + (b || 0); }, 0);
        var pct   = total > 0 ? (value / total * 100) : 0;
        return value.toLocaleString('pt-BR') + (pct >= 1 ? '\n' + pct.toFixed(0) + '%' : '');
      },
    };
  }
  function _dlBarH() {
    return {
      display:  true,
      anchor:   'end',
      align:    'right',
      offset:   4,
      color:    'var(--tx-2,#404040)',
      font:     { size: 10, weight: '600' },
      formatter: function(value, ctx) {
        if (!value) return '';
        var total = (ctx.dataset.data || []).reduce(function(a, b){ return a + (b || 0); }, 0);
        var pct   = total > 0 ? (value / total * 100) : 0;
        return value.toLocaleString('pt-BR') + (pct >= 1 ? ' · ' + pct.toFixed(0) + '%' : '');
      },
    };
  }
  function _dlDonut() {
    return {
      display:  function(ctx) {
        var v = ctx.dataset.data[ctx.dataIndex] || 0;
        var t = (ctx.dataset.data || []).reduce(function(a,b){ return a+(b||0); }, 0);
        return t > 0 && (v / t) >= 0.04; // só mostra fatia ≥ 4%
      },
      color:    '#fff',
      font:     { size: 11, weight: '700' },
      formatter: function(value, ctx) {
        var total = (ctx.dataset.data || []).reduce(function(a, b){ return a + (b || 0); }, 0);
        if (!total) return '';
        return (value / total * 100).toFixed(0) + '%';
      },
    };
  }

  var optsBarH = {
    indexAxis: 'y',
    plugins: { legend: { display: false }, datalabels: _dlBarH() },
    layout:  { padding: { right: 60 } },  // espaço pro label da % à direita
    scales:  { x: { beginAtZero: true, ticks: { font: { size: 10 } } },
               y: { ticks: { font: { size: 10 } } } },
  };
  var optsBarV = {
    plugins: { legend: { display: false }, datalabels: _dlBarV() },
    layout:  { padding: { top: 24 } },    // espaço pro label acima da barra
    scales:  { y: { beginAtZero: true, ticks: { font: { size: 10 } } },
               x: { ticks: { font: { size: 10 } } } },
  };
  // Rich tooltip do Donut Fabricante — top 3 clientes daquele fabricante
  function _richTooltipFab(ctx) {
    var fab = ctx.label;
    if (!fab) return '';
    var n = ctx.parsed;
    var total = ctx.dataset.data.reduce(function(a,b){ return a+b; }, 0);
    var pct = total > 0 ? (n / total * 100).toFixed(1) : 0;
    // Top 3 clientes desse fabricante
    var cnt = {};
    frota.forEach(function(m) {
      if (m.fabricante === fab && m.cliente_id) {
        cnt[m.cliente_id] = (cnt[m.cliente_id] || 0) + 1;
      }
    });
    var top = Object.entries(cnt).sort(function(a,b){ return b[1]-a[1]; }).slice(0,3);
    var linhas = [
      fab + ': ' + n.toLocaleString('pt-BR') + ' (' + pct + '%)',
      ''
    ];
    if (top.length) {
      linhas.push('Top clientes:');
      top.forEach(function(x) {
        var c = cliIdx[x[0]];
        var nome = c ? (c.razao || x[0]) : x[0];
        if (nome.length > 36) nome = nome.slice(0, 33) + '...';
        linhas.push('  • ' + nome + ' (' + x[1] + ')');
      });
    }
    return linhas;
  }

  var optsDonut = {
    plugins: {
      legend:     { position: 'right', labels: { boxWidth: 10, font: { size: 10 } } },
      datalabels: _dlDonut(),
      tooltip: {
        callbacks: { label: _richTooltipFab },
        padding: 10,
        boxPadding: 4,
      },
    },
    cutout: '55%',
  };

  // ── INSIGHTS narrativos ──────────────────────────────────────────────────
  var insights = useFrotaMemo(function() {
    var arr = [];
    if (!totalMaq) return arr;

    // 1. Fabricante predominante
    var topFab = dataFab.labels[0];
    var topFabN = dataFab.datasets[0].data[0];
    if (topFab && topFabN) {
      var pctTopFab = (topFabN / totalMaq * 100).toFixed(0);
      arr.push({
        tipo: 'ok',
        texto: <><strong>{topFab}</strong> domina a frota: <strong>{pctTopFab}%</strong> ({topFabN.toLocaleString('pt-BR')} de {totalMaq.toLocaleString('pt-BR')} máquinas)</>
      });
    }

    // 2. Modelo mais comum
    if (dataModelos.labels[0]) {
      var topMod   = dataModelos.labels[0];
      var topModN  = dataModelos.datasets[0].data[0];
      var pctTopM  = (topModN / totalMaq * 100).toFixed(0);
      arr.push({
        tipo: 'ok',
        texto: <>Modelo mais comum: <strong>{topMod}</strong> — {topModN.toLocaleString('pt-BR')} máquinas ({pctTopM}%)</>
      });
    }

    // 3. UF concentração
    if (dataUF.labels[0] && dataUF.labels[0] !== '—') {
      var topUF   = dataUF.labels[0];
      var topUFn  = dataUF.datasets[0].data[0];
      var pctTopUF = (topUFn / totalMaq * 100).toFixed(0);
      arr.push({
        tipo: pctTopUF > 60 ? 'warn' : 'ok',
        texto: <><strong>{topUF}</strong> concentra <strong>{pctTopUF}%</strong> da frota ({topUFn.toLocaleString('pt-BR')} máquinas)</>
      });
    }

    // 4. Idade
    if (idadeInfo.media) {
      var med = parseFloat(idadeInfo.media);
      var nMaduras = frota.filter(function(m){ var a = parseInt(m.ano); return a > 1990 && a <= _F_THRESH_ANO; }).length;
      var pctMad = (nMaduras / totalMaq * 100).toFixed(0);
      arr.push({
        tipo: med > 10 ? 'warn' : 'ok',
        texto: <>Frota com <strong>{idadeInfo.media} anos</strong> em média · <strong>{pctMad}%</strong> com +10 anos</>
      });
    }

    // 5. Candidatas a renovação
    if (candidatos.length) {
      var pctCandLocal = (candidatos.length / totalMaq * 100).toFixed(0);
      arr.push({
        tipo: pctCandLocal > 30 ? 'warn' : 'ok',
        texto: <><strong>{pctCandLocal}%</strong> candidatas a renovação ({candidatos.length.toLocaleString('pt-BR')} máquinas) — &gt;{_F_THRESH_H.toLocaleString('pt-BR')}h ou idade &gt;{_F_ANO_ATUAL - _F_THRESH_ANO} anos</>
      });
    }

    // 6. Clientes em renovação sem op ativa (negativo)
    if (cliSemOp.length) {
      arr.push({
        tipo: 'neg',
        texto: <><strong>{cliSemOp.length}</strong> cliente{cliSemOp.length>1?'s':''} com máquina candidata SEM oportunidade aberta</>
      });
    }

    // 7. Cobertura
    if (clientes.length) {
      arr.push({
        tipo: pctCob < 30 ? 'warn' : 'ok',
        texto: <><strong>{pctCob}%</strong> dos clientes da base têm frota mapeada ({clientesComFrota.toLocaleString('pt-BR')} de {clientes.length.toLocaleString('pt-BR')})</>
      });
    }

    // 8. Órfãs (no SP sem cliente)
    var nOrfas = frota.filter(function(m){ return !m.cliente_id; }).length;
    if (nOrfas > 0) {
      arr.push({
        tipo: 'warn',
        texto: <><strong>{nOrfas.toLocaleString('pt-BR')}</strong> máquina{nOrfas>1?'s':''} sem cliente vinculado — necessita curadoria</>
      });
    }

    return arr;
  }, [frota, dataFab, dataModelos, dataUF, idadeInfo, candidatos, cliSemOp, pctCob, clientesComFrota, clientes, totalMaq]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

      {/* Strip de insights narrativos — padrão Market Share */}
      {insights.length > 0 && (
        <div style={{
          background:   'linear-gradient(135deg, var(--grn-050,#ecfdf5) 0%, var(--surface-2) 100%)',
          border:       '1px solid var(--grn-100,#d1fae5)',
          borderLeft:   '4px solid var(--grn)',
          borderRadius: 'var(--r-md)',
          padding:      '14px 18px',
          boxShadow:    'var(--shadow-1)',
        }}>
          <div style={{
            font: '600 13px/1.2 var(--ff-display)', letterSpacing: '.04em',
            color: 'var(--grn)', marginBottom: 8,
            display: 'flex', alignItems: 'center', gap: 8,
          }}>
            💡 Destaques da frota
            {nFiltrosAtivos > 0 && (
              <span style={{
                font: '400 10px/1 var(--ff-mono)', color: 'var(--tx-3)',
                background: 'var(--surface)', border: '1px solid var(--border)',
                padding: '3px 8px', borderRadius: 999, marginLeft: 4,
              }}>
                {nFiltrosAtivos} filtro{nFiltrosAtivos>1?'s':''} ativo{nFiltrosAtivos>1?'s':''}
              </span>
            )}
          </div>
          <ul style={{
            listStyle: 'none', padding: 0, margin: 0,
            display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '6px 18px',
          }}>
            {insights.map(function(ins, i) {
              var cor = ins.tipo === 'warn' ? '#d97706' : ins.tipo === 'neg' ? '#dc2626' : 'var(--grn)';
              return (
                <li key={i} style={{
                  font: '400 12px/1.45 var(--ff-body)', color: 'var(--tx)',
                  paddingLeft: 14, position: 'relative',
                }}>
                  <span style={{ position: 'absolute', left: 0, color: cor, fontWeight: 'bold' }}>▸</span>
                  {ins.texto}
                </li>
              );
            })}
          </ul>
        </div>
      )}

      {/* KPI Hero + KPIs secundários (grid 2fr | 1fr 1fr) */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: '2fr 1fr 1fr',
        gridAutoRows: 'minmax(auto, auto)',
        gap: 12,
      }}>
        {/* HERO — % para renovação, métrica de ação comercial */}
        <div style={{
          gridRow: 'span 2',
          background: pctCand > 40
            ? 'linear-gradient(135deg, #fee2e2 0%, #fef2f2 100%)'
            : pctCand > 25
              ? 'linear-gradient(135deg, var(--warn-050, #fef3c7) 0%, #fffbeb 100%)'
              : 'linear-gradient(135deg, var(--grn-050, #ecfdf5) 0%, #f0fdf4 100%)',
          border: '1px solid ' + (pctCand > 40 ? '#fca5a5' : pctCand > 25 ? '#fcd34d' : 'var(--grn-100,#d1fae5)'),
          borderRadius: 'var(--r-lg)',
          padding: '24px 28px',
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'space-between',
          minHeight: 180,
        }}>
          <div>
            <div style={{
              font: '600 11px/1 var(--ff-body)', textTransform: 'uppercase', letterSpacing: '.1em',
              color: pctCand > 40 ? '#991b1b' : pctCand > 25 ? '#92400e' : '#15803d',
              marginBottom: 8,
            }}>
              🔧 Frota para renovação
            </div>
            <div style={{
              font: '400 80px/1 var(--ff-display)', letterSpacing: '-.02em',
              color: pctCand > 40 ? '#dc2626' : pctCand > 25 ? '#b45309' : '#15803d',
            }}>
              {pctCand}%
            </div>
            <div style={{
              font: '500 14px/1.3 var(--ff-body)',
              color: pctCand > 40 ? '#7f1d1d' : pctCand > 25 ? '#78350f' : '#14532d',
              marginTop: 4,
            }}>
              {candidatos.length.toLocaleString('pt-BR')} máquinas candidatas
            </div>
          </div>
          <div style={{
            font: '400 11px/1.4 var(--ff-body)',
            color: 'var(--tx-3)', marginTop: 12,
          }}>
            Critério: &gt;{_F_THRESH_H.toLocaleString('pt-BR')}h ou idade &gt;{_F_ANO_ATUAL - _F_THRESH_ANO} anos ·
            {cliSemOp.length > 0
              ? <strong style={{ color: '#dc2626', marginLeft: 4 }}>{cliSemOp.length} cliente{cliSemOp.length>1?'s':''} sem op. ativa</strong>
              : <span style={{ marginLeft: 4 }}>todos com op. ativa ✓</span>}
          </div>
        </div>

        {/* 4 KPIs secundários em 2x2 */}
        <div className="kpi-card">
          <div className="kpi-card__eyebrow">Total</div>
          <div className="kpi-card__v kpi-card__v--mono">{totalMaq.toLocaleString('pt-BR')}</div>
          <div className="kpi-card__delta kpi-card__sub">
            {nFiltrosAtivos > 0
              ? 'de ' + frotaSemFiltro.length.toLocaleString('pt-BR') + ' (filtrado)'
              : clientesComFrota + ' clientes'}
          </div>
        </div>
        <div className="kpi-card">
          <div className="kpi-card__eyebrow">Cobertura</div>
          <div className="kpi-card__v kpi-card__v--mono">{pctCob}%</div>
          <div className="kpi-card__delta kpi-card__sub" style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
            <span>{clientesComFrota.toLocaleString('pt-BR')}/{clientes.length.toLocaleString('pt-BR')}</span>
            {/* G2: indicador de meta (40% interno informal) */}
            <span style={{
              marginLeft: 'auto',
              font: '600 9px/1 var(--ff-body)',
              color: pctCob >= 40 ? '#15803d' : pctCob >= 25 ? '#92400e' : '#991b1b',
              background: pctCob >= 40 ? 'var(--grn-050)' : pctCob >= 25 ? '#fef3c7' : '#fee2e2',
              padding: '2px 6px', borderRadius: 999,
            }} title="Meta interna: 40%">
              meta 40%
            </span>
          </div>
        </div>
        <div className="kpi-card">
          <div className="kpi-card__eyebrow">Idade média</div>
          <div className="kpi-card__v kpi-card__v--mono">{idadeInfo.media ? idadeInfo.media + ' anos' : '—'}</div>
          <div className="kpi-card__delta kpi-card__sub">{idadeInfo.n.toLocaleString('pt-BR')} com data</div>
        </div>
        <div className="kpi-card">
          <div className="kpi-card__eyebrow">Horímetro médio</div>
          <div className="kpi-card__v kpi-card__v--mono">{horiMed != null ? horiMed.toLocaleString('pt-BR') + 'h' : '—'}</div>
          <div className="kpi-card__delta kpi-card__sub">por máquina ativa</div>
        </div>
      </div>

      {/* G6: Forecast de renovação 6m / 12m */}
      <div className="panel" style={{ background: 'linear-gradient(180deg, var(--surface) 0%, var(--surface-2) 100%)' }}>
        <div className="panel__hd">
          <h3>🔮 Forecast de renovação</h3>
          <span style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>
            Premissa: ~500h/ano de uso médio
          </span>
        </div>
        <div className="panel__body">
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16 }}>
            {[
              { label: 'Hoje',         n: forecast.hoje,  pct: forecast.pctHoje,  cor: '#15803d', delta: null },
              { label: 'Em 6 meses',   n: forecast.em6m,  pct: forecast.pct6m,    cor: '#b45309', delta: forecast.em6m  - forecast.hoje },
              { label: 'Em 12 meses',  n: forecast.em12m, pct: forecast.pct12m,   cor: '#dc2626', delta: forecast.em12m - forecast.hoje },
            ].map(function(f, i) {
              return (
                <div key={f.label} style={{
                  padding: '16px 18px',
                  background: 'var(--surface)',
                  border: '1px solid var(--border)',
                  borderRadius: 'var(--r-md)',
                  borderTop: '3px solid ' + f.cor,
                }}>
                  <div style={{ font: '600 10px/1 var(--ff-body)', textTransform: 'uppercase', letterSpacing: '.08em', color: 'var(--tx-3)' }}>
                    {f.label}
                  </div>
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginTop: 8 }}>
                    <span style={{ font: '400 32px/1 var(--ff-display)', color: f.cor }}>
                      {f.n.toLocaleString('pt-BR')}
                    </span>
                    <span style={{ font: '500 14px/1 var(--ff-mono)', color: 'var(--tx-2)' }}>
                      {f.pct.toFixed(0)}%
                    </span>
                  </div>
                  {f.delta != null && f.delta > 0 && (
                    <div style={{ font: '400 11px/1.3 var(--ff-body)', color: 'var(--tx-3)', marginTop: 4 }}>
                      <span style={{ color: f.cor, fontWeight: 600 }}>+{f.delta.toLocaleString('pt-BR')}</span> vão amadurecer
                    </div>
                  )}
                </div>
              );
            })}
          </div>
          {forecast.em12m > forecast.hoje && (
            <div style={{ marginTop: 12, padding: '10px 14px',
                          background: 'var(--info-050, #e4eef8)', border: '1px solid #c1d6ec',
                          borderRadius: 'var(--r-sm)',
                          font: '400 12px/1.4 var(--ff-body)', color: '#1e3a8a' }}>
              💡 Nos próximos 12 meses, <strong>+{(forecast.em12m - forecast.hoje).toLocaleString('pt-BR')} máquinas</strong> entram
              na faixa de renovação — antecipar contato comercial com esses clientes pode acelerar o ciclo de vendas.
            </div>
          )}
        </div>
      </div>

      {/* Grid 2 colunas */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>

        {/* Fabricante — DONUT (clicável) */}
        <div className="panel">
          <div className="panel__hd">
            <h3>Por fabricante</h3>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              {filtros.fab && (
                <span style={{ font: '500 11px/1 var(--ff-mono)', color: 'var(--grn)' }}>
                  ▶ {filtros.fab}
                </span>
              )}
              <FrotaExportBtn filename="frota-fabricante" />
            </div>
          </div>
          <div className="panel__body" style={{ paddingTop: 4 }}>
            <FrotaChart type="doughnut" data={dataFab} options={optsDonut}
              activeLabel={filtros.fab}
              onElementClick={function(label){ toggle('fab', label); setF('modelo', ''); }}
              height={260} />
          </div>
        </div>

        {/* Top 10 modelos — BARRAS HORIZONTAIS (clicável) */}
        <div className="panel">
          <div className="panel__hd">
            <h3>Top 10 modelos</h3>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              {filtros.modelo && (
                <span style={{ font: '500 11px/1 var(--ff-mono)', color: '#dc2626' }}>
                  ▶ {filtros.modelo}
                </span>
              )}
              <FrotaExportBtn filename="frota-modelos" />
            </div>
          </div>
          <div className="panel__body" style={{ paddingTop: 4 }}>
            <FrotaChart type="bar" data={dataModelos} options={optsBarH}
              activeLabel={filtros.modelo}
              onElementClick={function(label){ toggle('modelo', label); }}
              height={260} />
          </div>
        </div>

        {/* Por UF — BARRAS VERTICAIS (clicável) */}
        <div className="panel">
          <div className="panel__hd">
            <h3>Por UF</h3>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              {filtros.uf && (
                <span style={{ font: '500 11px/1 var(--ff-mono)', color: '#dc2626' }}>
                  ▶ {filtros.uf}
                </span>
              )}
              <FrotaExportBtn filename="frota-uf" />
            </div>
          </div>
          <div className="panel__body" style={{ paddingTop: 4 }}>
            <FrotaChart type="bar" data={dataUF} options={optsBarV}
              activeLabel={filtros.uf}
              onElementClick={function(label){ toggle('uf', label === '—' ? '' : label); }}
              height={260} />
          </div>
        </div>

        {/* G3: Histograma por ano completo (substitui as 4 faixas) */}
        <div className="panel">
          <div className="panel__hd">
            <h3>Distribuição por ano</h3>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
              <span style={{ font: '400 10px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>
                <span style={{ color: '#16a34a' }}>■</span> &lt;5 anos
                <span style={{ marginLeft: 8, color: '#d97706' }}>■</span> 5–10
                <span style={{ marginLeft: 8, color: '#dc2626' }}>■</span> +10
              </span>
              <FrotaExportBtn filename="frota-distribuicao-ano" />
            </div>
          </div>
          <div className="panel__body" style={{ paddingTop: 4 }}>
            <FrotaChart type="bar" data={dataAnoCompleto}
              options={{
                plugins: { legend: { display: false }, datalabels: { display: false } },
                scales: {
                  y: { beginAtZero: true, ticks: { font: { size: 9 } } },
                  x: { ticks: { font: { size: 9 }, maxRotation: 0, autoSkip: true, maxTicksLimit: 13 } },
                },
              }}
              height={260} />
          </div>
        </div>

        {/* Horímetro — BARRAS VERTICAIS */}
        <div className="panel">
          <div className="panel__hd">
            <h3>Distribuição de horímetro</h3>
            <FrotaExportBtn filename="frota-distribuicao-horimetro" />
          </div>
          <div className="panel__body" style={{ paddingTop: 4 }}>
            <FrotaChart type="bar" data={dataHori} options={optsBarV} height={260} />
          </div>
        </div>

        {/* Top 10 clientes — LISTA com filtro + navegação */}
        <div className="panel">
          <div className="panel__hd">
            <h3>Top clientes por frota</h3>
            {filtros.clienteId && top10.find(function(x){ return x.id === filtros.clienteId; }) && (
              <button onClick={function(){ setF('clienteId', ''); }}
                style={{ font: '500 11px/1 var(--ff-mono)', color: '#dc2626',
                         background: 'transparent', border: 'none', cursor: 'pointer', padding: 0 }}>
                ▶ filtro ativo · limpar ✕
              </button>
            )}
          </div>
          <div>
            {top10.map(function(x, i) {
              var sel = filtros.clienteId === x.id;
              return (
                <div key={x.cli.id}
                  style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 18px',
                           borderBottom: i < top10.length - 1 ? '1px solid var(--border)' : 'none',
                           background: sel ? 'var(--grn-050, #ecfdf5)' : 'transparent',
                           transition: 'background 120ms' }}
                  onMouseEnter={function(e){ if (!sel) e.currentTarget.style.background = 'var(--surface-2)'; }}
                  onMouseLeave={function(e){ if (!sel) e.currentTarget.style.background = 'transparent'; }}>
                  <div style={{ flex: 1, minWidth: 0, cursor: 'pointer' }}
                    onClick={function(){ toggle('clienteId', x.id); }}
                    title="Clique para filtrar o dashboard por este cliente">
                    <div style={{ font: '500 13px/1.2 var(--ff-body)', color: 'var(--tx)',
                                  overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {x.cli.razao || x.cli.id}
                      {sel && <span style={{ marginLeft: 6, font: '600 9px/1 var(--ff-body)', color: 'var(--grn)',
                                              background: 'var(--surface)', padding: '2px 6px', borderRadius: 999 }}>filtrado</span>}
                    </div>
                    <div style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)', marginTop: 3 }}>
                      {[x.cli.cidade, x.cli.uf].filter(Boolean).join(' / ')}
                    </div>
                  </div>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0 }}>
                    <div style={{ width: 64, height: 5, background: 'var(--border)',
                                  borderRadius: 999, overflow: 'hidden' }}>
                      <div style={{ height: '100%', width: Math.round(x.n / maxTop * 100) + '%',
                                    background: 'var(--grn)', borderRadius: 999 }} />
                    </div>
                    <span style={{ font: '600 13px/1 var(--ff-mono)', color: 'var(--grn)',
                                   minWidth: 24, textAlign: 'right' }}>{x.n}</span>
                    <button onClick={function(e){ e.stopPropagation(); _fAbrirFrota(x.cli.id, onNav); }}
                      title="Ver frota deste cliente"
                      style={{ background: 'transparent', border: 'none', cursor: 'pointer',
                               color: 'var(--tx-3)', padding: 2, display: 'flex', alignItems: 'center' }}>
                      <i data-lucide="external-link" style={{ width: 12, height: 12 }}></i>
                    </button>
                  </div>
                </div>
              );
            })}
            {top10.length === 0 && (
              <div style={{ padding: '20px 18px', font: '400 12px/1 var(--ff-body)', color: 'var(--tx-3)' }}>
                Nenhuma frota cadastrada.
              </div>
            )}
          </div>
        </div>

      </div>

      {/* G5: Mapa Brasil com bolhas proporcionais por UF */}
      <div className="panel">
        <div className="panel__hd">
          <h3>Distribuição geográfica</h3>
          <span style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>
            Tamanho da bolha proporcional ao volume · clique para filtrar
          </span>
        </div>
        <div className="panel__body" style={{ paddingTop: 4 }}>
          <FrotaMapaBrasil
            porUF={dataUF.labels.map(function(uf, i) { return [uf, dataUF.datasets[0].data[i]]; }).filter(function(x){ return x[0] !== '—'; })}
            onSelectUF={function(uf){ toggle('uf', uf); }} />
        </div>
      </div>

      {/* G4: Matrix UF × Fabricante — stacked bar full-width */}
      {dataUFFab.labels.length > 0 && dataUFFab.datasets.length > 0 && (
        <div className="panel">
          <div className="panel__hd">
            <h3>Composição por UF × Fabricante</h3>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
              <span style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>
                Top 8 UFs · Top 5 fabricantes
              </span>
              <FrotaExportBtn filename="frota-uf-fabricante" />
            </div>
          </div>
          <div className="panel__body" style={{ paddingTop: 4 }}>
            <FrotaChart type="bar" data={dataUFFab}
              options={{
                plugins: {
                  legend:     { position: 'bottom', labels: { boxWidth: 10, font: { size: 10 } } },
                  datalabels: { display: false },
                },
                scales: {
                  x: { stacked: true, ticks: { font: { size: 10 } } },
                  y: { stacked: true, beginAtZero: true, ticks: { font: { size: 10 } } },
                },
              }}
              height={300} />
          </div>
        </div>
      )}

      {/* G10: Anomalias — bloco expansível */}
      {anomalias.length > 0 && (
        <AnomaliasBloco anomalias={anomalias} cliIdx={cliIdx} onNav={onNav} />
      )}

      {/* Renovação — full-width no fim */}
      <div className="panel">
        <div className="panel__hd">
          <h3>Oportunidades de renovação</h3>
          <span style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>
            &gt;{_F_THRESH_H.toLocaleString('pt-BR')}h ou &gt;{_F_ANO_ATUAL - _F_THRESH_ANO} anos
          </span>
        </div>
        <div className="panel__body">
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10, marginBottom: 14 }}>
            <div style={{ background: 'var(--warn-050)', border: '1px solid rgba(180,83,9,.2)',
                          borderRadius: 'var(--r-md)', padding: '14px 12px', textAlign: 'center' }}>
              <div style={{ font: '400 32px/1 var(--ff-display)', color: '#b45309', letterSpacing: '.02em' }}>
                {candidatos.length}
              </div>
              <div style={{ font: '400 11px/1.3 var(--ff-body)', color: '#92400e', marginTop: 5 }}>máquinas candidatas</div>
            </div>
            <div style={{ background: '#fee2e2', border: '1px solid rgba(185,28,28,.2)',
                          borderRadius: 'var(--r-md)', padding: '14px 12px', textAlign: 'center' }}>
              <div style={{ font: '400 32px/1 var(--ff-display)', color: '#b91c1c', letterSpacing: '.02em' }}>
                {cliSemOp.length}
              </div>
              <div style={{ font: '400 11px/1.3 var(--ff-body)', color: '#991b1b', marginTop: 5 }}>clientes sem op. ativa</div>
            </div>
            <div style={{ background: '#dcfce7', border: '1px solid rgba(22,163,74,.2)',
                          borderRadius: 'var(--r-md)', padding: '14px 12px', textAlign: 'center' }}>
              <div style={{ font: '400 32px/1 var(--ff-display)', color: '#15803d', letterSpacing: '.02em' }}>
                {cliCandids.length - cliSemOp.length}
              </div>
              <div style={{ font: '400 11px/1.3 var(--ff-body)', color: '#166534', marginTop: 5 }}>clientes já em negociação</div>
            </div>
          </div>
          <button className="btn btn-secondary" style={{ width: '100%', fontSize: 12 }}
            onClick={function() { onSetAba('renovacao'); }}>
            <i data-lucide="alert-triangle" style={{ width: 12, height: 12 }}></i> Ver aba Renovação →
          </button>
        </div>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// ABA 2 — Máquinas
// ═══════════════════════════════════════════════════════
// FrotaMaquinas — recebe frota JÁ FILTRADA pelo FrotaScreen (filtros centralizados)
// + frotaSemFiltro (escopo aplicado, mas sem filtros) p/ saber a base de comparação
// + cliIdx (índice pronto) + filtros/setF/limparFiltros (controles compartilhados)
function FrotaMaquinas({ frota, frotaSemFiltro, clientes, cliIdx, filtros, setF, limparFiltros, nFiltrosAtivos, onNav, onMutate }) {
  var [pagina,  setPagina]  = useFrotaState(0);
  var [sortCol, setSortCol] = useFrotaState('');
  var [sortDir, setSortDir] = useFrotaState('asc');
  var POR_PAG = 50;

  // Reseta paginação ao trocar de filtro ou ordenação
  useFrotaEffect(function() { setPagina(0); }, [filtros, sortCol, sortDir]);

  // Dropdowns derivados da BASE SEM FILTRO (mostra opções mesmo quando algum filtro está ativo)
  var fabricantes = useFrotaMemo(function() {
    var s = new Set(frotaSemFiltro.map(function(m) { return m.fabricante; }).filter(Boolean));
    return Array.from(s).sort();
  }, [frotaSemFiltro]);

  // Modelos cascateiam com fabricante selecionado
  var modelos = useFrotaMemo(function() {
    var fonte = filtros.fab ? frotaSemFiltro.filter(function(m){ return m.fabricante === filtros.fab; }) : frotaSemFiltro;
    var s = new Set(fonte.map(function(m) { return m.modelo; }).filter(Boolean));
    return Array.from(s).sort();
  }, [frotaSemFiltro, filtros.fab]);

  var ufs = useFrotaMemo(function() {
    var s = new Set();
    frotaSemFiltro.forEach(function(m) { var c = cliIdx[m.cliente_id]; if (c && c.uf) s.add(c.uf.toUpperCase()); });
    return Array.from(s).sort();
  }, [frotaSemFiltro, cliIdx]);

  // filtradas = frota (já passou pelo filtro do FrotaScreen)
  var filtradas = frota;

  // Ordenação por coluna
  var sortadas = useFrotaMemo(function() {
    if (!sortCol) return filtradas;
    var dir = sortDir === 'asc' ? 1 : -1;
    var getV = function(m) {
      if (sortCol === 'Fabricante') return (m.fabricante || '').toLowerCase();
      if (sortCol === 'Modelo')     return (m.modelo || '').toLowerCase();
      if (sortCol === 'Série')      return (m.serie || '').toLowerCase();
      if (sortCol === 'Ano')        return parseInt(m.ano) || 0;
      if (sortCol === 'Horímetro')  return parseFloat(m.horimetro) || 0;
      if (sortCol === 'Cliente')    return ((cliIdx[m.cliente_id] || {}).razao || '').toLowerCase();
      if (sortCol === 'UF')         return ((cliIdx[m.cliente_id] || {}).uf || '').toLowerCase();
      return '';
    };
    return filtradas.slice().sort(function(a, b) {
      var va = getV(a), vb = getV(b);
      if (typeof va === 'number') return dir * (va - vb);
      return dir * va.localeCompare(vb, 'pt-BR', { sensitivity: 'base' });
    });
  }, [filtradas, sortCol, sortDir, cliIdx]);

  var totalPag = Math.ceil(sortadas.length / POR_PAG);
  var paginadas = sortadas.slice(pagina * POR_PAG, (pagina + 1) * POR_PAG);
  var temFiltro = nFiltrosAtivos > 0;
  function limpar() { limparFiltros(); setPagina(0); }

  async function deletarMaquina(m) {
    var cli  = cliIdx[m.cliente_id];
    var desc = [m.fabricante, m.modelo].filter(Boolean).join(' ') || m.id;
    var conf = 'Excluir "' + desc + '"' + (cli ? ' de ' + (cli.razao || cli.id) : '') + '?';
    if (!await window.CRM_CONFIRM(conf, { danger: true })) return;
    try {
      await CRM_API.deleteItem('FrotaCliente', m._spId);
      var arr = CRM_DATA.frotaCliente;
      var idx = arr.findIndex(function(x) { return x.id === m.id; });
      if (idx > -1) arr.splice(idx, 1);
      if (onMutate) onMutate();
    } catch(e) {
      window.CRM_TOAST('Erro ao excluir: ' + e.message, 'error');
    }
  }

  function exportarCsv() {
    var cols = ['ID', 'Série', 'Fabricante', 'Modelo', 'Ano', 'Horímetro (h)', 'Origem', 'Cliente', 'Cidade', 'UF'];
    var linhas = filtradas.map(function(m) {
      var cli = cliIdx[m.cliente_id] || {};
      return [
        m.id, m.serie || '', m.fabricante || '', m.modelo || '', m.ano || '',
        parseFloat(m.horimetro) || '',
        _fIsKom(m) ? 'Komtrax' : 'Manual',
        cli.razao || '', cli.cidade || '', cli.uf || ''
      ].map(function(v) { return '"' + String(v).replace(/"/g, '""') + '"'; }).join(',');
    });
    var csv = [cols.join(',')].concat(linhas).join('\n');
    var blob = new Blob(['﻿' + csv], { type: 'text/csv;charset=utf-8;' });
    var url = URL.createObjectURL(blob);
    var a = document.createElement('a');
    a.href = url; a.download = 'frota-crm.csv'; a.click();
    URL.revokeObjectURL(url);
  }

  return (
    <div className="panel">
      <div className="panel__hd">
        <h3>Máquinas</h3>
        <button className="btn btn-secondary" onClick={exportarCsv} style={{ fontSize: 12, padding: '6px 10px' }}>
          <i data-lucide="download" style={{ width: 13, height: 13 }}></i> CSV
        </button>
      </div>
      <div className="panel__body" style={{ paddingBottom: 0 }}>
      {/* Toolbar de filtros — linha 1: busca + dropdowns principais */}
      <div style={{ display: 'flex', gap: 8, marginBottom: 8, flexWrap: 'wrap', alignItems: 'center' }}>
        <input className="inp" value={filtros.busca}
          onChange={function(e) { setF('busca', e.target.value); }}
          placeholder="Buscar fabricante, modelo, série ou cliente…"
          style={{ flex: '1 1 280px', padding: '6px 10px', fontSize: 13 }} />
        <select className="inp" value={filtros.fab}
          onChange={function(e) { setF('fab', e.target.value); setF('modelo', ''); /* reseta modelo ao trocar fab */ }}
          style={{ padding: '6px 8px', fontSize: 13, minWidth: 130 }}>
          <option value="">Todos fabricantes</option>
          {fabricantes.map(function(f) { return <option key={f} value={f}>{f}</option>; })}
        </select>
        <select className="inp" value={filtros.modelo}
          onChange={function(e) { setF('modelo', e.target.value); }}
          style={{ padding: '6px 8px', fontSize: 13, minWidth: 130 }}>
          <option value="">{filtros.fab ? 'Todos modelos' : 'Modelos (selecione fabricante)'}</option>
          {filtros.fab && modelos.map(function(m) { return <option key={m} value={m}>{m}</option>; })}
        </select>
        <select className="inp" value={filtros.uf}
          onChange={function(e) { setF('uf', e.target.value); }}
          style={{ padding: '6px 8px', fontSize: 13, minWidth: 100 }}>
          <option value="">Todas UFs</option>
          {ufs.map(function(u) { return <option key={u} value={u}>{u}</option>; })}
        </select>
        <select className="inp" value={filtros.status}
          onChange={function(e) { setF('status', e.target.value); }}
          style={{ padding: '6px 8px', fontSize: 13 }}>
          <option value="ativos">Clientes ativos</option>
          <option value="inativos">Clientes inativos</option>
          <option value="todos">Todos</option>
        </select>
      </div>
      {/* Toolbar de filtros — linha 2: ranges */}
      <div style={{ display: 'flex', gap: 8, marginBottom: 12, flexWrap: 'wrap', alignItems: 'center' }}>
        <span style={{ font: '500 11px/1 var(--ff-body)', color: 'var(--tx-3)', whiteSpace: 'nowrap' }}>Ano:</span>
        <input className="inp" type="number" value={filtros.anoMin} min="1990" max={_F_ANO_ATUAL}
          onChange={function(e) { setF('anoMin', e.target.value); }}
          placeholder="de" style={{ width: 70, padding: '5px 7px', fontSize: 12 }} />
        <input className="inp" type="number" value={filtros.anoMax} min="1990" max={_F_ANO_ATUAL}
          onChange={function(e) { setF('anoMax', e.target.value); }}
          placeholder="até" style={{ width: 70, padding: '5px 7px', fontSize: 12 }} />
        <span style={{ font: '500 11px/1 var(--ff-body)', color: 'var(--tx-3)', whiteSpace: 'nowrap', marginLeft: 8 }}>Horímetro:</span>
        <input className="inp" type="number" value={filtros.horiMin} min="0"
          onChange={function(e) { setF('horiMin', e.target.value); }}
          placeholder="de" style={{ width: 80, padding: '5px 7px', fontSize: 12 }} />
        <input className="inp" type="number" value={filtros.horiMax} min="0"
          onChange={function(e) { setF('horiMax', e.target.value); }}
          placeholder="até" style={{ width: 80, padding: '5px 7px', fontSize: 12 }} />
        {temFiltro && (
          <button className="btn btn-secondary" onClick={limpar}
            style={{ fontSize: 12, padding: '5px 10px', marginLeft: 'auto' }}>
            <i data-lucide="filter-x" style={{ width: 12, height: 12 }}></i> Limpar filtros
          </button>
        )}
      </div>

      {/* Contagem */}
      <div style={{ font: '400 12px/1 var(--ff-body)', color: 'var(--tx-3)', marginBottom: 8 }}>
        {filtradas.length.toLocaleString('pt-BR')} máquina(s)
        {filtradas.length !== frotaSemFiltro.length
          ? ' filtradas de ' + frotaSemFiltro.length.toLocaleString('pt-BR')
          : ' no total'}
      </div>

      {/* Tabela */}
      <div style={{ overflow: 'auto', border: '1px solid var(--border)', borderRadius: 'var(--r-sm)' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
          <thead>
            <tr style={{ background: 'var(--surface-2)', position: 'sticky', top: 0, zIndex: 1 }}>
              {['Fabricante', 'Modelo', 'Série', 'Ano', 'Horímetro', 'Cliente', 'UF', ''].map(function(h) {
                var isSortable = h !== '';
                var isActive   = sortCol === h;
                return (
                  <th key={h}
                    onClick={isSortable ? function() {
                      if (sortCol === h) setSortDir(function(d) { return d === 'asc' ? 'desc' : 'asc'; });
                      else { setSortCol(h); setSortDir('asc'); }
                      setPagina(0);
                    } : undefined}
                    style={{ padding: '8px 10px', textAlign: 'left', fontWeight: 600,
                             color: isActive ? 'var(--grn)' : 'var(--tx-2)',
                             whiteSpace: 'nowrap', fontSize: 12,
                             borderBottom: '1px solid var(--border)',
                             cursor: isSortable ? 'pointer' : 'default',
                             userSelect: 'none' }}>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3 }}>
                      {h}
                      {isSortable && (
                        <span style={{ fontSize: 9, color: isActive ? 'var(--grn)' : 'var(--tx-3)', lineHeight: 1 }}>
                          {isActive ? (sortDir === 'asc' ? '▲' : '▼') : '⇅'}
                        </span>
                      )}
                    </span>
                  </th>
                );
              })}
            </tr>
          </thead>
          <tbody>
            {paginadas.map(function(m) {
              var cli   = cliIdx[m.cliente_id] || {};
              var isKom = _fIsKom(m);
              var isCand = _fIsCand(m, _F_THRESH_H, _F_THRESH_ANO);
              return (
                <tr key={m.id}
                  style={{ borderTop: '1px solid var(--border)',
                           background: isCand ? 'rgba(254,243,199,.35)' : 'transparent' }}>
                  <td style={{ padding: '7px 10px', fontWeight: 500 }}>{m.fabricante || '—'}</td>
                  <td style={{ padding: '7px 10px', color: 'var(--tx-2)' }}>{m.modelo || '—'}</td>
                  <td style={{ padding: '7px 10px', fontFamily: 'var(--ff-mono)', fontSize: 12,
                               color: 'var(--tx-2)', whiteSpace: 'nowrap' }}>
                    {m.serie || <span style={{ color: 'var(--tx-3)' }}>—</span>}
                  </td>
                  <td style={{ padding: '7px 10px', color: 'var(--tx-2)', whiteSpace: 'nowrap' }}>
                    {m.ano || '—'}
                  </td>
                  <td style={{ padding: '7px 10px', whiteSpace: 'nowrap' }}>
                    <span style={{ color: parseFloat(m.horimetro) > _F_THRESH_H ? '#b45309' : 'var(--tx-2)' }}>
                      {_fFmtH(m.horimetro)}
                    </span>
                    {isKom && <FrotaKomBadge />}
                  </td>
                  <td style={{ padding: '7px 10px', maxWidth: 200,
                               overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                    {cli.razao ? (
                      <span style={{ cursor: 'pointer', color: 'var(--grn)', fontWeight: 500 }}
                        onClick={function() { _fAbrirFrota(m.cliente_id, onNav); }}>
                        {cli.razao}
                      </span>
                    ) : <span style={{ color: 'var(--tx-3)' }}>—</span>}
                  </td>
                  <td style={{ padding: '7px 10px', color: 'var(--tx-3)', fontSize: 12 }}>
                    {cli.uf || '—'}
                  </td>
                  <td style={{ padding: '7px 10px', whiteSpace: 'nowrap' }}>
                    <button className="btn btn-secondary"
                      onClick={function() { _fAbrirFrota(m.cliente_id, onNav); }}
                      style={{ padding: '3px 8px', fontSize: 11, marginRight: 4 }}
                      title="Editar frota do cliente">
                      <i data-lucide="pencil" style={{ width: 12, height: 12 }}></i>
                    </button>
                    <button className="btn btn-secondary"
                      onClick={function() { deletarMaquina(m); }}
                      style={{ padding: '3px 8px', fontSize: 11, color: '#b91c1c' }}
                      title="Excluir máquina">
                      <i data-lucide="trash-2" style={{ width: 12, height: 12 }}></i>
                    </button>
                  </td>
                </tr>
              );
            })}
            {paginadas.length === 0 && (
              <tr>
                <td colSpan={8} style={{ padding: '24px', textAlign: 'center', color: 'var(--tx-3)', fontSize: 13 }}>
                  Nenhuma máquina encontrada.
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>

      </div>{/* /panel__body */}

      {/* Paginação */}
      {totalPag > 1 && (
        <div style={{ display: 'flex', justifyContent: 'center', gap: 8, padding: '12px 18px', borderTop: '1px solid var(--border)', alignItems: 'center' }}>
          <button className="btn btn-secondary"
            onClick={function() { setPagina(function(p) { return Math.max(0, p - 1); }); }}
            disabled={pagina === 0} style={{ fontSize: 12 }}>← Anterior</button>
          <span style={{ font: '400 12px/1 var(--ff-mono)', color: 'var(--tx-2)' }}>{pagina + 1} / {totalPag}</span>
          <button className="btn btn-secondary"
            onClick={function() { setPagina(function(p) { return Math.min(totalPag - 1, p + 1); }); }}
            disabled={pagina >= totalPag - 1} style={{ fontSize: 12 }}>Próxima →</button>
        </div>
      )}
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// ABA 3 — Renovação
// ═══════════════════════════════════════════════════════
function FrotaRenovacao({ frota, clientes, oportunidades, onNav }) {
  var [thH,      setThH]      = useFrotaState(_F_THRESH_H);
  var [thAno,    setThAno]    = useFrotaState(_F_THRESH_ANO);
  var [expanded, setExpanded] = React.useState({});
  function toggleExpand(id) {
    setExpanded(function(prev) { var n = Object.assign({}, prev); n[id] = !n[id]; return n; });
  }

  var cliIdx = useFrotaMemo(function() {
    var idx = {};
    clientes.forEach(function(c) { idx[c.id] = c; });
    return idx;
  }, [clientes]);

  var opAtivaMap = useFrotaMemo(function() {
    var ativas = ['prospeccao', 'qualificacao', 'proposta', 'negociacao'];
    var m = {};
    (oportunidades || []).filter(function(o) { return ativas.indexOf(o.etapa) > -1; })
      .forEach(function(o) {
        if (!m[o.cliente_id]) m[o.cliente_id] = [];
        m[o.cliente_id].push(o);
      });
    return m;
  }, [oportunidades]);

  var grupos = useFrotaMemo(function() {
    var acc = {};
    frota.filter(function(m) { return _fIsCand(m, thH, thAno); }).forEach(function(m) {
      if (!acc[m.cliente_id]) acc[m.cliente_id] = [];
      acc[m.cliente_id].push(m);
    });
    return Object.entries(acc)
      .map(function(x) {
        var id = x[0], maquinas = x[1];
        var ops = opAtivaMap[id] || [];
        return { cli: cliIdx[id], id: id, maquinas: maquinas, ops: ops, temOp: ops.length > 0 };
      })
      .filter(function(g) { return !!g.cli; })
      .sort(function(a, b) {
        if (!a.temOp && b.temOp) return -1;
        if (a.temOp && !b.temOp) return 1;
        return b.maquinas.length - a.maquinas.length;
      });
  }, [frota, thH, thAno, cliIdx, opAtivaMap]);

  var totalCand = grupos.reduce(function(acc, g) { return acc + g.maquinas.length; }, 0);

  return (
    <div>
      {/* Thresholds ajustáveis */}
      <div className="panel" style={{ marginBottom: 16 }}>
        <div className="panel__hd">
          <h3>Critérios de renovação</h3>
          <span style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>
            {grupos.length} cliente(s) · {totalCand} máquina(s) candidatas
          </span>
        </div>
        <div className="panel__body">
          <div style={{ display: 'flex', gap: 20, alignItems: 'center', flexWrap: 'wrap' }}>
            <label style={{ display: 'flex', alignItems: 'center', gap: 8, font: '400 13px/1 var(--ff-body)', color: 'var(--tx-2)' }}>
              Horímetro &gt;
              <input type="number" className="inp" value={thH}
                onChange={function(e) { setThH(parseInt(e.target.value) || _F_THRESH_H); }}
                style={{ width: 90, padding: '5px 8px', fontSize: 13 }} />
              <span style={{ font: '400 12px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>h</span>
            </label>
            <span style={{ color: 'var(--tx-3)', font: '400 11px/1 var(--ff-mono)' }}>ou</span>
            <label style={{ display: 'flex', alignItems: 'center', gap: 8, font: '400 13px/1 var(--ff-body)', color: 'var(--tx-2)' }}>
              Fabricado até
              <input type="number" className="inp" value={thAno} min="1990" max={_F_ANO_ATUAL}
                onChange={function(e) { setThAno(parseInt(e.target.value) || _F_THRESH_ANO); }}
                style={{ width: 80, padding: '5px 8px', fontSize: 13 }} />
            </label>
          </div>
        </div>
      </div>

      {/* Cards por cliente — colapsáveis */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {grupos.map(function(g) {
          var isExp = !!expanded[g.id];
          return (
            <div key={g.id} className="panel"
              style={{ border: g.temOp ? '1px solid var(--border)' : '1px solid #fca5a5',
                       padding: '14px 16px' }}>
              {/* Cabeçalho — clicável para expandir/recolher */}
              <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12,
                            cursor: 'pointer', marginBottom: isExp ? 10 : 0 }}
                onClick={function() { toggleExpand(g.id); }}>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', marginBottom: 3 }}>
                    <span style={{ fontWeight: 600, fontSize: 14 }}>{g.cli.razao || g.cli.id}</span>
                    {g.temOp ? (
                      <span className="b bo">
                        <span className="b-dot"></span>
                        {g.ops.length} oportunidade{g.ops.length > 1 ? 's' : ''} ativa{g.ops.length > 1 ? 's' : ''}
                      </span>
                    ) : (
                      <span className="b bd">
                        <span className="b-dot"></span>Sem oportunidade ativa
                      </span>
                    )}
                    <span style={{ font: '400 11px/1 var(--ff-mono)', color: 'var(--tx-3)' }}>
                      {g.maquinas.length} máquina{g.maquinas.length > 1 ? 's' : ''}
                    </span>
                  </div>
                  <div style={{ fontSize: 12, color: 'var(--tx-3)' }}>
                    {[g.cli.cidade, g.cli.uf].filter(Boolean).join(' / ')}
                    {g.cli.vendedor_id && (
                      <span> · Vendedor: {_fVendedorNome(g.cli.vendedor_id) || g.cli.vendedor_id}</span>
                    )}
                  </div>
                </div>
                <div style={{ display: 'flex', gap: 6, alignItems: 'center', flexShrink: 0 }}>
                  <button className="btn btn-secondary"
                    style={{ fontSize: 11, padding: '4px 10px' }}
                    onClick={function(e) { e.stopPropagation(); _fAbrirFrota(g.id, onNav); }}>
                    <i data-lucide="truck" style={{ width: 12, height: 12 }}></i> Ver frota
                  </button>
                  <i data-lucide={isExp ? 'chevron-up' : 'chevron-down'}
                    style={{ width: 16, height: 16, color: 'var(--tx-3)' }}></i>
                </div>
              </div>

              {/* Chips de máquinas — visíveis apenas quando expandido */}
              {isExp && (
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                  {g.maquinas.map(function(m) {
                    var h    = parseFloat(m.horimetro) || 0;
                    var ano  = parseInt(m.ano) || 0;
                    var motH   = h > thH;
                    var motAno = ano > 1990 && ano <= thAno;
                    var desc = [m.fabricante, m.modelo].filter(Boolean).join(' ') || m.id;
                    return (
                      <div key={m.id}
                        style={{ padding: '5px 10px', borderRadius: 'var(--r-sm)', fontSize: 12,
                                 background: 'var(--surface-2)', border: '1px solid var(--border)' }}>
                        <div style={{ fontWeight: 600 }}>{desc}</div>
                        <div style={{ display: 'flex', gap: 8, marginTop: 2 }}>
                          {ano > 1990 && (
                            <span style={{ color: motAno ? '#dc2626' : 'var(--tx-3)', fontSize: 11 }}>
                              {ano}
                            </span>
                          )}
                          {h > 0 && (
                            <span style={{ color: motH ? '#b45309' : 'var(--tx-3)', fontSize: 11 }}>
                              {_fFmtH(h)}{_fIsKom(m) && <FrotaKomBadge />}
                            </span>
                          )}
                        </div>
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
          );
        })}

        {grupos.length === 0 && (
          <div style={{ textAlign: 'center', padding: '48px 0', color: 'var(--tx-3)',
                        font: '400 13px/1.6 var(--ff-body)' }}>
            🎉 Nenhuma máquina candidata a renovação com os critérios atuais.
          </div>
        )}
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════
// COMPONENTE PRINCIPAL
// ═══════════════════════════════════════════════════════
function FrotaScreen({ onNav }) {
  var [aba,  setAba]  = useFrotaState('dashboard');
  var [tick, setTick] = useFrotaState(0);
  // Escopo da carteira: 'meus' filtra por vendedor_id do CRM_USER; 'todos' = base inteira.
  var [escopo, setEscopo] = useFrotaState('meus');

  // ── Filtros centralizados (compartilhados entre Dashboard e Máquinas) ────
  // Cada filtro vazio = inativo. Os filtros se acumulam (AND).
  var [filtros, setFiltros] = useFrotaState({
    busca:    '',  // texto livre — razao do cliente, modelo, série
    fab:      '',  // fabricante exato
    modelo:   '',  // modelo exato (cascateia com fab)
    uf:       '',  // UF do cliente
    anoMin:   '',
    anoMax:   '',
    horiMin:  '',
    horiMax:  '',
    clienteId:'',  // id exato (via autocomplete)
    status:   'ativos', // 'ativos' | 'inativos' | 'todos' (status do cliente)
  });
  function setF(k, v) { setFiltros(function(prev){ var n = Object.assign({}, prev); n[k] = v; return n; }); }
  function limparFiltros() {
    setFiltros({
      busca:'', fab:'', modelo:'', uf:'', anoMin:'', anoMax:'',
      horiMin:'', horiMax:'', clienteId:'', status:'ativos'
    });
  }
  // Conta filtros ativos (para exibir badge "X filtros ativos")
  var nFiltrosAtivos =
    (filtros.busca   ? 1 : 0) +
    (filtros.fab     ? 1 : 0) +
    (filtros.modelo  ? 1 : 0) +
    (filtros.uf      ? 1 : 0) +
    (filtros.anoMin || filtros.anoMax  ? 1 : 0) +
    (filtros.horiMin || filtros.horiMax ? 1 : 0) +
    (filtros.clienteId ? 1 : 0) +
    (filtros.status !== 'ativos' ? 1 : 0);

  function onMutate() { setTick(function(t) { return t + 1; }); }

  useFrotaEffect(function() {
    try { if (window.lucide) window.lucide.createIcons({ attrs: { 'stroke-width': 1.75 } }); }
    catch(e) {}
  });

  var frotaTodos = CRM_DATA.frotaCliente  || [];
  var clientes   = CRM_DATA.clientes      || [];
  var ops        = CRM_DATA.oportunidades || [];

  // Índice cliente por id (usado em vários filtros)
  var cliIdx = useFrotaMemo(function() {
    var idx = {};
    clientes.forEach(function(c) { idx[c.id] = c; });
    return idx;
  }, [clientes]);

  // Aplica escopo de carteira
  var _meuId    = (window.CRM_USER && window.CRM_USER.userId) || null;
  var _meuEmail = (window.CRM_USER && window.CRM_USER.email)  || '';
  var clienteEhMeu = {};
  clientes.forEach(function(c) {
    var vid = c.vendedor_id || c.proprietario || '';
    if (vid === _meuId || (vid && vid.toLowerCase && vid.toLowerCase() === _meuEmail)) {
      clienteEhMeu[c.id] = true;
    }
  });
  var frotaEscopo = (escopo === 'meus')
    ? frotaTodos.filter(function(m) { return m.cliente_id && clienteEhMeu[m.cliente_id]; })
    : frotaTodos;

  // Aplica os filtros centralizados (encadeado, eficiente)
  var frota = useFrotaMemo(function() {
    var bN = filtros.busca.trim().toLowerCase();
    var anoMin = filtros.anoMin ? parseInt(filtros.anoMin) : null;
    var anoMax = filtros.anoMax ? parseInt(filtros.anoMax) : null;
    var hMin   = filtros.horiMin ? parseFloat(filtros.horiMin) : null;
    var hMax   = filtros.horiMax ? parseFloat(filtros.horiMax) : null;
    return frotaEscopo.filter(function(m) {
      var cli = cliIdx[m.cliente_id];
      // Status do cliente (default 'ativos')
      if (filtros.status === 'ativos'   && cli && cli.status === 'inativo') return false;
      if (filtros.status === 'inativos' && (!cli || cli.status !== 'inativo')) return false;
      // Fabricante exato
      if (filtros.fab    && m.fabricante !== filtros.fab)    return false;
      // Modelo exato (cascateia com fab)
      if (filtros.modelo && m.modelo     !== filtros.modelo) return false;
      // UF (do cliente)
      if (filtros.uf     && (!cli || (cli.uf || '').toUpperCase() !== filtros.uf)) return false;
      // Range ano
      var ano = parseInt(m.ano) || 0;
      if (anoMin != null && ano < anoMin) return false;
      if (anoMax != null && ano > anoMax) return false;
      // Range horímetro
      var h = parseFloat(m.horimetro) || 0;
      if (hMin != null && h < hMin) return false;
      if (hMax != null && h > hMax) return false;
      // Cliente específico
      if (filtros.clienteId && m.cliente_id !== filtros.clienteId) return false;
      // Busca livre
      if (bN) {
        var txt = [m.fabricante, m.modelo, m.serie, cli && cli.razao, cli && cli.cidade].filter(Boolean).join(' ').toLowerCase();
        if (txt.indexOf(bN) === -1) return false;
      }
      return true;
    });
  }, [frotaEscopo, filtros, cliIdx]);

  var abas = [
    { id: 'dashboard', label: 'Dashboard',  icon: 'bar-chart-2'    },
    { id: 'maquinas',  label: 'Máquinas',   icon: 'list'           },
    { id: 'renovacao', label: 'Renovação',  icon: 'alert-triangle' },
  ];

  return (
    <div data-screen-label="Frota">
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14, flexWrap: 'wrap' }}>
        <div className="tabs" style={{ marginBottom: 0 }}>
          {abas.map(function(a) {
            return (
              <button key={a.id} className={aba === a.id ? 'is-on' : ''}
                onClick={function() { setAba(a.id); }}>
                <i data-lucide={a.icon} style={{ width: 13, height: 13, marginRight: 5, verticalAlign: 'middle' }}></i>
                {a.label}
              </button>
            );
          })}
        </div>
        {nFiltrosAtivos > 0 && (
          <button onClick={limparFiltros}
            style={{ padding:'5px 12px', font:'500 12px/1 var(--ff-body)', cursor:'pointer',
                     background:'var(--warn-050)', border:'1px solid var(--warn)', color:'#8a5a00',
                     borderRadius:'var(--r-sm)', display:'inline-flex', alignItems:'center', gap:6 }}
            title="Limpar todos os filtros aplicados">
            <i data-lucide="filter-x" style={{ width:12, height:12 }}></i>
            {nFiltrosAtivos} filtro{nFiltrosAtivos>1?'s':''} ativo{nFiltrosAtivos>1?'s':''} · limpar
          </button>
        )}
        <div className="tabs" style={{ marginBottom: 0, marginLeft: 'auto' }}>
          {[
            { v: 'meus',  l: 'Minha carteira' },
            { v: 'todos', l: 'Toda a base' },
          ].map(function(f) {
            return (
              <button key={f.v} className={escopo === f.v ? 'is-on' : ''}
                onClick={function() { setEscopo(f.v); }}>
                {f.l}
              </button>
            );
          })}
        </div>
      </div>

      {aba === 'dashboard' && (
        <FrotaDashboard
          frota={frota} frotaSemFiltro={frotaEscopo}
          clientes={clientes} cliIdx={cliIdx} oportunidades={ops}
          filtros={filtros} setF={setF} limparFiltros={limparFiltros} nFiltrosAtivos={nFiltrosAtivos}
          onNav={onNav} onSetAba={setAba} />
      )}
      {aba === 'maquinas' && (
        <FrotaMaquinas
          frota={frota} frotaSemFiltro={frotaEscopo}
          clientes={clientes} cliIdx={cliIdx}
          filtros={filtros} setF={setF} limparFiltros={limparFiltros} nFiltrosAtivos={nFiltrosAtivos}
          onNav={onNav} onMutate={onMutate} />
      )}
      {aba === 'renovacao' && (
        <FrotaRenovacao
          frota={frota} clientes={clientes} oportunidades={ops} onNav={onNav} />
      )}
    </div>
  );
}
