// ============================================================
// NIRO ESTOQUE — Controle de estoque, consumo e compras
// React (via Babel) + Supabase + cache offline
// ============================================================

// ---------- Validação de config ----------
(function checkConfig() {
  var c = window.CONFIG || {};
  var bad = !c.SUPABASE_URL || String(c.SUPABASE_URL).indexOf('COLE_AQUI') === 0
    || !c.SUPABASE_KEY || String(c.SUPABASE_KEY).indexOf('COLE_AQUI') === 0;
  if (bad) {
    document.getElementById('root').innerHTML =
      '<div class="boot">' +
      '<div class="boot-logo"><svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>' +
      '<h1 class="boot-title">Configuração necessária</h1>' +
      '<p class="boot-sub">O sistema precisa das credenciais do Supabase.</p>' +
      '<div class="boot-error">Abra o arquivo <code>config.js</code> e preencha <code>SUPABASE_URL</code> e <code>SUPABASE_KEY</code> com os dados do seu projeto de estoque.</div>' +
      '</div>';
    throw new Error('Configuração ausente');
  }
})();

window.addEventListener('error', function(e) { console.error('Erro global:', e.message, e.error); });

const { useState, useEffect, useMemo, useCallback, useRef } = React;

// ---------- Cliente Supabase ----------
const sb = window.supabase.createClient(window.CONFIG.SUPABASE_URL, window.CONFIG.SUPABASE_KEY);

// ---------- Cores e fontes ----------
const colors = {
  bg: '#F2F5F3', surface: '#FFFFFF', surfaceAlt: '#EDF2F0',
  border: '#DAE2DE', borderDark: '#C3CFC9',
  text: '#1A211F', textSoft: '#5F6B66', textMute: '#94A099',
  primary: '#2C6E63', primaryDark: '#1F5249',
  accent: '#E0A93B', success: '#3E8B5A', danger: '#C24A2E', info: '#3B7CA8',
};
const displayFont = "'Fraunces', Georgia, serif";
const bodyFont = "'Inter', system-ui, sans-serif";

// ---------- Helpers ----------
const fmtBRL = (n) => (Number(n) || 0).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
const fmtNum = (n) => (Number(n) || 0).toLocaleString('pt-BR', { maximumFractionDigits: 3 });
const fmtDate = (iso) => new Date(iso).toLocaleDateString('pt-BR');
const fmtTime = (iso) => new Date(iso).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
const newId = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 7);

const localDay = (iso) => new Date(iso).toLocaleDateString('pt-BR');
const localMonth = (iso) => { const d = new Date(iso); return `${d.getMonth()}-${d.getFullYear()}`; };
const thisMonthKey = () => `${new Date().getMonth()}-${new Date().getFullYear()}`;
const todayLocal = () => new Date().toLocaleDateString('pt-BR');
const isSameDay = (iso, ref = todayLocal()) => iso && localDay(iso) === ref;
const isSameMonth = (iso, ref = thisMonthKey()) => iso && localMonth(iso) === ref;

// ---------- Conversores camelCase <-> snake_case ----------
const toSnake = (obj) => { const r = {}; for (const k in obj) r[k.replace(/([A-Z])/g, '_$1').toLowerCase()] = obj[k]; return r; };
const toCamel = (obj) => { const r = {}; for (const k in obj) r[k.replace(/_([a-z])/g, (_, c) => c.toUpperCase())] = obj[k]; return r; };

// ---------- Quem está usando (salvo por aparelho) ----------
const USER_KEY = 'estoque:user';
const getUser = () => { try { return localStorage.getItem(USER_KEY) || ''; } catch { return ''; } };
const setUser = (name) => { try { localStorage.setItem(USER_KEY, name); } catch {} };

// ---------- Autenticação ----------
function useAuth() {
  const [session, setSession] = useState(undefined); // undefined = carregando
  const [profile, setProfile] = useState(null);

  useEffect(() => {
    sb.auth.getSession().then(({ data }) => setSession(data.session || null));
    const { data: sub } = sb.auth.onAuthStateChange((_e, s) => setSession(s));
    return () => sub.subscription.unsubscribe();
  }, []);

  useEffect(() => {
    if (!session) { setProfile(null); return; }
    let active = true;
    (async () => {
      try {
        const { data } = await sb.from('profiles').select('*').eq('id', session.user.id).single();
        if (active) setProfile(data ? toCamel(data) : { id: session.user.id, name: session.user.email, role: 'operador' });
      } catch {
        if (active) setProfile({ id: session.user.id, name: session.user.email, role: 'operador' });
      }
    })();
    return () => { active = false; };
  }, [session]);

  return { session, profile };
}

// ---------- Fila offline ----------
const QUEUE_KEY = 'sync:queue';
const getQueue = () => { try { return JSON.parse(localStorage.getItem(QUEUE_KEY) || '[]'); } catch { return []; } };
const saveQueue = (q) => { try { localStorage.setItem(QUEUE_KEY, JSON.stringify(q)); } catch {} };
const enqueue = (op) => { const q = getQueue(); q.push({ ...op, queuedAt: Date.now() }); saveQueue(q); };

// IDs em processo de upsert (não removemos do estado local enquanto não confirmar persistência)
const pendingIds = new Set();

// ---------- Status de sincronização ----------
const syncListeners = new Set();
let syncState = { online: navigator.onLine, pending: getQueue().length };
const updateSync = (patch) => { syncState = { ...syncState, ...patch }; syncListeners.forEach(fn => fn(syncState)); };
const useSyncState = () => {
  const [s, setS] = useState(syncState);
  useEffect(() => { syncListeners.add(setS); return () => syncListeners.delete(setS); }, []);
  return s;
};

async function pushUpsert(table, item) { const { error } = await sb.from(table).upsert(toSnake(item)); if (error) throw error; }
async function pushDelete(table, id) { const { error } = await sb.from(table).delete().eq('id', id); if (error) throw error; }

let flushing = false;
async function flushQueue() {
  if (flushing) return;
  flushing = true;
  try {
    let queue = getQueue();
    if (queue.length === 0) { updateSync({ pending: 0 }); return; }
    const remaining = [];
    for (const op of queue) {
      try {
        if (op.action === 'upsert') await pushUpsert(op.table, op.data);
        else if (op.action === 'delete') await pushDelete(op.table, op.id);
        if (op.data && op.data.id) pendingIds.delete(op.data.id);
      } catch (e) { remaining.push(op); }
    }
    saveQueue(remaining);
    // Online segue navigator.onLine; pending reflete fila restante
    updateSync({ online: navigator.onLine, pending: remaining.length });
  } finally {
    flushing = false;
  }
}

// Tenta sincronizar em vários momentos críticos:
window.addEventListener('online', () => { updateSync({ online: true }); flushQueue(); });
window.addEventListener('offline', () => updateSync({ online: false }));
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible') { updateSync({ online: navigator.onLine }); flushQueue(); }
});
window.addEventListener('pagehide', () => { flushQueue(); });
setInterval(() => {
  // Sempre re-checa estado real do navegador
  if (navigator.onLine !== syncState.online) updateSync({ online: navigator.onLine });
  if (navigator.onLine && getQueue().length > 0) flushQueue();
}, 15000);

// ---------- Hook useTable ----------
function useTable(table) {
  const cacheKey = `cache:${table}`;
  const [items, setItemsState] = useState(() => {
    try { return JSON.parse(localStorage.getItem(cacheKey) || '[]'); } catch { return []; }
  });
  const [ready, setReady] = useState(false);
  const itemsRef = useRef(items);
  itemsRef.current = items;
  const writeCache = (arr) => { try { localStorage.setItem(cacheKey, JSON.stringify(arr)); } catch {} };

  // Mescla resposta do servidor com itens locais ainda pendentes na fila
  // (preserva itens que o usuário criou e ainda não foram enviados ao servidor)
  const mergeWithPending = useCallback((serverItems) => {
    const queue = getQueue();
    const pendingForTable = queue.filter(op => op.table === table && op.action === 'upsert');
    if (pendingForTable.length === 0) return serverItems;
    const result = [...serverItems];
    pendingForTable.forEach(op => {
      const idx = result.findIndex(s => s.id === op.data.id);
      if (idx >= 0) result[idx] = op.data;  // versão local é mais nova
      else result.push(op.data);  // ainda não chegou ao servidor
    });
    return result;
  }, [table]);

  const fetchAll = useCallback(async () => {
    try {
      const { data, error } = await sb.from(table).select('*');
      if (error) throw error;
      const camel = data.map(toCamel);
      // CORREÇÃO: mescla dados do servidor com itens locais pendentes
      // Antes, o fetchAll sobrescrevia o estado e o usuário via seu lançamento "sumir"
      const merged = mergeWithPending(camel);
      setItemsState(merged); writeCache(merged); updateSync({ online: navigator.onLine });
    } catch (e) {
      // Só marca offline se realmente o navegador estiver offline
      if (!navigator.onLine) updateSync({ online: false });
    }
    finally { setReady(true); }
  }, [table, mergeWithPending]);

  useEffect(() => {
    fetchAll();
    const channel = sb.channel(`rt-${table}`)
      .on('postgres_changes', { event: '*', schema: 'public', table }, fetchAll)
      .subscribe();
    const onFocus = () => fetchAll();
    const onVisible = () => { if (document.visibilityState === 'visible') fetchAll(); };
    window.addEventListener('focus', onFocus);
    document.addEventListener('visibilitychange', onVisible);
    return () => {
      sb.removeChannel(channel);
      window.removeEventListener('focus', onFocus);
      document.removeEventListener('visibilitychange', onVisible);
    };
  }, [table, fetchAll]);

  const setItems = useCallback(async (next) => {
    const prev = itemsRef.current;
    setItemsState(next); writeCache(next);
    const upserts = next.filter(n => {
      const old = prev.find(p => p.id === n.id);
      return !old || JSON.stringify(old) !== JSON.stringify(n);
    });
    const deletes = prev.filter(p => !next.find(n => n.id === p.id)).map(p => p.id);
    let fail = false;
    for (const item of upserts) {
      pendingIds.add(item.id);
      try {
        await pushUpsert(table, item);
        pendingIds.delete(item.id);
      } catch {
        enqueue({ action: 'upsert', table, data: item });
        fail = true;
      }
    }
    for (const id of deletes) { try { await pushDelete(table, id); } catch { enqueue({ action: 'delete', table, id }); fail = true; } }
    // Online segue navigator.onLine; pending reflete fila atual
    updateSync({ online: navigator.onLine, pending: getQueue().length });
  }, [table]);

  return [items, setItems, ready];
}

