// Injectar animação CSS do spinner (uma vez)
if (!document.getElementById('mrp-anim')) {
  const _s = document.createElement('style');
  _s.id = 'mrp-anim';
  _s.textContent = '@keyframes _mrpSpin { to { transform: rotate(360deg) } }';
  document.head.appendChild(_s);
}

/* screen_producao_mrp.jsx — MRP Dashboard nativo no portal (tema portal) */

// ─── helpers ──────────────────────────────────────────────────────────────────
const MRP_GN = '#8cb700';
const MRP_RD = '#dc2626';
const MRP_OR = '#d97706';

const mrpFn = (n) => (n == null || isNaN(n)) ? '—' : Number(Math.round(n)).toLocaleString('pt-PT');
const mrpFd = (s) => {
  if (!s) return '—';
  const parts = String(s).split('-');
  if (parts.length !== 3) return s;
  return `${parts[2]}/${parts[1]}/${parts[0].slice(2)}`;
};

const mrpAddDays = (base, d) => {
  const dt = new Date(base);
  dt.setDate(dt.getDate() + d);
  return dt.toISOString().split('T')[0];
};

// dlim = límite de data para horizonte (replica lógica de rObj original)
const mrpDlim = (hoje, horDias) => {
  if (horDias === 99999) return '9999-12-31';
  if (horDias >= 0) return mrpAddDays(hoje, horDias);
  return mrpAddDays(hoje, 90); // Vencidos → rObj usa 90 dias como fallback
};

// ─── estilos partilhados ───────────────────────────────────────────────────────
const MRP_TH = {
  padding: '7px 10px', fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700,
  letterSpacing: '0.06em', color: 'var(--text-dim)', textTransform: 'uppercase',
  background: 'var(--bg-sunken)', borderBottom: '1px solid var(--border)',
  whiteSpace: 'nowrap', userSelect: 'none', cursor: 'pointer',
  position: 'sticky', top: 0, zIndex: 1,
};
const MRP_TD      = { padding: '6px 10px', fontSize: 12, borderBottom: '1px solid var(--border)', verticalAlign: 'middle' };
const MRP_TD_MONO = { ...MRP_TD, fontFamily: 'var(--font-mono)', fontSize: 11 };

// ─── componentes partilhados ───────────────────────────────────────────────────
const MrpBadge = ({ label, color, bg, border }) => (
  <span style={{
    display: 'inline-block', padding: '2px 7px', borderRadius: 4,
    fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700,
    letterSpacing: '0.04em', color, background: bg, border: `1px solid ${border}`,
  }}>{label}</span>
);

const MrpSearch = ({ value, onChange, placeholder }) => (
  <div style={{ position: 'relative', flexShrink: 0 }}>
    <input value={value} onChange={e => onChange(e.target.value)}
      placeholder={placeholder || 'Filtrar…'}
      style={{
        padding: '6px 10px 6px 28px', fontSize: 12, borderRadius: 6,
        border: '1px solid var(--border)', background: 'var(--bg-sunken)',
        color: 'var(--text)', outline: 'none', width: 220, fontFamily: 'var(--font-body)',
      }}
    />
    <span style={{ position: 'absolute', left: 8, top: '50%', transform: 'translateY(-50%)', color: 'var(--text-dim)', fontSize: 12, pointerEvents: 'none' }}>⌕</span>
  </div>
);

const MrpShowMore = ({ shown, total, onMore }) => total <= shown ? null : (
  <div style={{ padding: '10px 0', textAlign: 'center' }}>
    <button className="btn btn-xs btn-ghost" onClick={onMore} style={{ fontSize: 11 }}>
      Mostrar mais ({(total - shown).toLocaleString('pt-PT')} restantes)
    </button>
  </div>
);

const MrpSortHdr = ({ label, col, sort, onSort, align }) => {
  const active = sort.col === col;
  return (
    <th style={{ ...MRP_TH, textAlign: align || 'left' }} onClick={() => onSort(col)}>
      {label}{active ? (sort.asc ? ' ↑' : ' ↓') : ''}
    </th>
  );
};

// ─── lógica central MRP (replica rObj do dashboard original) ──────────────────
const mrpBuildRows = (d, horDias) => {
  const hoje = d.HOJE || new Date().toISOString().slice(0, 10);
  const dlim = mrpDlim(hoje, horDias);

  // Reverse BOM (para cálculo de demanda derivada em artigos não-PA)
  const rBOM = {};
  const paPendMap = {};

  for (const [pa, bom] of Object.entries(d._BOM || {})) {
    for (const b of (bom || [])) {
      if (!b.sub) continue; // L1 embalagem — ignorar
      if (!rBOM[b.a]) rBOM[b.a] = [];
      rBOM[b.a].push({ pa, qn: b.qn });
      for (const s of (b.sub || [])) {
        if (!rBOM[s.a]) rBOM[s.a] = [];
        rBOM[s.a].push({ pa, qn: s.qn });
      }
    }
  }

  // paPendMap: qty pendente por PA dentro do horizonte (de _ENC)
  for (const [art, orders] of Object.entries(d._ENC || {})) {
    let p = 0;
    for (const e of orders) { if (e[0] <= dlim) p += e[2]; }
    if (p > 0) paPendMap[art] = Math.round(p * 100) / 100;
  }

  const rows = [];
  for (const [art, no] of Object.entries(d._NO || {})) {
    const stk  = d._S?.[art] || 0;
    const no3  = no.no3  || 0;
    const nom  = no.nom  || 0;
    const mk   = no.mk   || '';
    const fam  = no.fam  || '';
    const ds   = no.ds   || '';

    // OFs dentro do horizonte
    const ofEntries = (d._OF?.[art] || []).filter(o => o.df && o.df <= dlim && o.qn > 0);
    const ofQty = ofEntries.reduce((s, o) => s + o.qn, 0);

    // Encomendas de clientes dentro do horizonte
    let enc = 0, pend = 0;
    if (d._ENC?.[art]) {
      for (const e of d._ENC[art]) {
        if (e[0] <= dlim) { enc += e[1]; pend += e[2]; }
      }
      enc  = Math.round(enc  * 100) / 100;
      pend = Math.round(pend * 100) / 100;
    } else {
      enc  = no.enc  || 0;
      pend = no.pend || 0;
    }

    // Demanda derivada para artigos não-PA (PI, MPC, MPS, ME, MS...)
    if (mk !== 'DECAL.PA' && rBOM[art]) {
      let derivedPend = 0;
      for (const link of rBOM[art]) {
        derivedPend += (paPendMap[link.pa] || 0) * link.qn;
      }
      derivedPend = Math.round(derivedPend * 100) / 100;
      pend = Math.round(Math.max(nom, derivedPend + pend) * 100) / 100;
    }

    const target    = Math.max(nom, pend);
    const cobertura = stk + ofQty;
    const saldo_no  = cobertura - target;

    let status;
    if (target === 0)             status = 'sem_no';
    else if (stk >= target)       status = 'ok';
    else if (cobertura >= target) status = 'ok_of';
    else                          status = 'deficit';

    const excede = no3 > 0 && pend > no3;
    const hasOf  = ofEntries.length > 0;

    rows.push({ art, ds, mk, fam, no3, nom, enc, pend, stk, ofQty, cobertura, saldo_no, status, excede, hasOf });
  }
  return rows;
};

// ─── Tab: Objetivos ───────────────────────────────────────────────────────────
const HOR_PILLS = [
  { label: 'Vencidos', dias: -1 },
  { label: '1 Sem.',   dias: 7 },
  { label: '2 Sem.',   dias: 14 },
  { label: '3 Sem.',   dias: 21 },
  { label: '1 Mês',    dias: 30 },
  { label: '2 Meses',  dias: 60 },
  { label: '3 Meses',  dias: 90 },
  { label: 'Todos',    dias: 99999 },
];

const mrpEstadoStyle = (status) => {
  if (status === 'deficit') return { label: 'Déficit',  color: MRP_RD,    bg: 'color-mix(in oklch, #dc2626 10%, transparent)', border: 'color-mix(in oklch, #dc2626 40%, transparent)' };
  if (status === 'ok_of')   return { label: 'OF Cobre', color: '#1e7a1e', bg: 'color-mix(in oklch, #8cb700 12%, transparent)', border: 'color-mix(in oklch, #8cb700 40%, transparent)' };
  if (status === 'ok')      return { label: 'Stock OK', color: MRP_GN,    bg: 'color-mix(in oklch, #8cb700 10%, transparent)', border: 'color-mix(in oklch, #8cb700 40%, transparent)' };
  return { label: 'Sem NO', color: 'var(--text-dim)', bg: 'var(--bg-sunken)', border: 'var(--border)' };
};

