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

/* ============ helpers ============ */
const fmt = (n) => {
  const v = Number(n || 0);
  return (v < 0 ? '-' : '') + 'R$ ' + Math.abs(v).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
};
const fmtK = (n) => {
  const v = Number(n || 0), a = Math.abs(v);
  if (a >= 1000) return (v < 0 ? '-' : '') + 'R$ ' + (a / 1000).toLocaleString('pt-BR', { maximumFractionDigits: 1 }) + 'k';
  return fmt(v);
};
const num = (n) => Number(n || 0).toLocaleString('pt-BR');
const cls = (...a) => a.filter(Boolean).join(' ');
const getToken = () => localStorage.getItem('fm_token');
const setToken = (t) => t ? localStorage.setItem('fm_token', t) : localStorage.removeItem('fm_token');
const dataHora = (ts) => ts ? new Date(ts * 1000).toLocaleString('pt-BR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }) : '—';
const soData = (ts) => ts ? new Date(ts * 1000).toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' }) : '—';
const soDataStr = (s) => { if (!s) return '—'; const p = String(s).split('-'); return p.length === 3 ? `${p[2]}/${p[1]}/${p[0].slice(2)}` : s; };
const toDateInput = (ts) => ts ? new Date(ts * 1000).toISOString().slice(0, 10) : '';
const hojeInput = () => new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString().slice(0, 10);
const soDigitos = (s) => String(s || '').replace(/\D/g, '');
const waLink = (phone, texto) => {
  let d = soDigitos(phone); if (!d) return null;
  if (d.length <= 11) d = '55' + d;
  return `https://wa.me/${d}${texto ? '?text=' + encodeURIComponent(texto) : ''}`;
};
const fileToDataUrl = (file) => new Promise((res, rej) => {
  const r = new FileReader(); r.onload = () => res(r.result); r.onerror = rej; r.readAsDataURL(file);
});

async function api(path, opts = {}) {
  const res = await fetch('/api' + path, {
    method: opts.method || 'GET',
    headers: { 'Content-Type': 'application/json', ...(getToken() ? { Authorization: 'Bearer ' + getToken() } : {}) },
    body: opts.body ? JSON.stringify(opts.body) : undefined,
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw Object.assign(new Error(data.error || 'erro'), { data, status: res.status });
  return data;
}

/* ============ icons ============ */
const Ic = ({ d, size = 18, fill }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill={fill || 'none'} stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">{d}</svg>
);
const icons = {
  grid: <Ic d={<><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></>} />,
  card: <Ic d={<><rect x="2.5" y="5" width="19" height="14" rx="2"/><path d="M2.5 9.5h19"/></>} />,
  bolt: <Ic d={<path d="M13 2 4 14h7l-1 8 9-12h-7l1-8Z"/>} />,
  cash: <Ic d={<><rect x="2.5" y="6" width="19" height="12" rx="2"/><circle cx="12" cy="12" r="2.5"/></>} />,
  users: <Ic d={<><circle cx="9" cy="8" r="3.2"/><path d="M3.5 20a5.5 5.5 0 0 1 11 0"/><path d="M16 5.2a3.2 3.2 0 0 1 0 6M18.5 20a5.5 5.5 0 0 0-3-4.9"/></>} />,
  plus: <Ic d={<><path d="M12 5v14M5 12h14"/></>} />,
  logout: <Ic d={<><path d="M15 4h3a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-3"/><path d="M10 17l-5-5 5-5M4 12h11"/></>} />,
  sync: <Ic d={<><path d="M20 11a8 8 0 0 0-14-4.5L4 8M4 4v4h4"/><path d="M4 13a8 8 0 0 0 14 4.5L20 16M20 20v-4h-4"/></>} />,
  check: <Ic d={<path d="M20 6 9 17l-5-5"/>} />,
  alert: <Ic d={<><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9 2 18a2 2 0 0 0 1.7 3h16.6a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"/></>} />,
  wallet: <Ic d={<><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M16 12h3M3 9h18"/></>} />,
  cog: <Ic d={<><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.9 4.9l2.1 2.1M17 17l2.1 2.1M2 12h3M19 12h3M4.9 19.1l2.1-2.1M17 7l2.1-2.1"/></>} />,
  ext: <Ic d={<><path d="M14 4h6v6M20 4l-9 9M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5"/></>} size={14} />,
  trend: <Ic d={<><path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/></>} />,
  clock: <Ic d={<><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>} />,
  upload: <Ic d={<><path d="M12 16V4M7 9l5-5 5 5"/><path d="M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></>} />,
  phone: <Ic d={<path d="M4 4h4l2 5-2.5 1.5a11 11 0 0 0 5 5L20 13l1 4v3a1 1 0 0 1-1 1A16 16 0 0 1 4 5a1 1 0 0 1 0-1Z"/>} size={15} />,
  x: <Ic d={<path d="M18 6 6 18M6 6l12 12"/>} />,
  eye: <Ic d={<><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/></>} size={15} />,
  trash: <Ic d={<><path d="M4 7h16M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M6 7l1 13a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-13"/></>} size={15} />,
  target: <Ic d={<><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1"/></>} />,
  coins: <Ic d={<><ellipse cx="8" cy="6" rx="5" ry="2.5"/><path d="M3 6v5c0 1.4 2.2 2.5 5 2.5s5-1.1 5-2.5V6"/><path d="M13 12.5c.6 1 2.5 1.8 5 1.8 2.8 0 5-1.1 5-2.5V8c0-1.4-2.2-2.5-5-2.5"/></>} />,
  spark: <Ic d={<path d="M12 3v4M12 17v4M3 12h4M17 12h4M6 6l2.5 2.5M15.5 15.5 18 18M18 6l-2.5 2.5M8.5 15.5 6 18"/>} size={15} />,
};

/* ============ atoms ============ */
function Brand({ small }) {
  return (
    <div className="flex items-center gap-2.5">
      <div className="grid place-items-center w-8 h-8 rounded-lg bg-brand text-ink font-head font-bold text-lg shadow-[0_0_20px_#2dd4bf55]">F</div>
      {!small && <div className="head text-[17px] font-bold text-bright tracking-tight">Flow<span className="text-brand">Money</span></div>}
    </div>
  );
}
function Btn({ children, onClick, variant = 'primary', size = 'md', type, disabled, icon, full }) {
  const base = 'inline-flex items-center justify-center gap-2 rounded-lg font-medium transition-all disabled:opacity-40 disabled:cursor-not-allowed select-none';
  const sizes = { sm: 'text-[13px] px-3 py-1.5', md: 'text-sm px-4 py-2.5', lg: 'text-[15px] px-5 py-3' };
  const variants = {
    primary: 'bg-brand text-ink hover:brightness-110 active:brightness-95 font-semibold',
    ghost: 'border border-line text-soft hover:text-bright hover:border-line2 bg-transparent',
    subtle: 'bg-panel2 text-text hover:bg-line border border-line',
    danger: 'bg-neg/15 text-neg border border-neg/30 hover:bg-neg/25',
  };
  return <button type={type || 'button'} onClick={onClick} disabled={disabled}
    className={cls(base, sizes[size], variants[variant], full && 'w-full')}>{icon}{children}</button>;
}
function Badge({ tone = 'muted', children }) {
  const tones = {
    pos: 'bg-pos/12 text-pos border-pos/25', neg: 'bg-neg/12 text-neg border-neg/25',
    warn: 'bg-warn/12 text-warn border-warn/25', brand: 'bg-brand/12 text-brand border-brand/25',
    muted: 'bg-panel2 text-soft border-line',
  };
  return <span className={cls('inline-flex items-center gap-1 text-[11px] font-medium px-2 py-0.5 rounded-full border', tones[tone])}>{children}</span>;
}
function Money({ v, className }) {
  const t = Number(v || 0) < 0 ? 'text-neg' : 'text-bright';
  return <span className={cls('num', t, className)}>{fmt(v)}</span>;
}
function Card({ children, className, pad = 'p-5' }) {
  return <div className={cls('bg-panel border border-line rounded-xl', pad, className)}>{children}</div>;
}
function Kpi({ label, value, sub, tone, icon, big, accent }) {
  const col = tone === 'pos' ? 'text-pos' : tone === 'neg' ? 'text-neg' : tone === 'brand' ? 'text-brand' : tone === 'warn' ? 'text-warn' : 'text-bright';
  return (
    <div className={cls('rise bg-panel border rounded-xl p-4 relative overflow-hidden', accent ? 'border-brand/40 glow-brand' : 'border-line')}>
      {accent && <div className="absolute -top-10 -right-8 w-28 h-28 rounded-full bg-brand/10 blur-2xl" />}
      <div className="flex items-start justify-between relative">
        <div className="text-[11px] uppercase tracking-wider text-muted font-medium">{label}</div>
        {icon && <div className={accent ? 'text-brand' : 'text-line2'}>{icon}</div>}
      </div>
      <div className={cls('num font-semibold mt-2 relative', big ? 'text-[27px]' : 'text-[22px]', col)}>{value}</div>
      {sub && <div className="text-xs text-muted mt-1 relative">{sub}</div>}
    </div>
  );
}
function Empty({ children }) { return <div className="py-14 text-center text-muted text-sm">{children}</div>; }
function Skeleton({ h = 64 }) { return <div className="shimmer rounded-xl" style={{ height: h }} />; }
function Toast({ msg }) {
  if (!msg) return null;
  const bad = /erro|inv|insufic|falha|indispon/i.test(msg);
  return (
    <div className="fixed bottom-5 right-5 z-[60] fade-in">
      <div className={cls('flex items-center gap-2 px-4 py-2.5 rounded-lg border text-sm shadow-xl bg-panel', bad ? 'border-neg/40 text-neg' : 'border-pos/40 text-pos')}>
        <span>{bad ? icons.alert : icons.check}</span>{msg}
      </div>
    </div>
  );
}
function Modal({ open, onClose, title, children, wide }) {
  if (!open) return null;
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-ink/70 backdrop-blur-sm fade-in" onClick={onClose}>
      <div className={cls('w-full bg-panel border border-line rounded-2xl shadow-2xl rise', wide ? 'max-w-lg' : 'max-w-md')} onClick={e => e.stopPropagation()}>
        <div className="flex items-center justify-between px-5 py-4 border-b border-line">
          <h3 className="head text-base font-semibold text-bright">{title}</h3>
          <button onClick={onClose} className="text-muted hover:text-bright p-1">{icons.x}</button>
        </div>
        <div className="p-5">{children}</div>
      </div>
    </div>
  );
}
function Field({ label, hint, children }) {
  return (
    <div className="mb-4">
      <label className="block text-xs text-muted mb-1.5 font-medium tracking-wide">{label}</label>
      {children}
      {hint && <p className="text-[11px] text-muted mt-1.5 leading-relaxed">{hint}</p>}
    </div>
  );
}

/* ============ table ============ */
function Table({ cols, rows, empty, align = {} }) {
  return (
    <div className="overflow-x-auto">
      <table className="w-full">
        <thead>
          <tr className="border-b border-line">
            {cols.map((c, i) => <th key={i} className={cls('text-[11px] uppercase tracking-wider text-muted font-medium py-2.5 px-3 text-left', align[i] === 'r' && '!text-right')}>{c}</th>)}
          </tr>
        </thead>
        <tbody>
          {rows.map((r, i) => (
            <tr key={i} className="border-b border-line/60 hover:bg-panel2/60 transition-colors">
              {r.map((c, j) => <td key={j} className={cls('py-2.5 px-3 text-[13px]', align[j] === 'r' && 'text-right')}>{c}</td>)}
            </tr>
          ))}
          {!rows.length && <tr><td colSpan={cols.length}><Empty>{empty}</Empty></td></tr>}
        </tbody>
      </table>
    </div>
  );
}

/* ============ profit chart ============ */
function ProfitChart({ dias }) {
  const data = useMemo(() => [...(dias || [])].slice(0, 21).reverse(), [dias]);
  if (!data.length) return <Empty>Sem movimento nos últimos dias.</Empty>;
  const W = 680, H = 160, pad = 4, gap = 5;
  const bw = (W - pad * 2 - gap * (data.length - 1)) / data.length;
  const max = Math.max(1, ...data.map(d => Math.abs(d.lucro)));
  const zeroY = H / 2 + 8;
  return (
    <div className="w-full overflow-hidden">
      <svg viewBox={`0 0 ${W} ${H}`} className="w-full" style={{ height: 160 }}>
        <line x1="0" y1={zeroY} x2={W} y2={zeroY} stroke="#232A33" strokeWidth="1" />
        {data.map((d, i) => {
          const h = (Math.abs(d.lucro) / max) * (H / 2 - 14);
          const x = pad + i * (bw + gap);
          const pos = d.lucro >= 0;
          const y = pos ? zeroY - h : zeroY;
          return (
            <g key={i}>
              <rect x={x} y={y} width={bw} height={Math.max(2, h)} rx="2.5" fill={pos ? '#34D399' : '#FB7185'} opacity="0.92">
                <title>{d.dia}: {fmt(d.lucro)}</title>
              </rect>
              <text x={x + bw / 2} y={H - 1} textAnchor="middle" fontSize="8" fill="#6B7684" className="num">{d.dia.slice(8)}</text>
            </g>
          );
        })}
      </svg>
    </div>
  );
}

/* ============ Auth — fundo ambiente calmo (nada de distração) ============ */
// Brilho verde suave que respira bem devagar + poucas partículas leves subindo.
// Sem rastros, sem vórtice, sem correr — só uma atmosfera discreta pra dar profundidade.
function useAmbient(canvasRef, animated) {
  useEffect(() => {
    const canvas = canvasRef.current; if (!canvas) return;
    const ctx = canvas.getContext('2d', { alpha: true }); if (!ctx) return;
    let raf = 0, w = 0, h = 0, t = 0;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    let ps = [];
    const resize = () => {
      const r = canvas.getBoundingClientRect();
      w = Math.max(1, r.width); h = Math.max(1, r.height);
      canvas.width = Math.floor(w * dpr); canvas.height = Math.floor(h * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      const n = w < 700 ? 22 : 40; // poucas, calmas
      ps = Array.from({ length: n }, () => ({
        x: Math.random() * w, y: Math.random() * h,
        r: 0.8 + Math.random() * 2.0,
        vy: -(0.05 + Math.random() * 0.13),          // sobe bem devagar
        sway: Math.random() * Math.PI * 2, ss: 0.0016 + Math.random() * 0.003,
        a: 0.05 + Math.random() * 0.18,
      }));
    };
    const draw = (step) => {
      ctx.clearRect(0, 0, w, h);
      if (step) t += 0.016;
      const beat = 0.5 + 0.5 * Math.sin(t * 0.35);   // respiro lento
      const cx = w / 2, cy = h * 0.44, R = Math.max(w, h) * 0.62;
      const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, R);
      g.addColorStop(0, `rgba(34,197,94,${0.05 + beat * 0.028})`);
      g.addColorStop(0.55, 'rgba(16,110,66,0.035)');
      g.addColorStop(1, 'rgba(0,0,0,0)');
      ctx.fillStyle = g; ctx.fillRect(0, 0, w, h);
      for (const p of ps) {
        if (step) { p.sway += p.ss; p.y += p.vy; p.x += Math.sin(p.sway) * 0.12; if (p.y < -6) { p.y = h + 6; p.x = Math.random() * w; } }
        ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(130,235,175,${p.a})`; ctx.fill();
      }
    };
    const tick = () => { draw(true); raf = requestAnimationFrame(tick); };
    resize();
    window.addEventListener('resize', resize);
    if (animated) raf = requestAnimationFrame(tick); else draw(false);
    return () => { cancelAnimationFrame(raf); window.removeEventListener('resize', resize); };
  }, [canvasRef, animated]);
}

function MLine({ type = 'text', label, value, onChange, autoFocus, mono, filled }) {
  const [show, setShow] = useState(false);
  const isPwd = type === 'password';
  return (
    <div className={cls('mo-line', filled && 'mo-line--filled')}>
      <input type={isPwd && show ? 'text' : type} value={value} onChange={onChange} placeholder=" " autoFocus={autoFocus} className={mono ? 'num' : ''} />
      <label>{label}</label>
      <span className="mo-rule" />
      {isPwd && <button type="button" className="mo-eye" tabIndex={-1} onClick={() => setShow(s => !s)}>{icons.eye}</button>}
    </div>
  );
}

function GoBtn({ busy, disabled, caption }) {
  return (
    <div className="mo-submit">
      <button type="submit" disabled={busy || disabled} className={cls('mo-go', busy && 'is-busy')} aria-label={caption}>
        {busy ? <span className="mo-go__spin" /> : (
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="4" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" /></svg>
        )}
      </button>
      <span className="mo-submit__cap">{caption}</span>
    </div>
  );
}

function AuthScreen({ onAuthed }) {
  const [modo, setModo] = useState('entrar');
  const canvasRef = useRef(null);
  const reduce = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  useAmbient(canvasRef, !reduce);
  // login
  const [login, setLogin] = useState('');
  const [senha, setSenha] = useState('');
  // signup
  const [f, setF] = useState({ username: '', senha: '', thebest_api_key: '', data_inicio: '' });
  const setf = (k) => (e) => setF({ ...f, [k]: e.target.value });
  const [erro, setErro] = useState('');
  const [busy, setBusy] = useState(false);

  const entrar = async (e) => {
    e.preventDefault(); setErro(''); setBusy(true);
    try { const r = await api('/auth/login', { method: 'POST', body: { email: login, password: senha } }); setToken(r.token); onAuthed(); }
    catch { setErro('Login ou senha inválidos.'); } finally { setBusy(false); }
  };
  const criar = async (e) => {
    e.preventDefault(); setErro(''); setBusy(true);
    try { const r = await api('/auth/signup', { method: 'POST', body: f }); setToken(r.token); onAuthed(); }
    catch (err) {
      const m = { login_ja_existe: 'Esse login já tem conta. Use "Entrar".', chave_invalida: 'Api-Key do TheBest inválida.', senha_curta: 'Senha muito curta.', campos_obrigatorios: 'Preencha login, senha e a Api-Key.' };
      setErro(m[err.data?.error] || err.data?.detalhe || 'Não foi possível criar a conta.');
    } finally { setBusy(false); }
  };
  const trocar = (k) => { setModo(k); setErro(''); };

  return (
    <div className="mo-root">
      <canvas ref={canvasRef} className="mo-neural" aria-hidden />
      <div className="mo-veil" aria-hidden />
      <div className="mo-grain" aria-hidden />

      <div className="mo-center">
        <div className="mo-auth">
          <div className="mo-brand rise" style={{ animationDelay: '.05s' }}>
            <div className="mo-logo">
              <svg viewBox="0 0 24 24" fill="none" stroke="#05170E" strokeWidth="2.3" strokeLinecap="round" strokeLinejoin="round">
                <path d="M4 15 L9.5 9.5 L13 13 L20 6" />
                <path d="M14.5 6H20v5.5" />
              </svg>
            </div>
            <div className="mo-word head">Flow<span>Money</span></div>
          </div>
          <p className="mo-tag rise" style={{ animationDelay: '.12s' }}>gestão financeira da sua revenda</p>

          <div className="mo-tabs rise" style={{ animationDelay: '.18s' }}>
            <button className={modo === 'entrar' ? 'on' : ''} onClick={() => trocar('entrar')}>Entrar</button>
            <button className={modo === 'criar' ? 'on' : ''} onClick={() => trocar('criar')}>Criar conta</button>
            <span className="mo-tabs__ink" style={{ transform: modo === 'criar' ? 'translateX(100%)' : 'translateX(0)' }} />
          </div>

          {modo === 'entrar' ? (
            <form onSubmit={entrar} className="mo-form fade-in" key="entrar">
              <MLine label="Login do TheBest" value={login} onChange={e => setLogin(e.target.value)} autoFocus />
              <MLine type="password" label="Senha" value={senha} onChange={e => setSenha(e.target.value)} />
              {erro && <div className="mo-err">{erro}</div>}
              <GoBtn busy={busy} disabled={!login || !senha} caption={busy ? 'Entrando…' : 'Entrar no painel'} />
            </form>
          ) : (
            <form onSubmit={criar} className="mo-form fade-in" key="criar">
              <MLine label="Login do TheBest" value={f.username} onChange={setf('username')} autoFocus />
              <MLine type="password" label="Criar senha" value={f.senha} onChange={setf('senha')} />
              <MLine label="Api-Key do TheBest" value={f.thebest_api_key} onChange={setf('thebest_api_key')} mono />
              <MLine type="date" label="Contar a partir de (opcional)" value={f.data_inicio} onChange={setf('data_inicio')} mono filled />
              {erro && <div className="mo-err">{erro}</div>}
              <GoBtn busy={busy} disabled={!f.username || !f.senha || !f.thebest_api_key} caption={busy ? 'Validando e importando…' : 'Criar conta e importar'} />
              <p className="mo-hint">Api-Key só leitura — nunca renovamos nem gastamos crédito seu.</p>
            </form>
          )}
        </div>
      </div>

      <div className="mo-foot">LiquidBR · TheBest — reconciliado sozinho</div>

      <style>{`
        .mo-root { position:fixed; inset:0; overflow:hidden; background:#04120B; color:#EEF2F6; }
        .mo-neural { position:absolute; inset:0; width:100%; height:100%; display:block; z-index:0; }
        .mo-veil { position:absolute; inset:0; z-index:1; pointer-events:none;
          background:radial-gradient(42% 46% at 50% 48%, rgba(4,18,11,0.62), transparent 72%),
                     radial-gradient(130% 120% at 50% 132%, rgba(4,18,11,0.6), transparent 50%); }
        .mo-grain { position:absolute; inset:-50%; z-index:1; pointer-events:none; opacity:0.035; mix-blend-mode:overlay;
          background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
        .mo-center { position:absolute; inset:0; z-index:2; display:grid; place-items:center; padding:24px; pointer-events:none; }
        .mo-auth { pointer-events:auto; width:min(348px,100%); display:flex; flex-direction:column; align-items:center; }
        .mo-brand { display:flex; align-items:center; gap:11px; margin-bottom:12px; }
        .mo-logo { width:46px; height:46px; border-radius:14px; display:grid; place-items:center;
          background:linear-gradient(150deg,#26D168,#16A34A); box-shadow:inset 0 1px 0 rgba(255,255,255,0.25), inset 0 -2px 6px rgba(0,40,20,0.35); animation:mo-glow 5s ease-in-out infinite; }
        .mo-logo svg { width:24px; height:24px; }
        @keyframes mo-glow { 0%,100%{box-shadow:0 0 18px rgba(34,197,94,0.4)} 50%{box-shadow:0 0 34px rgba(34,197,94,0.85)} }
        .mo-word { font-size:23px; font-weight:800; letter-spacing:-0.02em; color:#EEF2F6; }
        .mo-word span { color:#22C55E; }
        .mo-tag { margin:0 0 30px; font-size:12.5px; font-weight:500; letter-spacing:0.06em; white-space:nowrap;
          background:linear-gradient(100deg,#5d7a72 0%,#5d7a72 38%,#eafff8 50%,#5d7a72 62%,#5d7a72 100%); background-size:220% auto;
          -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; color:transparent; animation:mo-sheen 5.5s linear infinite; }
        @keyframes mo-sheen { from{background-position:130% center} to{background-position:-70% center} }
        .mo-tabs { position:relative; display:flex; gap:4px; width:100%; margin-bottom:30px; }
        .mo-tabs button { flex:1; background:none; border:none; cursor:pointer; padding:8px 0; font:600 13.5px/1 inherit; color:#6B7684; transition:color .25s; }
        .mo-tabs button.on { color:#EEF2F6; }
        .mo-tabs button:hover { color:#c9d2dc; }
        .mo-tabs__ink { position:absolute; bottom:0; left:0; width:50%; height:2px; border-radius:2px; background:linear-gradient(90deg,#22C55E,#34D399); box-shadow:0 0 10px rgba(34,197,94,0.7); transition:transform .32s cubic-bezier(.22,1,.36,1); }
        .mo-tabs::after { content:""; position:absolute; bottom:0; left:0; right:0; height:1px; background:rgba(150,190,255,0.1); }
        .mo-form { width:100%; display:flex; flex-direction:column; align-items:center; }
        .mo-line { position:relative; width:100%; margin-bottom:24px; }
        .mo-line input { width:100%; padding:9px 26px 9px 0; background:transparent; border:none; color:#EEF2F6; font:400 15px/1 inherit; letter-spacing:0.01em; outline:none; }
        .mo-line input::placeholder { color:transparent; }
        .mo-line input:-webkit-autofill,.mo-line input:-webkit-autofill:hover,.mo-line input:-webkit-autofill:focus {
          -webkit-text-fill-color:#EEF2F6 !important; caret-color:#EEF2F6; -webkit-box-shadow:0 0 0 1000px transparent inset !important;
          transition:background-color 600000s 0s, color 600000s 0s !important; }
        .mo-line input[type=date]::-webkit-calendar-picker-indicator { filter:invert(0.6); cursor:pointer; }
        .mo-rule { position:absolute; left:0; right:0; bottom:0; height:1px; background:rgba(150,190,255,0.16); }
        .mo-rule::after { content:""; position:absolute; left:50%; right:50%; bottom:0; height:1px; background:linear-gradient(90deg,#22C55E,#34D399); box-shadow:0 0 10px rgba(34,197,94,0.7); transition:left .35s cubic-bezier(.22,1,.36,1), right .35s cubic-bezier(.22,1,.36,1); }
        .mo-line input:focus ~ .mo-rule::after { left:0; right:0; }
        .mo-line label { position:absolute; left:0; top:9px; pointer-events:none; transition:all .22s ease; font:300 14.5px/1 inherit; color:#6B7684; letter-spacing:0.02em; }
        .mo-line input:focus + label, .mo-line input:not(:placeholder-shown) + label, .mo-line--filled label {
          top:-13px; font-size:10.5px; font-weight:600; letter-spacing:0.12em; text-transform:uppercase; color:#22C55E; }
        .mo-eye { position:absolute; right:0; top:5px; background:none; border:none; cursor:pointer; color:#6B7684; padding:4px; display:grid; place-items:center; border-radius:6px; transition:color .2s; }
        .mo-eye:hover { color:#22C55E; }
        .mo-err { color:#FB7185; font-size:12.5px; font-weight:500; margin:-4px 0 16px; text-align:center; }
        .mo-submit { display:flex; flex-direction:column; align-items:center; gap:11px; margin-top:6px; }
        .mo-go { width:56px; height:56px; border-radius:50%; cursor:pointer; display:grid; place-items:center; position:relative;
          background:radial-gradient(circle at 50% 35%, rgba(34,197,94,0.16), rgba(52,211,153,0.06)); border:1px solid rgba(34,197,94,0.4); color:#dffff5;
          transition:transform .25s cubic-bezier(.22,1,.36,1), box-shadow .25s, border-color .25s, background .25s; }
        .mo-go::before { content:""; position:absolute; inset:-7px; border-radius:50%; border:1px solid transparent; border-top-color:#22C55E; border-right-color:rgba(52,211,153,0.5); opacity:0; transition:opacity .3s; }
        .mo-go svg { width:20px; height:20px; transition:transform .25s; }
        .mo-go:hover:not(:disabled) { transform:translateY(-2px); border-color:#22C55E; box-shadow:0 0 30px rgba(34,197,94,0.5); background:radial-gradient(circle at 50% 35%, rgba(34,197,94,0.3), rgba(52,211,153,0.12)); }
        .mo-go:hover:not(:disabled)::before { opacity:1; animation:mo-ring 1.1s linear infinite; }
        .mo-go:hover:not(:disabled) svg { transform:translateX(3px); }
        @keyframes mo-ring { to { transform:rotate(360deg); } }
        .mo-go:disabled { cursor:not-allowed; opacity:.45; }
        .mo-go__spin { width:18px; height:18px; border:2px solid rgba(150,255,225,0.3); border-top-color:#22C55E; border-radius:50%; animation:mo-spin .7s linear infinite; }
        @keyframes mo-spin { to { transform:rotate(360deg); } }
        .mo-submit__cap { font-size:11.5px; letter-spacing:0.04em; color:#8A93A0; }
        .mo-hint { margin:16px 0 0; font-size:11px; line-height:1.5; color:#586b78; text-align:center; max-width:30ch; }
        .mo-foot { position:absolute; left:0; right:0; bottom:20px; z-index:2; text-align:center; font-size:11px; letter-spacing:0.08em; text-transform:uppercase; color:#4a5568; pointer-events:none; }
        @media (max-width:640px){
          .mo-auth { width:min(360px,88vw); }
          .mo-line input { font-size:16px; }
          .mo-veil { background:radial-gradient(52% 40% at 50% 44%, rgba(4,18,11,0.78), transparent 72%), radial-gradient(130% 120% at 50% 130%, rgba(4,18,11,0.55), transparent 50%); }
        }
        @media (prefers-reduced-motion: reduce){ .mo-logo,.mo-tag { animation:none !important; } }
      `}</style>
    </div>
  );
}

/* ============ LiquidBR connect (reutilizável) ============ */
function LiquidBRConnect({ onDone, compact }) {
  const [lbKey, setLbKey] = useState('');
  const [lbSecret, setLbSecret] = useState('');
  const [busy, setBusy] = useState(false);
  const [erro, setErro] = useState('');
  const [webhookUrl, setWebhookUrl] = useState('');
  const salvar = async () => {
    setErro(''); setBusy(true);
    try { const r = await api('/onboarding/liquidbr', { method: 'POST', body: { api_key: lbKey, webhook_secret: lbSecret } }); setWebhookUrl(r.webhook_url); setTimeout(() => onDone && onDone(), 1600); }
    catch (e) { setErro(e.data?.detalhe || 'Chave do LiquidBR inválida.'); } finally { setBusy(false); }
  };
  return (
    <div>
      {!compact && <p className="text-soft text-sm mb-5">No LiquidBR, abra <b className="text-text">API Keys &amp; Webhooks</b> e copie a <b className="text-text">API Key</b> e o <b className="text-text">Webhook Secret</b>.</p>}
      <Field label="API KEY"><input className="w-full px-3.5 py-2.5 num" placeholder="pk_live_…" value={lbKey} onChange={e => setLbKey(e.target.value)} /></Field>
      <Field label="WEBHOOK SECRET"><input className="w-full px-3.5 py-2.5 num" placeholder="whsec_…" value={lbSecret} onChange={e => setLbSecret(e.target.value)} /></Field>
      {webhookUrl && (
        <div className="mb-4 p-3.5 rounded-lg bg-brand/8 border border-brand/25 text-sm">
          <div className="text-pos flex items-center gap-1.5 mb-1.5">{icons.check} Conectado! Cadastre esta URL de webhook no LiquidBR:</div>
          <code className="text-brand text-xs break-all num">{webhookUrl}</code>
        </div>
      )}
      {erro && <div className="text-neg text-sm mb-4 flex items-center gap-1.5">{icons.alert}{erro}</div>}
      <Btn onClick={salvar} disabled={busy || !lbKey} full>{busy ? 'Validando…' : 'Conectar LiquidBR'}</Btn>
    </div>
  );
}

/* ============ Onboarding (contas sem TheBest — criadas pelo admin) ============ */
function Onboarding({ me, onDone }) {
  const [tbUser, setTbUser] = useState(me.empresa?.thebest_username || '');
  const [tbKey, setTbKey] = useState('');
  const [tbInicio, setTbInicio] = useState('');
  const [busy, setBusy] = useState(false);
  const [erro, setErro] = useState('');
  const [tbRes, setTbRes] = useState(null);
  const salvarTB = async () => {
    setErro(''); setBusy(true);
    try { const r = await api('/onboarding/thebest', { method: 'POST', body: { username: tbUser, api_key: tbKey, data_inicio: tbInicio } }); setTbRes(r); }
    catch (e) { setErro(e.data?.detalhe || 'Chave do TheBest inválida.'); } finally { setBusy(false); }
  };
  return (
    <div className="min-h-screen">
      <div className="border-b border-line px-6 py-4"><Brand /></div>
      <div className="max-w-xl mx-auto px-6 py-12">
        {!tbRes ? (
          <Card className="rise">
            <h2 className="head text-xl font-semibold text-bright">Conecte seu painel TheBest</h2>
            <p className="text-soft text-sm mt-1.5 mb-5">Informe seu login e a Api-Key. Importamos suas vendas e o consumo de créditos automaticamente.</p>
            <Field label="LOGIN (USERNAME)"><input className="w-full px-3.5 py-2.5" placeholder="ex: tdsminharevenda" value={tbUser} onChange={e => setTbUser(e.target.value)} /></Field>
            <Field label="API KEY"><input className="w-full px-3.5 py-2.5 num" placeholder="cole a Api-Key" value={tbKey} onChange={e => setTbKey(e.target.value)} /></Field>
            <Field label="CONTAR CRÉDITOS A PARTIR DE (opcional)" hint="Créditos antes desta data não contam como custo."><input type="date" className="w-full px-3.5 py-2.5 num" value={tbInicio} onChange={e => setTbInicio(e.target.value)} /></Field>
            {erro && <div className="text-neg text-sm mb-4 flex items-center gap-1.5">{icons.alert}{erro}</div>}
            <Btn onClick={salvarTB} disabled={busy || !tbKey} full>{busy ? 'Validando e importando…' : 'Conectar e importar vendas'}</Btn>
          </Card>
        ) : (
          <Card className="rise">
            <div className="mb-5 p-3.5 rounded-lg bg-pos/8 border border-pos/25 text-sm text-text flex items-center gap-2">
              <span className="text-pos">{icons.check}</span>
              TheBest conectado — <b className="text-bright">{tbRes.conta.username}</b> · {num(tbRes.ativas ?? tbRes.sync?.ativas ?? 0)} clientes ativos.
            </div>
            <h2 className="head text-xl font-semibold text-bright">Conectar o LiquidBR</h2>
            <p className="text-soft text-sm mt-1.5 mb-5">Para importar os pagamentos PIX automaticamente. Você também pode pular e lançar pagamentos manuais.</p>
            <LiquidBRConnect compact onDone={onDone} />
            <button onClick={onDone} className="w-full text-center text-sm text-muted hover:text-bright mt-3 py-1">Pular por agora →</button>
          </Card>
        )}
      </div>
    </div>
  );
}

/* ============ Shell ============ */
function Shell({ me, onLogout, nav, current, setCurrent, title, subtitle, actions, children }) {
  const papel = me.user.papel;
  const nome = papel === 'admin' ? 'Administrador' : (me.empresa?.nome || 'Revenda');
  const tag = papel === 'admin' ? 'admin · vê tudo' : (me.empresa?.is_owner ? 'minha revenda · 100%' : 'revenda');
  return (
    <div className="min-h-screen md:flex">
      <aside className="md:w-60 md:h-screen md:sticky md:top-0 border-b md:border-b-0 md:border-r border-line bg-panel flex md:flex-col z-20">
        <div className="p-5"><Brand /></div>
        <nav className="flex md:flex-col gap-1 px-3 pb-3 md:pb-0 overflow-x-auto md:overflow-visible flex-1">
          {nav.map(item => (
            <button key={item.key} onClick={() => setCurrent(item.key)}
              className={cls('flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm whitespace-nowrap transition-colors relative',
                current === item.key ? 'bg-brand/12 text-brand font-medium' : 'text-soft hover:text-bright hover:bg-panel2')}>
              {current === item.key && <span className="hidden md:block absolute left-0 top-1.5 bottom-1.5 w-0.5 rounded-full bg-brand" />}
              <span className={current === item.key ? 'text-brand' : 'text-muted'}>{item.icon}</span>{item.label}
              {item.badge ? <span className="ml-auto text-[10px] bg-warn/20 text-warn px-1.5 rounded-full num">{item.badge}</span> : null}
            </button>
          ))}
        </nav>
        <div className="hidden md:block p-3 border-t border-line">
          <div className="flex items-center gap-2.5 px-2 py-1.5">
            <div className="grid place-items-center w-8 h-8 rounded-full bg-panel2 border border-line text-xs num text-brand">{nome.slice(0, 2).toUpperCase()}</div>
            <div className="min-w-0 flex-1">
              <div className="text-[13px] text-text truncate">{nome}</div>
              <div className="text-[11px] text-muted truncate">{tag}</div>
            </div>
            <button onClick={onLogout} className="text-muted hover:text-neg p-1.5" title="Sair">{icons.logout}</button>
          </div>
        </div>
      </aside>
      <main className="flex-1 min-w-0">
        <header className="sticky top-0 z-10 flex items-center justify-between px-6 py-3.5 border-b border-line bg-ink/80 backdrop-blur">
          <div>
            <h1 className="head text-lg font-semibold text-bright leading-tight">{title}</h1>
            {subtitle && <div className="text-xs text-muted mt-0.5">{subtitle}</div>}
          </div>
          <div className="flex items-center gap-2">
            {actions}
            <button onClick={onLogout} className="md:hidden text-muted hover:text-neg p-2">{icons.logout}</button>
          </div>
        </header>
        <div className="p-6 max-w-6xl">{children}</div>
      </main>
    </div>
  );
}

/* ============ Manual payment modal ============ */
function ManualPaymentModal({ open, onClose, onSaved, toast }) {
  const [valor, setValor] = useState('');
  const [data, setData] = useState(hojeInput());
  const [descricao, setDescricao] = useState('');
  const [file, setFile] = useState(null);
  const [preview, setPreview] = useState('');
  const [busy, setBusy] = useState(false);
  const [drag, setDrag] = useState(false);
  const inputRef = useRef(null);

  const reset = () => { setValor(''); setData(hojeInput()); setDescricao(''); setFile(null); setPreview(''); };
  const pick = (f) => {
    if (!f) return;
    setFile(f);
    if (/image/.test(f.type)) fileToDataUrl(f).then(setPreview); else setPreview('');
  };
  const salvar = async () => {
    setBusy(true);
    try {
      let base64 = null;
      if (file) base64 = await fileToDataUrl(file);
      await api('/revenda/pagamento-manual', { method: 'POST', body: { valor: Number(valor), pago_em: data, descricao, comprovante_base64: base64, comprovante_nome: file?.name } });
      reset(); onSaved(); onClose(); toast('Pagamento manual lançado.');
    } catch (e) { toast(e.data?.error === 'valor_invalido' ? 'Valor inválido.' : 'Erro ao lançar.'); } finally { setBusy(false); }
  };
  return (
    <Modal open={open} onClose={onClose} title="Novo pagamento manual" wide>
      <div className="grid grid-cols-2 gap-3">
        <Field label="VALOR (R$)"><input className="w-full px-3.5 py-2.5 num" placeholder="29,90" value={valor} onChange={e => setValor(e.target.value.replace(',', '.'))} autoFocus /></Field>
        <Field label="DATA DO PAGAMENTO"><input type="date" className="w-full px-3.5 py-2.5 num" value={data} onChange={e => setData(e.target.value)} /></Field>
      </div>
      <Field label="DESCRIÇÃO (opcional)"><input className="w-full px-3.5 py-2.5" placeholder="ex: PIX João - plano anual" value={descricao} onChange={e => setDescricao(e.target.value)} /></Field>
      <label className="block text-xs text-muted mb-1.5 font-medium tracking-wide">COMPROVANTE (opcional)</label>
      <div
        onClick={() => inputRef.current?.click()}
        onDragOver={e => { e.preventDefault(); setDrag(true); }}
        onDragLeave={() => setDrag(false)}
        onDrop={e => { e.preventDefault(); setDrag(false); pick(e.dataTransfer.files?.[0]); }}
        className={cls('cursor-pointer rounded-lg border border-dashed border-line2 p-4 text-center transition-all mb-5', drag && 'drop-active')}>
        {preview ? (
          <div className="flex items-center gap-3">
            <img src={preview} className="w-14 h-14 object-cover rounded-md border border-line" />
            <div className="text-left min-w-0"><div className="text-sm text-text truncate">{file?.name}</div><div className="text-xs text-muted">clique para trocar</div></div>
            <button onClick={e => { e.stopPropagation(); setFile(null); setPreview(''); }} className="ml-auto text-muted hover:text-neg p-1">{icons.x}</button>
          </div>
        ) : file ? (
          <div className="text-sm text-text flex items-center justify-center gap-2">{icons.check} {file.name}</div>
        ) : (
          <div className="text-muted text-sm flex flex-col items-center gap-1.5 py-2">
            <span className="text-line2">{icons.upload}</span>
            Arraste o print/PDF do PIX aqui, ou <span className="text-brand">clique para escolher</span>
          </div>
        )}
        <input ref={inputRef} type="file" accept="image/*,.pdf" className="hidden" onChange={e => pick(e.target.files?.[0])} />
      </div>
      <Btn full onClick={salvar} disabled={busy || !valor}>{busy ? 'Salvando…' : 'Lançar pagamento'}</Btn>
    </Modal>
  );
}

/* ============ Revenda ============ */
function RevendaApp({ me, onLogout, reload }) {
  const [cur, setCur] = useState('overview');
  const [resumo, setResumo] = useState(null);
  const [pagamentos, setPagamentos] = useState([]);
  const [creditos, setCreditos] = useState([]);
  const [saques, setSaques] = useState([]);
  const [despesas, setDespesas] = useState([]);
  const [porDia, setPorDia] = useState([]);
  const [exp, setExp] = useState(null);
  const [despForm, setDespForm] = useState({ valor: '', data: hojeInput(), descricao: '' });
  const [msg, setMsg] = useState('');
  const [syncing, setSyncing] = useState(false);
  const [valSaque, setValSaque] = useState('');
  const [manualOpen, setManualOpen] = useState(false);
  const [cfgData, setCfgData] = useState('');
  const [cfgUser, setCfgUser] = useState('');
  const [cfgSaving, setCfgSaving] = useState(false);
  const [bannerOff, setBannerOff] = useState(false);

  const temLiquid = me.empresa?.tem_liquidbr;
  const toast = (m) => { setMsg(m); setTimeout(() => setMsg(''), 2600); };
  const load = useCallback(async () => {
    const [r, p, c, s, d, dsp] = await Promise.all([
      api('/revenda/resumo'), api('/revenda/pagamentos'), api('/revenda/creditos'), api('/revenda/saques'), api('/revenda/por-dia'), api('/revenda/despesas'),
    ]);
    setResumo(r); setPagamentos(p); setCreditos(c); setSaques(s); setPorDia(d); setDespesas(dsp);
    setCfgData(toDateInput(r.data_inicio)); setCfgUser(r.thebest_user_id || '');
    api('/revenda/expirando').then(setExp).catch(() => setExp({ hoje: 0, em3dias: 0, em7dias: 0, lista: [] }));
  }, []);
  useEffect(() => { load(); }, [load]);

  const sync = async () => { setSyncing(true); try { await api('/revenda/sync', { method: 'POST' }); await load(); toast('Dados atualizados.'); } finally { setSyncing(false); } };
  const pedirSaque = async () => {
    try { await api('/revenda/saque', { method: 'POST', body: { valor: Number(valSaque) } }); setValSaque(''); await load(); toast('Saque solicitado.'); }
    catch (e) { toast(e.data?.error === 'saldo_insuficiente' ? 'Saldo insuficiente.' : 'Erro ao solicitar.'); }
  };
  const excluirManual = async (id) => { if (!confirm('Excluir este pagamento manual?')) return; await api('/revenda/pagamento-manual/' + id, { method: 'DELETE' }); await load(); toast('Pagamento excluído.'); };
  const lancarDespesa = async () => {
    try { await api('/revenda/despesa', { method: 'POST', body: { valor: Number(despForm.valor), data: despForm.data, descricao: despForm.descricao } }); setDespForm({ valor: '', data: hojeInput(), descricao: '' }); await load(); toast('Despesa lançada.'); }
    catch { toast('Valor inválido.'); }
  };
  const excluirDespesa = async (id) => { if (!confirm('Excluir esta despesa?')) return; await api('/revenda/despesa/' + id, { method: 'DELETE' }); await load(); toast('Despesa excluída.'); };
  const salvarConfig = async () => {
    setCfgSaving(true);
    try { await api('/revenda/config', { method: 'POST', body: { data_inicio: cfgData, thebest_user_id: cfgUser } }); await load(); toast('Configuração salva e sincronizada.'); }
    catch { toast('Erro ao salvar.'); } finally { setCfgSaving(false); }
  };

  const proj = useMemo(() => {
    const ult = (porDia || []).slice(0, 14);
    if (!ult.length) return null;
    const somaL = ult.reduce((a, d) => a + d.lucro, 0);
    const somaR = ult.reduce((a, d) => a + (d.receita_liquidbr + d.receita_manual), 0);
    return { lucroMes: (somaL / ult.length) * 30, receitaMes: (somaR / ult.length) * 30, diaLucro: somaL / ult.length };
  }, [porDia]);

  const nav = [
    { key: 'overview', label: 'Visão geral', icon: icons.grid },
    { key: 'pagamentos', label: 'Pagamentos', icon: icons.card },
    { key: 'clientes', label: 'Clientes a vencer', icon: icons.clock, badge: exp?.hoje || null },
    { key: 'creditos', label: 'Créditos', icon: icons.bolt },
    { key: 'saques', label: 'Saques', icon: icons.cash },
    { key: 'despesas', label: 'Despesas', icon: icons.wallet },
    { key: 'config', label: 'Configurações', icon: icons.cog },
  ];
  const titles = { overview: 'Visão geral', pagamentos: 'Pagamentos', clientes: 'Clientes a vencer', creditos: 'Consumo de créditos', saques: 'Saques', despesas: 'Despesas da empresa', config: 'Configurações' };
  const actions = <>
    {cur === 'pagamentos' && <Btn size="sm" icon={icons.plus} onClick={() => setManualOpen(true)}>Pagamento manual</Btn>}
    <Btn variant="ghost" size="sm" icon={<span className={syncing ? 'animate-spin' : ''}>{icons.sync}</span>} onClick={sync} disabled={syncing}>{syncing ? 'Sincronizando…' : 'Sincronizar'}</Btn>
  </>;

  return (
    <Shell me={me} onLogout={onLogout} nav={nav} current={cur} setCurrent={setCur} title={titles[cur]}
      subtitle={resumo ? `${num(resumo.clientes_ativos)} clientes ativos · ${me.empresa?.nome || ''}` : ''} actions={actions}>
      <Toast msg={msg} />
      <ManualPaymentModal open={manualOpen} onClose={() => setManualOpen(false)} onSaved={load} toast={toast} />
      {!resumo ? <div className="grid md:grid-cols-4 gap-3"><Skeleton /><Skeleton /><Skeleton /><Skeleton /></div> : (
        <>
          {!temLiquid && !bannerOff && (
            <div className="mb-5 flex items-center gap-3 p-3.5 rounded-xl bg-brand/8 border border-brand/25 text-sm rise">
              <span className="text-brand">{icons.spark}</span>
              <span className="text-text flex-1">Conecte o <b>LiquidBR</b> para importar os pagamentos PIX sozinho — ou siga lançando manualmente.</span>
              <Btn size="sm" onClick={() => setCur('config')}>Conectar</Btn>
              <button onClick={() => setBannerOff(true)} className="text-muted hover:text-bright p-1">{icons.x}</button>
            </div>
          )}

          {cur === 'overview' && (
            <div className="space-y-5 fade-in">
              <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
                <Kpi accent label="Saldo disponível" big icon={icons.wallet} value={fmt(resumo.saldo_disponivel)} sub={resumo.saques_pendentes ? `${fmt(resumo.saques_pendentes)} em saque` : 'sua parte a sacar'} />
                <Kpi label="Lucro" tone={resumo.lucro >= 0 ? 'pos' : 'neg'} icon={icons.trend} value={fmt(resumo.lucro)} sub={`sua parte ${resumo.profit_share_pct}%`} />
                <Kpi label="Receita total" icon={icons.card} value={fmt(resumo.receita_total)} sub={`${fmtK(resumo.receita_liquidbr)} PIX · ${fmtK(resumo.receita_pix_manual)} manual`} />
                <Kpi label="Custo de créditos" icon={icons.coins} value={fmt(resumo.custo_creditos)} sub={`${num(resumo.creditos_gastos)} créditos`} />
              </div>

              {/* HOJE */}
              <Card pad="p-0" className="overflow-hidden">
                <div className="flex items-center gap-2 px-5 pt-4 pb-1">
                  <span className="w-1.5 h-1.5 rounded-full bg-pos animate-pulse" />
                  <h3 className="head text-sm font-semibold text-bright">Hoje</h3>
                  <span className="text-xs text-muted ml-auto">{new Date().toLocaleDateString('pt-BR', { weekday: 'long', day: '2-digit', month: 'long' })}</span>
                </div>
                <div className="grid grid-cols-2 md:grid-cols-4 divide-x divide-line/60 border-t border-line mt-2">
                  <HojeStat label="Pagamentos caíram" v={num(resumo.pagamentos_hoje)} sub={fmt(resumo.receita_hoje)} tone="pos" />
                  <HojeStat label="Clientes ativados" v={num(resumo.ativacoes_hoje)} sub={`${num(resumo.creditos_hoje)} créditos`} />
                  <HojeStat label="Vencem hoje" v={num(exp?.hoje ?? '—')} sub="renovar/cobrar" tone={exp?.hoje ? 'warn' : undefined} />
                  <HojeStat label="Ticket médio hoje" v={resumo.pagamentos_hoje ? fmt(resumo.receita_hoje / resumo.pagamentos_hoje) : '—'} sub="por pagamento" />
                </div>
              </Card>

              <div className="grid md:grid-cols-3 gap-4">
                <Card className="md:col-span-2">
                  <div className="flex items-center justify-between mb-3">
                    <h3 className="head text-sm font-semibold text-bright">Lucro por dia</h3>
                    <span className="text-xs text-muted">últimos 21 dias</span>
                  </div>
                  <ProfitChart dias={porDia} />
                </Card>
                {/* Projeção */}
                <Card>
                  <div className="flex items-center gap-2 mb-3"><span className="text-brand">{icons.target}</span><h3 className="head text-sm font-semibold text-bright">Projeção do mês</h3></div>
                  {proj ? (
                    <div className="space-y-3">
                      <div><div className="text-[11px] uppercase tracking-wider text-muted">Lucro projetado</div><div className={cls('num text-2xl font-semibold', proj.lucroMes >= 0 ? 'text-pos' : 'text-neg')}>{fmt(proj.lucroMes)}</div></div>
                      <div className="flex gap-4 text-sm">
                        <div><div className="text-[11px] text-muted">Receita proj.</div><div className="num text-text">{fmtK(proj.receitaMes)}</div></div>
                        <div><div className="text-[11px] text-muted">Média/dia</div><div className="num text-text">{fmt(proj.diaLucro)}</div></div>
                      </div>
                      <p className="text-[11px] text-muted leading-relaxed">Baseado na média dos últimos {Math.min(14, porDia.length)} dias × 30.</p>
                    </div>
                  ) : <Empty>Sem dados suficientes.</Empty>}
                </Card>
              </div>

              {/* Expirando preview + saque */}
              <div className="grid md:grid-cols-3 gap-4">
                <Card className="md:col-span-2" pad="p-0">
                  <div className="flex items-center justify-between px-5 pt-4 pb-2">
                    <div className="flex items-center gap-2"><span className="text-warn">{icons.clock}</span><h3 className="head text-sm font-semibold text-bright">Vencendo em breve</h3></div>
                    <button onClick={() => setCur('clientes')} className="text-xs text-brand hover:underline">ver todos →</button>
                  </div>
                  {!exp ? <div className="p-5"><Skeleton h={40} /></div> : exp.lista.length ? (
                    <div className="divide-y divide-line/60">
                      {exp.lista.slice(0, 5).map((l, i) => <ClienteRow key={i} l={l} />)}
                    </div>
                  ) : <Empty>Ninguém vencendo nos próximos dias. 🎉</Empty>}
                </Card>
                <Card>
                  <h3 className="head text-sm font-semibold text-bright mb-1">Solicitar saque</h3>
                  <p className="text-xs text-muted mb-4">Disponível: <b className="text-brand num">{fmt(resumo.saldo_disponivel)}</b></p>
                  <input className="w-full px-3.5 py-2.5 mb-3 num" placeholder="Valor (R$)" value={valSaque} onChange={e => setValSaque(e.target.value.replace(',', '.'))} />
                  <Btn full onClick={pedirSaque} disabled={!valSaque}>Pedir saque</Btn>
                  {me.empresa?.is_owner && <p className="text-[11px] text-muted mt-3">Sua própria revenda: o lucro é 100% seu.</p>}
                </Card>
              </div>
            </div>
          )}

          {cur === 'pagamentos' && (
            <div className="space-y-3 fade-in">
              <div className="grid grid-cols-3 gap-3">
                <Kpi label="Total recebido" value={fmt(resumo.receita_total)} />
                <Kpi label="Via LiquidBR" tone="brand" value={fmt(resumo.receita_liquidbr)} />
                <Kpi label="PIX manual" value={fmt(resumo.receita_pix_manual)} />
              </div>
              <Card pad="p-1.5">
                <Table cols={['Data', 'Origem', 'Descrição', 'Comprov.', 'Valor', 'Status', '']} align={{ 4: 'r' }}
                  rows={pagamentos.map(p => [
                    dataHora(p.pago_em),
                    <Badge tone={p.origem === 'liquidbr' ? 'brand' : 'muted'}>{p.origem === 'liquidbr' ? 'LiquidBR' : 'manual'}</Badge>,
                    <span className="text-soft">{p.descricao || '—'}</span>,
                    p.comprovante_id ? <a className="text-brand inline-flex" href={p.comprovante_id} target="_blank" title="ver comprovante">{icons.eye}</a> : <span className="text-muted">—</span>,
                    <Money v={p.valor_brl} />,
                    <Badge tone={p.status === 'pago' ? 'pos' : p.status === 'estornado_med' ? 'neg' : 'muted'}>{p.status}</Badge>,
                    p.origem === 'pix_manual' ? <button onClick={() => excluirManual(p.id)} className="text-muted hover:text-neg">{icons.trash}</button> : '',
                  ])}
                  empty="Nenhum pagamento ainda. Lance um manual ou conecte o LiquidBR." />
              </Card>
            </div>
          )}

          {cur === 'clientes' && (
            <div className="space-y-4 fade-in">
              <div className="grid grid-cols-3 gap-3">
                <Kpi label="Vencem hoje" tone="warn" big value={num(exp?.hoje ?? '—')} icon={icons.clock} />
                <Kpi label="Em 3 dias" value={num(exp?.em3dias ?? '—')} />
                <Kpi label="Em 7 dias" value={num(exp?.em7dias ?? '—')} />
              </div>
              <Card pad="p-0">
                <div className="px-5 py-3 border-b border-line flex items-center justify-between">
                  <h3 className="head text-sm font-semibold text-bright">Clientes a renovar (mais próximos)</h3>
                  <span className="text-xs text-muted">{exp?.lista?.length || 0} listados · clique pra cobrar no WhatsApp</span>
                </div>
                {!exp ? <div className="p-5"><Skeleton h={40} /></div> : exp.lista.length ? (
                  <div className="divide-y divide-line/60">{exp.lista.map((l, i) => <ClienteRow key={i} l={l} full />)}</div>
                ) : <Empty>Ninguém vencendo nos próximos dias.</Empty>}
              </Card>
            </div>
          )}

          {cur === 'creditos' && (
            <div className="space-y-3 fade-in">
              <div className="grid grid-cols-1 md:grid-cols-3 gap-3">
                <Kpi label="Custo de créditos" tone="neg" big value={fmt(resumo.custo_creditos)} sub={`${num(resumo.creditos_gastos)} créditos · renovações + vendas novas`} icon={icons.coins} />
                <Kpi label="Repasses às sub-revendas" value={num(resumo.creditos_repasse || 0) + ' cr'} sub={`${fmt((resumo.creditos_repasse || 0) * 6)} · não conta como seu custo`} />
                <Kpi label="Total que saiu do saldo" value={num((resumo.creditos_gastos || 0) + (resumo.creditos_repasse || 0)) + ' cr'} sub="desde o início configurado" />
              </div>
              <div className="p-3 rounded-lg bg-panel2 border border-line text-xs text-muted leading-relaxed">
                <b className="text-soft">Conta como custo</b> só o crédito gasto atendendo cliente final (renovação / venda nova / tela). Repasse de crédito pra sub-revenda e compra de créditos não entram — são estoque, não venda.
              </div>
              <Card pad="p-1.5">
                <Table cols={['Data', 'Motivo', 'Alvo', 'Créditos', 'Custo', 'Conta?']} align={{ 3: 'r', 4: 'r' }}
                  rows={creditos.map(c => [dataHora(c.created_at), <span className="text-text">{c.reason || <span className="text-muted italic">repasse s/ motivo</span>}</span>, <span className="num text-muted">{c.target_id || '—'}</span>, <span className="num">{num(c.amount)}</span>, <Money v={c.custo_brl} />, c.conta_como_custo ? <Badge tone="pos">sim</Badge> : <Badge>não</Badge>])}
                  empty="Nenhum consumo importado." />
              </Card>
            </div>
          )}

          {cur === 'saques' && (
            <Card pad="p-1.5" className="fade-in">
              <Table cols={['Data', 'Valor', 'Status', 'Comprovante']} align={{ 1: 'r' }}
                rows={saques.map(s => [dataHora(s.solicitado_em), <Money v={s.valor_brl} />, <Badge tone={s.status === 'pago' ? 'pos' : 'warn'}>{s.status}</Badge>, s.comprovante_url ? <a className="text-brand text-xs" href={s.comprovante_url} target="_blank">ver</a> : '—'])}
                empty="Nenhum saque solicitado." />
            </Card>
          )}

          {cur === 'despesas' && (
            <div className="grid md:grid-cols-3 gap-4 fade-in">
              <Card className="md:col-span-1 h-fit">
                <h3 className="head text-sm font-semibold text-bright mb-1">Lançar despesa</h3>
                <p className="text-xs text-muted mb-4">CNPJ, contas, custos da empresa. Desconta do saldo.</p>
                <Field label="VALOR (R$)"><input className="w-full px-3.5 py-2.5 num" placeholder="0,00" value={despForm.valor} onChange={e => setDespForm({ ...despForm, valor: e.target.value.replace(',', '.') })} /></Field>
                <Field label="DATA"><input type="date" className="w-full px-3.5 py-2.5 num" value={despForm.data} onChange={e => setDespForm({ ...despForm, data: e.target.value })} /></Field>
                <Field label="DESCRIÇÃO"><input className="w-full px-3.5 py-2.5" placeholder="ex: contador, conta de luz" value={despForm.descricao} onChange={e => setDespForm({ ...despForm, descricao: e.target.value })} /></Field>
                <Btn full onClick={lancarDespesa} disabled={!despForm.valor}>Lançar despesa</Btn>
              </Card>
              <div className="md:col-span-2 space-y-3">
                <Kpi label="Total de despesas" tone="neg" value={fmt(resumo.despesas || 0)} sub={`${despesas.length} lançamento(s) · descontado do saldo`} icon={icons.wallet} />
                <Card pad="p-1.5">
                  <Table cols={['Data', 'Descrição', 'Valor', '']} align={{ 2: 'r' }}
                    rows={despesas.map(d => [soDataStr(d.data), <span className="text-text">{d.descricao || '—'}</span>, <Money v={d.valor_brl} />, <button onClick={() => excluirDespesa(d.id)} className="text-muted hover:text-neg">{icons.trash}</button>])}
                    empty="Nenhuma despesa lançada." />
                </Card>
              </div>
            </div>
          )}

          {cur === 'config' && (
            <div className="grid md:grid-cols-2 gap-4 fade-in max-w-3xl">
              <Card>
                <h3 className="head text-base font-semibold text-bright">Fonte dos números (TheBest)</h3>
                <p className="text-sm text-muted mt-1 mb-5">De onde vêm receita e custo.</p>
                <Field label="CONTAR CRÉDITOS A PARTIR DE" hint="Créditos antes desta data não contam como custo.">
                  <input type="date" className="w-full px-3.5 py-2.5 num" value={cfgData} onChange={e => setCfgData(e.target.value)} />
                </Field>
                <Field label="ID DO USUÁRIO NO THEBEST" hint="Só o consumo deste usuário é contado. Em branco = sua própria conta.">
                  <input className="w-full px-3.5 py-2.5 num" placeholder="ex: 2054" value={cfgUser} onChange={e => setCfgUser(e.target.value)} />
                </Field>
                <Btn full onClick={salvarConfig} disabled={cfgSaving}>{cfgSaving ? 'Salvando…' : 'Salvar e sincronizar'}</Btn>
              </Card>
              <Card>
                <div className="flex items-center gap-2 mb-1">
                  <h3 className="head text-base font-semibold text-bright">Pagamentos automáticos</h3>
                  {temLiquid ? <Badge tone="pos">conectado</Badge> : <Badge tone="warn">não conectado</Badge>}
                </div>
                <p className="text-sm text-muted mt-1 mb-5">LiquidBR importa cada PIX na hora.</p>
                {temLiquid
                  ? <div className="text-sm text-soft p-3.5 rounded-lg bg-pos/8 border border-pos/25 flex items-center gap-2">{icons.check} Tudo certo. Os pagamentos entram sozinhos.</div>
                  : <LiquidBRConnect compact onDone={() => reload()} />}
              </Card>
            </div>
          )}
        </>
      )}
    </Shell>
  );
}
function HojeStat({ label, v, sub, tone }) {
  const col = tone === 'pos' ? 'text-pos' : tone === 'warn' ? 'text-warn' : 'text-bright';
  return (
    <div className="px-5 py-4">
      <div className="text-[11px] uppercase tracking-wider text-muted">{label}</div>
      <div className={cls('num text-2xl font-semibold mt-1', col)}>{v}</div>
      {sub && <div className="text-xs text-muted mt-0.5">{sub}</div>}
    </div>
  );
}
function ClienteRow({ l, full }) {
  const dias = l.dias_restantes;
  const tone = dias <= 0 ? 'neg' : dias <= 2 ? 'warn' : 'muted';
  const wa = waLink(l.phone, `Olá! Seu acesso vence ${dias <= 0 ? 'hoje' : 'em ' + dias + ' dia(s)'}. Quer renovar?`);
  return (
    <div className="flex items-center gap-3 px-5 py-2.5 hover:bg-panel2/50 transition-colors">
      <div className="min-w-0 flex-1">
        <div className="text-sm text-text truncate num">{l.username}</div>
        {full && l.phone && <div className="text-[11px] text-muted num">{l.phone}</div>}
      </div>
      <Badge tone={tone}>{dias <= 0 ? 'vence hoje' : `${dias}d`}</Badge>
      <div className="text-xs text-muted num w-14 text-right hidden sm:block">{soData(l.exp_date)}</div>
      {wa ? <a href={wa} target="_blank" className="text-pos hover:text-bright p-1.5 rounded-lg hover:bg-pos/10" title="Cobrar no WhatsApp">{icons.phone}</a>
          : <span className="w-7" />}
    </div>
  );
}

/* ============ Admin ============ */
function AdminApp({ me, onLogout }) {
  const [cur, setCur] = useState('overview');
  const [geral, setGeral] = useState(null);
  const [empresas, setEmpresas] = useState([]);
  const [saques, setSaques] = useState([]);
  const [msg, setMsg] = useState('');
  const [syncing, setSyncing] = useState(false);
  const [nova, setNova] = useState({ nome: '', email: '', senha: '', profit_share_pct: 50 });

  const toast = (m) => { setMsg(m); setTimeout(() => setMsg(''), 2600); };
  const load = useCallback(async () => {
    const [g, e, s] = await Promise.all([api('/admin/resumo-geral'), api('/admin/empresas'), api('/admin/saques')]);
    setGeral(g); setEmpresas(e); setSaques(s);
  }, []);
  useEffect(() => { load(); }, [load]);

  const sync = async () => { setSyncing(true); try { await api('/admin/sync', { method: 'POST' }); await load(); toast('Sincronizado.'); } finally { setSyncing(false); } };
  const criar = async () => {
    try { await api('/admin/empresas', { method: 'POST', body: nova }); setNova({ nome: '', email: '', senha: '', profit_share_pct: 50 }); await load(); setCur('empresas'); toast('Revenda criada.'); }
    catch (e) { toast(e.data?.error === 'email_ja_existe' ? 'E-mail já existe.' : 'Erro ao criar.'); }
  };
  const pagarSaque = async (id) => { const c = prompt('Link/observação do comprovante:') || ''; await api('/admin/saques/' + id + '/pagar', { method: 'POST', body: { comprovante_url: c } }); await load(); toast('Saque pago.'); };
  const lancarAds = async (id) => {
    const data = prompt('Data (AAAA-MM-DD):', hojeInput()); if (!data) return;
    const valor = prompt('Valor gasto em ads (R$):'); if (!valor) return;
    await api('/admin/empresas/' + id + '/ads', { method: 'POST', body: { data, valor: Number(valor), descricao: 'ads' } }); await load(); toast('Ads lançado.');
  };

  const pend = saques.filter(s => s.status === 'solicitado');
  const nav = [
    { key: 'overview', label: 'Visão geral', icon: icons.grid },
    { key: 'empresas', label: 'Revendas', icon: icons.users },
    { key: 'saques', label: 'Saques', icon: icons.cash, badge: pend.length || null },
    { key: 'nova', label: 'Nova revenda', icon: icons.plus },
  ];
  const titles = { overview: 'Visão geral', empresas: 'Revendas', saques: 'Fila de saques', nova: 'Nova revenda' };
  const actions = <Btn variant="ghost" size="sm" icon={<span className={syncing ? 'animate-spin' : ''}>{icons.sync}</span>} onClick={sync} disabled={syncing}>{syncing ? 'Sincronizando…' : 'Sincronizar tudo'}</Btn>;
  const setupBadge = (e) => e.is_owner ? <Badge tone="brand">minha (100%)</Badge> : e.onboarding_step >= 2 ? <Badge tone="pos">completo</Badge> : e.onboarding_step === 1 ? <Badge tone="warn">falta LiquidBR</Badge> : <Badge>pendente</Badge>;

  return (
    <Shell me={me} onLogout={onLogout} nav={nav} current={cur} setCurrent={setCur} title={titles[cur]}
      subtitle={geral ? `${geral.empresas} revendas · você vê tudo` : ''} actions={actions}>
      <Toast msg={msg} />
      {!geral ? <div className="grid md:grid-cols-4 gap-3">{[0,1,2,3].map(i => <Skeleton key={i} />)}</div> : (
        <>
          {cur === 'overview' && (
            <div className="space-y-5 fade-in">
              <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
                <Kpi accent label="Seu lucro (bolso)" big icon={icons.wallet} value={fmt(geral.parte_admin)} sub="100% da sua + 50% das outras" />
                <Kpi label="Receita total" icon={icons.card} value={fmt(geral.receita)} />
                <Kpi label="Custo créditos" icon={icons.coins} value={fmt(geral.custo_creditos)} />
                <Kpi label="Devido às revendas" tone="warn" icon={icons.cash} value={fmt(geral.saldo_devido_revendas)} />
              </div>
              <Card pad="p-0" className="overflow-hidden">
                <div className="flex items-center gap-2 px-5 pt-4 pb-1"><span className="w-1.5 h-1.5 rounded-full bg-pos animate-pulse" /><h3 className="head text-sm font-semibold text-bright">Hoje · todas as revendas</h3></div>
                <div className="grid grid-cols-3 divide-x divide-line/60 border-t border-line mt-2">
                  <HojeStat label="Pagamentos caíram" v={num(geral.pagamentos_hoje)} sub={fmt(geral.receita_hoje)} tone="pos" />
                  <HojeStat label="Clientes ativados" v={num(geral.ativacoes_hoje)} />
                  <HojeStat label="Lucro total (mês+)" v={fmtK(geral.lucro)} sub="acumulado" />
                </div>
              </Card>
              <Card pad="p-1.5">
                <div className="px-3.5 pt-3 pb-1 flex items-center justify-between">
                  <h3 className="head text-sm font-semibold text-bright">Revendas</h3>
                  <span className="text-xs text-muted num">{geral.empresas} ativas</span>
                </div>
                <Table cols={['Revenda', 'Setup', 'Receita', 'Custo', 'Lucro', 'Saldo revenda']} align={{ 2: 'r', 3: 'r', 4: 'r', 5: 'r' }}
                  rows={empresas.map(e => [<span className="text-bright font-medium">{e.nome}</span>, setupBadge(e), <Money v={e.resumo.receita_total} />, <Money v={e.resumo.custo_creditos} />, <Money v={e.resumo.lucro} />, <span className="num text-brand">{e.is_owner ? '—' : fmt(e.resumo.saldo_disponivel)}</span>])}
                  empty="Nenhuma revenda cadastrada." />
              </Card>
            </div>
          )}
          {cur === 'empresas' && (
            <Card pad="p-1.5" className="fade-in">
              <Table cols={['Revenda', 'TheBest', 'Setup', 'Receita', 'Créditos', 'Lucro', 'Saldo', 'Ads']} align={{ 3: 'r', 4: 'r', 5: 'r', 6: 'r' }}
                rows={empresas.map(e => [
                  <span className="text-bright font-medium">{e.nome}</span>,
                  <span className="num text-soft text-xs">{e.thebest_username || '—'}</span>,
                  setupBadge(e),
                  <Money v={e.resumo.receita_total} />, <Money v={e.resumo.custo_creditos} />, <Money v={e.resumo.lucro} />,
                  <span className="num text-brand">{e.is_owner ? '—' : fmt(e.resumo.saldo_disponivel)}</span>,
                  <Btn size="sm" variant="subtle" onClick={() => lancarAds(e.id)}>+ ads</Btn>,
                ])}
                empty="Nenhuma revenda cadastrada." />
            </Card>
          )}
          {cur === 'saques' && (
            <Card pad="p-1.5" className="fade-in">
              <Table cols={['Revenda', 'Valor', 'Solicitado', 'Status', '']} align={{ 1: 'r' }}
                rows={saques.map(s => [
                  <span className="text-bright font-medium">{s.empresa_nome}</span>, <Money v={s.valor_brl} />, dataHora(s.solicitado_em),
                  <Badge tone={s.status === 'pago' ? 'pos' : 'warn'}>{s.status}</Badge>,
                  s.status === 'solicitado' ? <Btn size="sm" onClick={() => pagarSaque(s.id)}>marcar pago</Btn> : (s.comprovante_url ? <span className="text-xs text-muted">comprovante ok</span> : ''),
                ])}
                empty="Nenhum saque na fila." />
            </Card>
          )}
          {cur === 'nova' && (
            <Card className="max-w-md fade-in">
              <h3 className="head text-base font-semibold text-bright">Cadastrar revenda (manual)</h3>
              <p className="text-sm text-muted mt-1 mb-5">Cria o login. A revenda conecta TheBest e LiquidBR no primeiro acesso. (Ou peça pra ela criar sozinha em “Criar conta”.)</p>
              {[['nome', 'Nome da revenda', 'text'], ['email', 'Login / e-mail', 'text'], ['senha', 'Senha', 'password']].map(([k, l, t]) => (
                <Field key={k} label={l.toUpperCase()}><input type={t} className="w-full px-3.5 py-2.5" value={nova[k]} onChange={e => setNova({ ...nova, [k]: e.target.value })} /></Field>
              ))}
              <Field label="% DO LUCRO DA REVENDA"><input type="number" className="w-full px-3.5 py-2.5 num" value={nova.profit_share_pct} onChange={e => setNova({ ...nova, profit_share_pct: Number(e.target.value) })} /></Field>
              <Btn full onClick={criar} disabled={!nova.nome || !nova.email || !nova.senha}>Criar revenda</Btn>
            </Card>
          )}
        </>
      )}
    </Shell>
  );
}

/* ============ Root ============ */
function App() {
  const [me, setMe] = useState(null);
  const [loading, setLoading] = useState(true);
  const [tick, setTick] = useState(0);

  const carregar = useCallback(async () => {
    if (!getToken()) { setMe(null); setLoading(false); return; }
    try { setMe(await api('/me')); } catch { setToken(null); setMe(null); } finally { setLoading(false); }
  }, []);
  useEffect(() => { carregar(); }, [carregar, tick]);
  const reload = () => setTick(t => t + 1);

  const logout = () => { setToken(null); setMe(null); };
  if (loading) return <div className="min-h-screen grid place-items-center text-muted text-sm">Carregando…</div>;
  if (!me) return <AuthScreen onAuthed={() => { setLoading(true); reload(); }} />;
  if (me.user.papel === 'admin') return <AdminApp me={me} onLogout={logout} />;
  if (me.empresa && !me.empresa.tem_thebest) return <Onboarding me={me} onDone={reload} />;
  return <RevendaApp me={me} onLogout={logout} reload={reload} />;
}

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