// ============================================================
// ÍCONES
// ============================================================
const I = ({ d, size = 16, color = 'currentColor', sw = 2 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">{d}</svg>
);
const Icons = {
  Dashboard: (p) => <I {...p} d={<><rect x="3" y="3" width="7" height="9" /><rect x="14" y="3" width="7" height="5" /><rect x="14" y="12" width="7" height="9" /><rect x="3" y="16" width="7" height="5" /></>} />,
  Box: (p) => <I {...p} d={<><path d="M16.5 9.4l-9-5.19M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" /><polyline points="3.27 6.96 12 12.01 20.73 6.96" /><line x1="12" y1="22.08" x2="12" y2="12" /></>} />,
  Consumo: (p) => <I {...p} d={<><path d="M3 3v18h18" /><path d="m19 9-5 5-4-4-3 3" /></>} />,
  Cart: (p) => <I {...p} d={<><circle cx="9" cy="21" r="1" /><circle cx="20" cy="21" r="1" /><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6" /></>} />,
  Layers: (p) => <I {...p} d={<><polygon points="12 2 2 7 12 12 22 7 12 2" /><polyline points="2 17 12 22 22 17" /><polyline points="2 12 12 17 22 12" /></>} />,
  Chart: (p) => <I {...p} d={<><line x1="18" y1="20" x2="18" y2="10" /><line x1="12" y1="20" x2="12" y2="4" /><line x1="6" y1="20" x2="6" y2="14" /></>} />,
  Plus: (p) => <I {...p} d={<><line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" /></>} />,
  Minus: (p) => <I {...p} d={<><line x1="5" y1="12" x2="19" y2="12" /></>} />,
  Trash: (p) => <I {...p} d={<><polyline points="3 6 5 6 21 6" /><path d="M19 6l-2 14a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2L5 6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /></>} />,
  X: (p) => <I {...p} d={<><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></>} />,
  Check: (p) => <I {...p} d={<polyline points="20 6 9 17 4 12" />} />,
  Check2: (p) => <I {...p} d={<><circle cx="12" cy="12" r="10" /><polyline points="9 12 11 14 15 10" /></>} />,
  Alert: (p) => <I {...p} d={<><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /><line x1="12" y1="9" x2="12" y2="13" /><line x1="12" y1="17" x2="12.01" y2="17" /></>} />,
  Edit: (p) => <I {...p} d={<><path d="M12 20h9" /><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4Z" /></>} />,
  ArrowUp: (p) => <I {...p} d={<><line x1="7" y1="17" x2="17" y2="7" /><polyline points="7 7 17 7 17 17" /></>} />,
  ArrowDown: (p) => <I {...p} d={<><line x1="17" y1="7" x2="7" y2="17" /><polyline points="17 17 7 17 7 7" /></>} />,
  Search: (p) => <I {...p} d={<><circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" /></>} />,
  Printer: (p) => <I {...p} d={<><polyline points="6 9 6 2 18 2 18 9" /><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" /><rect x="6" y="14" width="12" height="8" /></>} />,
  Cloud: (p) => <I {...p} d={<path d="M17.5 19a4.5 4.5 0 1 0 0-9 5.5 5.5 0 0 0-10.83.94A4 4 0 0 0 7 18.86" />} />,
  CloudOff: (p) => <I {...p} d={<><path d="M22.61 16.95A5 5 0 0 0 18 10h-1.26a8 8 0 0 0-7.05-6M5 5a8 8 0 0 0 4 15h9a5 5 0 0 0 1.7-.3" /><line x1="1" y1="1" x2="23" y2="23" /></>} />,
  User: (p) => <I {...p} d={<><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" /></>} />,
  Coffee: (p) => <I {...p} d={<><path d="M18 8h1a4 4 0 0 1 0 8h-1" /><path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V8z" /><line x1="6" y1="1" x2="6" y2="4" /><line x1="10" y1="1" x2="10" y2="4" /><line x1="14" y1="1" x2="14" y2="4" /></>} />,
  Spray: (p) => <I {...p} d={<><path d="M3 3h0M7 3h0M3 7h0M11 3h0M3 11h0M7 7h0" /><rect x="9" y="8" width="8" height="13" rx="2" /><path d="M11 8V5a2 2 0 0 1 2-2h0" /></>} />,
  Tag: (p) => <I {...p} d={<><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" /><line x1="7" y1="7" x2="7.01" y2="7" /></>} />,
  Dollar: (p) => <I {...p} d={<><circle cx="12" cy="12" r="10" /><path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8" /><line x1="12" y1="6" x2="12" y2="8" /><line x1="12" y1="16" x2="12" y2="18" /></>} />,
  Calc: (p) => <I {...p} d={<><rect x="4" y="2" width="16" height="20" rx="2" /><line x1="8" y1="6" x2="16" y2="6" /><line x1="8" y1="10" x2="8" y2="10" /><line x1="12" y1="10" x2="12" y2="10" /><line x1="16" y1="10" x2="16" y2="10" /><line x1="8" y1="14" x2="8" y2="14" /><line x1="12" y1="14" x2="12" y2="14" /><line x1="16" y1="14" x2="16" y2="18" /><line x1="8" y1="18" x2="12" y2="18" /></>} />,
};

// ============================================================
// PRIMITIVAS DE UI
// ============================================================
const Btn = ({ children, onClick, variant = 'primary', size = 'md', Icon, type = 'button', disabled, full }) => {
  const v = {
    primary: { bg: colors.primary, color: '#fff', border: colors.primary },
    dark: { bg: colors.text, color: '#fff', border: colors.text },
    outline: { bg: 'transparent', color: colors.text, border: colors.borderDark },
    ghost: { bg: 'transparent', color: colors.textSoft, border: 'transparent' },
    danger: { bg: colors.danger, color: '#fff', border: colors.danger },
    success: { bg: colors.success, color: '#fff', border: colors.success },
  }[variant];
  const s = { sm: { padding: '6px 12px', fontSize: 13 }, md: { padding: '9px 16px', fontSize: 14 }, lg: { padding: '12px 20px', fontSize: 15 } }[size];
  return (
    <button type={type} onClick={onClick} disabled={disabled}
      style={{
        backgroundColor: v.bg, color: v.color, border: `1px solid ${v.border}`,
        borderRadius: 8, fontWeight: 500, cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.5 : 1, transition: 'all 150ms', fontFamily: bodyFont,
        display: 'inline-flex', alignItems: 'center', gap: 6, justifyContent: 'center',
        width: full ? '100%' : 'auto', ...s,
      }}>
      {Icon && <Icon size={size === 'sm' ? 14 : 16} />}
      {children}
    </button>
  );
};

const Input = ({ label, value, onChange, type = 'text', placeholder, step, min, suffix }) => (
  <label style={{ display: 'block', fontFamily: bodyFont }}>
    {label && <div style={{ fontSize: 12, fontWeight: 500, color: colors.textSoft, marginBottom: 4, letterSpacing: 0.3, textTransform: 'uppercase' }}>{label}</div>}
    <div style={{ position: 'relative' }}>
      <input type={type} value={value ?? ''} onChange={e => onChange(e.target.value)} placeholder={placeholder} step={step} min={min}
        style={{
          width: '100%', padding: '9px 12px', paddingRight: suffix ? 36 : 12,
          border: `1px solid ${colors.border}`, borderRadius: 8,
          backgroundColor: colors.surface, color: colors.text, fontSize: 14, fontFamily: bodyFont, outline: 'none',
        }}
        onFocus={e => e.target.style.borderColor = colors.primary}
        onBlur={e => e.target.style.borderColor = colors.border} />
      {suffix && <span style={{ position: 'absolute', right: 12, top: '50%', transform: 'translateY(-50%)', color: colors.textMute, fontSize: 13 }}>{suffix}</span>}
    </div>
  </label>
);

const Select = ({ label, value, onChange, options }) => (
  <label style={{ display: 'block', fontFamily: bodyFont }}>
    {label && <div style={{ fontSize: 12, fontWeight: 500, color: colors.textSoft, marginBottom: 4, letterSpacing: 0.3, textTransform: 'uppercase' }}>{label}</div>}
    <select value={value ?? ''} onChange={e => onChange(e.target.value)}
      style={{
        width: '100%', padding: '9px 12px', border: `1px solid ${colors.border}`, borderRadius: 8,
        backgroundColor: colors.surface, color: colors.text, fontSize: 14, fontFamily: bodyFont, outline: 'none', cursor: 'pointer',
      }}>
      {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
    </select>
  </label>
);

const Card = ({ children, style }) => (
  <div style={{ backgroundColor: colors.surface, border: `1px solid ${colors.border}`, borderRadius: 12, padding: 20, ...style }}>{children}</div>
);

const Badge = ({ children, color = colors.textSoft, bg }) => (
  <span style={{
    display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, fontWeight: 600,
    letterSpacing: 0.4, textTransform: 'uppercase', color, backgroundColor: bg || `${color}15`,
    padding: '3px 8px', borderRadius: 999, fontFamily: bodyFont,
  }}>{children}</span>
);

const Modal = ({ open, onClose, title, children, width = 480 }) => {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, backgroundColor: 'rgba(26,33,31,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 50, padding: 16 }}>
      <div onClick={e => e.stopPropagation()} style={{ backgroundColor: colors.surface, borderRadius: 14, width: '100%', maxWidth: width, maxHeight: '90vh', overflowY: 'auto', boxShadow: '0 20px 60px rgba(0,0,0,0.25)' }}>
        <div style={{ padding: '16px 20px', borderBottom: `1px solid ${colors.border}`, display: 'flex', alignItems: 'center', justifyContent: 'space-between', position: 'sticky', top: 0, backgroundColor: colors.surface, zIndex: 1 }}>
          <h3 style={{ margin: 0, fontFamily: displayFont, fontSize: 20, color: colors.text, fontWeight: 600 }}>{title}</h3>
          <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textSoft, padding: 4 }}><Icons.X size={20} /></button>
        </div>
        <div style={{ padding: 20 }}>{children}</div>
      </div>
    </div>
  );
};

const Empty = ({ Icon, title, hint }) => (
  <div style={{ padding: '48px 20px', textAlign: 'center', color: colors.textMute }}>
    <div style={{ width: 56, height: 56, borderRadius: 14, backgroundColor: colors.surfaceAlt, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', marginBottom: 12 }}>
      <Icon size={26} color={colors.textMute} />
    </div>
    <div style={{ fontFamily: displayFont, fontSize: 18, color: colors.text, marginBottom: 4 }}>{title}</div>
    <div style={{ fontFamily: bodyFont, fontSize: 13 }}>{hint}</div>
  </div>
);

// cor de um setor pelo nome
const sectorColor = (sectors, name) => {
  const s = sectors.find(x => x.name === name);
  return s ? s.color : colors.textMute;
};

// ============================================================
// IMPRESSÃO DE RELATÓRIOS / LISTA DE COMPRAS
// ============================================================
function openPrintWindow(html) {
  const w = window.open('', '_blank', 'width=420,height=640');
  if (!w) { alert('Permita pop-ups neste site para imprimir.'); return; }
  w.document.write(html); w.document.close();
  setTimeout(() => { w.focus(); w.print(); }, 250);
}

function buildShoppingList(items, businessName) {
  const bySector = {};
  items.forEach(it => { const s = it.sector || 'Geral'; if (!bySector[s]) bySector[s] = []; bySector[s].push(it); });
  return `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Lista de Compras</title>
  <style>
    @page { size: A4; margin: 14mm; }
    * { box-sizing: border-box; }
    body { font-family: 'Inter', Arial, sans-serif; font-size: 13px; color: #1A211F; margin: 0; }
    h1 { font-family: 'Fraunces', Georgia, serif; font-size: 24px; margin: 0 0 4px; color: #2C6E63; }
    .sub { color: #5F6B66; font-size: 13px; margin-bottom: 18px; }
    h2 { font-family: 'Fraunces', Georgia, serif; font-size: 16px; margin: 16px 0 6px; border-bottom: 1px solid #C3CFC9; padding-bottom: 4px; }
    table { width: 100%; border-collapse: collapse; }
    th { text-align: left; padding: 6px 8px; font-size: 10px; text-transform: uppercase; letter-spacing: 0.4px; color: #5F6B66; border-bottom: 1px solid #C3CFC9; }
    td { padding: 8px; border-bottom: 1px solid #DAE2DE; }
    .chk { width: 22px; height: 22px; border: 2px solid #94A099; border-radius: 4px; display: inline-block; }
    .actions { padding: 12px; text-align: center; background: #f0f0f0; }
    .actions button { padding: 8px 16px; margin: 0 4px; cursor: pointer; }
    @media print { .actions { display: none; } }
  </style></head><body>
    <div class="actions"><button onclick="window.print()">Imprimir / Salvar PDF</button><button onclick="window.close()">Fechar</button></div>
    <div style="padding:0 4px">
      <h1>${businessName || 'Niro Estoque'}</h1>
      <div class="sub">Lista de Compras · ${new Date().toLocaleDateString('pt-BR')}</div>
      ${Object.keys(bySector).length === 0 ? '<div class="sub">Nenhum item na lista.</div>' :
        Object.entries(bySector).map(([sec, list]) => `
        <h2>${sec}</h2>
        <table>
          <thead><tr><th style="width:30px"></th><th>Item</th><th style="text-align:right">Qtd. sugerida</th></tr></thead>
          <tbody>
            ${list.map(it => `<tr><td><span class="chk"></span></td><td>${it.name}</td><td style="text-align:right">${it.quantity ? (it.quantity + ' ' + (it.unit || '')) : '—'}</td></tr>`).join('')}
          </tbody>
        </table>`).join('')}
    </div>
  </body></html>`;
}

function buildStockReport(data, businessName) {
  const { dateLabel, totalItems, totalValue, lowStock, consumption, bySector } = data;
  return `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Relatório de Estoque</title>
  <style>
    @page { size: A4; margin: 14mm; }
    * { box-sizing: border-box; }
    body { font-family: 'Inter', Arial, sans-serif; font-size: 12px; color: #1A211F; margin: 0; line-height: 1.4; }
    h1 { font-family: 'Fraunces', Georgia, serif; font-size: 26px; margin: 0 0 4px; color: #2C6E63; }
    .sub { color: #5F6B66; font-size: 13px; margin-bottom: 18px; }
    h2 { font-family: 'Fraunces', Georgia, serif; font-size: 16px; margin: 18px 0 8px; border-bottom: 1px solid #C3CFC9; padding-bottom: 4px; }
    .cards { display: flex; gap: 12px; flex-wrap: wrap; }
    .card { flex: 1; min-width: 130px; padding: 12px 14px; border: 1px solid #DAE2DE; border-radius: 8px; background: #EDF2F0; }
    .card .lbl { font-size: 10px; color: #5F6B66; text-transform: uppercase; letter-spacing: 0.4px; }
    .card .val { font-family: 'Fraunces', Georgia, serif; font-size: 20px; font-weight: 600; margin-top: 4px; }
    .red { color: #C24A2E; } .green { color: #3E8B5A; }
    table { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 6px; }
    th { text-align: left; padding: 6px 8px; background: #EDF2F0; border-bottom: 1px solid #C3CFC9; font-size: 10px; text-transform: uppercase; letter-spacing: 0.4px; color: #5F6B66; }
    td { padding: 6px 8px; border-bottom: 1px solid #DAE2DE; }
    .right { text-align: right; }
    .actions { padding: 12px; text-align: center; background: #f0f0f0; }
    .actions button { padding: 8px 16px; margin: 0 4px; cursor: pointer; }
    @media print { .actions { display: none; } }
  </style></head><body>
    <div class="actions"><button onclick="window.print()">Imprimir / Salvar PDF</button><button onclick="window.close()">Fechar</button></div>
    <div style="padding:0 4px">
      <h1>${businessName || 'Niro Estoque'}</h1>
      <div class="sub">Relatório · ${dateLabel} · Gerado em ${new Date().toLocaleString('pt-BR')}</div>
      <div class="cards">
        <div class="card"><div class="lbl">Itens cadastrados</div><div class="val">${totalItems}</div></div>
        <div class="card"><div class="lbl">Valor em estoque</div><div class="val">${fmtBRL(totalValue)}</div></div>
        <div class="card"><div class="lbl">Abaixo do mínimo</div><div class="val ${lowStock.length > 0 ? 'red' : 'green'}">${lowStock.length}</div></div>
      </div>

      <h2>Itens para repor</h2>
      ${lowStock.length === 0 ? '<div class="sub">Nenhum item abaixo do mínimo.</div>' : `
      <table><thead><tr><th>Item</th><th>Setor</th><th class="right">Atual</th><th class="right">Mínimo</th></tr></thead><tbody>
        ${lowStock.map(i => `<tr><td>${i.name}</td><td>${i.sector}</td><td class="right">${fmtNum(i.quantity)} ${i.unit}</td><td class="right">${fmtNum(i.minStock)} ${i.unit}</td></tr>`).join('')}
      </tbody></table>`}

      <h2>Mais consumidos no período</h2>
      ${consumption.length === 0 ? '<div class="sub">Sem consumo registrado.</div>' : `
      <table><thead><tr><th>Item</th><th>Setor</th><th class="right">Qtd. consumida</th></tr></thead><tbody>
        ${consumption.map(c => `<tr><td>${c.name}</td><td>${c.sector}</td><td class="right">${fmtNum(c.qty)}</td></tr>`).join('')}
      </tbody></table>`}

      <h2>Estoque por setor</h2>
      <table><thead><tr><th>Setor</th><th class="right">Itens</th><th class="right">Valor</th></tr></thead><tbody>
        ${bySector.map(s => `<tr><td>${s.name}</td><td class="right">${s.count}</td><td class="right">${fmtBRL(s.value)}</td></tr>`).join('')}
      </tbody></table>
    </div>
  </body></html>`;
}

// ============================================================
// DASHBOARD
// ============================================================
function Dashboard({ items, movements, shopping, sectors, onTab }) {
  const stats = useMemo(() => {
    const totalValue = items.reduce((s, i) => s + (i.quantity * i.unitCost), 0);
    const lowStock = items.filter(i => i.quantity <= i.minStock);
    const todayConsumption = movements.filter(m => m.type === 'saida' && isSameDay(m.createdAt));
    const pendingShopping = shopping.filter(s => s.status === 'pendente');
    return { totalValue, lowStock, todayConsumption, pendingShopping };
  }, [items, movements, shopping]);

  const StatCard = ({ label, value, Icon, color, sub, onClick }) => (
    <div onClick={onClick} style={{ backgroundColor: colors.surface, border: `1px solid ${colors.border}`, borderRadius: 12, padding: 18, cursor: onClick ? 'pointer' : 'default' }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 8 }}>
        <div style={{ fontSize: 12, fontWeight: 500, color: colors.textSoft, letterSpacing: 0.4, textTransform: 'uppercase', fontFamily: bodyFont }}>{label}</div>
        <div style={{ width: 32, height: 32, borderRadius: 8, backgroundColor: `${color}15`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon size={16} color={color} /></div>
      </div>
      <div style={{ fontFamily: displayFont, fontSize: 28, fontWeight: 600, color: colors.text, lineHeight: 1.1 }}>{value}</div>
      {sub && <div style={{ marginTop: 4, fontSize: 12, color: colors.textMute, fontFamily: bodyFont }}>{sub}</div>}
    </div>
  );

  const sectorStats = useMemo(() => sectors.map(sec => {
    const secItems = items.filter(i => i.sector === sec.name);
    const low = secItems.filter(i => i.quantity <= i.minStock).length;
    return { ...sec, count: secItems.length, low, value: secItems.reduce((s, i) => s + i.quantity * i.unitCost, 0) };
  }), [sectors, items]);

  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: 14, marginBottom: 24 }}>
        <StatCard label="Itens cadastrados" value={items.length} Icon={Icons.Box} color={colors.primary} sub="No estoque" onClick={() => onTab('estoque')} />
        <StatCard label="Valor em estoque" value={fmtBRL(stats.totalValue)} Icon={Icons.Tag} color={colors.info} sub="Total investido" />
        <StatCard label="Para repor" value={stats.lowStock.length} Icon={Icons.Alert} color={stats.lowStock.length > 0 ? colors.danger : colors.success} sub="Abaixo do mínimo" onClick={() => onTab('estoque')} />
        <StatCard label="Lista de compras" value={stats.pendingShopping.length} Icon={Icons.Cart} color={colors.accent} sub="Itens pendentes" onClick={() => onTab('compras')} />
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', gap: 16 }}>
        <Card>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
            <h3 style={{ margin: 0, fontFamily: displayFont, fontSize: 18, color: colors.text }}>Estoque baixo</h3>
            {stats.lowStock.length > 0 && <Badge color={colors.danger}>{stats.lowStock.length} item{stats.lowStock.length === 1 ? '' : 's'}</Badge>}
          </div>
          {stats.lowStock.length === 0 ? (
            <div style={{ padding: '20px 0', textAlign: 'center', color: colors.textMute, fontFamily: bodyFont, fontSize: 14 }}>
              <Icons.Check2 size={28} color={colors.success} /><div style={{ marginTop: 8 }}>Tudo dentro do mínimo.</div>
            </div>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {stats.lowStock.slice(0, 6).map(item => (
                <div key={item.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 12px', backgroundColor: colors.surfaceAlt, borderRadius: 8, borderLeft: `3px solid ${colors.danger}` }}>
                  <div>
                    <div style={{ fontWeight: 500, color: colors.text, fontFamily: bodyFont, fontSize: 14 }}>{item.name}</div>
                    <div style={{ fontSize: 12, color: colors.textSoft, fontFamily: bodyFont }}>{item.sector} · mín: {fmtNum(item.minStock)} {item.unit}</div>
                  </div>
                  <div style={{ textAlign: 'right' }}>
                    <div style={{ fontFamily: displayFont, fontSize: 18, color: colors.danger, fontWeight: 600 }}>{fmtNum(item.quantity)}</div>
                    <div style={{ fontSize: 11, color: colors.textMute }}>{item.unit}</div>
                  </div>
                </div>
              ))}
            </div>
          )}
        </Card>

        <Card>
          <h3 style={{ margin: '0 0 14px', fontFamily: displayFont, fontSize: 18, color: colors.text }}>Por setor</h3>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {sectorStats.map(sec => (
              <div key={sec.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 12px', backgroundColor: colors.surfaceAlt, borderRadius: 8, borderLeft: `3px solid ${sec.color}` }}>
                <div>
                  <div style={{ fontWeight: 500, color: colors.text, fontFamily: bodyFont, fontSize: 14 }}>{sec.name}</div>
                  <div style={{ fontSize: 12, color: colors.textSoft, fontFamily: bodyFont }}>{sec.count} item{sec.count === 1 ? '' : 's'}{sec.low > 0 ? ` · ${sec.low} p/ repor` : ''}</div>
                </div>
                <div style={{ fontFamily: displayFont, fontSize: 15, color: colors.text, fontWeight: 600 }}>{fmtBRL(sec.value)}</div>
              </div>
            ))}
          </div>
        </Card>
      </div>
    </div>
  );
}

// ============================================================
// ESTOQUE
// ============================================================
function EstoqueView({ items, setItems, movements, setMovements, shopping, setShopping, sectors, setSectors, categoriesData, setCategoriesData, isAdmin, currentUser }) {
  const [editing, setEditing] = useState(null);
  const [moving, setMoving] = useState(null);
  const [movingToGroup, setMovingToGroup] = useState(null);
  const [renamingCategory, setRenamingCategory] = useState(null);
  const [viewingHistory, setViewingHistory] = useState(null);
  const [filterSector, setFilterSector] = useState('todos');
  const [renamingSector, setRenamingSector] = useState(null);
  const [creatingSector, setCreatingSector] = useState(false);
  const [search, setSearch] = useState('');
  const blank = { id: '', name: '', sector: sectors[0]?.name || 'Geral', category: 'Outros', unit: 'un', quantity: 0, minStock: 0, unitCost: 0 };

  const save = (item) => {
    const data = { ...item, quantity: parseFloat(item.quantity) || 0, minStock: parseFloat(item.minStock) || 0, unitCost: parseFloat(item.unitCost) || 0 };
    if (!data.name.trim()) return;
    if (data.id && items.find(x => x.id === data.id)) setItems(items.map(x => x.id === data.id ? data : x));
    else setItems([...items, { ...data, id: newId(), createdAt: new Date().toISOString() }]);
    setEditing(null);
  };

  const remove = (id) => { if (window.confirm('Remover este item?')) setItems(items.filter(x => x.id !== id)); };

  // ---- Gestão de Setores (direto no Estoque) ----
  const sectorItemCount = (sectorName) => items.filter(i => i.sector === sectorName).length;

  const saveSector = (sector) => {
    if (!sector.name.trim()) return;
    const newName = sector.name.trim();
    if (sector.id && sectors.find(s => s.id === sector.id)) {
      // Renomear: atualizar nos itens também
      const old = sectors.find(s => s.id === sector.id);
      if (newName !== old.name && sectors.find(s => s.id !== sector.id && s.name === newName)) {
        alert('Já existe um setor com esse nome.');
        return;
      }
      setSectors(sectors.map(s => s.id === sector.id ? { ...s, name: newName, color: sector.color } : s));
      if (newName !== old.name) {
        setItems(items.map(i => i.sector === old.name ? { ...i, sector: newName } : i));
        // se o filtro atual era o nome antigo, ajusta
        if (filterSector === old.name) setFilterSector(newName);
      }
    } else {
      if (sectors.find(s => s.name === newName)) { alert('Já existe um setor com esse nome.'); return; }
      setSectors([...sectors, { ...sector, id: newId(), name: newName, createdAt: new Date().toISOString() }]);
    }
    setRenamingSector(null);
    setCreatingSector(false);
  };

  const removeSector = (sector) => {
    const count = sectorItemCount(sector.name);
    if (count > 0) {
      alert(`Não dá pra remover "${sector.name}": tem ${count} item${count === 1 ? '' : 's'} usando esse setor. Mude os itens de setor primeiro.`);
      return;
    }
    if (!window.confirm(`Remover o setor "${sector.name}"?`)) return;
    setSectors(sectors.filter(s => s.id !== sector.id));
    if (filterSector === sector.name) setFilterSector('todos');
  };

  // Detecta setores "fantasma" (usados pelos itens mas não estão na tabela sectors)
  const ghostSectors = useMemo(() => {
    const knownNames = new Set(sectors.map(s => s.name));
    const usedNames = new Set(items.map(i => i.sector).filter(Boolean));
    return Array.from(usedNames).filter(n => !knownNames.has(n));
  }, [sectors, items]);

  const moveItemToGroup = (itemId, newGroup) => {
    const trimmed = (newGroup || '').trim();
    if (!trimmed) { setMovingToGroup(null); return; }
    setItems(items.map(i => i.id === itemId ? { ...i, category: trimmed } : i));
    // Se for um subgrupo novo (não existe ainda), cadastra na tabela de categorias
    const exists = (categoriesData || []).find(c => c.name === trimmed);
    if (!exists && setCategoriesData) {
      const maxPos = Math.max(0, ...(categoriesData || []).map(c => c.position || 0));
      setCategoriesData([...(categoriesData || []), { id: newId(), name: trimmed, position: maxPos + 10, createdAt: new Date().toISOString() }]);
    }
    setMovingToGroup(null);
  };

  // Renomeia uma categoria: atualiza a categoria no banco + todos os itens vinculados
  const renameCategory = (oldName, newName) => {
    const trimmed = (newName || '').trim();
    if (!trimmed || trimmed === oldName) { setRenamingCategory(null); return; }
    // Verifica se já existe outra categoria com o novo nome
    if ((categoriesData || []).find(c => c.name === trimmed && c.name !== oldName)) {
      alert('Já existe uma categoria com esse nome. Escolha outro.');
      return;
    }
    // Atualiza ou cria a categoria
    const existingCat = (categoriesData || []).find(c => c.name === oldName);
    if (existingCat && setCategoriesData) {
      setCategoriesData(categoriesData.map(c => c.id === existingCat.id ? { ...c, name: trimmed } : c));
    } else if (setCategoriesData) {
      const maxPos = Math.max(0, ...(categoriesData || []).map(c => c.position || 0));
      setCategoriesData([...(categoriesData || []), { id: newId(), name: trimmed, position: maxPos + 10, createdAt: new Date().toISOString() }]);
    }
    // Atualiza todos os itens com a categoria antiga para usar a nova
    const updatedItems = items.map(i => (i.category || 'Outros') === oldName ? { ...i, category: trimmed } : i);
    setItems(updatedItems);
    setRenamingCategory(null);
  };

  // Registra movimentação (entrada ou saída/consumo) e atualiza quantidade
  const registerMovement = (item, type, qty, notes, paidAmount) => {
    const delta = type === 'entrada' ? qty : -qty;
    const newQty = Math.max(0, item.quantity + delta);

    // Calcula o preço unitário desta movimentação (se foi entrada com valor pago)
    const paid = Number(paidAmount) || 0;
    const unitPrice = (type === 'entrada' && paid > 0 && qty > 0) ? (paid / qty) : 0;

    // Atualiza o item: estoque + (se foi entrada com preço) atualiza custo atual
    let updatedItem = { ...item, quantity: newQty };
    if (unitPrice > 0) updatedItem.unitCost = unitPrice;
    setItems(items.map(x => x.id === item.id ? updatedItem : x));

    setMovements([...movements, {
      id: newId(), itemId: item.id, itemName: item.name, sector: item.sector,
      type, quantity: qty,
      unitCost: unitPrice > 0 ? unitPrice : (Number(item.unitCost) || 0),
      paidAmount: paid,
      registeredBy: currentUser || '', notes: notes || '',
      createdAt: new Date().toISOString(),
    }]);
    // Se ficou abaixo do mínimo, sugere na lista de compras (se ainda não estiver)
    if (newQty <= item.minStock && !shopping.find(s => s.itemId === item.id && s.status === 'pendente')) {
      const sugestao = Math.max(item.minStock - newQty, item.minStock);
      setShopping([...shopping, {
        id: newId(), name: item.name, sector: item.sector, unit: item.unit,
        quantity: sugestao, status: 'pendente', auto: true, itemId: item.id, notes: '',
        createdAt: new Date().toISOString(),
      }]);
    }
    setMoving(null);
  };

  // Calcula estatísticas de preço de um item (últimas 5 entradas com valor pago)
  const priceStatsFor = (itemId) => {
    const purchases = movements
      .filter(m => m.itemId === itemId && m.type === 'entrada' && (Number(m.paidAmount) || 0) > 0 && (Number(m.quantity) || 0) > 0)
      .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
      .slice(0, 5);
    if (purchases.length === 0) return null;
    const unitPrices = purchases.map(p => (Number(p.paidAmount) || 0) / (Number(p.quantity) || 1));
    const avg = unitPrices.reduce((s, p) => s + p, 0) / unitPrices.length;
    const min = Math.min(...unitPrices);
    const max = Math.max(...unitPrices);
    const last = unitPrices[0];
    return { avg, min, max, last, count: purchases.length, purchases };
  };

  const filtered = useMemo(() => {
    let list = [...items].sort((a, b) => a.name.localeCompare(b.name));
    if (filterSector !== 'todos') list = list.filter(i => i.sector === filterSector);
    if (search.trim()) list = list.filter(i => i.name.toLowerCase().includes(search.toLowerCase()));
    return list;
  }, [items, filterSector, search]);

  // Ordem das categorias vem do banco (gerenciável pelo admin)
  const categoryOrder = useMemo(() => {
    const ordered = [...(categoriesData || [])].sort((a, b) => (a.position || 0) - (b.position || 0));
    return ordered.map(c => c.name);
  }, [categoriesData]);
  const grouped = useMemo(() => {
    const map = {};
    filtered.forEach(it => {
      const cat = it.category || 'Outros';
      if (!map[cat]) map[cat] = [];
      map[cat].push(it);
    });
    const used = Object.keys(map);
    const ordered = [
      ...categoryOrder.filter(c => used.includes(c)),
      ...used.filter(c => !categoryOrder.includes(c)).sort(),
    ];
    return ordered.map(c => ({ name: c, items: map[c] }));
  }, [filtered, categoryOrder]);

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16, flexWrap: 'wrap', gap: 12 }}>
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
          <button onClick={() => setFilterSector('todos')} style={chipStyle(filterSector === 'todos')}>Todos</button>
          {sectors.map(s => {
            const isActive = filterSector === s.name;
            return (
              <div key={s.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 2 }}>
                <button onClick={() => setFilterSector(s.name)} style={{ ...chipStyle(isActive, s.color), paddingRight: isActive && isAdmin ? 6 : undefined }}>
                  {s.name} <span style={{ marginLeft: 4, opacity: 0.7, fontSize: 11 }}>({sectorItemCount(s.name)})</span>
                </button>
                {isActive && isAdmin && (
                  <>
                    <button onClick={() => setRenamingSector(s)} title="Renomear setor"
                      style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textSoft, padding: 4 }}>
                      <Icons.Edit size={14} />
                    </button>
                    <button onClick={() => removeSector(s)} title="Remover setor"
                      style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 4 }}>
                      <Icons.Trash size={14} />
                    </button>
                  </>
                )}
              </div>
            );
          })}
          {/* Setores "fantasma" - usados pelos itens mas não cadastrados ainda */}
          {ghostSectors.map(name => (
            <button key={name} onClick={() => setFilterSector(name)} style={{ ...chipStyle(filterSector === name), borderStyle: 'dashed', opacity: 0.7 }}
              title="Setor usado pelos itens mas não cadastrado. Clique no + ao lado para regularizar.">
              {name} <span style={{ marginLeft: 4, opacity: 0.7, fontSize: 11 }}>({sectorItemCount(name)})</span>
            </button>
          ))}
          {isAdmin && (
            <button onClick={() => setCreatingSector(true)} title="Criar novo setor"
              style={{
                padding: '6px 10px', borderRadius: 999, border: `1px dashed ${colors.borderDark}`,
                background: 'transparent', cursor: 'pointer', color: colors.textSoft, fontSize: 13, fontFamily: bodyFont,
                display: 'inline-flex', alignItems: 'center', gap: 4,
              }}>
              <Icons.Plus size={13} /> Novo setor
            </button>
          )}
        </div>
        <Btn variant="primary" Icon={Icons.Plus} onClick={() => setEditing({ ...blank, sector: filterSector !== 'todos' ? filterSector : (sectors[0]?.name || 'Geral') })}>Novo item</Btn>
      </div>

      <div style={{ position: 'relative', marginBottom: 16, maxWidth: 360 }}>
        <div style={{ position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)', color: colors.textMute }}><Icons.Search size={16} /></div>
        <input placeholder="Buscar item..." value={search} onChange={e => setSearch(e.target.value)}
          style={{ width: '100%', padding: '9px 12px 9px 36px', border: `1px solid ${colors.border}`, borderRadius: 8, fontSize: 14, fontFamily: bodyFont, outline: 'none' }} />
      </div>

      {items.length === 0 ? (
        <Card><Empty Icon={Icons.Box} title="Estoque vazio" hint="Cadastre seu primeiro item para começar." /></Card>
      ) : filtered.length === 0 ? (
        <Card><Empty Icon={Icons.Search} title="Nenhum item encontrado" hint="Tente outro filtro ou termo de busca." /></Card>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {grouped.map(group => (
            <Card key={group.name} style={{ padding: 0, overflow: 'hidden' }}>
              <div
                onClick={() => isAdmin && setRenamingCategory(group.name)}
                title={isAdmin ? 'Clique para renomear' : ''}
                style={{
                  padding: '10px 16px', backgroundColor: colors.primary, color: '#fff',
                  fontFamily: displayFont, fontSize: 14, fontWeight: 600, letterSpacing: 0.4,
                  textTransform: 'uppercase', display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                  cursor: isAdmin ? 'pointer' : 'default',
                }}>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                  {group.name}
                  {isAdmin && <Icons.Edit size={13} color="rgba(255,255,255,0.7)" />}
                </span>
                <span style={{ fontSize: 11, opacity: 0.85, fontWeight: 500 }}>{group.items.length} item{group.items.length === 1 ? '' : 's'}</span>
              </div>
              <div style={{ overflowX: 'auto' }}>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontFamily: bodyFont }}>
                  <thead>
                    <tr style={{ backgroundColor: colors.surfaceAlt, borderBottom: `1px solid ${colors.border}` }}>
                      {['Item', 'Setor', 'Qtd', 'Mínimo', 'Preço médio', 'Status', ''].map(h => (
                        <th key={h} style={{ padding: '8px 14px', textAlign: 'left', fontSize: 10, fontWeight: 600, color: colors.textSoft, letterSpacing: 0.4, textTransform: 'uppercase' }}>{h}</th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {group.items.map(it => {
                      const low = it.quantity <= it.minStock;
                      const stats = priceStatsFor(it.id);
                      return (
                        <tr key={it.id} style={{ borderBottom: `1px solid ${colors.border}` }}>
                          <td style={{ padding: '10px 14px', fontWeight: 500, color: colors.text, fontSize: 14 }}>{it.name}</td>
                          <td style={{ padding: '10px 14px' }}><Badge color={sectorColor(sectors, it.sector)}>{it.sector}</Badge></td>
                          <td style={{ padding: '10px 14px', fontFamily: displayFont, fontSize: 16, fontWeight: 600, color: low ? colors.danger : colors.text }}>
                            {fmtNum(it.quantity)} <span style={{ fontSize: 12, color: colors.textMute, fontFamily: bodyFont, fontWeight: 400 }}>{it.unit}</span>
                          </td>
                          <td style={{ padding: '10px 14px', color: colors.textSoft, fontSize: 14 }}>{fmtNum(it.minStock)} {it.unit}</td>
                          <td style={{ padding: '10px 14px', fontSize: 14 }}>
                            {stats ? (
                              <div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
                                <span style={{ color: colors.text, fontWeight: 500 }}>
                                  {fmtBRL(stats.avg)}
                                  <span style={{ fontSize: 10, color: colors.textMute, marginLeft: 4, fontWeight: 400 }}>média ({stats.count})</span>
                                </span>
                                <span style={{ fontSize: 11, color: stats.last > stats.avg ? colors.danger : (stats.last < stats.avg ? colors.success : colors.textMute) }}>
                                  Última: {fmtBRL(stats.last)} {stats.last > stats.avg ? '↑' : stats.last < stats.avg ? '↓' : '='}
                                </span>
                              </div>
                            ) : (
                              <span style={{ color: colors.textSoft }}>{fmtBRL(it.unitCost)}<span style={{ fontSize: 10, color: colors.textMute, marginLeft: 4 }}>sem histórico</span></span>
                            )}
                          </td>
                          <td style={{ padding: '10px 14px' }}>{low ? <Badge color={colors.danger}>Repor</Badge> : <Badge color={colors.success}>Ok</Badge>}</td>
                          <td style={{ padding: '10px 14px', whiteSpace: 'nowrap' }}>
                            <button onClick={() => setMoving(it)} style={{ background: 'none', border: `1px solid ${colors.border}`, cursor: 'pointer', color: colors.text, padding: '4px 10px', borderRadius: 6, fontSize: 13, marginRight: 4 }}>± Mov.</button>
                            <button onClick={() => setMovingToGroup(it)} title="Mover para outro subgrupo" style={{ background: 'none', border: `1px solid ${colors.border}`, cursor: 'pointer', color: colors.text, padding: '4px 10px', borderRadius: 6, fontSize: 13, marginRight: 4 }}>Mover</button>
                            <button onClick={() => setViewingHistory(it)} title="Histórico de preços" style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textSoft, padding: 4 }}><Icons.Chart size={15} /></button>
                            <button onClick={() => setEditing(it)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textSoft, padding: 4 }}><Icons.Edit size={15} /></button>
                            <button onClick={() => remove(it.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 4 }}><Icons.Trash size={15} /></button>
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </Card>
          ))}
        </div>
      )}

      {editing && (
        <Modal open onClose={() => setEditing(null)} title={editing.id ? 'Editar item' : 'Novo item'}>
          <ItemForm initial={editing} sectors={sectors} categoriesData={categoriesData} onSave={save} onCancel={() => setEditing(null)} />
        </Modal>
      )}
      {moving && (
        <Modal open onClose={() => setMoving(null)} title={`Movimentar: ${moving.name}`} width={400}>
          <MovementForm item={moving} currentUser={currentUser} onRegister={registerMovement} onCancel={() => setMoving(null)} />
        </Modal>
      )}
      {renamingCategory && (
        <Modal open onClose={() => setRenamingCategory(null)} title={`Renomear "${renamingCategory}"`} width={400}>
          <RenameCategoryForm
            oldName={renamingCategory}
            onSave={(newName) => renameCategory(renamingCategory, newName)}
            onCancel={() => setRenamingCategory(null)} />
        </Modal>
      )}
      {movingToGroup && (
        <Modal open onClose={() => setMovingToGroup(null)} title={`Mover "${movingToGroup.name}" para outro subgrupo`} width={420}>
          <MoveToGroupForm
            item={movingToGroup}
            existingGroups={grouped.map(g => g.name)}
            allCategories={(categoriesData || []).map(c => c.name)}
            onMove={(newGroup) => moveItemToGroup(movingToGroup.id, newGroup)}
            onCancel={() => setMovingToGroup(null)} />
        </Modal>
      )}
      {viewingHistory && (
        <Modal open onClose={() => setViewingHistory(null)} title={`Histórico de preços — ${viewingHistory.name}`} width={520}>
          <PriceHistoryView item={viewingHistory} movements={movements} />
        </Modal>
      )}
      {(renamingSector || creatingSector) && (
        <Modal open
          onClose={() => { setRenamingSector(null); setCreatingSector(false); }}
          title={renamingSector ? `Renomear setor` : 'Novo setor'}
          width={420}>
          <SectorFormInline
            initial={renamingSector || { id: '', name: '', color: '#2C6E63' }}
            onSave={saveSector}
            onCancel={() => { setRenamingSector(null); setCreatingSector(false); }} />
        </Modal>
      )}
    </div>
  );
}

function SectorFormInline({ initial, onSave, onCancel }) {
  const [sector, setSector] = useState(initial);
  const palette = ['#2C6E63', '#D9A521', '#8B2331', '#3F5DA8', '#7C4FB0', '#3F8A5C', '#B5651D', '#5C5147'];
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <Input label="Nome do setor" value={sector.name} onChange={v => setSector({ ...sector, name: v })} placeholder="Ex: Café da Manhã, Produtos de Limpeza" />
      <div>
        <div style={{ fontSize: 11, fontWeight: 500, color: colors.textSoft, marginBottom: 6, letterSpacing: 0.3, textTransform: 'uppercase', fontFamily: bodyFont }}>Cor</div>
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
          {palette.map(c => (
            <button key={c} onClick={() => setSector({ ...sector, color: c })}
              style={{
                width: 28, height: 28, borderRadius: 999, backgroundColor: c,
                border: sector.color === c ? `3px solid ${colors.text}` : `2px solid ${colors.border}`,
                cursor: 'pointer',
              }} />
          ))}
        </div>
      </div>
      {initial.id && (
        <div style={{ padding: 10, backgroundColor: colors.surfaceAlt, borderRadius: 8, fontSize: 12, color: colors.textSoft, fontFamily: bodyFont, lineHeight: 1.5 }}>
          Se renomear, todos os itens deste setor serão atualizados automaticamente.
        </div>
      )}
      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={() => onSave(sector)} disabled={!sector.name.trim()}>Salvar</Btn>
      </div>
    </div>
  );
}

function chipStyle(active, color) {
  return {
    padding: '7px 14px', borderRadius: 999,
    border: `1px solid ${active ? (color || colors.text) : colors.border}`,
    backgroundColor: active ? (color || colors.text) : 'transparent',
    color: active ? '#fff' : colors.textSoft,
    fontFamily: bodyFont, fontSize: 13, cursor: 'pointer', fontWeight: 500,
  };
}

function ItemForm({ initial, sectors, categoriesData, onSave, onCancel }) {
  const [item, setItem] = useState({ category: 'Outros', ...initial });
  const units = ['un', 'kg', 'g', 'L', 'ml', 'cx', 'pct', 'rolo', 'fardo', 'galão', 'pote', 'band'];
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <Input label="Nome do item" value={item.name} onChange={v => setItem({ ...item, name: v })} placeholder="Ex: Detergente / Pão francês" />
      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 12 }}>
        <Select label="Setor" value={item.sector} onChange={v => setItem({ ...item, sector: v })} options={sectors.map(s => ({ value: s.name, label: s.name }))} />
        <Select label="Unidade" value={item.unit} onChange={v => setItem({ ...item, unit: v })} options={units.map(u => ({ value: u, label: u }))} />
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
        <Input label="Quantidade" value={item.quantity} onChange={v => setItem({ ...item, quantity: v })} type="number" step="0.001" min="0" />
        <Input label="Mínimo" value={item.minStock} onChange={v => setItem({ ...item, minStock: v })} type="number" step="0.001" min="0" />
        <Input label="Custo un." value={item.unitCost} onChange={v => setItem({ ...item, unitCost: v })} type="number" step="0.01" min="0" suffix="R$" />
      </div>
      {item.category && (
        <div style={{ padding: 10, backgroundColor: colors.surfaceAlt, borderRadius: 8, fontSize: 12, color: colors.textSoft, fontFamily: bodyFont }}>
          Subgrupo atual: <strong style={{ color: colors.text }}>{item.category}</strong>
          <span style={{ marginLeft: 6, color: colors.textMute }}>· Use o botão "Mover" na lista para mudar de subgrupo.</span>
        </div>
      )}
      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={() => onSave(item)} disabled={!item.name.trim()}>Salvar</Btn>
      </div>
    </div>
  );
}

function RenameCategoryForm({ oldName, onSave, onCancel }) {
  const [name, setName] = useState(oldName);
  const submit = () => { if (name.trim() && name.trim() !== oldName) onSave(name); else onCancel(); };
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <p style={{ margin: 0, fontFamily: bodyFont, fontSize: 13, color: colors.textSoft, lineHeight: 1.5 }}>
        Mudar o nome desta categoria. Todos os itens vinculados serão atualizados automaticamente.
      </p>
      <Input label="Novo nome" value={name} onChange={setName} placeholder="Ex: Biscoitos, Doces, Frios" />
      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={submit} disabled={!name.trim() || name.trim() === oldName}>Salvar</Btn>
      </div>
    </div>
  );
}

function PriceHistoryView({ item, movements }) {
  // Todas as compras (entradas com valor pago) deste item, mais recentes primeiro
  const purchases = useMemo(() => {
    return movements
      .filter(m => m.itemId === item.id && m.type === 'entrada' && (Number(m.paidAmount) || 0) > 0 && (Number(m.quantity) || 0) > 0)
      .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
  }, [movements, item.id]);

  // Últimas 5 para a média
  const last5 = purchases.slice(0, 5);
  const unitPrices = last5.map(p => (Number(p.paidAmount) || 0) / (Number(p.quantity) || 1));

  if (purchases.length === 0) {
    return (
      <div style={{ padding: '20px 0' }}>
        <Empty Icon={Icons.Chart} title="Sem histórico de preços" hint="Quando você registrar uma entrada com valor pago, aparece aqui." />
      </div>
    );
  }

  const avg = unitPrices.reduce((s, p) => s + p, 0) / unitPrices.length;
  const min = Math.min(...unitPrices);
  const max = Math.max(...unitPrices);
  const last = unitPrices[0];
  const lastVsAvg = avg > 0 ? ((last - avg) / avg) * 100 : 0;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10 }}>
        <div style={{ padding: 12, backgroundColor: colors.surfaceAlt, borderRadius: 8 }}>
          <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Média ({last5.length})</div>
          <div style={{ fontFamily: displayFont, fontSize: 18, fontWeight: 600, color: colors.text }}>{fmtBRL(avg)}</div>
        </div>
        <div style={{ padding: 12, backgroundColor: '#EAF3EE', borderRadius: 8 }}>
          <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Menor</div>
          <div style={{ fontFamily: displayFont, fontSize: 18, fontWeight: 600, color: colors.success }}>{fmtBRL(min)}</div>
        </div>
        <div style={{ padding: 12, backgroundColor: '#FBEDE8', borderRadius: 8 }}>
          <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Maior</div>
          <div style={{ fontFamily: displayFont, fontSize: 18, fontWeight: 600, color: colors.danger }}>{fmtBRL(max)}</div>
        </div>
      </div>

      <div style={{
        padding: 12, borderRadius: 8, fontFamily: bodyFont, fontSize: 13,
        backgroundColor: lastVsAvg > 5 ? '#FBEDE8' : (lastVsAvg < -5 ? '#EAF3EE' : colors.surfaceAlt),
      }}>
        Última compra: <strong style={{ color: colors.text }}>{fmtBRL(last)}</strong> por {item.unit}
        {Math.abs(lastVsAvg) > 0.5 && (
          <span style={{ marginLeft: 8, color: lastVsAvg > 0 ? colors.danger : colors.success, fontWeight: 600 }}>
            {lastVsAvg > 0 ? '↑' : '↓'} {Math.abs(lastVsAvg).toFixed(1)}% em relação à média
          </span>
        )}
      </div>

      <div>
        <div style={{ fontFamily: displayFont, fontSize: 14, fontWeight: 600, color: colors.text, marginBottom: 8 }}>
          Compras registradas ({purchases.length})
        </div>
        <div style={{ border: `1px solid ${colors.border}`, borderRadius: 8, maxHeight: 300, overflowY: 'auto' }}>
          {purchases.map((p, idx) => {
            const unitPrice = (Number(p.paidAmount) || 0) / (Number(p.quantity) || 1);
            const inLast5 = idx < 5;
            return (
              <div key={p.id} style={{
                padding: '10px 12px', display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                borderBottom: idx < purchases.length - 1 ? `1px solid ${colors.border}` : 'none',
                opacity: inLast5 ? 1 : 0.6,
              }}>
                <div>
                  <div style={{ fontFamily: bodyFont, fontSize: 13, color: colors.text, fontWeight: 500 }}>
                    {fmtDate(p.createdAt)}
                    {idx === 0 && <span style={{ marginLeft: 6, fontSize: 10, color: colors.primary, fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.4 }}>Última</span>}
                    {!inLast5 && <span style={{ marginLeft: 6, fontSize: 10, color: colors.textMute }}>(fora da média)</span>}
                  </div>
                  <div style={{ fontFamily: bodyFont, fontSize: 12, color: colors.textMute }}>
                    {fmtNum(p.quantity)} {item.unit} · {p.registeredBy || 'sem usuário'}
                    {p.notes ? ` · ${p.notes}` : ''}
                  </div>
                </div>
                <div style={{ textAlign: 'right' }}>
                  <div style={{ fontFamily: displayFont, fontSize: 15, fontWeight: 600, color: colors.text }}>{fmtBRL(unitPrice)}</div>
                  <div style={{ fontFamily: bodyFont, fontSize: 11, color: colors.textMute }}>total {fmtBRL(p.paidAmount)}</div>
                </div>
              </div>
            );
          })}
        </div>
        {purchases.length > 5 && (
          <div style={{ marginTop: 6, fontSize: 11, color: colors.textMute, fontFamily: bodyFont, fontStyle: 'italic' }}>
            Apenas as 5 compras mais recentes contam para a média.
          </div>
        )}
      </div>
    </div>
  );
}