const ofEstadoStyle = (es) => {
  const s = (es || '').toLowerCase();
  if (s.includes('curso'))    return { color: MRP_GN,    bg: 'color-mix(in oklch, #8cb700 10%, transparent)', border: 'color-mix(in oklch, #8cb700 40%, transparent)' };
  if (s.includes('planeada')) return { color: '#6366f1', bg: 'color-mix(in oklch, #6366f1 10%, transparent)', border: 'color-mix(in oklch, #6366f1 40%, transparent)' };
  return { color: 'var(--text-dim)', bg: 'var(--bg-sunken)', border: 'var(--border)' };
};

const MrpObjetivos = ({ d }) => {
  const [horDias,      setHorDias]      = React.useState(7);
  const [marca,        setMarca]        = React.useState('all');
  const [familia,      setFamilia]      = React.useState('');
  const [filtro,       setFiltro]       = React.useState('all');
  const [q,            setQ]            = React.useState('');
  const [sort,         setSort]         = React.useState({ col: 'saldo_no', asc: true });
  const [limit,        setLimit]        = React.useState(150);
  const [expandedArt,  setExpandedArt]  = React.useState(null);
  const FAM = d._FAM || {};

  // Calcular todas as linhas (memoizado por horizonte)
  const allRows = React.useMemo(() => mrpBuildRows(d, horDias), [d, horDias]);

  // KPIs globais (antes de filtrar por marca/família)
  const kpis = React.useMemo(() => ({
    all:     allRows.length,
    deficit: allRows.filter(r => r.status === 'deficit').length,
    ok_of:   allRows.filter(r => r.status === 'ok_of').length,
    ok:      allRows.filter(r => r.status === 'ok').length,
    excede:  allRows.filter(r => r.excede).length,
  }), [allRows]);

  // Marcas e famílias disponíveis
  const marcas   = React.useMemo(() => [...new Set(allRows.map(r => r.mk).filter(Boolean))].sort(), [allRows]);
  const familias = React.useMemo(() => [...new Set(allRows.map(r => r.fam).filter(Boolean))].sort(), [allRows]);

  // Filtrar e ordenar
  const filtered = React.useMemo(() => {
    let rows = allRows;
    if (marca !== 'all') rows = rows.filter(r => r.mk === marca);
    if (familia)         rows = rows.filter(r => r.fam === familia);
    if (filtro === 'deficit')  rows = rows.filter(r => r.status === 'deficit');
    else if (filtro === 'ok_of') rows = rows.filter(r => r.status === 'ok_of');
    else if (filtro === 'ok')    rows = rows.filter(r => r.status === 'ok');
    else if (filtro === 'excede') rows = rows.filter(r => r.excede);
    if (q) {
      const ql = q.toLowerCase();
      const sL = { ok: 'stock ok', ok_of: 'of cobre', deficit: 'deficit', sem_no: 'sem no' };
      rows = rows.filter(r => [r.art, r.ds, r.mk, r.fam, sL[r.status] || ''].join(' ').toLowerCase().includes(ql));
    }
    return [...rows].sort((a, b) => {
      let va = a[sort.col], vb = b[sort.col];
      if (typeof va === 'string') { va = va.toLowerCase(); vb = vb.toLowerCase(); }
      if (va < vb) return sort.asc ? -1 : 1;
      if (va > vb) return sort.asc ? 1 : -1;
      return 0;
    });
  }, [allRows, marca, familia, filtro, q, sort]);

  const onSort = (col) => setSort(s => ({ col, asc: s.col === col ? !s.asc : true }));
  const onHor  = (dias) => { setHorDias(dias); setLimit(150); };
  const shown  = filtered.slice(0, limit);

  // Estilo pill activo/inactivo
  const pillSt = (active) => ({
    padding: '3px 10px', borderRadius: 12, fontSize: 10.5, fontFamily: 'var(--font-mono)',
    fontWeight: 700, cursor: 'pointer', border: '1px solid var(--border)',
    background: active ? MRP_GN : 'var(--bg-sunken)',
    color: active ? '#fff' : 'var(--text-dim)', transition: 'background 0.15s',
  });

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>

      {/* ── Barra de filtros ─────────────────────────────────────────────── */}
      <div style={{ padding: '10px 16px', borderBottom: '1px solid var(--border)', flexShrink: 0, display: 'flex', flexDirection: 'column', gap: 8 }}>

        {/* Horizonte */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', color: 'var(--text-dim)', textTransform: 'uppercase', marginRight: 2 }}>Horizonte</span>
          {HOR_PILLS.map(p => (
            <button key={p.dias} onClick={() => onHor(p.dias)} style={pillSt(horDias === p.dias)}>{p.label}</button>
          ))}
        </div>

        {/* KPI row */}
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {[
            { id: 'all',     label: 'Total artigos',  v: kpis.all,     color: 'var(--text)' },
            { id: 'deficit', label: 'Déficit vs NO',  v: kpis.deficit, color: MRP_RD },
            { id: 'ok_of',   label: 'OF Cobre',       v: kpis.ok_of,   color: '#1e7a1e' },
            { id: 'ok',      label: 'Stock OK',       v: kpis.ok,      color: MRP_GN },
            { id: 'excede',  label: 'Enc > NO',       v: kpis.excede,  color: MRP_OR },
          ].map(k => (
            <div key={k.id} onClick={() => { setFiltro(filtro === k.id ? 'all' : k.id); setLimit(150); }}
              style={{
                padding: '6px 14px', borderRadius: 8, cursor: 'pointer',
                border: filtro === k.id ? `1px solid ${k.color}` : '1px solid var(--border)',
                background: filtro === k.id ? `color-mix(in oklch, ${k.color} 10%, var(--bg-sunken))` : 'var(--bg-sunken)',
                display: 'flex', flexDirection: 'column', alignItems: 'flex-start', minWidth: 100,
              }}>
              <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>{k.label}</span>
              <span style={{ fontSize: 18, fontWeight: 700, color: k.color, fontFamily: 'var(--font-mono)' }}>{k.v.toLocaleString('pt-PT')}</span>
            </div>
          ))}
        </div>

        {/* Marca + Família + Search */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', color: 'var(--text-dim)', textTransform: 'uppercase' }}>Marca</span>
          <button onClick={() => setMarca('all')} style={pillSt(marca === 'all')}>Todas</button>
          {marcas.map(mk => (
            <button key={mk} onClick={() => setMarca(mk)} style={pillSt(marca === mk)}>{mk}</button>
          ))}
          <div style={{ width: 1, height: 18, background: 'var(--border)', alignSelf: 'center' }} />
          <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', color: 'var(--text-dim)', textTransform: 'uppercase' }}>Família</span>
          <select value={familia} onChange={e => { setFamilia(e.target.value); setLimit(150); }}
            style={{ fontSize: 11, padding: '4px 8px', borderRadius: 6, border: '1px solid var(--border)', background: 'var(--bg-sunken)', color: 'var(--text)', cursor: 'pointer' }}>
            <option value="">Todas as famílias</option>
            {familias.map(f => (
              <option key={f} value={f}>{FAM[f] || f}</option>
            ))}
          </select>
          <MrpSearch value={q} onChange={v => { setQ(v); setLimit(150); }} placeholder="Pesquisar artigo…" />
          <span style={{ fontSize: 11, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', marginLeft: 'auto' }}>
            {filtered.length.toLocaleString('pt-PT')} artigos
          </span>
        </div>
      </div>

      {/* ── Tabela ─────────────────────────────────────────────────────────── */}
      <div className="scrollbar" style={{ flex: 1, overflowY: 'auto' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse' }}>
          <thead>
            <tr>
              <MrpSortHdr label="Artigo"     col="art"     sort={sort} onSort={onSort} />
              <MrpSortHdr label="Marca"      col="mk"      sort={sort} onSort={onSort} />
              <MrpSortHdr label="Stock"      col="stk"     sort={sort} onSort={onSort} align="right" />
              <MrpSortHdr label="NO (3M)"    col="no3"     sort={sort} onSort={onSort} align="right" />
              <MrpSortHdr label="NO Mensal"  col="nom"     sort={sort} onSort={onSort} align="right" />
              <MrpSortHdr label="Pendentes"  col="pend"    sort={sort} onSort={onSort} align="right" />
              <MrpSortHdr label="OFs Plan."  col="ofQty"   sort={sort} onSort={onSort} align="right" />
              <MrpSortHdr label="Saldo"      col="saldo_no" sort={sort} onSort={onSort} align="right" />
              <th style={MRP_TH}>Estado</th>
            </tr>
          </thead>
          <tbody>
            {shown.map((r, i) => {
              const ec = mrpEstadoStyle(r.status);
              const saldoPos = r.saldo_no >= 0;
              const isExp = expandedArt === r.art;

              // Painel expandido — OFs + BOM
              const renderExpanded = () => {
                const ofs = (d._OF?.[r.art] || []).slice().sort((a, b) => (a.df || '') < (b.df || '') ? -1 : 1);
                const bom = d._BOM?.[r.art] || [];
                const prodTarget = Math.max(r.nom, r.pend);
                const ofTotalQty = ofs.reduce((s, o) => s + (o.qn || 0), 0);
                const prodQty = ofTotalQty > 0 ? ofTotalQty : prodTarget;

                const bomComps = bom.map(b => {
                  const nec   = Math.round((b.qn || 0) * prodQty);
                  const stk   = d._S?.[b.a] || 0;
                  const enc   = d._NO?.[b.a]?.enc || 0;
                  const saldo = stk + enc - nec;
                  return { a: b.a, ds: b.ds || '', un: b.un || '', nec, stk, enc, saldo, deficit: saldo < 0 };
                });
                const deficitCount = bomComps.filter(c => c.deficit).length;

                const thS = { ...MRP_TH, background: 'transparent', position: 'static', fontSize: 9 };

                return (
                  <tr key={`exp-${r.art}`}>
                    <td colSpan={9} style={{ padding: 0, background: 'color-mix(in oklch, var(--bg-sunken) 55%, transparent)', borderBottom: '2px solid var(--border)' }}>
                      <div style={{ padding: '14px 16px 16px 36px' }}>

                        {/* OFs Planeadas ou Simulação */}
                        {ofs.length > 0 ? (
                          <div style={{ marginBottom: 14 }}>
                            <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', color: 'var(--text-dim)', textTransform: 'uppercase', marginBottom: 6 }}>OFs Planeadas</div>
                            <div style={{ display: 'flex', flexDirection: 'column', gap: 2, maxHeight: 260, overflowY: 'auto' }}>
                              {ofs.map((o, oi) => {
                                const esS = ofEstadoStyle(o.es);
                                return (
                                  <div key={oi} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '5px 12px', background: 'var(--bg)', borderRadius: 5, border: '1px solid var(--border)' }}>
                                    <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 600, minWidth: 100 }}>OF {o.of}</span>
                                    <MrpBadge label={o.es || '?'} color={esS.color} bg={esS.bg} border={esS.border} />
                                    <span style={{ fontSize: 11, color: 'var(--text-dim)', fontStyle: 'italic' }}>{o.cli || 'sem cliente'}</span>
                                    <span style={{ marginLeft: 'auto', fontFamily: 'var(--font-mono)', fontSize: 12, fontWeight: 700, color: MRP_GN }}>+{mrpFn(o.qn)}</span>
                                    <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-muted)', minWidth: 75, textAlign: 'right' }}>{mrpFd(o.df)}</span>
                                  </div>
                                );
                              })}
                            </div>
                          </div>
                        ) : (
                          <div style={{ padding: '9px 14px', borderRadius: 6, border: '1px solid color-mix(in oklch, #6366f1 40%, transparent)', background: 'color-mix(in oklch, #6366f1 6%, transparent)', marginBottom: 14 }}>
                            <div style={{ fontSize: 12, fontWeight: 700, color: '#6366f1' }}>SIMULAÇÃO — sem OF criada</div>
                            <div style={{ fontSize: 11.5, color: 'var(--text-muted)', marginTop: 3 }}>
                              Necessidades para produzir {mrpFn(prodTarget)} un. e atingir o NO Mensal
                            </div>
                          </div>
                        )}

                        {/* BOM Componentes */}
                        {bomComps.length > 0 && (
                          <div>
                            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
                              <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', color: 'var(--text-dim)', textTransform: 'uppercase' }}>
                                Componentes necessários — {bomComps.length} componentes
                              </span>
                              {deficitCount > 0 && (
                                <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, padding: '2px 7px', borderRadius: 4, background: 'color-mix(in oklch, #dc2626 10%, transparent)', border: '1px solid color-mix(in oklch, #dc2626 40%, transparent)', color: MRP_RD }}>
                                  {deficitCount} em défice
                                </span>
                              )}
                            </div>
                            <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                              <thead><tr>
                                <th style={thS}>Componente</th>
                                <th style={{ ...thS, textAlign: 'right' }}>Necessário</th>
                                <th style={{ ...thS, textAlign: 'right' }}>Stock</th>
                                <th style={{ ...thS, textAlign: 'right' }}>Chegadas</th>
                                <th style={{ ...thS, textAlign: 'right' }}>Saldo</th>
                                <th style={thS}>Estado</th>
                              </tr></thead>
                              <tbody>
                                {bomComps.map((c, ci) => (
                                  <tr key={ci} style={{ borderBottom: '1px solid var(--border)' }}>
                                    <td style={{ ...MRP_TD, padding: '5px 10px' }}>
                                      <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 600 }}>{c.a}</span>
                                      {c.ds && <span style={{ fontSize: 11, color: 'var(--text-muted)', marginLeft: 8 }}>{c.ds}</span>}
                                    </td>
                                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', padding: '5px 10px' }}>{mrpFn(c.nec)} <span style={{ fontSize: 10, color: 'var(--text-dim)' }}>{c.un}</span></td>
                                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', padding: '5px 10px' }}>{mrpFn(c.stk)}</td>
                                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', padding: '5px 10px', color: 'var(--text-dim)' }}>{c.enc > 0 ? mrpFn(c.enc) : '—'}</td>
                                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', padding: '5px 10px', fontWeight: 700, color: c.deficit ? MRP_RD : MRP_GN }}>
                                      {c.saldo >= 0 ? '+' : ''}{mrpFn(c.saldo)}
                                    </td>
                                    <td style={{ ...MRP_TD, padding: '5px 10px' }}>
                                      <MrpBadge
                                        label={c.deficit ? 'Défice' : 'Stock OK'}
                                        color={c.deficit ? MRP_RD : MRP_GN}
                                        bg={c.deficit ? 'color-mix(in oklch, #dc2626 10%, transparent)' : 'color-mix(in oklch, #8cb700 10%, transparent)'}
                                        border={c.deficit ? 'color-mix(in oklch, #dc2626 40%, transparent)' : 'color-mix(in oklch, #8cb700 40%, transparent)'}
                                      />
                                    </td>
                                  </tr>
                                ))}
                              </tbody>
                            </table>
                          </div>
                        )}
                        {bomComps.length === 0 && (
                          <div style={{ fontSize: 11, color: 'var(--text-dim)', fontStyle: 'italic' }}>Sem BOM definida para este artigo.</div>
                        )}
                      </div>
                    </td>
                  </tr>
                );
              };

              return (
                <React.Fragment key={r.art}>
                  <tr
                    style={{ background: i % 2 === 0 ? 'transparent' : 'color-mix(in oklch, var(--bg-sunken) 40%, transparent)', cursor: 'pointer' }}
                    onClick={() => setExpandedArt(isExp ? null : r.art)}
                  >
                    <td style={MRP_TD}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                        <span style={{ fontSize: 9, color: 'var(--text-dim)', flexShrink: 0 }}>{isExp ? '▼' : '▶'}</span>
                        <div>
                          <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', fontWeight: 600, color: 'var(--text)' }}>{r.art}</div>
                          <div style={{ fontSize: 10.5, color: 'var(--text-muted)', marginTop: 1, maxWidth: 210, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.ds}</div>
                        </div>
                      </div>
                    </td>
                    <td style={{ ...MRP_TD, fontSize: 11, color: 'var(--text-muted)' }}>{r.mk}</td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right' }}>{mrpFn(r.stk)}</td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', color: 'var(--text-muted)' }}>{mrpFn(r.no3)}</td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right' }}>{mrpFn(r.nom)}</td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', color: r.pend > r.no3 ? MRP_OR : 'var(--text)', fontWeight: r.pend > r.no3 ? 700 : 400 }}>
                      {mrpFn(r.pend)}
                      {r.excede && <span style={{ marginLeft: 4, fontSize: 9, color: MRP_OR }}>▲ NO</span>}
                    </td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', color: r.ofQty > 0 ? '#1e7a1e' : 'var(--text-dim)' }}>
                      {r.ofQty > 0 ? mrpFn(r.ofQty) : '—'}
                    </td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', fontWeight: 700, color: saldoPos ? MRP_GN : MRP_RD }}>
                      {saldoPos ? '+' : ''}{mrpFn(r.saldo_no)}
                    </td>
                    <td style={MRP_TD}>
                      <MrpBadge label={ec.label} color={ec.color} bg={ec.bg} border={ec.border} />
                    </td>
                  </tr>
                  {isExp && renderExpanded()}
                </React.Fragment>
              );
            })}
          </tbody>
        </table>
        <MrpShowMore shown={limit} total={filtered.length} onMore={() => setLimit(l => l + 150)} />
      </div>
    </div>
  );
};