function MoveToGroupForm({ item, existingGroups, allCategories, onMove, onCancel }) {
  // Junta os subgrupos que já têm itens + categorias cadastradas, sem repetir
  const allOptions = useMemo(() => {
    const set = new Set([...existingGroups, ...allCategories, 'Outros']);
    set.delete(item.category || 'Outros');
    return Array.from(set).sort();
  }, [existingGroups, allCategories, item.category]);
  const [selected, setSelected] = useState(allOptions[0] || '');
  const [creating, setCreating] = useState(false);
  const [newName, setNewName] = useState('');

  const submit = () => {
    const target = creating ? newName.trim() : selected;
    if (!target) return;
    onMove(target);
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ padding: 12, backgroundColor: colors.surfaceAlt, borderRadius: 8, fontFamily: bodyFont, fontSize: 13, color: colors.textSoft }}>
        Item: <strong style={{ color: colors.text }}>{item.name}</strong><br />
        Subgrupo atual: <strong style={{ color: colors.text }}>{item.category || 'Outros'}</strong>
      </div>

      {!creating ? (
        <>
          <Select
            label="Mover para o subgrupo"
            value={selected}
            onChange={setSelected}
            options={allOptions.map(g => ({ value: g, label: g }))} />
          <button onClick={() => setCreating(true)} style={{
            background: 'none', border: `1px dashed ${colors.borderDark}`, borderRadius: 6,
            padding: '6px 12px', cursor: 'pointer', color: colors.text, fontSize: 13,
            fontFamily: bodyFont, display: 'inline-flex', alignItems: 'center', gap: 4, justifyContent: 'center',
          }}>
            <Icons.Plus size={13} /> Criar um subgrupo novo
          </button>
        </>
      ) : (
        <>
          <Input label="Nome do novo subgrupo" value={newName} onChange={setNewName} placeholder="Ex: Conservas, Frios caseiros" />
          <button onClick={() => setCreating(false)} style={{
            background: 'none', border: 'none', cursor: 'pointer', color: colors.textSoft,
            fontSize: 12, fontFamily: bodyFont, textAlign: 'left', padding: 0,
          }}>← Escolher um subgrupo existente</button>
        </>
      )}

      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={submit} disabled={creating ? !newName.trim() : !selected}>Mover</Btn>
      </div>
    </div>
  );
}

function MovementForm({ item, currentUser, onRegister, onCancel }) {
  const [qty, setQty] = useState('');
  const [mode, setMode] = useState('saida');
  const [notes, setNotes] = useState('');
  const [paidValue, setPaidValue] = useState('');
  const value = parseFloat(qty) || 0;
  const delta = mode === 'entrada' ? value : -value;
  const newQty = Math.max(0, item.quantity + delta);
  const paid = parseFloat(paidValue) || 0;
  const unitFromPaid = (mode === 'entrada' && value > 0 && paid > 0) ? (paid / value) : 0;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ padding: 12, backgroundColor: colors.surfaceAlt, borderRadius: 8, fontFamily: bodyFont, fontSize: 13, color: colors.textSoft }}>
        Estoque atual: <strong style={{ color: colors.text }}>{fmtNum(item.quantity)} {item.unit}</strong>
      </div>
      <div style={{ display: 'flex', gap: 6 }}>
        {[{ v: 'entrada', l: 'Entrada (+)' }, { v: 'saida', l: 'Saída / Consumo (−)' }].map(m => (
          <button key={m.v} onClick={() => setMode(m.v)} style={{
            flex: 1, padding: '10px', borderRadius: 8,
            border: `1px solid ${mode === m.v ? colors.text : colors.border}`,
            backgroundColor: mode === m.v ? colors.text : 'transparent',
            color: mode === m.v ? '#fff' : colors.textSoft, fontFamily: bodyFont, fontSize: 13, cursor: 'pointer', fontWeight: 500,
          }}>{m.l}</button>
        ))}
      </div>
      <Input label="Quantidade" value={qty} onChange={setQty} type="number" step="0.001" min="0" suffix={item.unit} />
      {mode === 'entrada' && (
        <>
          <Input label="Valor pago (opcional)" value={paidValue} onChange={setPaidValue} type="number" step="0.01" min="0" suffix="R$" placeholder="Total pago nesta compra" />
          {unitFromPaid > 0 && (
            <div style={{ padding: 10, backgroundColor: '#E9F1ED', borderRadius: 8, fontSize: 12, color: colors.textSoft, fontFamily: bodyFont }}>
              Preço por {item.unit}: <strong style={{ color: colors.text, fontFamily: displayFont, fontSize: 15 }}>{fmtBRL(unitFromPaid)}</strong>
              {item.unitCost > 0 && (
                <span style={{ marginLeft: 8, color: unitFromPaid > item.unitCost ? colors.danger : colors.success }}>
                  {unitFromPaid > item.unitCost ? '↑' : '↓'} {(((unitFromPaid - item.unitCost) / item.unitCost) * 100).toFixed(1)}% vs custo atual
                </span>
              )}
            </div>
          )}
        </>
      )}
      <Input label="Observação (opcional)" value={notes} onChange={setNotes} placeholder="Ex: reposição semanal, uso na cozinha" />
      {!currentUser && (
        <div style={{ padding: 10, backgroundColor: '#FFF6E5', border: `1px solid ${colors.accent}`, borderRadius: 8, fontSize: 12, color: colors.textSoft, fontFamily: bodyFont }}>
          Dica: defina seu nome no topo da tela para registrar quem fez a movimentação.
        </div>
      )}
      <div style={{ padding: 12, backgroundColor: '#E9F1ED', borderRadius: 8, fontFamily: bodyFont, fontSize: 13 }}>
        Novo estoque: <strong style={{ color: colors.text, fontFamily: displayFont, fontSize: 17 }}>{fmtNum(newQty)} {item.unit}</strong>
      </div>
      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={() => onRegister(item, mode, value, notes, paid)} disabled={value <= 0}>Registrar</Btn>
      </div>
    </div>
  );
}

// ============================================================
// CONSUMO (histórico de movimentações)
// ============================================================
function ConsumoView({ movements, setMovements, sectors, items, setItems }) {
  const [filterType, setFilterType] = useState('todos');
  const [filterSector, setFilterSector] = useState('todos');

  const filtered = useMemo(() => {
    let list = [...movements].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
    if (filterType !== 'todos') list = list.filter(m => m.type === filterType);
    if (filterSector !== 'todos') list = list.filter(m => m.sector === filterSector);
    return list;
  }, [movements, filterType, filterSector]);

  const remove = (id) => {
    const mov = movements.find(m => m.id === id);
    if (!mov) return;
    const item = items.find(i => i.id === mov.itemId);
    const qty = Number(mov.quantity) || 0;
    // Calcula reversão: se foi entrada (+qty), removemos (-qty); se foi saída (-qty), devolvemos (+qty)
    const reversal = mov.type === 'entrada' ? -qty : qty;
    const itemInfo = item ? `\n\nEstoque atual de "${item.name}": ${item.quantity} ${item.unit}\nApós reversão: ${Math.max(0, item.quantity + reversal)} ${item.unit}` : '';
    if (!window.confirm(`Excluir este registro e reverter o estoque?\n\n${mov.type === 'entrada' ? 'Entrada' : 'Saída'} de ${qty} ${item?.unit || ''} de "${mov.itemName}"${itemInfo}`)) return;
    if (item) {
      const newQty = Math.max(0, item.quantity + reversal);
      setItems(items.map(i => i.id === item.id ? { ...i, quantity: newQty } : i));
    }
    setMovements(movements.filter(m => m.id !== id));
  };

  return (
    <div>
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 16, alignItems: 'center' }}>
        <button onClick={() => setFilterType('todos')} style={chipStyle(filterType === 'todos')}>Tudo</button>
        <button onClick={() => setFilterType('entrada')} style={chipStyle(filterType === 'entrada', colors.success)}>Entradas</button>
        <button onClick={() => setFilterType('saida')} style={chipStyle(filterType === 'saida', colors.danger)}>Saídas / Consumo</button>
        <div style={{ width: 1, height: 24, backgroundColor: colors.border, margin: '0 4px' }} />
        <button onClick={() => setFilterSector('todos')} style={chipStyle(filterSector === 'todos')}>Todos setores</button>
        {sectors.map(s => <button key={s.id} onClick={() => setFilterSector(s.name)} style={chipStyle(filterSector === s.name, s.color)}>{s.name}</button>)}
      </div>

      {filtered.length === 0 ? (
        <Card><Empty Icon={Icons.Consumo} title="Nenhuma movimentação" hint="As entradas e saídas registradas no estoque aparecem aqui." /></Card>
      ) : (
        <Card style={{ padding: 0 }}>
          {filtered.map(m => (
            <div key={m.id} style={{ padding: '12px 18px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: `1px solid ${colors.border}`, gap: 12 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, flex: 1, minWidth: 0 }}>
                <div style={{ width: 32, height: 32, borderRadius: 8, backgroundColor: m.type === 'entrada' ? `${colors.success}15` : `${colors.danger}15`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  {m.type === 'entrada' ? <Icons.ArrowUp size={16} color={colors.success} /> : <Icons.ArrowDown size={16} color={colors.danger} />}
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontFamily: bodyFont, fontSize: 14, color: colors.text, fontWeight: 500 }}>{m.itemName}</div>
                  <div style={{ fontFamily: bodyFont, fontSize: 12, color: colors.textMute }}>
                    {fmtDate(m.createdAt)} {fmtTime(m.createdAt)} · {m.sector}
                    {m.registeredBy ? ` · ${m.registeredBy}` : ''}
                    {m.notes ? ` · ${m.notes}` : ''}
                  </div>
                </div>
              </div>
              <div style={{ fontFamily: displayFont, fontSize: 16, fontWeight: 600, color: m.type === 'entrada' ? colors.success : colors.danger }}>
                {m.type === 'entrada' ? '+' : '−'} {fmtNum(m.quantity)}
              </div>
              <button onClick={() => remove(m.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 4 }}><Icons.Trash size={14} /></button>
            </div>
          ))}
        </Card>
      )}
    </div>
  );
}