// ─── Tab: Encomendas ──────────────────────────────────────────────────────────
// Labels dos grupos de marca — mapa fixo para mk conhecidos, fallback genérico
const ENC_MK_COL  = {
  'DECAL.PID': 'Marca Decal · DECAL.PID',
  'DECAL.PI':  'Marca Branca · DECAL.PI',
  'DECAL.PA':  'Marca Decal · DECAL.PA',
  'DECAL.ME':  'Marca DECAL · ME',
  'DECAL.MPS': 'Marca DECAL · MPS',
  'DECAL.MPC': 'Marca DECAL · MPC',
};
const ENC_MK_PILL = {
  'DECAL.PID': 'Decal · PID',
  'DECAL.PI':  'Branca · PI',
  'DECAL.PA':  'Decal · PA',
  'DECAL.ME':  'DECAL · ME',
  'DECAL.MPS': 'DECAL · MPS',
  'DECAL.MPC': 'DECAL · MPC',
};
const encMkColLabel = mk => {
  if (mk === '_outros') return 'Outros';
  if (ENC_MK_COL[mk]) return ENC_MK_COL[mk];
  const p = mk.split('.');
  return p.length > 1 ? `Marca ${p[0]} · ${mk}` : `Marca ${mk}`;
};
const encMkPillLabel = mk => {
  if (mk === '_outros') return 'Outros';
  if (ENC_MK_PILL[mk]) return ENC_MK_PILL[mk];
  const p = mk.split('.');
  return p.length > 1 ? `${p[0]} · ${p.slice(1).join('.')}` : mk;
};