// ============================================================
// LISTA DE COMPRAS
// ============================================================
function ComprasView({ shopping, setShopping, items, sectors, businessName }) {
  const [adding, setAdding] = useState(false);
  const [showBought, setShowBought] = useState(false);

  const pending = useMemo(() => shopping.filter(s => s.status === 'pendente').sort((a, b) => (a.sector || '').localeCompare(b.sector || '')), [shopping]);
  const bought = useMemo(() => shopping.filter(s => s.status === 'comprado').sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)), [shopping]);

  const toggleBought = (id) => setShopping(shopping.map(s => s.id === id ? { ...s, status: s.status === 'comprado' ? 'pendente' : 'comprado' } : s));
  const remove = (id) => setShopping(shopping.filter(s => s.id !== id));
  const clearBought = () => { if (window.confirm('Remover todos os itens já comprados da lista?')) setShopping(shopping.filter(s => s.status !== 'comprado')); };

  const addItem = (entry) => { setShopping([...shopping, { ...entry, id: newId(), status: 'pendente', auto: false, createdAt: new Date().toISOString() }]); setAdding(false); };

  // Sugestão: itens abaixo do mínimo que ainda não estão na lista
  const suggestions = useMemo(() => items.filter(i => i.quantity <= i.minStock && !shopping.find(s => s.itemId === i.id && s.status === 'pendente')), [items, shopping]);

  const addSuggestion = (item) => {
    setShopping([...shopping, {
      id: newId(), name: item.name, sector: item.sector, unit: item.unit,
      quantity: Math.max(item.minStock - item.quantity, item.minStock), status: 'pendente', auto: true, itemId: item.id, notes: '',
      createdAt: new Date().toISOString(),
    }]);
  };
  const addAllSuggestions = () => {
    const news = suggestions.map(item => ({
      id: newId(), name: item.name, sector: item.sector, unit: item.unit,
      quantity: Math.max(item.minStock - item.quantity, item.minStock), status: 'pendente', auto: true, itemId: item.id, notes: '',
      createdAt: new Date().toISOString(),
    }));
    setShopping([...shopping, ...news]);
  };

  const printList = () => openPrintWindow(buildShoppingList(pending, businessName));

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16, flexWrap: 'wrap', gap: 12 }}>
        <p style={{ margin: 0, fontFamily: bodyFont, color: colors.textSoft, fontSize: 14 }}>
          {pending.length} item{pending.length === 1 ? '' : 's'} para comprar.
        </p>
        <div style={{ display: 'flex', gap: 8 }}>
          <Btn variant="outline" Icon={Icons.Printer} onClick={printList} disabled={pending.length === 0}>Imprimir lista</Btn>
          <Btn variant="primary" Icon={Icons.Plus} onClick={() => setAdding(true)}>Adicionar item</Btn>
        </div>
      </div>

      {suggestions.length > 0 && (
        <Card style={{ marginBottom: 16, backgroundColor: '#FFF6E5', borderColor: '#E8D08A' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <Icons.Alert size={18} color={colors.accent} />
              <span style={{ fontFamily: displayFont, fontSize: 16, color: colors.text, fontWeight: 600 }}>Sugestões (estoque baixo)</span>
            </div>
            <Btn size="sm" variant="primary" onClick={addAllSuggestions}>Adicionar todos</Btn>
          </div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
            {suggestions.map(item => (
              <button key={item.id} onClick={() => addSuggestion(item)} style={{
                padding: '6px 12px', borderRadius: 999, border: `1px solid ${colors.borderDark}`,
                backgroundColor: colors.surface, cursor: 'pointer', fontFamily: bodyFont, fontSize: 13, color: colors.text,
                display: 'inline-flex', alignItems: 'center', gap: 6,
              }}>
                <Icons.Plus size={12} /> {item.name} <span style={{ color: colors.textMute }}>({item.sector})</span>
              </button>
            ))}
          </div>
        </Card>
      )}

      {pending.length === 0 ? (
        <Card><Empty Icon={Icons.Cart} title="Lista vazia" hint="Adicione itens manualmente ou pelas sugestões de estoque baixo." /></Card>
      ) : (
        <Card style={{ padding: 0 }}>
          {pending.map(s => (
            <div key={s.id} style={{ padding: '12px 18px', display: 'flex', alignItems: 'center', gap: 12, borderBottom: `1px solid ${colors.border}` }}>
              <button onClick={() => toggleBought(s.id)} style={{ width: 24, height: 24, borderRadius: 6, border: `2px solid ${colors.borderDark}`, backgroundColor: 'transparent', cursor: 'pointer', flexShrink: 0 }} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontFamily: bodyFont, fontSize: 14, color: colors.text, fontWeight: 500 }}>
                  {s.name} {s.auto && <Badge color={colors.accent}>auto</Badge>}
                </div>
                <div style={{ fontFamily: bodyFont, fontSize: 12, color: colors.textMute }}>
                  {s.sector}{s.quantity ? ` · ${fmtNum(s.quantity)} ${s.unit}` : ''}{s.notes ? ` · ${s.notes}` : ''}
                </div>
              </div>
              <button onClick={() => remove(s.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 4 }}><Icons.Trash size={15} /></button>
            </div>
          ))}
        </Card>
      )}

      {bought.length > 0 && (
        <div style={{ marginTop: 16 }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
            <button onClick={() => setShowBought(!showBought)} style={{ background: 'none', border: 'none', cursor: 'pointer', fontFamily: bodyFont, fontSize: 14, color: colors.textSoft, fontWeight: 500 }}>
              {showBought ? '▾' : '▸'} Comprados ({bought.length})
            </button>
            {showBought && <Btn size="sm" variant="ghost" onClick={clearBought}>Limpar comprados</Btn>}
          </div>
          {showBought && (
            <Card style={{ padding: 0 }}>
              {bought.map(s => (
                <div key={s.id} style={{ padding: '10px 18px', display: 'flex', alignItems: 'center', gap: 12, borderBottom: `1px solid ${colors.border}`, opacity: 0.7 }}>
                  <button onClick={() => toggleBought(s.id)} style={{ width: 24, height: 24, borderRadius: 6, border: `2px solid ${colors.success}`, backgroundColor: colors.success, cursor: 'pointer', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icons.Check size={14} color="#fff" /></button>
                  <div style={{ flex: 1, minWidth: 0, textDecoration: 'line-through', color: colors.textMute, fontFamily: bodyFont, fontSize: 14 }}>{s.name}</div>
                  <button onClick={() => remove(s.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 4 }}><Icons.Trash size={15} /></button>
                </div>
              ))}
            </Card>
          )}
        </div>
      )}

      {adding && (
        <Modal open onClose={() => setAdding(false)} title="Adicionar à lista">
          <ShoppingForm sectors={sectors} onSave={addItem} onCancel={() => setAdding(false)} />
        </Modal>
      )}
    </div>
  );
}

function ShoppingForm({ sectors, onSave, onCancel }) {
  const [entry, setEntry] = useState({ name: '', sector: sectors[0]?.name || 'Geral', quantity: '', unit: 'un', notes: '' });
  const units = ['un', 'kg', 'g', 'L', 'ml', 'cx', 'pct', 'rolo', 'fardo', 'galão'];
  const submit = () => { if (!entry.name.trim()) return; onSave({ ...entry, quantity: parseFloat(entry.quantity) || 0 }); };
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <Input label="Item" value={entry.name} onChange={v => setEntry({ ...entry, name: v })} placeholder="Ex: Papel toalha" />
      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr', gap: 12 }}>
        <Select label="Setor" value={entry.sector} onChange={v => setEntry({ ...entry, sector: v })} options={sectors.map(s => ({ value: s.name, label: s.name }))} />
        <Input label="Qtd" value={entry.quantity} onChange={v => setEntry({ ...entry, quantity: v })} type="number" step="0.001" min="0" />
        <Select label="Unidade" value={entry.unit} onChange={v => setEntry({ ...entry, unit: v })} options={units.map(u => ({ value: u, label: u }))} />
      </div>
      <Input label="Observação (opcional)" value={entry.notes} onChange={v => setEntry({ ...entry, notes: v })} placeholder="Ex: marca específica" />
      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={submit} disabled={!entry.name.trim()}>Adicionar</Btn>
      </div>
    </div>
  );
}

// ============================================================
// SETORES
// ============================================================
function SetoresView({ sectors, setSectors, items }) {
  const [editing, setEditing] = useState(null);
  const palette = ['#3B7CA8', '#E0A93B', '#3E8B5A', '#C24A2E', '#7C5CBF', '#2C6E63', '#B8567A', '#5A7C3F'];
  const blank = { id: '', name: '', color: palette[0] };

  const save = (sec) => {
    if (!sec.name.trim()) return;
    if (sec.id && sectors.find(s => s.id === sec.id)) setSectors(sectors.map(s => s.id === sec.id ? sec : s));
    else setSectors([...sectors, { ...sec, id: newId(), createdAt: new Date().toISOString() }]);
    setEditing(null);
  };
  const remove = (sec) => {
    const count = items.filter(i => i.sector === sec.name).length;
    if (count > 0) { alert(`Não dá para remover "${sec.name}": existem ${count} itens nesse setor. Mova ou remova os itens antes.`); return; }
    if (window.confirm(`Remover o setor "${sec.name}"?`)) setSectors(sectors.filter(s => s.id !== sec.id));
  };

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
        <p style={{ margin: 0, fontFamily: bodyFont, color: colors.textSoft, fontSize: 14 }}>Organize seus itens por setor. Crie quantos precisar.</p>
        <Btn variant="primary" Icon={Icons.Plus} onClick={() => setEditing(blank)}>Novo setor</Btn>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))', gap: 12 }}>
        {sectors.map(sec => {
          const count = items.filter(i => i.sector === sec.name).length;
          return (
            <Card key={sec.id} style={{ borderLeft: `4px solid ${sec.color}` }}>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                <div>
                  <div style={{ fontFamily: displayFont, fontSize: 18, color: colors.text, fontWeight: 600 }}>{sec.name}</div>
                  <div style={{ fontSize: 13, color: colors.textSoft, fontFamily: bodyFont }}>{count} item{count === 1 ? '' : 's'}</div>
                </div>
                <div style={{ display: 'flex', gap: 4 }}>
                  <button onClick={() => setEditing(sec)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textSoft, padding: 6 }}><Icons.Edit size={16} /></button>
                  <button onClick={() => remove(sec)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 6 }}><Icons.Trash size={16} /></button>
                </div>
              </div>
            </Card>
          );
        })}
      </div>
      {editing && (
        <Modal open onClose={() => setEditing(null)} title={editing.id ? 'Editar setor' : 'Novo setor'} width={400}>
          <SectorForm initial={editing} palette={palette} onSave={save} onCancel={() => setEditing(null)} />
        </Modal>
      )}
    </div>
  );
}

function SectorForm({ initial, palette, onSave, onCancel }) {
  const [sec, setSec] = useState(initial);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      <Input label="Nome do setor" value={sec.name} onChange={v => setSec({ ...sec, name: v })} placeholder="Ex: Cozinha, Bar, Escritório" />
      <div>
        <div style={{ fontSize: 12, fontWeight: 500, color: colors.textSoft, marginBottom: 8, letterSpacing: 0.3, textTransform: 'uppercase', fontFamily: bodyFont }}>Cor</div>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {palette.map(c => (
            <button key={c} onClick={() => setSec({ ...sec, color: c })} style={{
              width: 36, height: 36, borderRadius: 8, backgroundColor: c, cursor: 'pointer',
              border: sec.color === c ? `3px solid ${colors.text}` : `1px solid ${colors.border}`,
            }} />
          ))}
        </div>
      </div>
      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={() => onSave(sec)} disabled={!sec.name.trim()}>Salvar</Btn>
      </div>
    </div>
  );
}

// ============================================================
// RELATÓRIOS
// ============================================================
function RelatoriosView({ items, movements, sectors, demand, businessName }) {
  // Mês atual em YYYY-MM
  const now = new Date();
  const defaultMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
  const [month, setMonth] = useState(defaultMonth);
  const [selectedSector, setSelectedSector] = useState('todos');

  // Identifica setores reais (do banco + fantasmas dos itens)
  const allSectors = useMemo(() => {
    const known = sectors.map(s => ({ id: s.id, name: s.name, color: s.color }));
    const usedNames = new Set(items.map(i => i.sector).filter(Boolean));
    const ghosts = Array.from(usedNames).filter(n => !known.find(s => s.name === n)).map(name => ({ id: `ghost-${name}`, name, color: colors.textMute }));
    return [...known, ...ghosts];
  }, [sectors, items]);

  // Filtros de período
  const monthMatches = (iso, ym) => {
    if (!iso) return false;
    const d = new Date(iso);
    const targetY = parseInt(ym.split('-')[0], 10);
    const targetM = parseInt(ym.split('-')[1], 10) - 1;
    return d.getFullYear() === targetY && d.getMonth() === targetM;
  };

  const previousMonth = useMemo(() => {
    const [y, m] = month.split('-').map(Number);
    const d = new Date(y, m - 2, 1);
    return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
  }, [month]);

  // Calcula relatório completo de um setor para um mês
  const buildSectorReport = (sectorName, ym) => {
    const sectorItems = items.filter(i => i.sector === sectorName);
    const sectorMovements = movements.filter(m => m.sector === sectorName && monthMatches(m.createdAt, ym));

    const entradas = sectorMovements.filter(m => m.type === 'entrada');
    const saidas = sectorMovements.filter(m => m.type === 'saida');

    const moveCost = (m) => {
      let unit = (typeof m.unitCost === 'number' && m.unitCost > 0) ? m.unitCost : null;
      if (unit === null) { const it = items.find(i => i.id === m.itemId); unit = it ? (Number(it.unitCost) || 0) : 0; }
      return unit * (Number(m.quantity) || 0);
    };

    const custoSaidas = saidas.reduce((s, m) => s + moveCost(m), 0);
    const totalEntradas = entradas.reduce((s, m) => s + (Number(m.paidAmount) || moveCost(m)), 0);
    const saldoEstoque = sectorItems.reduce((s, i) => s + (Number(i.quantity) || 0) * (Number(i.unitCost) || 0), 0);

    // Demanda total no mês (clientes — global, não por setor, já que demanda é geral)
    const customers = (demand || [])
      .filter(d => monthMatches(d.date + 'T12:00:00', ym))
      .reduce((s, d) => s + (Number(d.customers) || 0), 0);

    const custoPorCabeca = customers > 0 ? custoSaidas / customers : 0;

    // Top 10 itens mais consumidos
    const itemSaidas = {};
    saidas.forEach(m => {
      const k = m.itemId || m.itemName;
      if (!itemSaidas[k]) itemSaidas[k] = { name: m.itemName, qty: 0, cost: 0, unit: '' };
      itemSaidas[k].qty += Number(m.quantity) || 0;
      itemSaidas[k].cost += moveCost(m);
      const it = items.find(i => i.id === m.itemId);
      if (it) itemSaidas[k].unit = it.unit;
    });
    const topConsumo = Object.values(itemSaidas).sort((a, b) => b.cost - a.cost).slice(0, 10);

    // Top 5 maiores entradas
    const topEntradas = entradas
      .map(m => ({ ...m, valor: Number(m.paidAmount) || moveCost(m) }))
      .sort((a, b) => b.valor - a.valor)
      .slice(0, 5);

    // Itens abaixo do mínimo
    const abaixoMinimo = sectorItems.filter(i => Number(i.quantity) <= Number(i.minStock) && Number(i.minStock) > 0);

    return {
      sectorName,
      sectorItems,
      entradas, saidas,
      custoSaidas, totalEntradas, saldoEstoque,
      customers, custoPorCabeca,
      topConsumo, topEntradas, abaixoMinimo,
    };
  };

  const sectorsToShow = selectedSector === 'todos' ? allSectors : allSectors.filter(s => s.name === selectedSector);

  const reports = useMemo(() => {
    return sectorsToShow.map(s => ({
      sector: s,
      current: buildSectorReport(s.name, month),
      previous: buildSectorReport(s.name, previousMonth),
    }));
  }, [sectorsToShow, month, previousMonth, items, movements, demand]);

  // Para exportação em PDF: imprime a página
  const exportPDF = () => {
    window.print();
  };

  const monthLabel = (() => {
    const [y, m] = month.split('-').map(Number);
    const monthNames = ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'];
    return `${monthNames[m - 1]}/${y}`;
  })();

  return (
    <div className="relatorio-area">
      {/* Filtros - não imprimem */}
      <div className="no-print" style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'flex-end', marginBottom: 20 }}>
        <div>
          <div style={{ fontSize: 11, color: colors.textSoft, marginBottom: 4, letterSpacing: 0.3, textTransform: 'uppercase', fontFamily: bodyFont }}>Mês de referência</div>
          <input type="month" value={month} onChange={e => setMonth(e.target.value)}
            style={{ padding: '8px 10px', border: `1px solid ${colors.border}`, borderRadius: 8, fontSize: 13, fontFamily: bodyFont }} />
        </div>
        <div>
          <div style={{ fontSize: 11, color: colors.textSoft, marginBottom: 4, letterSpacing: 0.3, textTransform: 'uppercase', fontFamily: bodyFont }}>Setor</div>
          <select value={selectedSector} onChange={e => setSelectedSector(e.target.value)}
            style={{ padding: '8px 10px', border: `1px solid ${colors.border}`, borderRadius: 8, fontSize: 13, fontFamily: bodyFont, backgroundColor: colors.surface, minWidth: 180 }}>
            <option value="todos">Todos os setores</option>
            {allSectors.map(s => <option key={s.id} value={s.name}>{s.name}</option>)}
          </select>
        </div>
        <Btn variant="primary" Icon={Icons.Printer} onClick={exportPDF}>Exportar / Imprimir</Btn>
      </div>

      {/* Cabeçalho do relatório (aparece também na impressão) */}
      <div style={{ marginBottom: 24, padding: 18, backgroundColor: colors.surface, borderRadius: 12, border: `1px solid ${colors.border}`, textAlign: 'center' }}>
        <div style={{ fontSize: 11, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.6, textTransform: 'uppercase' }}>{businessName}</div>
        <div style={{ fontFamily: displayFont, fontSize: 26, fontWeight: 700, color: colors.text, marginTop: 4 }}>Relatório de Fechamento Mensal</div>
        <div style={{ fontFamily: bodyFont, fontSize: 14, color: colors.textSoft, marginTop: 4 }}>{monthLabel}</div>
      </div>

      {reports.length === 0 ? (
        <Card><Empty Icon={Icons.Chart} title="Nenhum setor para mostrar" hint="Cadastre setores e itens para gerar relatórios." /></Card>
      ) : (
        reports.map(({ sector, current, previous }) => (
          <SectorReportBlock key={sector.id} sector={sector} current={current} previous={previous} />
        ))
      )}
    </div>
  );
}

function SectorReportBlock({ sector, current, previous }) {
  const pctChange = (cur, prev) => {
    if (!prev || prev === 0) return null;
    return ((cur - prev) / prev) * 100;
  };

  const custoChange = pctChange(current.custoSaidas, previous.custoSaidas);
  const customersChange = pctChange(current.customers, previous.customers);

  const changeBadge = (value, inverted = false) => {
    if (value === null) return null;
    const isUp = value > 0;
    const color = inverted
      ? (isUp ? colors.danger : colors.success)
      : (isUp ? colors.success : colors.danger);
    return (
      <span style={{ fontSize: 11, fontWeight: 600, color, marginLeft: 6 }}>
        {isUp ? '↑' : '↓'} {Math.abs(value).toFixed(1)}% vs mês anterior
      </span>
    );
  };

  return (
    <div style={{ marginBottom: 28, pageBreakInside: 'avoid' }}>
      {/* Cabeçalho do setor */}
      <div style={{
        padding: '14px 18px', backgroundColor: sector.color || colors.primary, color: '#fff',
        borderRadius: '12px 12px 0 0',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      }}>
        <div>
          <div style={{ fontSize: 11, opacity: 0.85, fontFamily: bodyFont, letterSpacing: 0.4, textTransform: 'uppercase' }}>Setor</div>
          <div style={{ fontFamily: displayFont, fontSize: 22, fontWeight: 700 }}>{sector.name}</div>
        </div>
        <div style={{ textAlign: 'right' }}>
          <div style={{ fontSize: 11, opacity: 0.85, fontFamily: bodyFont, letterSpacing: 0.4, textTransform: 'uppercase' }}>Itens</div>
          <div style={{ fontFamily: displayFont, fontSize: 22, fontWeight: 700 }}>{current.sectorItems.length}</div>
        </div>
      </div>

      {/* Cards de resumo */}
      <div style={{
        padding: 18, backgroundColor: colors.surface,
        border: `1px solid ${colors.border}`, borderTop: 'none',
      }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 12, marginBottom: 18 }}>
          <div style={{ padding: 14, backgroundColor: colors.surfaceAlt, borderRadius: 10, borderLeft: `3px solid ${colors.danger}` }}>
            <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.4, textTransform: 'uppercase' }}>Custo consumido</div>
            <div style={{ fontFamily: displayFont, fontSize: 22, fontWeight: 700, color: colors.text }}>{fmtBRL(current.custoSaidas)}</div>
            {changeBadge(custoChange, true)}
          </div>
          <div style={{ padding: 14, backgroundColor: colors.surfaceAlt, borderRadius: 10, borderLeft: `3px solid ${colors.success}` }}>
            <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.4, textTransform: 'uppercase' }}>Total de entradas</div>
            <div style={{ fontFamily: displayFont, fontSize: 22, fontWeight: 700, color: colors.text }}>{fmtBRL(current.totalEntradas)}</div>
            <div style={{ fontSize: 11, color: colors.textMute, fontFamily: bodyFont, marginTop: 2 }}>{current.entradas.length} compra{current.entradas.length === 1 ? '' : 's'}</div>
          </div>
          <div style={{ padding: 14, backgroundColor: colors.surfaceAlt, borderRadius: 10, borderLeft: `3px solid ${colors.primary}` }}>
            <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.4, textTransform: 'uppercase' }}>Saldo em estoque</div>
            <div style={{ fontFamily: displayFont, fontSize: 22, fontWeight: 700, color: colors.text }}>{fmtBRL(current.saldoEstoque)}</div>
            <div style={{ fontSize: 11, color: colors.textMute, fontFamily: bodyFont, marginTop: 2 }}>valor atual em prateleira</div>
          </div>
          {current.customers > 0 && (
            <div style={{ padding: 14, backgroundColor: colors.surfaceAlt, borderRadius: 10, borderLeft: `3px solid ${colors.accent}` }}>
              <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.4, textTransform: 'uppercase' }}>Custo por cabeça</div>
              <div style={{ fontFamily: displayFont, fontSize: 22, fontWeight: 700, color: colors.text }}>{fmtBRL(current.custoPorCabeca)}</div>
              <div style={{ fontSize: 11, color: colors.textMute, fontFamily: bodyFont, marginTop: 2 }}>
                {current.customers} cliente{current.customers === 1 ? '' : 's'}
                {customersChange !== null && changeBadge(customersChange)}
              </div>
            </div>
          )}
        </div>

        {/* Resumo de movimentações */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 12, marginBottom: 20, padding: 12, backgroundColor: colors.surfaceAlt, borderRadius: 8 }}>
          <div style={{ fontFamily: bodyFont, fontSize: 13, color: colors.text }}>
            <strong>Entradas:</strong> {current.entradas.length} movimentação{current.entradas.length === 1 ? '' : 'ões'} · <span style={{ color: colors.success, fontWeight: 600 }}>{fmtBRL(current.totalEntradas)}</span>
          </div>
          <div style={{ fontFamily: bodyFont, fontSize: 13, color: colors.text }}>
            <strong>Saídas:</strong> {current.saidas.length} movimentação{current.saidas.length === 1 ? '' : 'ões'} · <span style={{ color: colors.danger, fontWeight: 600 }}>{fmtBRL(current.custoSaidas)}</span>
          </div>
          {current.customers > 0 && (
            <div style={{ fontFamily: bodyFont, fontSize: 13, color: colors.text }}>
              <strong>Demanda:</strong> <span style={{ color: colors.primary, fontWeight: 600 }}>{current.customers}</span> cliente{current.customers === 1 ? '' : 's'} atendido{current.customers === 1 ? '' : 's'}
            </div>
          )}
        </div>

        {/* Top consumo + Top entradas */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: 16, marginBottom: 18 }}>
          {/* Top 10 mais consumidos */}
          <div>
            <h4 style={{ fontFamily: displayFont, fontSize: 15, fontWeight: 700, color: colors.text, margin: '0 0 8px' }}>Top 10 mais consumidos</h4>
            {current.topConsumo.length === 0 ? (
              <div style={{ padding: 12, backgroundColor: colors.surfaceAlt, borderRadius: 8, fontSize: 12, color: colors.textMute, fontFamily: bodyFont, fontStyle: 'italic' }}>Sem consumo no mês.</div>
            ) : (
              <div style={{ border: `1px solid ${colors.border}`, borderRadius: 8 }}>
                {current.topConsumo.map((it, i) => (
                  <div key={i} style={{ padding: '8px 12px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: i < current.topConsumo.length - 1 ? `1px solid ${colors.border}` : 'none', fontFamily: bodyFont, fontSize: 13 }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flex: 1 }}>
                      <span style={{ fontSize: 10, color: colors.textMute, fontWeight: 600, minWidth: 20 }}>{i + 1}.</span>
                      <span style={{ color: colors.text, fontWeight: 500 }}>{it.name}</span>
                    </div>
                    <div style={{ textAlign: 'right' }}>
                      <div style={{ color: colors.text, fontWeight: 600, fontFamily: displayFont }}>{fmtBRL(it.cost)}</div>
                      <div style={{ fontSize: 10, color: colors.textMute }}>{fmtNum(it.qty)} {it.unit}</div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>

          {/* Top 5 maiores entradas */}
          <div>
            <h4 style={{ fontFamily: displayFont, fontSize: 15, fontWeight: 700, color: colors.text, margin: '0 0 8px' }}>Top 5 maiores compras</h4>
            {current.topEntradas.length === 0 ? (
              <div style={{ padding: 12, backgroundColor: colors.surfaceAlt, borderRadius: 8, fontSize: 12, color: colors.textMute, fontFamily: bodyFont, fontStyle: 'italic' }}>Nenhuma compra no mês.</div>
            ) : (
              <div style={{ border: `1px solid ${colors.border}`, borderRadius: 8 }}>
                {current.topEntradas.map((e, i) => (
                  <div key={i} style={{ padding: '8px 12px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: i < current.topEntradas.length - 1 ? `1px solid ${colors.border}` : 'none', fontFamily: bodyFont, fontSize: 13 }}>
                    <div style={{ minWidth: 0, flex: 1 }}>
                      <div style={{ color: colors.text, fontWeight: 500 }}>{e.itemName}</div>
                      <div style={{ fontSize: 10, color: colors.textMute }}>{fmtDate(e.createdAt)} · {fmtNum(e.quantity)}</div>
                    </div>
                    <div style={{ fontFamily: displayFont, fontWeight: 600, color: colors.success }}>{fmtBRL(e.valor)}</div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* Itens a repor */}
        {current.abaixoMinimo.length > 0 && (
          <div>
            <h4 style={{ fontFamily: displayFont, fontSize: 15, fontWeight: 700, color: colors.danger, margin: '0 0 8px' }}>
              Itens abaixo do mínimo ({current.abaixoMinimo.length})
            </h4>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
              {current.abaixoMinimo.map(it => (
                <span key={it.id} style={{
                  padding: '4px 10px', borderRadius: 999,
                  backgroundColor: '#FBEDE8', border: `1px solid ${colors.danger}`,
                  fontFamily: bodyFont, fontSize: 12, color: colors.danger, fontWeight: 500,
                }}>
                  {it.name} · {fmtNum(it.quantity)}/{fmtNum(it.minStock)} {it.unit}
                </span>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// ============================================================
// CUSTOS (custo no período + custo por porção)
// ============================================================
function CustosView({ items, movements, recipes, setRecipes, sectors, demand, setDemand, currentUser }) {
  const [mode, setMode] = useState('periodo');
  return (
    <div>
      <div style={{ display: 'flex', gap: 6, marginBottom: 18 }}>
        <button onClick={() => setMode('periodo')} style={chipStyle(mode === 'periodo')}>Custo no período</button>
        <button onClick={() => setMode('porcao')} style={chipStyle(mode === 'porcao')}>Custo por porção</button>
      </div>
      {mode === 'periodo'
        ? <CustoPeriodo items={items} movements={movements} demand={demand} setDemand={setDemand} currentUser={currentUser} />
        : <CustoPorcao items={items} recipes={recipes} setRecipes={setRecipes} sectors={sectors} />}
    </div>
  );
}

// ---------- Opção A: custo do consumo no período ----------
function CustoPeriodo({ items, movements, demand, setDemand, currentUser }) {
  const [period, setPeriod] = useState('mes');
  const [customStart, setCustomStart] = useState(() => {
    const d = new Date(); d.setDate(d.getDate() - 7);
    return d.toISOString().slice(0, 10);
  });
  const [customEnd, setCustomEnd] = useState(() => new Date().toISOString().slice(0, 10));
  const [showDemandForm, setShowDemandForm] = useState(false);

  const range = useMemo(() => {
    if (period === 'hoje') return (iso) => isSameDay(iso);
    if (period === 'semana') { const start = new Date(); start.setDate(start.getDate() - 7); return (iso) => new Date(iso) >= start; }
    if (period === 'mes') return (iso) => isSameMonth(iso);
    if (period === 'custom') {
      const start = new Date(customStart + 'T00:00:00');
      const end = new Date(customEnd + 'T23:59:59');
      return (iso) => { const d = new Date(iso); return d >= start && d <= end; };
    }
    return () => true;
  }, [period, customStart, customEnd]);

  // custo de uma movimentação
  const moveCost = (m) => {
    let unit = (typeof m.unitCost === 'number' && m.unitCost > 0) ? m.unitCost : null;
    if (unit === null) { const it = items.find(i => i.id === m.itemId); unit = it ? (Number(it.unitCost) || 0) : 0; }
    return unit * (Number(m.quantity) || 0);
  };

  const consumo = useMemo(() => movements.filter(m => m.type === 'saida' && range(m.createdAt)), [movements, range]);
  const total = consumo.reduce((s, m) => s + moveCost(m), 0);

  // Demanda (clientes) no mesmo período
  const customersInPeriod = useMemo(() => {
    return (demand || []).filter(d => {
      const iso = d.date + 'T12:00:00';
      return range(iso);
    }).reduce((s, d) => s + (Number(d.customers) || 0), 0);
  }, [demand, range]);

  const costPerCustomer = customersInPeriod > 0 ? total / customersInPeriod : 0;

  const byItem = useMemo(() => {
    const map = {};
    consumo.forEach(m => {
      const key = m.itemId || m.itemName;
      if (!map[key]) map[key] = { name: m.itemName, sector: m.sector, qty: 0, cost: 0 };
      map[key].qty += Number(m.quantity) || 0;
      map[key].cost += moveCost(m);
    });
    return Object.values(map).sort((a, b) => b.cost - a.cost);
  }, [consumo, items]);

  const dateLabel = period === 'hoje' ? 'Hoje'
    : period === 'semana' ? 'Últimos 7 dias'
    : period === 'mes' ? 'Este mês'
    : `${customStart.split('-').reverse().join('/')} a ${customEnd.split('-').reverse().join('/')}`;
  const maxItemCost = Math.max(...byItem.map(i => i.cost), 1);

  return (
    <div>
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 16, alignItems: 'center' }}>
        {[
          { v: 'hoje', l: 'Hoje' },
          { v: 'semana', l: '7 dias' },
          { v: 'mes', l: 'Este mês' },
          { v: 'custom', l: 'Período específico' },
        ].map(p => (
          <button key={p.v} onClick={() => setPeriod(p.v)} style={chipStyle(period === p.v)}>{p.l}</button>
        ))}
        <Btn variant="outline" size="sm" Icon={Icons.User} onClick={() => setShowDemandForm(true)}>Lançar demanda</Btn>
      </div>

      {period === 'custom' && (
        <Card style={{ marginBottom: 16, padding: 14 }}>
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'flex-end' }}>
            <div>
              <div style={{ fontSize: 11, color: colors.textSoft, marginBottom: 4, letterSpacing: 0.3, textTransform: 'uppercase', fontFamily: bodyFont }}>De</div>
              <input type="date" value={customStart} onChange={e => setCustomStart(e.target.value)}
                style={{ padding: '8px 10px', border: `1px solid ${colors.border}`, borderRadius: 8, fontSize: 13, fontFamily: bodyFont }} />
            </div>
            <div>
              <div style={{ fontSize: 11, color: colors.textSoft, marginBottom: 4, letterSpacing: 0.3, textTransform: 'uppercase', fontFamily: bodyFont }}>Até</div>
              <input type="date" value={customEnd} onChange={e => setCustomEnd(e.target.value)}
                style={{ padding: '8px 10px', border: `1px solid ${colors.border}`, borderRadius: 8, fontSize: 13, fontFamily: bodyFont }} />
            </div>
          </div>
        </Card>
      )}

      <div style={{ display: 'grid', gridTemplateColumns: customersInPeriod > 0 ? 'repeat(auto-fit, minmax(280px, 1fr))' : '1fr', gap: 12, marginBottom: 16 }}>
        <Card style={{ background: `linear-gradient(135deg, ${colors.primary}, ${colors.primaryDark})`, border: 'none' }}>
          <div style={{ fontSize: 12, color: 'rgba(255,255,255,0.8)', fontFamily: bodyFont, letterSpacing: 0.4, textTransform: 'uppercase' }}>
            Custo consumido · {dateLabel}
          </div>
          <div style={{ fontFamily: displayFont, fontSize: 38, color: '#fff', fontWeight: 700, lineHeight: 1.1, marginTop: 4 }}>{fmtBRL(total)}</div>
          <div style={{ fontSize: 13, color: 'rgba(255,255,255,0.85)', fontFamily: bodyFont, marginTop: 4 }}>{consumo.length} movimentação{consumo.length === 1 ? '' : 'ões'} de saída</div>
        </Card>

        {customersInPeriod > 0 && (
          <Card style={{ background: `linear-gradient(135deg, #2C6E63, #1A4F45)`, border: 'none' }}>
            <div style={{ fontSize: 12, color: 'rgba(255,255,255,0.8)', fontFamily: bodyFont, letterSpacing: 0.4, textTransform: 'uppercase' }}>
              Custo por cabeça
            </div>
            <div style={{ fontFamily: displayFont, fontSize: 38, color: '#fff', fontWeight: 700, lineHeight: 1.1, marginTop: 4 }}>{fmtBRL(costPerCustomer)}</div>
            <div style={{ fontSize: 13, color: 'rgba(255,255,255,0.85)', fontFamily: bodyFont, marginTop: 4 }}>
              {customersInPeriod} cliente{customersInPeriod === 1 ? '' : 's'} atendido{customersInPeriod === 1 ? '' : 's'} no período
            </div>
          </Card>
        )}
      </div>

      {customersInPeriod === 0 && (consumo.length > 0) && (
        <Card style={{ marginBottom: 16, backgroundColor: '#FFF6E5', border: `1px solid ${colors.accent}` }}>
          <div style={{ fontFamily: bodyFont, fontSize: 13, color: colors.text, lineHeight: 1.5 }}>
            Nenhuma demanda registrada no período. Clique em <strong>"Lançar demanda"</strong> acima para informar quantos clientes foram atendidos e calcular o custo por cabeça.
          </div>
        </Card>
      )}

      {byItem.length === 0 ? (
        <Card><Empty Icon={Icons.Dollar} title="Sem consumo no período" hint="Registre saídas no Estoque para ver o custo aqui." /></Card>
      ) : (
        <Card>
          <h3 style={{ margin: '0 0 12px', fontFamily: displayFont, fontSize: 17, color: colors.text }}>Custo por item</h3>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {byItem.slice(0, 20).map((it, i) => (
              <div key={i}>
                <div style={{ display: 'flex', justifyContent: 'space-between', fontFamily: bodyFont, fontSize: 13, marginBottom: 4 }}>
                  <span style={{ color: colors.text }}>{it.name} <span style={{ color: colors.textMute }}>· {fmtNum(it.qty)}</span></span>
                  <span style={{ color: colors.textSoft, fontWeight: 600 }}>{fmtBRL(it.cost)}</span>
                </div>
                <div style={{ height: 8, backgroundColor: colors.surfaceAlt, borderRadius: 4, overflow: 'hidden' }}>
                  <div style={{ width: `${(it.cost / maxItemCost) * 100}%`, height: '100%', backgroundColor: colors.primary, borderRadius: 4 }} />
                </div>
              </div>
            ))}
          </div>
          <div style={{ marginTop: 12, padding: 12, backgroundColor: '#E9F1ED', borderRadius: 8, fontSize: 12, color: colors.textSoft, fontFamily: bodyFont }}>
            O custo usa o valor do item no momento de cada saída. Movimentações antigas usam o custo atual do item.
          </div>
        </Card>
      )}

      {showDemandForm && (
        <Modal open onClose={() => setShowDemandForm(false)} title="Lançar demanda (clientes atendidos)" width={460}>
          <DemandForm demand={demand} setDemand={setDemand} currentUser={currentUser} onClose={() => setShowDemandForm(false)} />
        </Modal>
      )}
    </div>
  );
}

function DemandForm({ demand, setDemand, currentUser, onClose }) {
  const [date, setDate] = useState(new Date().toISOString().slice(0, 10));
  const [customers, setCustomers] = useState('');
  const [notes, setNotes] = useState('');

  // Se já existir registro para a data selecionada, pré-preenche
  useEffect(() => {
    const existing = (demand || []).find(d => d.date === date);
    if (existing) {
      setCustomers(String(existing.customers || ''));
      setNotes(existing.notes || '');
    } else {
      setCustomers('');
      setNotes('');
    }
  }, [date, demand]);

  const save = () => {
    const n = parseInt(customers, 10);
    if (isNaN(n) || n < 0) { alert('Informe um número válido de clientes.'); return; }
    const existing = (demand || []).find(d => d.date === date);
    if (existing) {
      setDemand((demand || []).map(d => d.id === existing.id
        ? { ...d, customers: n, notes: notes.trim(), registeredBy: currentUser || '', updatedAt: new Date().toISOString() }
        : d));
    } else {
      setDemand([...(demand || []), {
        id: newId(), date, customers: n, notes: notes.trim(),
        registeredBy: currentUser || '',
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
      }]);
    }
    onClose();
  };

  // Lista os últimos 7 registros para contexto
  const recent = useMemo(() => {
    return [...(demand || [])].sort((a, b) => b.date.localeCompare(a.date)).slice(0, 7);
  }, [demand]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <p style={{ margin: 0, fontFamily: bodyFont, fontSize: 13, color: colors.textSoft }}>
        Registre quantos clientes foram atendidos no dia. Esse número é usado para calcular o <strong>custo por cabeça</strong> no relatório de Custos.
      </p>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <div>
          <div style={{ fontSize: 11, color: colors.textSoft, marginBottom: 4, letterSpacing: 0.3, textTransform: 'uppercase', fontFamily: bodyFont }}>Data</div>
          <input type="date" value={date} onChange={e => setDate(e.target.value)} max={new Date().toISOString().slice(0, 10)}
            style={{ width: '100%', padding: '8px 10px', border: `1px solid ${colors.border}`, borderRadius: 8, fontSize: 13, fontFamily: bodyFont }} />
        </div>
        <Input label="Clientes atendidos" value={customers} onChange={setCustomers} type="number" min="0" placeholder="Ex: 32" />
      </div>

      <Input label="Observação (opcional)" value={notes} onChange={setNotes} placeholder="Ex: feriado, evento, dia chuvoso" />

      {recent.length > 0 && (
        <div style={{ marginTop: 4 }}>
          <div style={{ fontSize: 11, color: colors.textSoft, marginBottom: 6, letterSpacing: 0.3, textTransform: 'uppercase', fontFamily: bodyFont }}>Últimos registros</div>
          <div style={{ border: `1px solid ${colors.border}`, borderRadius: 8, maxHeight: 180, overflowY: 'auto' }}>
            {recent.map(d => (
              <div key={d.id} style={{ padding: '8px 12px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: `1px solid ${colors.border}`, fontFamily: bodyFont, fontSize: 13 }}>
                <div>
                  <div style={{ color: colors.text, fontWeight: 500 }}>{d.date.split('-').reverse().join('/')}</div>
                  {d.notes && <div style={{ fontSize: 11, color: colors.textMute }}>{d.notes}</div>}
                </div>
                <div style={{ fontFamily: displayFont, fontSize: 15, fontWeight: 600, color: colors.text }}>{d.customers}</div>
              </div>
            ))}
          </div>
        </div>
      )}

      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onClose}>Cancelar</Btn>
        <Btn variant="primary" onClick={save} disabled={!customers}>Salvar</Btn>
      </div>
    </div>
  );
}

// ---------- Opção B: custo por porção (ficha) ----------
function CustoPorcao({ items, recipes, setRecipes, sectors }) {
  const [editing, setEditing] = useState(null);
  const blank = { id: '', name: '', sector: sectors.find(s => s.name === 'Café da manhã') ? 'Café da manhã' : (sectors[0]?.name || 'Geral'), servings: 1, items: [] };

  const recipeCost = (recipe) => {
    const total = (recipe.items || []).reduce((s, r) => {
      const it = items.find(i => i.id === r.itemId);
      return s + (it ? (Number(it.unitCost) || 0) * (Number(r.quantity) || 0) : 0);
    }, 0);
    const servings = Number(recipe.servings) || 1;
    return { total, perServing: total / servings };
  };

  const save = (recipe) => {
    if (!recipe.name.trim()) return;
    const data = { ...recipe, servings: parseFloat(recipe.servings) || 1 };
    if (data.id && recipes.find(r => r.id === data.id)) setRecipes(recipes.map(r => r.id === data.id ? data : r));
    else setRecipes([...recipes, { ...data, id: newId(), createdAt: new Date().toISOString() }]);
    setEditing(null);
  };
  const remove = (id) => { if (window.confirm('Remover esta ficha?')) setRecipes(recipes.filter(r => r.id !== id)); };

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
        <p style={{ margin: 0, fontFamily: bodyFont, color: colors.textSoft, fontSize: 14 }}>
          Monte o que compõe uma porção (ex: 1 café da manhã) e veja o custo por pessoa.
        </p>
        <Btn variant="primary" Icon={Icons.Plus} onClick={() => setEditing(blank)} disabled={items.length === 0}>Nova ficha</Btn>
      </div>

      {items.length === 0 ? (
        <Card><Empty Icon={Icons.Calc} title="Cadastre itens primeiro" hint="Você precisa ter itens no Estoque (com custo) para montar uma ficha." /></Card>
      ) : recipes.length === 0 ? (
        <Card><Empty Icon={Icons.Calc} title="Nenhuma ficha criada" hint="Crie a ficha do café da manhã para calcular o custo por pessoa." /></Card>
      ) : (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 14 }}>
          {recipes.map(recipe => {
            const { total, perServing } = recipeCost(recipe);
            return (
              <Card key={recipe.id} style={{ borderLeft: `4px solid ${sectorColor(sectors, recipe.sector)}` }}>
                <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 8 }}>
                  <div>
                    <div style={{ fontFamily: displayFont, fontSize: 18, color: colors.text, fontWeight: 600 }}>{recipe.name}</div>
                    <div style={{ fontSize: 12, color: colors.textSoft, fontFamily: bodyFont }}>{recipe.sector} · rende {fmtNum(recipe.servings)} porç{Number(recipe.servings) === 1 ? 'ão' : 'ões'}</div>
                  </div>
                  <div style={{ display: 'flex', gap: 4 }}>
                    <button onClick={() => setEditing(recipe)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textSoft, padding: 6 }}><Icons.Edit size={16} /></button>
                    <button onClick={() => remove(recipe.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 6 }}><Icons.Trash size={16} /></button>
                  </div>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4, marginBottom: 12 }}>
                  {(recipe.items || []).map((r, i) => {
                    const it = items.find(x => x.id === r.itemId);
                    return (
                      <div key={i} style={{ display: 'flex', justifyContent: 'space-between', fontFamily: bodyFont, fontSize: 13, color: colors.textSoft }}>
                        <span>{it ? it.name : '(item removido)'} <span style={{ color: colors.textMute }}>{fmtNum(r.quantity)} {it?.unit || ''}</span></span>
                        <span>{it ? fmtBRL((Number(it.unitCost) || 0) * (Number(r.quantity) || 0)) : '—'}</span>
                      </div>
                    );
                  })}
                </div>
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, paddingTop: 12, borderTop: `1px dashed ${colors.borderDark}` }}>
                  <div>
                    <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Custo total</div>
                    <div style={{ fontFamily: displayFont, fontSize: 17, fontWeight: 600, color: colors.text }}>{fmtBRL(total)}</div>
                  </div>
                  <div>
                    <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Por porção</div>
                    <div style={{ fontFamily: displayFont, fontSize: 17, fontWeight: 600, color: colors.primary }}>{fmtBRL(perServing)}</div>
                  </div>
                </div>
              </Card>
            );
          })}
        </div>
      )}

      {editing && (
        <Modal open onClose={() => setEditing(null)} title={editing.id ? 'Editar ficha' : 'Nova ficha de porção'} width={560}>
          <RecipeForm initial={editing} items={items} sectors={sectors} onSave={save} onCancel={() => setEditing(null)} />
        </Modal>
      )}
    </div>
  );
}

function RecipeForm({ initial, items, sectors, onSave, onCancel }) {
  const [r, setR] = useState({ ...initial, items: initial.items || [] });

  const addIngredient = () => {
    const avail = items.filter(i => !r.items.find(x => x.itemId === i.id));
    if (avail.length === 0) { alert('Todos os itens já foram adicionados.'); return; }
    setR({ ...r, items: [...r.items, { itemId: avail[0].id, quantity: 1 }] });
  };
  const updateIng = (idx, patch) => { const next = [...r.items]; next[idx] = { ...next[idx], ...patch }; setR({ ...r, items: next }); };
  const removeIng = (idx) => setR({ ...r, items: r.items.filter((_, i) => i !== idx) });

  const total = r.items.reduce((s, ing) => {
    const it = items.find(i => i.id === ing.itemId);
    return s + (it ? (Number(it.unitCost) || 0) * (Number(ing.quantity) || 0) : 0);
  }, 0);
  const perServing = total / (parseFloat(r.servings) || 1);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <Input label="Nome da ficha" value={r.name} onChange={v => setR({ ...r, name: v })} placeholder="Ex: Café da manhã padrão" />
      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 12 }}>
        <Select label="Setor" value={r.sector} onChange={v => setR({ ...r, sector: v })} options={sectors.map(s => ({ value: s.name, label: s.name }))} />
        <Input label="Rende quantas porções" value={r.servings} onChange={v => setR({ ...r, servings: v })} type="number" step="1" min="1" />
      </div>

      <div style={{ padding: 14, backgroundColor: colors.surfaceAlt, borderRadius: 10, border: `1px solid ${colors.border}` }}>
        <div style={{ fontFamily: displayFont, fontSize: 15, fontWeight: 600, color: colors.text, marginBottom: 8 }}>Itens da porção</div>
        {r.items.length === 0 ? (
          <div style={{ padding: '8px 0', fontSize: 13, color: colors.textMute, fontFamily: bodyFont, fontStyle: 'italic' }}>Nenhum item adicionado ainda.</div>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {r.items.map((ing, idx) => {
              const it = items.find(i => i.id === ing.itemId);
              const lineCost = it ? (Number(it.unitCost) || 0) * (Number(ing.quantity) || 0) : 0;
              return (
                <div key={idx} style={{ display: 'flex', alignItems: 'center', gap: 6, backgroundColor: colors.surface, padding: 8, borderRadius: 8, border: `1px solid ${colors.border}` }}>
                  <select value={ing.itemId} onChange={e => updateIng(idx, { itemId: e.target.value })} style={{ flex: 2, padding: '6px 8px', border: `1px solid ${colors.border}`, borderRadius: 6, fontSize: 13, fontFamily: bodyFont, backgroundColor: colors.surface }}>
                    {items.map(i => <option key={i.id} value={i.id}>{i.name}</option>)}
                  </select>
                  <input type="number" step="0.001" min="0" value={ing.quantity} onChange={e => updateIng(idx, { quantity: e.target.value })}
                    style={{ width: 70, padding: '6px 8px', border: `1px solid ${colors.border}`, borderRadius: 6, fontSize: 13, fontFamily: bodyFont, textAlign: 'right' }} />
                  <span style={{ fontSize: 12, color: colors.textSoft, fontFamily: bodyFont, minWidth: 24 }}>{it?.unit || ''}</span>
                  <span style={{ fontSize: 12, color: colors.textMute, fontFamily: bodyFont, minWidth: 56, textAlign: 'right' }}>{fmtBRL(lineCost)}</span>
                  <button onClick={() => removeIng(idx)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 4 }}><Icons.Trash size={14} /></button>
                </div>
              );
            })}
          </div>
        )}
        <button onClick={addIngredient} style={{ marginTop: 8, padding: '6px 12px', backgroundColor: 'transparent', border: `1px dashed ${colors.borderDark}`, borderRadius: 6, cursor: 'pointer', color: colors.text, fontSize: 13, fontFamily: bodyFont, display: 'inline-flex', alignItems: 'center', gap: 4 }}>
          <Icons.Plus size={13} /> Adicionar item
        </button>
        {r.items.length > 0 && (
          <div style={{ marginTop: 12, paddingTop: 10, borderTop: `1px dashed ${colors.borderDark}`, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <div>
              <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Custo total</div>
              <div style={{ fontFamily: displayFont, fontSize: 16, fontWeight: 600, color: colors.text }}>{fmtBRL(total)}</div>
            </div>
            <div>
              <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Por porção</div>
              <div style={{ fontFamily: displayFont, fontSize: 16, fontWeight: 600, color: colors.primary }}>{fmtBRL(perServing)}</div>
            </div>
          </div>
        )}
      </div>

      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={() => onSave(r)} disabled={!r.name.trim()}>Salvar</Btn>
      </div>
    </div>
  );
}

// ============================================================
// TELA DE LOGIN
// ============================================================
function LoginScreen({ businessName }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const submit = async () => {
    if (!email.trim() || !password) { setError('Preencha e-mail e senha.'); return; }
    setLoading(true); setError('');
    try {
      const { error } = await sb.auth.signInWithPassword({ email: email.trim(), password });
      if (error) {
        if (error.message.toLowerCase().includes('invalid')) setError('E-mail ou senha incorretos.');
        else setError(error.message);
      }
    } catch (e) { setError('Erro ao conectar. Verifique a internet.'); }
    finally { setLoading(false); }
  };

  return (
    <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20, backgroundColor: colors.bg }}>
      <div style={{ width: '100%', maxWidth: 380 }}>
        <div style={{ textAlign: 'center', marginBottom: 28 }}>
          <div style={{ width: 64, height: 64, borderRadius: 16, backgroundColor: colors.primary, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', marginBottom: 16 }}>
            <Icons.Box size={32} color="#fff" />
          </div>
          <h1 style={{ fontFamily: displayFont, fontSize: 26, fontWeight: 700, color: colors.text, margin: '0 0 4px' }}>{businessName}</h1>
          <p style={{ fontFamily: bodyFont, fontSize: 14, color: colors.textSoft, margin: 0 }}>Faça login para continuar</p>
        </div>
        <Card>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <Input label="E-mail" value={email} onChange={setEmail} type="email" placeholder="seu@email.com" />
            <label style={{ display: 'block', fontFamily: bodyFont }}>
              <div style={{ fontSize: 12, fontWeight: 500, color: colors.textSoft, marginBottom: 4, letterSpacing: 0.3, textTransform: 'uppercase' }}>Senha</div>
              <input type="password" value={password} onChange={e => setPassword(e.target.value)}
                onKeyDown={e => { if (e.key === 'Enter') submit(); }}
                placeholder="••••••••"
                style={{ width: '100%', padding: '9px 12px', border: `1px solid ${colors.border}`, borderRadius: 8, backgroundColor: colors.surface, color: colors.text, fontSize: 14, fontFamily: bodyFont, outline: 'none' }} />
            </label>
            {error && (
              <div style={{ padding: '10px 12px', backgroundColor: '#FBEDE8', border: `1px solid ${colors.danger}`, borderRadius: 8, fontSize: 13, color: colors.danger, fontFamily: bodyFont }}>{error}</div>
            )}
            <Btn variant="primary" full size="lg" onClick={submit} disabled={loading}>
              {loading ? 'Entrando...' : 'Entrar'}
            </Btn>
          </div>
        </Card>
        <p style={{ textAlign: 'center', fontFamily: bodyFont, fontSize: 12, color: colors.textMute, marginTop: 16 }}>
          Não tem acesso? Peça ao administrador para criar seu usuário.
        </p>
      </div>
    </div>
  );
}

// ============================================================
// USUÁRIOS (visível só para admin)
// ============================================================
function UsuariosView({ profile }) {
  const [profiles, setProfiles] = useState([]);
  const [loading, setLoading] = useState(true);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const { data } = await sb.from('profiles').select('*').order('created_at');
      setProfiles((data || []).map(toCamel));
    } catch {}
    finally { setLoading(false); }
  }, []);

  useEffect(() => { load(); }, [load]);

  const changeRole = async (id, role) => {
    try {
      const { data, error } = await sb.from('profiles').update({ role }).eq('id', id).select();
      if (error) throw error;
      if (!data || data.length === 0) {
        alert('Não foi possível alterar. Verifique se você é admin e se rodou a migração database-fix-admin.sql no Supabase.');
        return;
      }
      setProfiles(profiles.map(p => p.id === id ? { ...p, role } : p));
    } catch (e) { alert('Não foi possível alterar: ' + (e.message || e)); }
  };

  return (
    <div>
      <Card style={{ marginBottom: 16, backgroundColor: '#E9F1ED', border: `1px solid ${colors.primary}` }}>
        <div style={{ fontFamily: bodyFont, fontSize: 14, color: colors.text, lineHeight: 1.6 }}>
          <strong>Como criar um novo usuário:</strong><br />
          1. Abra o Supabase → menu <strong>Authentication</strong> → <strong>Users</strong> → <strong>Add user</strong><br />
          2. Digite um e-mail (pode ser interno, ex: <code>copa@niro.com</code>) e uma senha<br />
          3. O usuário aparece aqui automaticamente como <strong>Operador</strong><br />
          4. Se quiser, mude o perfil dele para Admin no botão ao lado
        </div>
      </Card>

      {loading ? (
        <Card><div style={{ textAlign: 'center', padding: 30, color: colors.textMute, fontFamily: bodyFont }}>Carregando usuários...</div></Card>
      ) : profiles.length === 0 ? (
        <Card><Empty Icon={Icons.User} title="Nenhum usuário ainda" hint="Crie usuários pelo painel do Supabase (veja as instruções acima)." /></Card>
      ) : (
        <Card style={{ padding: 0 }}>
          {profiles.map(p => (
            <div key={p.id} style={{ padding: '14px 18px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: `1px solid ${colors.border}`, gap: 12 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                <div style={{ width: 38, height: 38, borderRadius: 999, backgroundColor: p.role === 'admin' ? `${colors.primary}20` : colors.surfaceAlt, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  <Icons.User size={18} color={p.role === 'admin' ? colors.primary : colors.textSoft} />
                </div>
                <div>
                  <div style={{ fontFamily: bodyFont, fontSize: 14, color: colors.text, fontWeight: 500 }}>
                    {p.name || 'Sem nome'} {p.id === profile.id && <span style={{ color: colors.textMute, fontWeight: 400, fontSize: 12 }}>(você)</span>}
                  </div>
                  <div style={{ fontFamily: bodyFont, fontSize: 12, color: colors.textMute }}>{p.role === 'admin' ? 'Administrador' : 'Operador'}</div>
                </div>
              </div>
              {p.id !== profile.id && (
                <select value={p.role} onChange={e => changeRole(p.id, e.target.value)}
                  style={{ padding: '6px 10px', border: `1px solid ${colors.border}`, borderRadius: 8, fontSize: 13, fontFamily: bodyFont, backgroundColor: colors.surface, cursor: 'pointer' }}>
                  <option value="operador">Operador</option>
                  <option value="admin">Administrador</option>
                </select>
              )}
            </div>
          ))}
        </Card>
      )}
    </div>
  );
}

// ============================================================
// ATIVIDADE (histórico por usuário - últimos 40 dias)
// ============================================================
function AtividadeView({ movements, sectors }) {
  const [filterUser, setFilterUser] = useState('todos');
  const [filterType, setFilterType] = useState('todos');
  const [filterSector, setFilterSector] = useState('todos');
  const RETENTION_DAYS = 40;

  // Filtra movimentações dos últimos 40 dias
  const recent = useMemo(() => {
    const cutoff = new Date();
    cutoff.setDate(cutoff.getDate() - RETENTION_DAYS);
    return movements.filter(m => new Date(m.createdAt) >= cutoff);
  }, [movements]);

  // Lista única de usuários que registraram movimentações
  const users = useMemo(() => {
    const set = new Set();
    recent.forEach(m => { if (m.registeredBy) set.add(m.registeredBy); });
    return Array.from(set).sort();
  }, [recent]);

  // Aplica filtros
  const filtered = useMemo(() => {
    let list = recent.slice().sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
    if (filterUser !== 'todos') list = list.filter(m => (m.registeredBy || '(sem usuário)') === filterUser);
    if (filterType !== 'todos') list = list.filter(m => m.type === filterType);
    if (filterSector !== 'todos') list = list.filter(m => m.sector === filterSector);
    return list;
  }, [recent, filterUser, filterType, filterSector]);

  // Estatísticas por usuário
  const stats = useMemo(() => {
    const map = {};
    recent.forEach(m => {
      const u = m.registeredBy || '(sem usuário)';
      if (!map[u]) map[u] = { user: u, total: 0, entradas: 0, saidas: 0, qtdEntradas: 0, qtdSaidas: 0 };
      map[u].total++;
      if (m.type === 'entrada') { map[u].entradas++; map[u].qtdEntradas += Number(m.quantity) || 0; }
      else { map[u].saidas++; map[u].qtdSaidas += Number(m.quantity) || 0; }
    });
    return Object.values(map).sort((a, b) => b.total - a.total);
  }, [recent]);

  return (
    <div>
      <Card style={{ marginBottom: 16, backgroundColor: '#E9F1ED', border: `1px solid ${colors.primary}` }}>
        <div style={{ fontFamily: bodyFont, fontSize: 13, color: colors.text, lineHeight: 1.5 }}>
          <strong>Histórico de movimentações</strong> dos últimos {RETENTION_DAYS} dias — quem fez o quê no estoque.
          {recent.length === 0 && ' Ainda não há movimentações no período.'}
        </div>
      </Card>

      {stats.length > 0 && (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: 12, marginBottom: 18 }}>
          {stats.map(s => (
            <Card key={s.user} style={{ padding: 16 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
                <div style={{ width: 36, height: 36, borderRadius: 999, backgroundColor: `${colors.primary}15`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  <Icons.User size={16} color={colors.primary} />
                </div>
                <div>
                  <div style={{ fontFamily: bodyFont, fontSize: 14, color: colors.text, fontWeight: 600 }}>{s.user}</div>
                  <div style={{ fontFamily: bodyFont, fontSize: 11, color: colors.textMute }}>{s.total} movimentação{s.total === 1 ? '' : 'ões'}</div>
                </div>
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, paddingTop: 10, borderTop: `1px dashed ${colors.borderDark}` }}>
                <div>
                  <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Entradas</div>
                  <div style={{ fontFamily: displayFont, fontSize: 16, fontWeight: 600, color: colors.success }}>{s.entradas}</div>
                </div>
                <div>
                  <div style={{ fontSize: 10, color: colors.textSoft, fontFamily: bodyFont, letterSpacing: 0.3, textTransform: 'uppercase' }}>Saídas</div>
                  <div style={{ fontFamily: displayFont, fontSize: 16, fontWeight: 600, color: colors.danger }}>{s.saidas}</div>
                </div>
              </div>
            </Card>
          ))}
        </div>
      )}

      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 16, alignItems: 'center' }}>
        <button onClick={() => setFilterUser('todos')} style={chipStyle(filterUser === 'todos')}>Todos usuários</button>
        {users.map(u => <button key={u} onClick={() => setFilterUser(u)} style={chipStyle(filterUser === u)}>{u}</button>)}
        <div style={{ width: 1, height: 24, backgroundColor: colors.border, margin: '0 4px' }} />
        <button onClick={() => setFilterType('todos')} style={chipStyle(filterType === 'todos')}>Tudo</button>
        <button onClick={() => setFilterType('entrada')} style={chipStyle(filterType === 'entrada', colors.success)}>Entradas</button>
        <button onClick={() => setFilterType('saida')} style={chipStyle(filterType === 'saida', colors.danger)}>Saídas</button>
        <div style={{ width: 1, height: 24, backgroundColor: colors.border, margin: '0 4px' }} />
        <button onClick={() => setFilterSector('todos')} style={chipStyle(filterSector === 'todos')}>Todos setores</button>
        {sectors.map(s => <button key={s.id} onClick={() => setFilterSector(s.name)} style={chipStyle(filterSector === s.name, s.color)}>{s.name}</button>)}
      </div>

      {filtered.length === 0 ? (
        <Card><Empty Icon={Icons.Consumo} title="Nenhuma atividade" hint="Movimentações filtradas vão aparecer aqui." /></Card>
      ) : (
        <Card style={{ padding: 0 }}>
          {filtered.map(m => (
            <div key={m.id} style={{ padding: '12px 18px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: `1px solid ${colors.border}`, gap: 12 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, flex: 1, minWidth: 0 }}>
                <div style={{ width: 32, height: 32, borderRadius: 8, backgroundColor: m.type === 'entrada' ? `${colors.success}15` : `${colors.danger}15`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  {m.type === 'entrada' ? <Icons.ArrowUp size={16} color={colors.success} /> : <Icons.ArrowDown size={16} color={colors.danger} />}
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontFamily: bodyFont, fontSize: 14, color: colors.text, fontWeight: 500 }}>
                    {m.itemName}
                    <span style={{ color: colors.textMute, fontWeight: 400, marginLeft: 6 }}>· {m.sector}</span>
                  </div>
                  <div style={{ fontFamily: bodyFont, fontSize: 12, color: colors.textMute }}>
                    {fmtDate(m.createdAt)} {fmtTime(m.createdAt)}
                    {m.registeredBy ? ` · ${m.registeredBy}` : ' · sem usuário'}
                    {m.notes ? ` · "${m.notes}"` : ''}
                  </div>
                </div>
              </div>
              <div style={{ fontFamily: displayFont, fontSize: 16, fontWeight: 600, color: m.type === 'entrada' ? colors.success : colors.danger }}>
                {m.type === 'entrada' ? '+' : '−'} {fmtNum(m.quantity)}
              </div>
            </div>
          ))}
        </Card>
      )}
    </div>
  );
}

// ============================================================
// CATEGORIAS (gerenciamento - só admin)
// ============================================================
function CategoriasView({ categoriesData, setCategoriesData, items, setItems }) {
  const [editing, setEditing] = useState(null);
  const blank = { id: '', name: '', position: 0 };

  const ordered = useMemo(() => {
    return [...categoriesData].sort((a, b) => (a.position || 0) - (b.position || 0));
  }, [categoriesData]);

  // Quantos itens cada categoria tem
  const counts = useMemo(() => {
    const map = {};
    items.forEach(i => { const c = i.category || 'Outros'; map[c] = (map[c] || 0) + 1; });
    return map;
  }, [items]);

  const save = (cat) => {
    if (!cat.name.trim()) return;
    const newName = cat.name.trim();

    // Edição: se mudou o nome, atualizar itens vinculados
    if (cat.id && categoriesData.find(c => c.id === cat.id)) {
      const old = categoriesData.find(c => c.id === cat.id);
      const oldName = old.name;
      // Verifica conflito de nome com outra categoria
      if (newName !== oldName && categoriesData.find(c => c.id !== cat.id && c.name === newName)) {
        alert('Já existe uma categoria com esse nome.');
        return;
      }
      const updated = { ...cat, name: newName, position: parseInt(cat.position) || 0 };
      setCategoriesData(categoriesData.map(c => c.id === cat.id ? updated : c));
      // Atualiza todos os itens que tinham o nome antigo
      if (newName !== oldName) {
        const itemsToUpdate = items.filter(i => (i.category || '') === oldName);
        if (itemsToUpdate.length > 0) {
          setItems(items.map(i => (i.category || '') === oldName ? { ...i, category: newName } : i));
        }
      }
    } else {
      // Criação: verifica duplicação
      if (categoriesData.find(c => c.name === newName)) {
        alert('Já existe uma categoria com esse nome.');
        return;
      }
      const maxPos = Math.max(0, ...categoriesData.map(c => c.position || 0));
      const newCat = { ...cat, id: newId(), name: newName, position: parseInt(cat.position) || (maxPos + 10), createdAt: new Date().toISOString() };
      setCategoriesData([...categoriesData, newCat]);
    }
    setEditing(null);
  };

  const remove = (cat) => {
    const count = counts[cat.name] || 0;
    if (count > 0) {
      alert(`Não dá para remover "${cat.name}": existem ${count} item${count === 1 ? '' : 's'} usando essa categoria. Mude esses itens para outra categoria antes.`);
      return;
    }
    if (window.confirm(`Remover a categoria "${cat.name}"?`)) {
      setCategoriesData(categoriesData.filter(c => c.id !== cat.id));
    }
  };

  const move = (cat, direction) => {
    // direction: -1 sobe (posição menor), +1 desce (posição maior)
    const idx = ordered.findIndex(c => c.id === cat.id);
    const swap = direction === -1 ? idx - 1 : idx + 1;
    if (swap < 0 || swap >= ordered.length) return;
    const other = ordered[swap];
    setCategoriesData(categoriesData.map(c => {
      if (c.id === cat.id) return { ...c, position: other.position };
      if (c.id === other.id) return { ...c, position: cat.position };
      return c;
    }));
  };

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16, flexWrap: 'wrap', gap: 12 }}>
        <p style={{ margin: 0, fontFamily: bodyFont, color: colors.textSoft, fontSize: 14 }}>
          Crie, renomeie e reordene as categorias. Mudanças refletem em todos os itens.
        </p>
        <Btn variant="primary" Icon={Icons.Plus} onClick={() => setEditing(blank)}>Nova categoria</Btn>
      </div>

      {ordered.length === 0 ? (
        <Card><Empty Icon={Icons.Tag} title="Nenhuma categoria" hint="Crie sua primeira categoria pelo botão acima." /></Card>
      ) : (
        <Card style={{ padding: 0 }}>
          {ordered.map((cat, idx) => {
            const count = counts[cat.name] || 0;
            return (
              <div key={cat.id} style={{ padding: '12px 18px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: `1px solid ${colors.border}`, gap: 12 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 12, flex: 1, minWidth: 0 }}>
                  <div style={{ width: 32, height: 32, borderRadius: 8, backgroundColor: `${colors.primary}15`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                    <Icons.Tag size={16} color={colors.primary} />
                  </div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontFamily: bodyFont, fontSize: 14, color: colors.text, fontWeight: 500 }}>{cat.name}</div>
                    <div style={{ fontFamily: bodyFont, fontSize: 12, color: colors.textMute }}>
                      {count} item{count === 1 ? '' : 's'}
                    </div>
                  </div>
                </div>
                <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
                  <button onClick={() => move(cat, -1)} disabled={idx === 0}
                    title="Mover para cima"
                    style={{ background: 'none', border: 'none', cursor: idx === 0 ? 'not-allowed' : 'pointer', color: idx === 0 ? colors.borderDark : colors.textSoft, padding: 6, opacity: idx === 0 ? 0.4 : 1 }}>↑</button>
                  <button onClick={() => move(cat, +1)} disabled={idx === ordered.length - 1}
                    title="Mover para baixo"
                    style={{ background: 'none', border: 'none', cursor: idx === ordered.length - 1 ? 'not-allowed' : 'pointer', color: idx === ordered.length - 1 ? colors.borderDark : colors.textSoft, padding: 6, opacity: idx === ordered.length - 1 ? 0.4 : 1 }}>↓</button>
                  <button onClick={() => setEditing(cat)} title="Renomear" style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textSoft, padding: 6 }}><Icons.Edit size={16} /></button>
                  <button onClick={() => remove(cat)} title="Apagar" style={{ background: 'none', border: 'none', cursor: 'pointer', color: colors.textMute, padding: 6 }}><Icons.Trash size={16} /></button>
                </div>
              </div>
            );
          })}
        </Card>
      )}

      {editing && (
        <Modal open onClose={() => setEditing(null)} title={editing.id ? 'Renomear categoria' : 'Nova categoria'} width={400}>
          <CategoryForm initial={editing} onSave={save} onCancel={() => setEditing(null)} />
        </Modal>
      )}
    </div>
  );
}