const encEstadoStyle = (st, vencido) => {
  if (vencido) return { label: 'VENCIDO',  color: MRP_RD,    bg: 'color-mix(in oklch, #dc2626 10%, transparent)', border: 'color-mix(in oklch, #dc2626 40%, transparent)' };
  const s = (st || '').toLowerCase();
  if (s.includes('stock'))                       return { label: st, color: MRP_GN,    bg: 'color-mix(in oklch, #8cb700 10%, transparent)', border: 'color-mix(in oklch, #8cb700 40%, transparent)' };
  if (s.includes('slitter') || s.includes('bobina')) return { label: st, color: '#6366f1', bg: 'color-mix(in oklch, #6366f1 10%, transparent)', border: 'color-mix(in oklch, #6366f1 40%, transparent)' };
  if (s.includes('fabricar'))                    return { label: st, color: MRP_OR,    bg: 'color-mix(in oklch, #d97706 10%, transparent)', border: 'color-mix(in oklch, #d97706 40%, transparent)' };
  if (s.includes('bom') || s.includes('ficha'))  return { label: st, color: MRP_OR,    bg: 'color-mix(in oklch, #d97706 10%, transparent)', border: 'color-mix(in oklch, #d97706 40%, transparent)' };
  return { label: st || '—', color: 'var(--text-dim)', bg: 'var(--bg-sunken)', border: 'var(--border)' };
};

// Card de uma linha de encomenda
const EncCard = ({ r, onClick }) => {
  const es = encEstadoStyle(r.status, r.vencido);
  return (
    <div onClick={onClick} style={{ padding: '8px 14px', borderBottom: '1px solid var(--border)', cursor: 'pointer' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 }}>
        <span style={{ fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 12, color: 'var(--text)' }}>{r.art}</span>
        <span style={{ fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 13, flexShrink: 0 }}>{mrpFn(r.qty_pend || r.qty)}</span>
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 }}>
        <span style={{ fontSize: 11, color: 'var(--text-dim)' }}>{r.ds || '—'}</span>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, flexShrink: 0, color: r.vencido ? MRP_RD : r.dias != null && r.dias <= 7 ? MRP_OR : 'var(--text-muted)' }}>{mrpFd(r.date)}</span>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 5, marginTop: 3, flexWrap: 'wrap' }}>
        <span style={{ fontSize: 11, color: 'var(--text-muted)', marginRight: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: 180 }}>{r.client}</span>
        <MrpBadge label={r.doc_type} color="var(--text-muted)" bg="var(--bg-sunken)" border="var(--border)" />
        <MrpBadge label={es.label} color={es.color} bg={es.bg} border={es.border} />
      </div>
    </div>
  );
};

// ─── Drill-down helpers (top-level to avoid remount on each render) ───────────