function CategoryForm({ initial, onSave, onCancel }) {
  const [cat, setCat] = useState(initial);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <Input label="Nome da categoria" value={cat.name} onChange={v => setCat({ ...cat, name: v })} placeholder="Ex: Cafés especiais, Lanches frios" />
      {cat.id && (
        <div style={{ padding: 10, backgroundColor: colors.surfaceAlt, borderRadius: 8, fontSize: 12, color: colors.textSoft, fontFamily: bodyFont, lineHeight: 1.5 }}>
          Se você mudar o nome, todos os itens dessa categoria serão atualizados automaticamente.
        </div>
      )}
      <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
        <Btn variant="ghost" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" onClick={() => onSave(cat)} disabled={!cat.name.trim()}>Salvar</Btn>
      </div>
    </div>
  );
}

// ============================================================
// APP RAIZ
// ============================================================
function App() {
  const { session, profile } = useAuth();
  const [tab, setTab] = useState('dashboard');
  const [sectors, setSectors, scReady] = useTable('sectors');
  const [items, setItems, iReady] = useTable('items');
  const [movements, setMovements, mReady] = useTable('movements');
  const [shopping, setShopping, shReady] = useTable('shopping');
  const [recipes, setRecipes, rReady] = useTable('recipes');
  const [categoriesData, setCategoriesData, catReady] = useTable('categories');
  const [demand, setDemand, dReady] = useTable('demand');
  const sync = useSyncState();
  const ready = scReady && iReady && mReady && shReady && rReady && catReady && dReady;
  const businessName = window.CONFIG.NOME_NEGOCIO || 'Niro Estoque';

  const isAdmin = profile && profile.role === 'admin';
  const currentUser = profile ? (profile.name || '') : '';

  const logout = async () => { await sb.auth.signOut(); };

  // Abas conforme o perfil: operador não vê Custos, Relatórios nem Usuários
  const allTabs = [
    { id: 'dashboard', label: 'Painel', Icon: Icons.Dashboard, adminOnly: false },
    { id: 'estoque', label: 'Estoque', Icon: Icons.Box, adminOnly: false },
    { id: 'compras', label: 'Compras', Icon: Icons.Cart, adminOnly: false },
    { id: 'consumo', label: 'Consumo', Icon: Icons.Consumo, adminOnly: false },
    { id: 'custos', label: 'Custos', Icon: Icons.Dollar, adminOnly: true },
    { id: 'relatorios', label: 'Relatórios', Icon: Icons.Chart, adminOnly: true },
    { id: 'atividade', label: 'Atividade', Icon: Icons.Consumo, adminOnly: true },
    { id: 'usuarios', label: 'Usuários', Icon: Icons.User, adminOnly: true },
  ];
  const tabs = allTabs.filter(t => isAdmin || !t.adminOnly);

  // Se o operador estiver numa aba que não pode ver, joga pro painel
  useEffect(() => {
    if (profile && !isAdmin && allTabs.find(t => t.id === tab)?.adminOnly) setTab('dashboard');
  }, [profile, isAdmin, tab]);

  // Carregando sessão
  if (session === undefined) {
    return <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: bodyFont, color: colors.textMute, backgroundColor: colors.bg }}>Carregando...</div>;
  }
  // Sem login → tela de login
  if (!session) return <LoginScreen businessName={businessName} />;

  return (
    <div style={{ minHeight: '100vh', backgroundColor: colors.bg, fontFamily: bodyFont, color: colors.text }}>
      <header style={{ backgroundColor: colors.surface, borderBottom: `1px solid ${colors.border}`, padding: '14px 24px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', position: 'sticky', top: 0, zIndex: 10 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ width: 38, height: 38, borderRadius: 10, backgroundColor: colors.primary, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icons.Box size={20} color="#fff" /></div>
          <div>
            <div style={{ fontFamily: displayFont, fontSize: 18, fontWeight: 700, color: colors.text, lineHeight: 1.1, letterSpacing: -0.2 }}>{businessName}</div>
            <div style={{ fontSize: 11, color: colors.textMute, letterSpacing: 0.4, textTransform: 'uppercase' }}>Gestão de estoque</div>
          </div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '5px 10px', borderRadius: 999, backgroundColor: colors.surfaceAlt, border: `1px solid ${colors.border}`, fontFamily: bodyFont, fontSize: 12, color: colors.textSoft, fontWeight: 500 }}>
            <Icons.User size={14} color={isAdmin ? colors.primary : colors.textSoft} />
            <span style={{ display: window.innerWidth > 480 ? 'inline' : 'none' }}>{currentUser}{isAdmin ? ' · Admin' : ''}</span>
          </div>
          <SyncIndicator sync={sync} />
          <button onClick={logout} title="Sair" style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '5px 10px', borderRadius: 999, backgroundColor: 'transparent', border: `1px solid ${colors.border}`, cursor: 'pointer', fontFamily: bodyFont, fontSize: 12, color: colors.textSoft, fontWeight: 500 }}>
            Sair
          </button>
        </div>
      </header>

      <nav style={{ backgroundColor: colors.surface, borderBottom: `1px solid ${colors.border}`, padding: '0 24px', display: 'flex', gap: 2, overflowX: 'auto' }}>
        {tabs.map(t => {
          const active = tab === t.id;
          return (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              padding: '12px 16px', background: 'none', border: 'none',
              borderBottom: `2px solid ${active ? colors.primary : 'transparent'}`,
              color: active ? colors.primary : colors.textSoft,
              fontWeight: active ? 600 : 500, fontFamily: bodyFont, fontSize: 14, cursor: 'pointer',
              display: 'flex', alignItems: 'center', gap: 7, whiteSpace: 'nowrap',
            }}>
              <t.Icon size={16} />{t.label}
            </button>
          );
        })}
      </nav>

      <main style={{ padding: '24px', maxWidth: 1280, margin: '0 auto' }}>
        {!ready ? (
          <Card><div style={{ textAlign: 'center', padding: 40, color: colors.textMute, fontFamily: bodyFont }}>Conectando...</div></Card>
        ) : (
          <>
            <div style={{ marginBottom: 20 }}>
              <h2 style={{ margin: 0, fontFamily: displayFont, fontSize: 30, color: colors.text, fontWeight: 600, letterSpacing: -0.5 }}>{tabs.find(t => t.id === tab)?.label}</h2>
            </div>
            {tab === 'dashboard' && <Dashboard items={items} movements={movements} shopping={shopping} sectors={sectors} onTab={setTab} />}
            {tab === 'estoque' && <EstoqueView items={items} setItems={setItems} movements={movements} setMovements={setMovements} shopping={shopping} setShopping={setShopping} sectors={sectors} setSectors={setSectors} categoriesData={categoriesData} setCategoriesData={setCategoriesData} isAdmin={isAdmin} currentUser={currentUser} />}
            {tab === 'consumo' && <ConsumoView movements={movements} setMovements={setMovements} sectors={sectors} items={items} setItems={setItems} />}
            {tab === 'compras' && <ComprasView shopping={shopping} setShopping={setShopping} items={items} sectors={sectors} businessName={businessName} />}
            {tab === 'custos' && isAdmin && <CustosView items={items} movements={movements} recipes={recipes} setRecipes={setRecipes} sectors={sectors} demand={demand} setDemand={setDemand} currentUser={currentUser} />}
            {tab === 'relatorios' && isAdmin && <RelatoriosView items={items} movements={movements} sectors={sectors} demand={demand} businessName={businessName} />}
            {tab === 'atividade' && isAdmin && <AtividadeView movements={movements} sectors={sectors} />}
            {tab === 'usuarios' && isAdmin && <UsuariosView profile={profile} />}
          </>
        )}
      </main>
    </div>
  );
}