const DdOfExpandable = ({ o, expOf, setExpOf, fmtN }) => {
  const key   = String(o.of);
  const isExp = expOf === key;
  const esS   = ofEstadoStyle(o.es);
  return (
    <div style={{ borderBottom: '1px solid var(--border)' }}>
      <div onClick={() => setExpOf(isExp ? null : key)} style={{ padding: '8px 12px', display: 'flex', alignItems: 'center', gap: 8, cursor: o.comps?.length ? 'pointer' : 'default', background: isExp ? 'var(--bg-sunken)' : 'transparent' }}>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, fontWeight: 700, color: MRP_GN }}>+{fmtN(o.qn)}</span>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-dim)' }}>OF {o.of}</span>
        <MrpBadge label={o.es || '?'} color={esS.color} bg={esS.bg} border={esS.border} />
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-muted)', marginLeft: 'auto' }}>{mrpFd(o.df)}</span>
        {o.cl && <span style={{ fontSize: 11, color: 'var(--text-dim)' }}>{o.cl}</span>}
        {o.comps?.length > 0 && <span style={{ fontSize: 10, color: 'var(--text-dim)' }}>{isExp ? '▲' : '▼'}</span>}
      </div>
      {isExp && o.comps?.length > 0 && (
        <div style={{ padding: '6px 12px 8px 24px', background: 'color-mix(in oklch, var(--bg-sunken) 60%, transparent)' }}>
          {o.comps.map((c, ci) => (
            <div key={ci} style={{ display: 'flex', alignItems: 'baseline', gap: 8, padding: '2px 0' }}>
              <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10.5, minWidth: 130, color: 'var(--text)' }}>{c.a}</span>
              <span style={{ fontSize: 10.5, color: 'var(--text-muted)', flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.ds}</span>
              <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-dim)', flexShrink: 0 }}>{fmtN(c.qn)} {c.un}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

// ─── Drill-down panel ─────────────────────────────────────────────────────────
const DrillDownPanel = ({ selected, nec, d, onClose, encDlim }) => {
  const [expOf, setExpOf] = React.useState(null);

  if (!selected) return null;
  const { _line: l, r } = selected;
  const S  = d._S  || {};
  const NO = d._NO || {};
  const OF = d._OF || {};
  const fmt = n => (n == null ? '—' : Math.round(n).toLocaleString('pt-PT'));

  const jArt   = l.j || null;
  const jBruto = jArt ? (S[jArt] || 0) : null;
  const jCart  = jArt ? -(nec[jArt] || 0) : null;
  const jLiq   = jArt != null ? jBruto + jCart : null;
  const jNeed  = jArt ? (l.jcu || 0) * (l.qp || 0) : null;
  const jOfsAll  = jArt ? [...(OF[jArt] || [])].sort((a, b) => (a.df || '') < (b.df || '') ? -1 : 1) : [];
  const jOfsIn   = encDlim ? jOfsAll.filter(o => o.df && o.df <= encDlim) : jOfsAll;
  const jOfsOut  = encDlim ? jOfsAll.filter(o => !o.df || o.df > encDlim) : [];

  const paStock = l.spa || 0;
  const paCart  = -(nec[l.a] || 0);
  const paLiq   = paStock + paCart;
  const paOfs   = [...(OF[l.a] || [])].sort((a, b) => (a.df || '') < (b.df || '') ? -1 : 1);
  const paOfsIn  = encDlim ? paOfs.filter(o => o.df && o.df <= encDlim) : paOfs;
  const paOfsOut = encDlim ? paOfs.filter(o => !o.df || o.df > encDlim) : [];

  const FAM = d._FAM || {};
  const compGroups = {};
  for (const [comp, cu] of Object.entries(l.cx || {})) {
    if (comp === jArt) continue;
    const no = NO[comp] || {};
    const fam = no.fam || '_outros';
    if (!compGroups[fam]) compGroups[fam] = [];
    compGroups[fam].push({
      art: comp, ds: no.ds || '', mk: no.mk || '',
      bruto: S[comp] || 0, cart: -(nec[comp] || 0),
      liq: (S[comp] || 0) - (nec[comp] || 0), need: cu * (l.qp || 0),
    });
  }
  const compGroupEntries = Object.entries(compGroups);

  const headSt = { padding: '5px 10px', fontSize: 10, fontWeight: 700, color: 'var(--text-dim)', borderBottom: '1px solid var(--border)', fontFamily: 'var(--font-mono)', textTransform: 'uppercase', letterSpacing: '0.06em', background: 'var(--bg-sunken)', textAlign: 'left' };
  const cellSt = { padding: '5px 10px', fontSize: 11, borderBottom: '1px solid var(--border)', fontFamily: 'var(--font-mono)' };

  const PANEL_W = 440;
  return (
    <React.Fragment>
      {/* backdrop — click para fechar */}
      <div onClick={onClose} style={{ position: 'fixed', top: 'var(--topbar-h, 56px)', right: PANEL_W, bottom: 0, left: 0, zIndex: 40, background: 'rgba(0,0,0,0.35)', cursor: 'pointer' }} />
      {/* panel lateral */}
      <div style={{ position: 'fixed', top: 'var(--topbar-h, 56px)', right: 0, bottom: 0, width: PANEL_W, zIndex: 40, background: 'var(--bg)', borderLeft: '1px solid var(--border)', overflow: 'hidden', boxShadow: '-4px 0 24px rgba(0,0,0,0.2)' }}>
        <div className="scrollbar" style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, overflowY: 'scroll' }}>
        {/* header sticky */}
        <div style={{ position: 'sticky', top: 0, zIndex: 2, background: 'var(--bg)', padding: '12px 16px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 8 }}>
          <div>
            <div style={{ fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 13 }}>{r.art}</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{r.ds || '—'} · {mrpFd(r.date)} · {fmt(r.qty)} un.</div>
            <div style={{ fontSize: 11, color: 'var(--text-dim)', marginTop: 1 }}>{r.client || '—'} · {r.order_num || '—'}</div>
          </div>
          <button onClick={onClose} className="btn btn-xs btn-ghost" style={{ fontSize: 12, flexShrink: 0 }}>✕</button>
        </div>

        <div style={{ padding: '14px 16px', display: 'flex', flexDirection: 'column', gap: 14 }}>

          {/* JUMBO */}
          {jArt && (
            <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
              <div style={{ padding: '8px 12px', background: 'color-mix(in oklch, #6366f1 8%, transparent)', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, color: '#6366f1', letterSpacing: '0.08em', textTransform: 'uppercase' }}>JUMBO</span>
                <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)' }}>{jArt}</span>
              </div>
              <div style={{ display: 'flex', borderBottom: '1px solid var(--border)' }}>
                {[['BRUTO', fmt(jBruto), false], ['CARTEIRA', fmt(jCart), jCart < 0], ['LÍQUIDO', fmt(jLiq), jLiq < 0], ['NEED', fmt(jNeed), false]].map(function(m, i) {
                  return (
                    <div key={i} style={{ flex: 1, padding: '8px 4px', textAlign: 'center', borderRight: i < 3 ? '1px solid var(--border)' : 'none' }}>
                      <div style={{ fontSize: 9, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.06em', textTransform: 'uppercase' }}>{m[0]}</div>
                      <div style={{ fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 700, color: m[2] ? MRP_RD : 'var(--text-muted)', marginTop: 2 }}>{m[1]}</div>
                    </div>
                  );
                })}
              </div>
              {jOfsAll.length > 0 && (
                <div>
                  {jOfsIn.length > 0 && (
                    <div>
                      <div style={{ padding: '5px 12px', background: 'var(--bg-sunken)', borderBottom: '1px solid var(--border)', borderTop: '1px solid var(--border)', fontSize: 9.5, fontFamily: 'var(--font-mono)', fontWeight: 700, color: '#6366f1', letterSpacing: '0.06em', textTransform: 'uppercase' }}>
                        OFs PLANEADAS +{fmt(jOfsIn.reduce((s, o) => s + (o.qn || 0), 0))} DENTRO DO PERÍODO
                      </div>
                      {jOfsIn.map((of, i) => <DdOfExpandable key={i} o={of} expOf={expOf} setExpOf={setExpOf} fmtN={fmt} />)}
                    </div>
                  )}
                  {jOfsOut.length > 0 && (
                    <div>
                      <div style={{ padding: '5px 12px', background: 'var(--bg-sunken)', borderBottom: '1px solid var(--border)', borderTop: '1px solid var(--border)', fontSize: 9.5, fontFamily: 'var(--font-mono)', fontWeight: 700, color: 'var(--text-dim)', letterSpacing: '0.06em', textTransform: 'uppercase' }}>
                        FORA DO PERÍODO
                      </div>
                      {jOfsOut.map((of, i) => <DdOfExpandable key={i} o={of} expOf={expOf} setExpOf={setExpOf} fmtN={fmt} />)}
                    </div>
                  )}
                </div>
              )}
            </div>
          )}

          {/* PRODUTO ACABADO */}
          <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
            <div style={{ padding: '8px 12px', background: 'color-mix(in oklch, #8cb700 8%, transparent)', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, color: MRP_GN, letterSpacing: '0.08em', textTransform: 'uppercase' }}>PRODUTO ACABADO</span>
              <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)' }}>{r.art}</span>
            </div>
            <div style={{ display: 'flex', borderBottom: '1px solid var(--border)' }}>
              {[['STOCK', fmt(paStock), false], ['CARTEIRA', fmt(paCart), paCart < 0], ['LÍQUIDO', fmt(paLiq), paLiq < 0]].map(function(m, i) {
                return (
                  <div key={i} style={{ flex: 1, padding: '8px 4px', textAlign: 'center', borderRight: i < 2 ? '1px solid var(--border)' : 'none' }}>
                    <div style={{ fontSize: 9, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.06em', textTransform: 'uppercase' }}>{m[0]}</div>
                    <div style={{ fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 700, color: m[2] ? MRP_RD : 'var(--text-muted)', marginTop: 2 }}>{m[1]}</div>
                  </div>
                );
              })}
            </div>
            {paOfsIn.length > 0 && (
              <div>
                <div style={{ padding: '5px 12px', background: 'var(--bg-sunken)', borderBottom: '1px solid var(--border)', fontSize: 9.5, fontFamily: 'var(--font-mono)', fontWeight: 700, color: MRP_GN, letterSpacing: '0.06em', textTransform: 'uppercase' }}>
                  OFs PLANEADAS +{fmt(paOfsIn.reduce((s, o) => s + (o.qn || 0), 0))} DENTRO DO PERÍODO
                </div>
                {paOfsIn.map((of, i) => <DdOfExpandable key={i} o={of} expOf={expOf} setExpOf={setExpOf} fmtN={fmt} />)}
              </div>
            )}
            {paOfsOut.length > 0 && (
              <div>
                <div style={{ padding: '5px 12px', background: 'var(--bg-sunken)', borderBottom: '1px solid var(--border)', fontSize: 9.5, fontFamily: 'var(--font-mono)', fontWeight: 700, color: 'var(--text-dim)', letterSpacing: '0.06em', textTransform: 'uppercase' }}>
                  FORA DO PERÍODO
                </div>
                {paOfsOut.map((of, i) => <DdOfExpandable key={i} o={of} expOf={expOf} setExpOf={setExpOf} fmtN={fmt} />)}
              </div>
            )}
          </div>

          {/* COMPONENTES grouped by family — no internal scroll, panel scrolls */}
          {compGroupEntries.length > 0 && (
            <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
              <div style={{ padding: '8px 12px', background: 'var(--bg-sunken)', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, color: 'var(--text-dim)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>COMPONENTES</span>
                <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)' }}>{compGroupEntries.reduce((s, [, it]) => s + it.length, 0)} artigos</span>
              </div>
              <div style={{ overflowX: 'auto' }}><table style={{ width: '100%', minWidth: 380, borderCollapse: 'collapse' }}>
                <thead>
                  <tr>
                    <th style={{ ...headSt, width: '42%' }}>Artigo</th>
                    <th style={{ ...headSt, textAlign: 'right' }}>Bruto</th>
                    <th style={{ ...headSt, textAlign: 'right' }}>Carteira</th>
                    <th style={{ ...headSt, textAlign: 'right' }}>Líq / Need</th>
                  </tr>
                </thead>
                <tbody>
                  {compGroupEntries.map(([fam, items]) => {
                    const famLabel = fam === '_outros' ? 'Componentes' : (FAM[fam] || fam);
                    return (
                      <React.Fragment key={fam}>
                        <tr>
                          <td colSpan={4} style={{ padding: '5px 10px', background: 'color-mix(in oklch, var(--bg-sunken) 70%, transparent)', borderBottom: '1px solid var(--border)', borderTop: '1px solid var(--border)' }}>
                            <span style={{ fontSize: 10.5, fontFamily: 'var(--font-mono)', fontWeight: 700, color: 'var(--text)', background: 'var(--border)', borderRadius: 4, padding: '1px 5px', marginRight: 6 }}>{fam === '_outros' ? '·' : fam}</span>
                            <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 600, color: 'var(--text-dim)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{famLabel}</span>
                            <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', marginLeft: 6 }}>{items.length} artigos</span>
                          </td>
                        </tr>
                        {items.map((e, i) => (
                          <tr key={i} style={{ background: i % 2 === 0 ? 'transparent' : 'color-mix(in oklch, var(--bg-sunken) 40%, transparent)' }}>
                            <td style={{ ...cellSt }}>
                              <div style={{ display: 'flex', alignItems: 'baseline', gap: 5 }}>
                                <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11 }}>{e.art}</span>
                                {e.mk && <span style={{ fontSize: 9, fontFamily: 'var(--font-mono)', padding: '1px 4px', border: '1px solid var(--border)', borderRadius: 3, color: 'var(--text-dim)', flexShrink: 0 }}>{e.mk}</span>}
                              </div>
                              {e.ds && <div style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: 170 }}>{e.ds}</div>}
                            </td>
                            <td style={{ ...cellSt, textAlign: 'right' }}>{fmt(e.bruto)}</td>
                            <td style={{ ...cellSt, textAlign: 'right', color: e.cart < 0 ? MRP_RD : 'var(--text)' }}>{fmt(e.cart)}</td>
                            <td style={{ ...cellSt, textAlign: 'right' }}>
                              <span style={{ color: e.liq < 0 ? MRP_RD : 'var(--text)', fontWeight: e.liq < 0 ? 700 : 400 }}>{fmt(e.liq)}</span>
                              <span style={{ color: MRP_OR, marginLeft: 4 }}>/{fmt(e.need)}</span>
                            </td>
                          </tr>
                        ))}
                      </React.Fragment>
                    );
                  })}
                </tbody>
              </table></div>
            </div>
          )}
        </div>
        </div>
      </div>
    </React.Fragment>
  );
};

const MrpEncomendas = ({ d, hoje }) => {
  const [horDias,      setHorDias]      = React.useState(7);
  const [docType,      setDocType]      = React.useState('all');
  const [marca,        setMarca]        = React.useState('all');
  const [filtroStatus, setFiltroStatus] = React.useState('all');
  const [q,            setQ]            = React.useState('');
  const [grpLimits,    setGrpLimits]    = React.useState({});
  const [selected,     setSelected]     = React.useState(null);

  // dlim para horizonte de encomendas
  const encDlim = React.useMemo(() => {
    if (horDias === 99999) return '9999-12-31';
    if (horDias < 0) return hoje ? mrpAddDays(hoje, -1) : '2000-01-01'; // Vencidos = só passado
    return hoje ? mrpAddDays(hoje, horDias) : '9999-12-31';
  }, [hoje, horDias]);

  // Todas as linhas de encomendas — fonte: _D (dm = data de entrega)
  // Lógica exacta do calcEngine do Márcio:
  // 1. filtLines = _D filtrado pelo horizonte
  // 2. nec[jumbo] = total de jumbo necessário por todas as filtLines (via l.cx)
  // 3. sjl_ef = _S[jumbo] - nec[jumbo]; es = stock_jumbo se sjl_ef >= sjn
  // 4. spaDisp sequencial para stock_pa
  const { allRows, nec } = React.useMemo(() => {
    const ES_LABEL = { stock_pa: 'Stock PA', stock_jumbo: 'Slitter', fabricar: 'Fabricar', sem_bom: 'Sem BOM' };
    const dLines = d._D || [];
    const S = d._S || {};

    // 1. Filtrar por horizonte
    const filtLines = dLines.filter(l => {
      const date = l.dm || '';
      if (date > encDlim) return false;
      if (horDias < 0 && hoje && date >= hoje) return false;
      return true;
    });

    // 2. Pre-calcular nec: total de cada componente/jumbo necessário
    const nec = {};
    for (const l of filtLines) {
      if (!l.cx) continue;
      for (const [art, cu] of Object.entries(l.cx)) {
        nec[art] = (nec[art] || 0) + cu * (l.qp || 0);
      }
    }

    // 3. Pre-calcular spaDisp (stock PA inicial por artigo, da primeira ocorrência)
    const spaTotal = {};
    for (const l of filtLines) {
      if (!(l.a in spaTotal)) spaTotal[l.a] = l.spa || 0;
    }
    const spaDisp = {...spaTotal};

    // 4. Classificar cada linha
    const rows = [];
    for (const l of filtLines) {
      const qp = l.qp || 0;
      const sjb = S[l.j] || 0;
      const sjnt = nec[l.j] || 0;
      const sjn = (l.jcu || 0) * qp;
      const sjl_ef = sjb - sjnt;
      const sr = spaDisp[l.a] || 0;
      let es;
      if (sr >= qp) { spaDisp[l.a] = sr - qp; es = 'stock_pa'; }
      else { spaDisp[l.a] = 0; es = l.j && sjn > 0 && sjl_ef >= sjn ? 'stock_jumbo' : l.tb ? 'fabricar' : 'sem_bom'; }

      const date = l.dm || '';
      const dias = !date || !hoje ? null : Math.round((new Date(date) - new Date(hoje)) / 86400000);
      const noInfo = d._NO?.[l.a] || {};
      rows.push({
        art: l.a,
        ds:  l.ds || noInfo.ds || '',
        mk:  l.mc || noInfo.mk || '_outros',
        date, qty: qp, qty_pend: qp,
        order_num: l.cc || '', client: l.cn || '',
        status: ES_LABEL[es] || '',
        doc_type: l.td || '???',
        dias, vencido: dias != null && dias < 0,
        _line: l,
      });
    }
    return { allRows: rows, nec };
  }, [d._D, d._NO, d._S, encDlim, horDias, hoje]);

  // KPIs filtrados pelo horizonte seleccionado (usa status enriquecido pelo artEsMap)
  const kpis = React.useMemo(() => {
    const sl = s => (s || '').toLowerCase();
    return {
      total:     allRows.length,
      stock_ok:  allRows.filter(r => sl(r.status).includes('stock')).length,
      bobinagem: allRows.filter(r => sl(r.status).includes('slitter') || sl(r.status).includes('bobina')).length,
      fabricar:  allRows.filter(r => sl(r.status).includes('fabricar')).length,
      sem_bom:   allRows.filter(r => sl(r.status).includes('bom') || sl(r.status).includes('ficha')).length,
    };
  }, [allRows]);

  // Tipos de documento com contagens
  const docTypes = React.useMemo(() => {
    const counts = {};
    for (const r of allRows) counts[r.doc_type] = (counts[r.doc_type] || 0) + 1;
    return Object.entries(counts).sort((a, b) => b[1] - a[1]);
  }, [allRows]);

  // Marcas com contagens
  const marcas = React.useMemo(() => {
    const counts = {};
    for (const r of allRows) if (r.mk) counts[r.mk] = (counts[r.mk] || 0) + 1;
    return Object.entries(counts).sort((a, b) => b[1] - a[1]);
  }, [allRows]);

  // Filtrar (sem sort — o card view ordena por data)
  const filtered = React.useMemo(() => {
    let rows = allRows;
    if (docType !== 'all') rows = rows.filter(r => r.doc_type === docType);
    if (marca   !== 'all') rows = rows.filter(r => r.mk === marca);
    const sl = s => (s || '').toLowerCase();
    if (filtroStatus === 'fabricar')     rows = rows.filter(r => sl(r.status).includes('fabricar'));
    else if (filtroStatus === 'slitter') rows = rows.filter(r => sl(r.status).includes('slitter') || sl(r.status).includes('bobina'));
    else if (filtroStatus === 'stock')   rows = rows.filter(r => sl(r.status).includes('stock'));
    else if (filtroStatus === 'sem_bom') rows = rows.filter(r => sl(r.status).includes('bom') || sl(r.status).includes('ficha'));
    else if (filtroStatus === 'vencido') rows = rows.filter(r => r.vencido);
    if (q) {
      const ql = q.toLowerCase();
      rows = rows.filter(r => [r.art, r.ds, r.client, r.order_num, r.status].join(' ').toLowerCase().includes(ql));
    }
    return [...rows].sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));
  }, [allRows, docType, marca, filtroStatus, q]);

  // Agrupar por marca para os quadros lado a lado
  const groups = React.useMemo(() => {
    const map = {};
    for (const r of filtered) {
      if (!map[r.mk]) map[r.mk] = [];
      map[r.mk].push(r);
    }
    return Object.entries(map).sort((a, b) => b[1].length - a[1].length);
  }, [filtered]);

  const GRP_PAGE = 80;
  const grpLimit = mk => grpLimits[mk] || GRP_PAGE;

  const pillSt  = active => ({
    padding: '3px 10px', borderRadius: 12, fontSize: 10.5, fontFamily: 'var(--font-mono)',
    fontWeight: 700, cursor: 'pointer', border: '1px solid var(--border)',
    background: active ? MRP_GN : 'var(--bg-sunken)',
    color: active ? '#fff' : 'var(--text-dim)', transition: 'background 0.15s',
  });

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
      <DrillDownPanel selected={selected} nec={nec} d={d} onClose={() => setSelected(null)} encDlim={encDlim} />

      {/* ── Filtros ─────────────────────────────────────────────────────────── */}
      <div style={{ padding: '10px 16px', borderBottom: '1px solid var(--border)', flexShrink: 0, display: 'flex', flexDirection: 'column', gap: 8 }}>

        {/* Horizonte */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', color: 'var(--text-dim)', textTransform: 'uppercase', marginRight: 2 }}>Horizonte</span>
          {HOR_PILLS.map(p => (
            <button key={p.dias} onClick={() => { setHorDias(p.dias); setLimit(150); }} style={pillSt(horDias === p.dias)}>{p.label}</button>
          ))}
        </div>

        {/* Documentos */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', color: 'var(--text-dim)', textTransform: 'uppercase', marginRight: 2 }}>Documentos</span>
          <button onClick={() => { setDocType('all'); setLimit(150); }} style={pillSt(docType === 'all')}>
            TODOS {allRows.length}
          </button>
          {docTypes.map(([dt, cnt]) => (
            <button key={dt} onClick={() => { setDocType(dt); setLimit(150); }} style={pillSt(docType === dt)}>
              {dt} {cnt}
            </button>
          ))}
        </div>

        {/* Marca + Estado + Search */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', color: 'var(--text-dim)', textTransform: 'uppercase' }}>Marca</span>
          <button onClick={() => { setMarca('all'); setLimit(150); }} style={pillSt(marca === 'all')}>Todas</button>
          {marcas.map(([mk, cnt]) => (
            <button key={mk} onClick={() => { setMarca(mk); setLimit(150); }} style={pillSt(marca === mk)}>{encMkPillLabel(mk)} {cnt}</button>
          ))}
          <div style={{ width: 1, height: 18, background: 'var(--border)', alignSelf: 'center' }} />
          {[
            { id: 'all',     label: 'Todos' },
            { id: 'fabricar',label: 'Fabricar' },
            { id: 'slitter', label: 'Slitter' },
            { id: 'stock',   label: 'Stock OK' },
            { id: 'sem_bom', label: 'Sem BOM' },
            { id: 'vencido', label: 'Vencidos' },
          ].map(f => (
            <button key={f.id} onClick={() => { setFiltroStatus(f.id); setLimit(150); }} style={pillSt(filtroStatus === f.id)}>{f.label}</button>
          ))}
          <MrpSearch value={q} onChange={v => { setQ(v); setLimit(150); }} placeholder="artigo / cliente…" />
          <span style={{ fontSize: 11, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', marginLeft: 'auto' }}>
            {filtered.length.toLocaleString('pt-PT')} linhas
          </span>
        </div>

        {/* KPI cards */}
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {[
            { id: 'all',     label: 'Encomendas', v: kpis.total,     color: 'var(--text)',  sub: marcas.map(([mk, cnt]) => `${encMkPillLabel(mk)} ${cnt}`).join(' · ') },
            { id: 'stock',   label: 'Stock PA OK', v: kpis.stock_ok,  color: MRP_GN,        sub: 'Pronto a expedir' },
            { id: 'slitter', label: 'Bobinagem',   v: kpis.bobinagem, color: '#6366f1',     sub: 'Jumbo liquido cobre' },
            { id: 'fabricar',label: 'Fabricar',    v: kpis.fabricar,  color: MRP_OR,        sub: 'Necessita produção' },
            { id: 'sem_bom', label: 'Sem BOM',     v: kpis.sem_bom,   color: '#d97706',     sub: 'Sem ficha técnica' },
          ].map(k => (
            <div key={k.id}
              onClick={() => { setFiltroStatus(filtroStatus === k.id ? 'all' : k.id); setLimit(150); }}
              style={{
                padding: '6px 14px', borderRadius: 8, cursor: 'pointer', minWidth: 110,
                border: filtroStatus === k.id ? `1px solid ${k.color}` : '1px solid var(--border)',
                background: filtroStatus === k.id ? `color-mix(in oklch, ${k.color} 10%, var(--bg-sunken))` : 'var(--bg-sunken)',
                display: 'flex', flexDirection: 'column', alignItems: 'flex-start',
              }}>
              <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>{k.label}</span>
              <span style={{ fontSize: 18, fontWeight: 700, color: k.color, fontFamily: 'var(--font-mono)' }}>{k.v.toLocaleString('pt-PT')}</span>
              {k.sub && <span style={{ fontSize: 10, color: 'var(--text-dim)' }}>{k.sub}</span>}
            </div>
          ))}
        </div>
      </div>

      {/* ── Quadros por marca ───────────────────────────────────────────────── */}
      <div className="scrollbar" style={{ flex: 1, overflowY: 'auto' }}>
        {groups.length === 0 ? (
          <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-dim)', fontSize: 13 }}>Sem encomendas para os filtros seleccionados.</div>
        ) : (
          <div style={{ display: 'grid', gridTemplateColumns: groups.length === 1 ? '1fr' : 'repeat(2, 1fr)', alignItems: 'start' }}>
            {groups.map(([mk, rows]) => {
              const lim = grpLimit(mk);
              return (
                <div key={mk} style={{ borderRight: '1px solid var(--border)', borderBottom: '1px solid var(--border)' }}>
                  {/* Cabeçalho do quadro */}
                  <div style={{ padding: '8px 14px', background: 'var(--bg-sunken)', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', position: 'sticky', top: 0, zIndex: 2 }}>
                    <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase', color: 'var(--text)' }}>
                      {encMkColLabel(mk)}
                    </span>
                    <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)' }}>{rows.length.toLocaleString('pt-PT')} registos</span>
                  </div>
                  {/* Cards */}
                  {rows.slice(0, lim).map((r, i) => <EncCard key={i} r={r} onClick={() => setSelected({ _line: r._line, r })} />)}
                  {rows.length > lim && (
                    <div style={{ padding: '10px 0', textAlign: 'center' }}>
                      <button className="btn btn-xs btn-ghost" onClick={() => setGrpLimits(prev => ({ ...prev, [mk]: lim + GRP_PAGE }))} style={{ fontSize: 11 }}>
                        Mostrar mais ({(rows.length - lim).toLocaleString('pt-PT')} restantes)
                      </button>
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
};

// ─── Tab: OFs ─────────────────────────────────────────────────────────────────
const MrpOfs = ({ d, hoje }) => {
  const [q, setQ] = React.useState('');
  const [sort, setSort] = React.useState({ col: 'df', asc: true });
  const [limit, setLimit] = React.useState(150);
  const [expanded, setExpanded] = React.useState(null);

  const allRows = React.useMemo(() => {
    const rows = [];
    for (const [art, ofs] of Object.entries(d._OF || {})) {
      for (const o of (ofs || [])) {
        const dias = (!o.df || !hoje) ? null : Math.round((new Date(o.df) - new Date(hoje)) / 86400000);
        rows.push({ art, ...o, dias });
      }
    }
    return rows;
  }, [d]);

  const filtered = React.useMemo(() => {
    const ql = q.toLowerCase();
    const rows = ql ? allRows.filter(r =>
      r.art.toLowerCase().includes(ql) || String(r.of || '').toLowerCase().includes(ql) ||
      (r.es || '').toLowerCase().includes(ql) || (r.mk || '').toLowerCase().includes(ql)
    ) : allRows;
    return [...rows].sort((a, b) => {
      let va = a[sort.col], vb = b[sort.col];
      if (typeof va === 'string') { va = va.toLowerCase(); vb = vb.toLowerCase(); }
      if (va < vb) return sort.asc ? -1 : 1;
      if (va > vb) return sort.asc ? 1 : -1;
      return 0;
    });
  }, [allRows, q, sort]);

  const onSort = (col) => setSort(s => ({ col, asc: s.col === col ? !s.asc : true }));
  const shown = filtered.slice(0, limit);


  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
      <div style={{ padding: '10px 16px', display: 'flex', alignItems: 'center', gap: 12, borderBottom: '1px solid var(--border)', flexShrink: 0 }}>
        <MrpSearch value={q} onChange={v => { setQ(v); setLimit(150); }} placeholder="Artigo, OF, estado, marca…" />
        <span style={{ fontSize: 11, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>{filtered.length.toLocaleString('pt-PT')} OFs</span>
      </div>
      <div className="scrollbar" style={{ flex: 1, overflowY: 'auto' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse' }}>
          <thead>
            <tr>
              <MrpSortHdr label="Nº OF"     col="of"   sort={sort} onSort={onSort} />
              <MrpSortHdr label="Artigo"    col="art"  sort={sort} onSort={onSort} />
              <MrpSortHdr label="Marca"     col="mk"   sort={sort} onSort={onSort} />
              <MrpSortHdr label="Estado"    col="es"   sort={sort} onSort={onSort} />
              <MrpSortHdr label="Início"    col="di"   sort={sort} onSort={onSort} />
              <MrpSortHdr label="Fim"       col="df"   sort={sort} onSort={onSort} />
              <MrpSortHdr label="Qtd Nec."  col="qn"   sort={sort} onSort={onSort} align="right" />
              <MrpSortHdr label="Qtd Prod." col="qp"   sort={sort} onSort={onSort} align="right" />
              <MrpSortHdr label="Dias"      col="dias" sort={sort} onSort={onSort} align="right" />
              <th style={MRP_TH}>Comp.</th>
            </tr>
          </thead>
          <tbody>
            {shown.map((r, i) => {
              const esStyle = ofEstadoStyle(r.es);
              const venc    = r.dias != null && r.dias < 0;
              const urgent  = r.dias != null && r.dias >= 0 && r.dias <= 7;
              const rowKey  = `${r.of}-${i}`;
              const isExp   = expanded === rowKey;
              return (
                <React.Fragment key={rowKey}>
                  <tr style={{ background: i % 2 === 0 ? 'transparent' : 'color-mix(in oklch, var(--bg-sunken) 40%, transparent)', cursor: r.comps?.length ? 'pointer' : 'default' }}
                    onClick={() => r.comps?.length && setExpanded(isExp ? null : rowKey)}>
                    <td style={MRP_TD_MONO}>{r.of}</td>
                    <td style={MRP_TD_MONO}>{r.art}</td>
                    <td style={{ ...MRP_TD, fontSize: 11, color: 'var(--text-muted)' }}>{r.mk}</td>
                    <td style={MRP_TD}><MrpBadge label={r.es} {...esStyle} /></td>
                    <td style={{ ...MRP_TD_MONO, color: 'var(--text-muted)' }}>{mrpFd(r.di)}</td>
                    <td style={{ ...MRP_TD_MONO, color: venc ? MRP_RD : urgent ? MRP_OR : 'var(--text)' }}>{mrpFd(r.df)}</td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right' }}>{mrpFn(r.qn)}</td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', color: r.qp < r.qn ? MRP_OR : MRP_GN }}>{mrpFn(r.qp)}</td>
                    <td style={{ ...MRP_TD_MONO, textAlign: 'right', color: venc ? MRP_RD : urgent ? MRP_OR : 'var(--text-dim)' }}>{r.dias != null ? r.dias : '—'}</td>
                    <td style={MRP_TD}>{r.comps?.length > 0 && <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', cursor: 'pointer' }}>{isExp ? '▲' : '▼'} {r.comps.length}</span>}</td>
                  </tr>
                  {isExp && r.comps?.length > 0 && (
                    <tr><td colSpan={10} style={{ padding: '0 0 0 40px', background: 'color-mix(in oklch, var(--bg-sunken) 70%, transparent)' }}>
                      <table style={{ width: '100%', borderCollapse: 'collapse', margin: '6px 0' }}>
                        <thead><tr>
                          <th style={{ ...MRP_TH, background: 'transparent', fontSize: 9 }}>Artigo comp.</th>
                          <th style={{ ...MRP_TH, background: 'transparent', fontSize: 9 }}>Descrição</th>
                          <th style={{ ...MRP_TH, background: 'transparent', fontSize: 9, textAlign: 'right' }}>Qtd</th>
                          <th style={{ ...MRP_TH, background: 'transparent', fontSize: 9 }}>Un</th>
                        </tr></thead>
                        <tbody>{r.comps.map((c, ci) => (
                          <tr key={ci}>
                            <td style={{ ...MRP_TD_MONO, fontSize: 10, padding: '4px 10px' }}>{c.a}</td>
                            <td style={{ ...MRP_TD, fontSize: 11, padding: '4px 10px', color: 'var(--text-muted)' }}>{c.ds}</td>
                            <td style={{ ...MRP_TD_MONO, fontSize: 10, textAlign: 'right', padding: '4px 10px' }}>{mrpFn(c.qn)}</td>
                            <td style={{ ...MRP_TD, fontSize: 10, padding: '4px 10px', color: 'var(--text-dim)' }}>{c.un}</td>
                          </tr>
                        ))}</tbody>
                      </table>
                    </td></tr>
                  )}
                </React.Fragment>
              );
            })}
          </tbody>
        </table>
        <MrpShowMore shown={limit} total={filtered.length} onMore={() => setLimit(l => l + 150)} />
      </div>
    </div>
  );
};

// ─── Ecrã principal ───────────────────────────────────────────────────────────
const PrdMrpScreen = ({ snap }) => {
  const [tab, setTab] = React.useState('objetivos');

  const d    = snap?.mrp_data || {};
  const hoje = d.HOJE || snap?.data_date || '';

  const nOf  = React.useMemo(() => Object.keys(d._OF  || {}).reduce((s, k) => s + (d._OF[k]?.length  || 0), 0), [d]);
  const nEnc = React.useMemo(() => (d._D || []).length, [d]);
  const nNo  = React.useMemo(() => Object.keys(d._NO  || {}).length, [d]);

  const TABS = [
    { id: 'objetivos',  label: `Objetivos (${nNo.toLocaleString('pt-PT')})` },
    { id: 'encomendas', label: `Encomendas (${nEnc.toLocaleString('pt-PT')})` },
    { id: 'ofs',        label: `OFs (${nOf.toLocaleString('pt-PT')})` },
  ];

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>

      {/* Header */}
      <div style={{ padding: '14px 20px 0', flexShrink: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
          <div>
            <div className="font-mono" style={{ fontSize: 10, color: 'var(--text-dim)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>PRODUÇÃO · PLANEAMENTO MRP</div>
            <h2 className="font-display" style={{ margin: '2px 0 0', fontSize: 20, fontWeight: 500, letterSpacing: '-0.01em' }}>Planeamento MRP</h2>
          </div>
          <span className="font-mono" style={{ fontSize: 10, color: 'var(--text-dim)' }}>
            Dados: {snap?.data_date}
          </span>
        </div>

        {/* Tab bar */}
        <div style={{ display: 'flex', gap: 0, marginTop: 12, borderBottom: '1px solid var(--border)' }}>
          {TABS.map(t => (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              padding: '7px 16px', fontSize: 12.5, border: 'none', outline: 'none',
              background: 'transparent', cursor: 'pointer',
              color: tab === t.id ? 'var(--text)' : 'var(--text-muted)',
              fontFamily: 'var(--font-body)', fontWeight: tab === t.id ? 600 : 400,
              borderBottom: tab === t.id ? `2px solid ${MRP_GN}` : '2px solid transparent',
              marginBottom: -1, transition: 'color 0.15s',
            }}>{t.label}</button>
          ))}
        </div>
      </div>

      {/* Conteúdo */}
      <div style={{ flex: 1, minHeight: 0 }}>
        {tab === 'objetivos'  && <MrpObjetivos d={d} />}
        {tab === 'encomendas' && <MrpEncomendas d={d} hoje={hoje} />}
        {tab === 'ofs'        && <MrpOfs d={d} hoje={hoje} />}
      </div>
    </div>
  );
};

window.PrdMrpScreen = PrdMrpScreen;