function SyncIndicator({ sync }) {
  const offline = !sync.online;
  const pending = sync.pending > 0;
  let label, color, Icon;
  if (offline) { label = 'Offline'; color = colors.danger; Icon = Icons.CloudOff; }
  else if (pending) { label = `${sync.pending} pendente${sync.pending === 1 ? '' : 's'}`; color = colors.accent; Icon = Icons.Cloud; }
  else { label = 'Sincronizado'; color = colors.success; Icon = Icons.Cloud; }
  // Mostra label mesmo no mobile quando tem pendência ou offline (importante!)
  const showLabel = pending || offline || window.innerWidth > 480;
  return (
    <button
      onClick={() => { if (pending || offline) flushQueue(); }}
      title={pending ? 'Toque para forçar sincronização' : (offline ? 'Sem conexão' : 'Tudo sincronizado')}
      style={{
        display: 'flex', alignItems: 'center', gap: 6, padding: '5px 10px', borderRadius: 999,
        backgroundColor: `${color}15`, color, fontSize: 12, fontWeight: 600, letterSpacing: 0.3,
        fontFamily: bodyFont, border: pending || offline ? `1px solid ${color}` : 'none',
        cursor: pending || offline ? 'pointer' : 'default',
        animation: pending ? 'pulse 2s ease-in-out infinite' : 'none',
      }}>
      <Icon size={14} color={color} />
      {showLabel && <span>{label}</span>}
    </button>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
