const { useState, useEffect, useCallback, useMemo, createContext, useContext } = React;

const ThemeCtx = createContext();

/* ===== LOCALSTORAGE + SERVER SYNC ===== */
function loadLS(key, fallback) { try { const v = localStorage.getItem("bg_" + key); return v ? JSON.parse(v) : fallback; } catch { return fallback; } }
function saveLS(key, val) {
  try { localStorage.setItem("bg_" + key, JSON.stringify(val)); } catch {}
  try { fetch("/api/store/" + key, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ value: val }) }); } catch {}
}
/* Load all keys from server on startup — SERVER ALWAYS WINS */
(function syncFromServer() {
  fetch("/api/store").then(r => r.json()).then(data => {
    Object.entries(data).forEach(([k, v]) => {
      try { localStorage.setItem("bg_" + k, JSON.stringify(v)); } catch {}
    });
    try { localStorage.setItem("bg_synced", Date.now().toString()); } catch {}
  }).catch(() => {});
})();

/* Hook: loads from server first, localStorage as instant fallback */
function useServerState(key, fallback) {
  const [val, setVal] = useState(() => loadLS(key, fallback));
  const [loaded, setLoaded] = useState(false);
  useEffect(() => {
    let cancelled = false;
    fetch("/api/store/" + key).then(r => r.json()).then(d => {
      if (cancelled) return;
      if (d && d.value !== undefined && d.value !== null) {
        setVal(d.value);
        try { localStorage.setItem("bg_" + key, JSON.stringify(d.value)); } catch {}
      }
      setLoaded(true);
    }).catch(() => { if (!cancelled) setLoaded(true); });
    return () => { cancelled = true; };
  }, []);
  const save = useCallback((newVal) => {
    setVal(newVal);
    saveLS(key, newVal);
  }, [key]);
  return [val, setVal, save, loaded];
}

/* ===== EMPTY SITES (will be filled from API) ===== */
const SITES_BASE = [];
const ALL_SITES = [];
function filterSite(site, from, to) {
  if (!site.daily) return { name: site.name || site.url, imp: site.imp || 0, rev: site.rev || 0, spend: site.spend || 0, leads: site.leads || 0, ecpm: 0 };
  const f = site.daily.filter(d => d.date >= from && d.date <= to);
  const imp = f.reduce((a, d) => a + d.imp, 0), rev = f.reduce((a, d) => a + d.rev, 0), spend = f.reduce((a, d) => a + d.spend, 0), leads = f.reduce((a, d) => a + d.leads, 0);
  return { name: site.name, imp, rev, spend, leads, ecpm: imp > 0 ? (rev / imp) * 1000 : 0 };
}

/* ===== SAVE BUTTON COMPONENT ===== */
function SaveBar({ storageKey, data, mob }) {
  const [saved, setSaved] = useState(false);
  const doSave = () => { saveLS(storageKey, data); setSaved(true); setTimeout(() => window.location.reload(), 1000); };
  return (
    <div style={{ position: "sticky", bottom: 0, padding: "12px 16px", background: C.card, borderTop: "1px solid " + C.bdr, borderRadius: "12px 12px 0 0", display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 16, zIndex: 10 }}>
      <span style={{ fontSize: 12, color: saved ? C.grn : C.mut, fontWeight: saved ? 600 : 400 }}>{saved ? "✓ Alterações salvas" : "Alterações não salvas"}</span>
      <Btn onClick={doSave} color={C.grn}>{saved ? "✓ Salvo!" : "💾 Salvar alterações"}</Btn>
    </div>
  );
}

/* ===== UTILS ===== */
function $(v, t) {
  const x = Number(v);
  if (t === "usd") return "$" + x.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  if (t === "int") return x.toLocaleString("en-US");
  if (t === "pct") return x.toFixed(2) + "%";
  return String(x);
}
function useIsMobile() {
  const [m, setM] = useState(typeof window !== "undefined" ? window.innerWidth < 768 : false);
  useEffect(() => { const h = () => setM(window.innerWidth < 768); window.addEventListener("resize", h); return () => window.removeEventListener("resize", h); }, []);
  return m;
}

/* ===== THEME ===== */
const C = { bg: "#080d1a", sb: "#0b1225", card: "#0f1a30", bdr: "rgba(30,48,80,0.45)", mut: "#4a5e78", txt: "#b0bfd0", br: "#e4eaf0", grn: "#2ecc71", blu: "#2b7ec9", pill: "#2478b5", red: "#e74c3c", yel: "#f39c12", cyan: "#5dade2" };

/* ===== UI COMPONENTS ===== */
function KPI({ label, value, color, mob }) {
  return <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 10, padding: mob ? "10px 12px" : "16px 20px" }}>
    <div style={{ fontSize: mob ? 9 : 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, marginBottom: mob ? 3 : 7, fontWeight: 600, lineHeight: 1.2 }}>{label}</div>
    <div style={{ fontSize: mob ? 18 : 22, fontWeight: 700, color: color || C.br, fontVariantNumeric: "tabular-nums", wordBreak: "break-all", lineHeight: 1.2 }}>{value}</div>
  </div>;
}
function Sec({ icon, label, count, open: dO, children, badge }) {
  const [open, setOpen] = useState(dO ?? false);
  return <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 12, marginBottom: 12 }}>
    <div onClick={() => setOpen(!open)} style={{ display: "flex", alignItems: "center", gap: 8, padding: "12px 16px", cursor: "pointer", userSelect: "none", flexWrap: "wrap" }}>
      <span style={{ color: C.mut, fontSize: 9, transform: open ? "rotate(0)" : "rotate(-90deg)", transition: "transform 0.2s" }}>▼</span>
      <span style={{ fontSize: 14 }}>{icon}</span>
      <span style={{ fontWeight: 700, fontSize: 14, color: C.br }}>{label}</span>
      {count !== undefined && <span style={{ color: C.mut, fontSize: 13 }}>({count})</span>}
      {badge && <span style={{ fontSize: 10, padding: "2px 8px", borderRadius: 10, background: badge.bg, color: badge.c, fontWeight: 600, marginLeft: "auto" }}>{badge.t}</span>}
    </div>
    {open && <div style={{ padding: "0 16px 14px" }}>{children}</div>}
  </div>;
}
function Btn({ children, onClick, color, disabled, small }) {
  return <button onClick={onClick} disabled={disabled} style={{ padding: small ? "5px 12px" : "7px 16px", borderRadius: 8, border: "none", background: disabled ? "rgba(30,48,80,0.4)" : (color || C.blu), color: "#fff", fontSize: 12, fontWeight: 700, cursor: disabled ? "wait" : "pointer", opacity: disabled ? 0.6 : 1, whiteSpace: "nowrap" }}>{children}</button>;
}
function Inp({ label, value, onChange, placeholder, pw, disabled, help, mob }) {
  return <div style={{ marginBottom: 8 }}>
    <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 2 }}>
      <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>{label}</span>
      {help && !mob && <span style={{ fontSize: 9, color: C.mut }}>{help}</span>}
    </div>
    <input type={pw ? "password" : "text"} value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder} disabled={disabled}
      style={{ width: "100%", padding: "7px 11px", borderRadius: 8, border: `1px solid ${disabled ? C.grn + "40" : C.bdr}`, background: disabled ? "rgba(46,204,113,0.05)" : "rgba(8,13,26,0.8)", color: C.br, fontSize: 12, outline: "none", boxSizing: "border-box", fontFamily: "monospace" }} />
  </div>;
}
function SDot({ s }) { return <span style={{ width: 8, height: 8, borderRadius: "50%", background: { connected: C.grn, disconnected: C.mut, testing: C.blu, error: C.red }[s], display: "inline-block", flexShrink: 0 }} />; }
function STag({ s }) {
  const l = { connected: "Conectado", disconnected: "Pendente", testing: "Testando...", error: "Erro" };
  const c = { connected: C.grn, disconnected: C.mut, testing: C.blu, error: C.red };
  return <span style={{ fontSize: 10, padding: "2px 8px", borderRadius: 10, background: `${c[s]}20`, color: c[s], fontWeight: 600 }}>{l[s]}</span>;
}
function MobCard({ title, rows, dot }) {
  return <div style={{ background: "rgba(8,13,26,0.4)", border: `1px solid ${C.bdr}`, borderRadius: 10, padding: "12px 14px", marginBottom: 8 }}>
    <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }}>
      {dot && <span style={{ width: 7, height: 7, borderRadius: "50%", background: dot, flexShrink: 0 }} />}
      <span style={{ color: C.cyan, fontFamily: "monospace", fontSize: 12, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{title}</span>
    </div>
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "4px 12px", fontSize: 12 }}>
      {rows.map((r, i) => <div key={i} style={{ display: "flex", justifyContent: "space-between" }}><span style={{ color: C.mut }}>{r.l}</span><span style={{ color: r.c || C.br, fontWeight: r.b ? 600 : 400 }}>{r.v}</span></div>)}
    </div>
  </div>;
}
function TH({ cols }) {
  return <div style={{ display: "flex", justifyContent: "space-between", padding: "0 0 6px", borderBottom: `1px solid ${C.bdr}`, marginBottom: 2, fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1 }}>
    <span style={{ flex: 1 }}>{cols[0]}</span>
    <div style={{ display: "flex", gap: 6 }}>{cols.slice(1).map((c, i) => <span key={i} style={{ minWidth: c.w, textAlign: "right" }}>{c.l}</span>)}</div>
  </div>;
}
function DR({ left, cells, last, dot }) {
  return <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "9px 0", borderBottom: last ? "none" : `1px solid ${C.bdr}`, fontSize: 13 }}>
    <div style={{ display: "flex", alignItems: "center", gap: 8, flex: 1, minWidth: 0 }}>
      {dot && <span style={{ width: 7, height: 7, borderRadius: "50%", background: dot, flexShrink: 0 }} />}
      <span style={{ color: C.cyan, fontFamily: "monospace", fontSize: 12, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{left}</span>
    </div>
    <div style={{ display: "flex", gap: 6 }}>{cells}</div>
  </div>;
}
function Cl({ val, w, color, bold }) { return <span style={{ minWidth: w, textAlign: "right", color: color || C.txt, fontWeight: bold ? 600 : 400 }}>{val}</span>; }
function InfoBox({ children }) { return <div style={{ padding: "12px 16px", marginTop: 12, background: "rgba(43,126,201,0.08)", borderRadius: 10, border: "1px solid rgba(43,126,201,0.2)", fontSize: 12, color: C.txt, lineHeight: 1.6 }}>{children}</div>; }

/* ========================================= */
/* ===== PAGE: AD MANAGERS (GAM/AdX) ======= */
/* ========================================= */
function PgAdManagers({ mob }) {
  const [items, setItems, saveItems] = useServerState("admanagers", [
    { id: 1, name: "GAM Lumora Principal", type: "gam", status: "disconnected", fields: { networkCode: "", serviceEmail: "", jsonKey: "" } },
    { id: 2, name: "GAM Lumora Finanças", type: "gam", status: "disconnected", fields: { networkCode: "", serviceEmail: "", jsonKey: "" } },
    { id: 3, name: "SendWebPush (AdX)", type: "adx", status: "disconnected", fields: { apiToken: "" } },
    { id: 4, name: "ActiveView (AdX)", type: "activeview", status: "disconnected", fields: { apiKey: "", networkCode: "", domains: "" } },
  ]);
  const [showAdd, setShowAdd] = useState(false);
  const [newName, setNewName] = useState("");
  const [newType, setNewType] = useState("gam");

  const upd = (id, field, val) => setItems(p => p.map(i => i.id === id ? { ...i, fields: { ...i.fields, [field]: val } } : i));
  const updStatus = (id, s) => setItems(p => {
    const updated = p.map(i => i.id === id ? { ...i, status: s } : i);
    saveLS("admanagers", updated);
    return updated;
  });

  const test = async (id) => {
    updStatus(id, "testing");
    await new Promise(r => setTimeout(r, 2200));
    const item = items.find(i => i.id === id);
    const filled = Object.values(item.fields).every(v => v.trim() !== "");
    updStatus(id, filled ? "connected" : "error");
  };

  const add = () => {
    if (!newName.trim()) return;
    const fields = newType === "gam" ? { networkCode: "", serviceEmail: "", jsonKey: "" } : newType === "activeview" ? { apiKey: "", networkCode: "", domains: "" } : { apiToken: "" };
    setItems(p => [...p, { id: Date.now(), name: newName, type: newType, status: "disconnected", fields }]);
    setNewName(""); setShowAdd(false);
  };

  const remove = (id) => setItems(p => p.filter(i => i.id !== id));

  const gamCount = items.filter(i => i.type === "gam").length;
  const adxCount = items.filter(i => i.type === "adx").length;
  const avCount = items.filter(i => i.type === "activeview").length;
  const connCount = items.filter(i => i.status === "connected").length;

  const GAM_FIELDS = [
    { key: "networkCode", label: "Network Code", placeholder: "12345678", help: "GAM → URL: admanager.google.com/XXXXX" },
    { key: "serviceEmail", label: "Service Account Email", placeholder: "name@project.iam.gserviceaccount.com", help: "Google Cloud Console → IAM → Service Accounts" },
    { key: "jsonKey", label: "JSON Key (Service Account)", placeholder: "Contenido del archivo .json descargado", help: "Service Account → Keys → Add Key → JSON", pw: true },
  ];

  const ADX_FIELDS = [
    { key: "apiToken", label: "Token API", placeholder: "Cole aqui o token gerado no painel SendWebPush", help: "SendWebPush → Dashboard → API → Token API", pw: true },
  ];

  const AV_FIELDS = [
    { key: "apiKey", label: "API Key", placeholder: "Cole aqui a API Key do ActiveView", help: "ActiveView → Settings → API Keys", pw: true },
    { key: "networkCode", label: "Network Code GAM", placeholder: "22995235769", help: "Código da rede GAM associada ao ActiveView" },
    { key: "domains", label: "Domínios (separados por vírgula)", placeholder: "sevenhora.com, centrocurioso.com", help: "Domínios configurados no ActiveView" },
  ];

  return <>
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(5,1fr)", gap: 8, marginBottom: 14 }}>
      <KPI label="Total" value={items.length} mob={mob} />
      <KPI label="GAM" value={gamCount} mob={mob} />
      <KPI label="SWP (AdX)" value={adxCount} mob={mob} />
      <KPI label="ActiveView" value={avCount} color={C.grn} mob={mob} />
      <KPI label="Conectados" value={`${connCount}/${items.length}`} color={connCount === items.length ? C.grn : C.yel} mob={mob} />
    </div>

    {items.map(item => {
      const fields = item.type === "gam" ? GAM_FIELDS : item.type === "activeview" ? AV_FIELDS : ADX_FIELDS;
      const typeLabel = item.type === "gam" ? "Google Ad Manager" : item.type === "activeview" ? "ActiveView (AdX)" : "SendWebPush (AdX)";
      const typeColor = item.type === "gam" ? C.blu : item.type === "activeview" ? "#2ecc71" : "#3b82f6";
      const typeIcon = item.type === "gam" ? "📡" : item.type === "activeview" ? "🔶" : "⚡";

      return (
        <Sec key={item.id} icon={item.status === "connected" ? "🟢" : item.status === "error" ? "🔴" : "⚪"} label={item.name} open={true}
          badge={{ t: item.status === "connected" ? "Conectado ✓" : item.status === "error" ? "Erro" : "Pendente", bg: `${({ connected: C.grn, error: C.red, disconnected: C.mut, testing: C.blu })[item.status]}20`, c: ({ connected: C.grn, error: C.red, disconnected: C.mut, testing: C.blu })[item.status] }}>

          {/* Type badge */}
          <div style={{ marginBottom: 14 }}>
            <span style={{ fontSize: 11, padding: "4px 12px", borderRadius: 8, background: `${typeColor}15`, border: `1px solid ${typeColor}30`, color: typeColor, fontWeight: 600 }}>
              {typeIcon} {typeLabel}
            </span>
          </div>

          {/* Credential fields */}
          {fields.map(f => (
            <Inp key={f.key} label={f.label} value={item.fields[f.key]} onChange={v => upd(item.id, f.key, v)} placeholder={f.placeholder} help={f.help} pw={f.pw} disabled={item.status === "connected"} mob={mob} />
          ))}

          {/* Actions */}
          <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 4 }}>
            {item.status !== "connected" && (
              <Btn onClick={() => test(item.id)} disabled={item.status === "testing"} color={C.grn} small>
                {item.status === "testing" ? "⏳ Testando conexão..." : "⚡ Testar conexão"}
              </Btn>
            )}
            {item.status === "connected" && <>
              <Btn onClick={() => test(item.id)} color={C.blu} small>↻ Re-testar</Btn>
              <Btn onClick={() => updStatus(item.id, "disconnected")} color="rgba(243,156,18,0.3)" small>Desconectar</Btn>
            </>}
            <Btn onClick={() => remove(item.id)} color="rgba(231,76,60,0.15)" small>Remover</Btn>
            {item.status === "error" && <span style={{ fontSize: 11, color: C.red, alignSelf: "center" }}>Verifique as credenciais</span>}
          </div>
        </Sec>
      );
    })}

    {/* Add new */}
    {showAdd ? (
      <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 12, padding: 16, marginBottom: 12 }}>
        <div style={{ fontSize: 13, fontWeight: 600, color: C.br, marginBottom: 10 }}>Novo Ad Manager</div>
        <Inp label="Nome" value={newName} onChange={v => setNewName(v)} placeholder="Ex: GAM Lumora 03 ou AdX SenWeb" mob={mob} />
        <div style={{ marginBottom: 10 }}>
          <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 6 }}>Tipo de conexão</span>
          <div style={{ display: "flex", gap: 8 }}>
            {[{ k: "gam", l: "📡 Google Ad Manager (GAM)", c: C.blu }, { k: "adx", l: "🔵 SendWebPush (AdX)", c: "#3b82f6" }, { k: "activeview", l: "🟢 ActiveView (AdX)", c: C.grn }].map(t => (
              <span key={t.k} onClick={() => setNewType(t.k)} style={{
                fontSize: 12, padding: "8px 16px", borderRadius: 8, cursor: "pointer",
                background: newType === t.k ? `${t.c}20` : "rgba(8,13,26,0.5)",
                border: `1px solid ${newType === t.k ? t.c : C.bdr}`,
                color: newType === t.k ? t.c : C.mut,
                fontWeight: newType === t.k ? 600 : 400,
              }}>{t.l}</span>
            ))}
          </div>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <Btn onClick={add} color={C.grn} small>Criar</Btn>
          <Btn onClick={() => setShowAdd(false)} color="rgba(30,48,80,0.6)" small>Cancelar</Btn>
        </div>
      </div>
    ) : (
      <div style={{ textAlign: "center", paddingTop: 4 }}>
        <Btn onClick={() => setShowAdd(true)} color={C.blu} small>+ Novo Ad Manager</Btn>
      </div>
    )}

    <InfoBox>
      <span style={{ fontWeight: 600, color: C.blu }}>GAM:</span> Crie um Service Account no Google Cloud Console, habilite a Ad Manager API, adicione o email como usuário no GAM (Admin → Users).
      <br /><br /><span style={{ fontWeight: 600, color: "#3b82f6" }}>SendWebPush (AdX):</span> Gere o Token API no painel (Dashboard → API). Base URL: <span style={{ fontFamily: "monospace", fontSize: 11 }}>https://sendwebpush.com/api/client/</span>
      <br />Endpoints disponíveis:
      <br />• <span style={{ fontFamily: "monospace", fontSize: 11 }}>/domain</span> — Listagem dos domínios (GET)
      <br />• <span style={{ fontFamily: "monospace", fontSize: 11 }}>/report</span> — Relatórios: revenue, impressions, ecpm, clicks, ctr (GET)
      <br />• <span style={{ fontFamily: "monospace", fontSize: 11 }}>/policies</span> — URLs com violações de políticas (GET)
      <br /><br /><span style={{ fontWeight: 600, color: C.grn }}>ActiveView (AdX):</span> API Key disponível no painel ActiveView. Revenue em micros (÷1.000.000). Suporta dimensão HOUR para dados mais frescos.
      <br />• <span style={{ fontFamily: "monospace", fontSize: 11 }}>/report/:NC/:DOMAIN</span> — Revenue por domínio (GET)
      <br />• <span style={{ fontFamily: "monospace", fontSize: 11 }}>/report/gam/custom/:NC/:DOMAIN</span> — Relatório custom com DATE, HOUR (GET)
    </InfoBox>
    <SaveBar storageKey="admanagers" data={items} mob={mob} />
  </>;
}

/* ========================================= */
/* ========================================= */
/* ===== PAGE: BMs FACEBOOK ================ */
/* ========================================= */
function PgBMs({ mob }) {
  const [bms, setBms, saveBms] = useServerState("bms", [
    { id: 1, name: "BM Lumora 01", bmId: "123456789", accessToken: "", tokenType: "", adAccounts: [
      { id: "act_111111", name: "Saúde - Messenger" }, { id: "act_222222", name: "Saúde - Remarketing" },
    ], status: "disconnected" },
    { id: 2, name: "BM Lumora 02", bmId: "234567890", accessToken: "", tokenType: "", adAccounts: [
      { id: "act_333333", name: "Receitas - Messenger" },
    ], status: "disconnected" },
    { id: 3, name: "BM Lumora 03", bmId: "345678901", accessToken: "", tokenType: "", adAccounts: [
      { id: "act_444444", name: "Lifestyle" }, { id: "act_555555", name: "Pets" },
    ], status: "disconnected" },
    { id: 4, name: "BM Finanças 01", bmId: "456789012", accessToken: "", tokenType: "", adAccounts: [
      { id: "act_666666", name: "Investimentos" },
    ], status: "disconnected" },
    { id: 5, name: "BM Finanças 02", bmId: "567890123", accessToken: "", tokenType: "", adAccounts: [
      { id: "act_777777", name: "Crédito" }, { id: "act_888888", name: "Crédito LAL" },
    ], status: "disconnected" },
    { id: 6, name: "BM Receitas", bmId: "678901234", accessToken: "", tokenType: "", adAccounts: [
      { id: "act_999999", name: "Receitas Fit" },
    ], status: "disconnected" },
  ]);
  const [showAdd, setShowAdd] = useState(false);
  const [newName, setNewName] = useState("");
  const [newBmId, setNewBmId] = useState("");
  const [showGuide, setShowGuide] = useState({});

  const upd = (id, f, v) => setBms(p => p.map(b => b.id === id ? { ...b, [f]: v } : b));
  const test = async (id) => {
    upd(id, "status", "testing");
    var b = bms.find(b => b.id === id);
    if (!b || !b.accessToken) { upd(id, "status", "error"); return; }
    try {
      var res = await fetch("/api/facebook/adaccounts/" + b.bmId, { headers: { "x-fb-token": b.accessToken } });
      var data = await res.json();
      if (data && data.data && Array.isArray(data.data)) {
        var accounts = data.data.map(function(a) { return { id: a.account_id, name: a.name, status: a.account_status }; });
        setBms(function(p) { return p.map(function(x) { return x.id === id ? { ...x, adAccounts: accounts, status: "connected", tokenDate: x.tokenDate || new Date().toISOString() } : x; }); });
      } else {
        upd(id, "status", "error");
      }
    } catch (e) {
      upd(id, "status", "error");
    }
  };
  const add = () => {
    if (!newName.trim()) return;
    setBms(p => [...p, { id: Date.now(), name: newName, bmId: newBmId, accessToken: "", tokenType: "", adAccounts: [], status: "disconnected" }]);
    setNewName(""); setNewBmId(""); setShowAdd(false);
  };

  const conn = bms.filter(b => b.status === "connected").length;
  const totalActs = bms.reduce((a, b) => a + b.adAccounts.length, 0);

  const GUIDE_QUICK = [
    "Acesse developers.facebook.com com sua conta do Facebook",
    "My Apps → selecione sua App (ou crie uma nova em Facebook Apps)",
    "Menu lateral → Marketing API → Tools",
    "Em Token Permissions marque: ads_read + ads_management",
    "Clique Get Token — copie o token gerado",
    "Cole o token no campo abaixo e clique Conectar",
  ];
  const GUIDE_PRO = [
    "Acesse business.facebook.com → Configurações do Negócio",
    "Usuários → Usuários do Sistema → + Adicionar",
    "Crie um System User (ex: 'Lumora360 API'), função: Admin",
    "Selecione o System User → Adicionar Ativos → suas Contas de Anúncio",
    "Dê permissão Gerenciar campanhas em cada conta",
    "Vá em Contas → Apps → + Adicionar → cole o App ID da sua Facebook App",
    "Volte em Usuários do Sistema → selecione o user → Gerar Token",
    "Selecione a App → marque ads_read + ads_management → Gerar",
    "Copie o token (NÃO EXPIRA) e cole no campo abaixo",
  ];

  return <>
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(4,1fr)", gap: 8, marginBottom: 14 }}>
      <KPI label="Business Managers" value={bms.length} mob={mob} />
      <KPI label="Conectados" value={`${conn}/${bms.length}`} color={conn === bms.length ? C.grn : C.yel} mob={mob} />
      <KPI label="Contas de anúncio" value={totalActs} mob={mob} />
      <KPI label="Dados trackeados" value="Spend, Leads, CPL" color={C.cyan} mob={mob} />
    </div>

    {bms.map(b => (
      <Sec key={b.id} icon={b.status === "connected" ? "🟢" : b.status === "error" ? "🔴" : "⚪"} label={b.name} count={`${b.adAccounts.length} contas`} open={true}
        badge={{ t: b.status === "connected" ? (b.tokenType === "system" ? "Permanente ✓" : (b.tokenDate ? (function() { var dl = 60 - Math.floor((Date.now() - new Date(b.tokenDate).getTime()) / 86400000); return dl <= 0 ? "EXPIRADO" : dl + " días"; })() : "60 días")) : b.status === "error" ? "Erro" : "Pendente", bg: (b.status === "connected" && b.tokenType !== "system" && b.tokenDate && (60 - Math.floor((Date.now() - new Date(b.tokenDate).getTime()) / 86400000)) <= 10) ? C.red + "20" : "rgba(" + (b.status === "connected" ? "46,204,113" : b.status === "error" ? "231,76,60" : "100,116,139") + ",0.12)", c: (b.status === "connected" && b.tokenType !== "system" && b.tokenDate && (60 - Math.floor((Date.now() - new Date(b.tokenDate).getTime()) / 86400000)) <= 10) ? C.red : ({ connected: C.grn, error: C.red, disconnected: C.mut, testing: C.blu })[b.status] }}>

        <div style={{ fontSize: 12, color: C.mut, marginBottom: 10 }}>
          BM ID: <span style={{ fontFamily: "monospace", color: C.txt }}>{b.bmId}</span>
        </div>

        {/* Token type */}
        {b.status !== "connected" && (
          <div style={{ marginBottom: 10 }}>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 6 }}>Método de conexão</span>
            <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
              {[{ k: "user", l: "⚡ Rápido — User Token (60 dias)", c: C.yel }, { k: "system", l: "🔒 Produção — System User (não expira)", c: C.grn }].map(t => (
                <span key={t.k} onClick={() => upd(b.id, "tokenType", t.k)} style={{ fontSize: 12, padding: "6px 14px", borderRadius: 8, cursor: "pointer", background: b.tokenType === t.k ? `${t.c}20` : "rgba(8,13,26,0.5)", border: `1px solid ${b.tokenType === t.k ? t.c : C.bdr}`, color: b.tokenType === t.k ? t.c : C.mut, fontWeight: b.tokenType === t.k ? 600 : 400 }}>{t.l}</span>
              ))}
            </div>
          </div>
        )}

        {/* Guide */}
        {b.tokenType && b.status !== "connected" && (
          <div style={{ marginBottom: 12 }}>
            <div onClick={() => setShowGuide(p => ({ ...p, [b.id]: !p[b.id] }))} style={{ display: "flex", alignItems: "center", gap: 6, cursor: "pointer", fontSize: 12, color: C.blu, fontWeight: 600 }}>
              <span style={{ transform: showGuide[b.id] ? "rotate(90deg)" : "rotate(0)", transition: "transform 0.2s" }}>▶</span>
              Passo a passo: {b.tokenType === "user" ? "User Token" : "System User Token"}
            </div>
            {showGuide[b.id] && (
              <div style={{ padding: "10px 12px", marginTop: 8, background: "rgba(8,13,26,0.5)", borderRadius: 8, border: `1px solid ${C.bdr}` }}>
                {(b.tokenType === "user" ? GUIDE_QUICK : GUIDE_PRO).map((step, i, arr) => (
                  <div key={i} style={{ display: "flex", gap: 10, padding: "7px 0", borderBottom: i < arr.length - 1 ? `1px solid ${C.bdr}` : "none", fontSize: 12 }}>
                    <span style={{ width: 22, height: 22, borderRadius: "50%", background: "rgba(43,126,201,0.2)", color: C.blu, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 10, fontWeight: 700, flexShrink: 0 }}>{i + 1}</span>
                    <span style={{ color: C.txt }}>{step}</span>
                  </div>
                ))}
                <div style={{ marginTop: 8, padding: "8px 10px", borderRadius: 6, fontSize: 11, background: b.tokenType === "system" ? "rgba(46,204,113,0.08)" : "rgba(243,156,18,0.08)", border: `1px solid ${b.tokenType === "system" ? "rgba(46,204,113,0.2)" : "rgba(243,156,18,0.2)"}`, color: b.tokenType === "system" ? C.grn : C.yel }}>
                  {b.tokenType === "system" ? "Recomendado: o System User Token não expira e não depende do seu login pessoal." : "O User Token expira em 60 dias. Para produção, use System User Token."}
                </div>
              </div>
            )}
          </div>
        )}

        {/* Token field */}
        <Inp label={b.tokenType === "system" ? "System User Access Token (permanente)" : "Access Token"} value={b.accessToken} onChange={v => upd(b.id, "accessToken", v)}
          placeholder={b.tokenType === "system" ? "Token gerado no BM → Usuários do Sistema (não expira)" : "EAAKw... (developers.facebook.com → Marketing API → Tools)"} pw disabled={b.status === "connected"} mob={mob} />

        {/* Ad accounts */}
        <div style={{ marginBottom: 12 }}>
          <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 6 }}>Contas de anúncio vinculadas</span>
          {b.adAccounts.length > 0 ? b.adAccounts.map((ac, i) => (
            <div key={i} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 10px", marginBottom: 4, borderRadius: 8, background: "rgba(8,13,26,0.4)", border: `1px solid ${C.bdr}` }}>
              <SDot s="connected" />
              <span style={{ fontFamily: "monospace", fontSize: 12, color: C.cyan }}>{ac.id}</span>
              <span style={{ fontSize: 12, color: C.txt }}>{ac.name}</span>
            </div>
          )) : <div style={{ fontSize: 12, color: C.mut, padding: "8px 10px", background: "rgba(8,13,26,0.3)", borderRadius: 8 }}>Detectado automaticamente ao conectar</div>}
        </div>

        {/* Actions */}
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {b.status !== "connected" && <Btn onClick={() => test(b.id)} disabled={b.status === "testing" || !b.accessToken} color={C.grn} small>{b.status === "testing" ? "⏳ Verificando token..." : "⚡ Conectar"}</Btn>}
          {b.status === "connected" && <><Btn onClick={() => test(b.id)} color={C.blu} small>↻ Re-testar</Btn><Btn onClick={() => upd(b.id, "status", "disconnected")} color="rgba(243,156,18,0.3)" small>Desconectar</Btn></>}
          <Btn onClick={() => setBms(p => p.filter(x => x.id !== b.id))} color="rgba(231,76,60,0.15)" small>Remover</Btn>
          {b.status === "error" && <span style={{ fontSize: 11, color: C.red, alignSelf: "center" }}>Token inválido ou sem permissão</span>}
        </div>
      </Sec>
    ))}

    {showAdd ? (
      <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 12, padding: 16, marginBottom: 12 }}>
        <div style={{ fontSize: 13, fontWeight: 600, color: C.br, marginBottom: 10 }}>Novo Business Manager</div>
        <Inp label="Nome do BM" value={newName} onChange={v => setNewName(v)} placeholder="Ex: BM Lumora 04" mob={mob} />
        <Inp label="BM ID" value={newBmId} onChange={v => setNewBmId(v)} placeholder="business.facebook.com → Configurações → ID do Negócio" mob={mob} />
        <div style={{ display: "flex", gap: 8 }}><Btn onClick={add} color={C.grn} small>Criar</Btn><Btn onClick={() => setShowAdd(false)} color="rgba(30,48,80,0.6)" small>Cancelar</Btn></div>
      </div>
    ) : <div style={{ textAlign: "center", paddingTop: 4 }}><Btn onClick={() => setShowAdd(true)} color={C.blu} small>+ Novo BM</Btn></div>}

    <InfoBox>
      <span style={{ fontWeight: 600, color: "#3b82f6" }}>Conexão:</span> Cada BM precisa de um Access Token com permissões <span style={{ fontFamily: "monospace", fontSize: 11 }}>ads_read</span> + <span style={{ fontFamily: "monospace", fontSize: 11 }}>ads_management</span>.
      <br />⚡ <span style={{ color: C.yel, fontWeight: 600 }}>Rápido:</span> developers.facebook.com → Marketing API → Tools → Get Token (expira 60 dias)
      <br />🔒 <span style={{ color: C.grn, fontWeight: 600 }}>Produção:</span> business.facebook.com → Usuários do Sistema → Gerar Token (não expira)
      <br /><br />O backend usa <span style={{ fontFamily: "monospace", fontSize: 11 }}>GET /act_ID/insights</span> para puxar: spend, leads, campanhas, ad sets, CPL, CPC, CTR por conta.
    </InfoBox>
    <SaveBar storageKey="bms" data={bms} mob={mob} />
  </>;
}

/* ========================================= */
/* ===== PAGE: OPERAÇÕES (PROJETOS) ======== */
/* ========================================= */
function PgOperacoes({ mob }) {
  const [gamOptionsList, setGamOptionsList] = useState([]);
  const [bmOptionsList, setBmOptionsList] = useState([]);
  useEffect(() => {
    const localGam = loadLS("admanagers", []);
    const localBm = loadLS("bms", []);
    if (localGam.length > 0) setGamOptionsList(localGam.map((i, idx) => ({ id: i.id || idx + 1, name: i.name })));
    if (localBm.length > 0) setBmOptionsList(localBm.map((b, idx) => ({ id: b.id || idx + 1, name: b.name })));
    fetch("/api/store/admanagers").then(r => r.json()).then(d => { if (d && d.value && Array.isArray(d.value)) setGamOptionsList(d.value.map((i, idx) => ({ id: i.id || idx + 1, name: i.name }))); }).catch(() => {});
    fetch("/api/store/bms").then(r => r.json()).then(d => { if (d && d.value && Array.isArray(d.value)) setBmOptionsList(d.value.map((b, idx) => ({ id: b.id || idx + 1, name: b.name }))); }).catch(() => {});
  }, []);
  const gamOptions = gamOptionsList;
  const bmOptions = bmOptionsList;

  const [projects, setProjects, saveProjects] = useServerState("operacoes", [
    { id: 1, name: "Projeto Saúde", gam: 1, bms: [1, 2], sites: ["saudevital.com", "bemestar.net", "dicasdemae.com"], status: "active" },
    { id: 2, name: "Projeto Finanças", gam: 2, bms: [4, 5], sites: ["financasfacil.com", "investehoje.com.br"], status: "active" },
    { id: 3, name: "Projeto Receitas", gam: 1, bms: [6], sites: ["receitasdavovo.com", "cozinhafacil.net"], status: "active" },
    { id: 4, name: "Projeto Tech", gam: 2, bms: [3], sites: ["techreview.com.br"], status: "paused" },
  ]);
  const [showAdd, setShowAdd] = useState(false);
  const [editing, setEditing] = useState(null);
  const [form, setForm] = useState({ name: "", gam: 1, bms: [], sites: [], adAccounts: [], status: "active" });
  const [swpDomains, setSwpDomains] = useState([]);
  const [avDomains, setAvDomains] = useState([]);
  const [adAccountOptions, setAdAccountOptions] = useState([]);
  useEffect(() => {
    fetch("/api/sendwebpush/domain").then(r => r.json()).then(d => { if (Array.isArray(d)) setSwpDomains(d.filter(x => x.url !== "redce.xyz").map(x => x.url)); }).catch(() => {});
    fetch("/api/store/admanagers").then(r => r.json()).then(d => {
      if (d && d.value && Array.isArray(d.value)) {
        var avItem = d.value.find(i => i.type === "activeview" && i.fields && i.fields.domains);
        if (avItem) setAvDomains(avItem.fields.domains.split(",").map(s => s.trim()).filter(Boolean));
      }
    }).catch(() => {});
    // Load ad accounts from connected BMs
    fetch("/api/store/bms").then(r => r.json()).then(d => {
      if (d && d.value && Array.isArray(d.value)) {
        var allAccounts = [];
        d.value.forEach(function(b) {
          if (b.adAccounts && Array.isArray(b.adAccounts)) {
            b.adAccounts.forEach(function(a) {
              allAccounts.push({ id: a.id || a.account_id, name: a.name, bmName: b.name });
            });
          }
        });
        setAdAccountOptions(allAccounts);
      }
    }).catch(() => {});
  }, []);
  const siteOptions = [...new Set([...swpDomains, ...avDomains, ...(projects || []).flatMap(p => p.sites || [])])];

  const startEdit = (p) => {
    setForm({ name: p.name, gam: p.gam, bms: [...p.bms], sites: [...p.sites], adAccounts: [...(p.adAccounts || [])], status: p.status });
    setEditing(p.id);
  };

  const saveEdit = () => {
    if (!form.name.trim()) return;
    var updated;
    if (editing) {
      updated = projects.map(pr => pr.id === editing ? { ...pr, ...form } : pr);
    } else {
      updated = [...projects, { id: Date.now(), ...form }];
    }
    setProjects(updated);
    saveLS("operacoes", updated);
    setEditing(null); setShowAdd(false); setForm({ name: "", gam: 1, bms: [], sites: [], adAccounts: [], status: "active" });
  };

  const toggleBm = (bmId) => setForm(p => ({ ...p, bms: p.bms.includes(bmId) ? p.bms.filter(b => b !== bmId) : [...p.bms, bmId] }));
  const toggleSite = (site) => setForm(p => ({ ...p, sites: p.sites.includes(site) ? p.sites.filter(s => s !== site) : [...p.sites, site] }));
  const toggleAdAccount = (accId) => setForm(p => ({ ...p, adAccounts: p.adAccounts.includes(accId) ? p.adAccounts.filter(a => a !== accId) : [...p.adAccounts, accId] }));

  const projectFormJSX = (
    <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 12, padding: 16, marginBottom: 12 }}>
      <div style={{ fontSize: 13, fontWeight: 600, color: C.br, marginBottom: 12 }}>{editing ? "Editar Projeto" : "Novo Projeto"}</div>
      <Inp label="Nome do projeto" value={form.name} onChange={v => setForm(p => ({ ...p, name: v }))} placeholder="Ex: Projeto Saúde" mob={mob} />

      <div style={{ marginBottom: 10 }}>
        <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>Ad Manager (GAM)</span>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {gamOptions.map(g => (
            <span key={g.id} onClick={() => setForm(p => ({ ...p, gam: g.id }))} style={{ fontSize: 12, padding: "5px 12px", borderRadius: 8, cursor: "pointer", background: form.gam === g.id ? "rgba(43,126,201,0.2)" : "rgba(8,13,26,0.5)", border: `1px solid ${form.gam === g.id ? C.blu : C.bdr}`, color: form.gam === g.id ? C.blu : C.mut, fontWeight: form.gam === g.id ? 600 : 400 }}>
              📡 {g.name}
            </span>
          ))}
        </div>
      </div>

      <div style={{ marginBottom: 10 }}>
        <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>BMs de Facebook (seleccione 1 ou mais)</span>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {bmOptions.map(b => (
            <span key={b.id} onClick={() => toggleBm(b.id)} style={{ fontSize: 12, padding: "5px 12px", borderRadius: 8, cursor: "pointer", background: form.bms.includes(b.id) ? "rgba(139,92,246,0.2)" : "rgba(8,13,26,0.5)", border: `1px solid ${form.bms.includes(b.id) ? "#a78bfa" : C.bdr}`, color: form.bms.includes(b.id) ? "#a78bfa" : C.mut, fontWeight: form.bms.includes(b.id) ? 600 : 400 }}>
              📘 {b.name}
            </span>
          ))}
        </div>
      </div>

      <div style={{ marginBottom: 10 }}>
        <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>Sites (seleccione os sites deste projeto)</span>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {siteOptions.map(s => (
            <span key={s} onClick={() => toggleSite(s)} style={{ fontSize: 11, padding: "4px 10px", borderRadius: 8, cursor: "pointer", fontFamily: "monospace", background: form.sites.includes(s) ? "rgba(93,173,226,0.2)" : "rgba(8,13,26,0.5)", border: `1px solid ${form.sites.includes(s) ? C.cyan : C.bdr}`, color: form.sites.includes(s) ? C.cyan : C.mut, fontWeight: form.sites.includes(s) ? 600 : 400 }}>
              {s}
            </span>
          ))}
        </div>
      </div>

      <div style={{ marginBottom: 10 }}>
        <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>Contas de anúncio Facebook (seleccione as contas deste projeto)</span>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {adAccountOptions.length > 0 ? adAccountOptions.map(function(a) { return (
            <span key={a.id} onClick={function() { toggleAdAccount(String(a.id)); }} style={{ fontSize: 11, padding: "4px 10px", borderRadius: 8, cursor: "pointer", fontFamily: "monospace", background: form.adAccounts.includes(String(a.id)) ? "rgba(243,156,18,0.2)" : "rgba(8,13,26,0.5)", border: "1px solid " + (form.adAccounts.includes(String(a.id)) ? C.yel : C.bdr), color: form.adAccounts.includes(String(a.id)) ? C.yel : C.mut, fontWeight: form.adAccounts.includes(String(a.id)) ? 600 : 400 }}>
              {a.name} <span style={{ fontSize: 9, opacity: 0.6 }}>({a.id})</span>
            </span>
          ); }) : <span style={{ fontSize: 11, color: C.mut }}>Conecte um BM em "BMs Facebook" para ver as contas</span>}
        </div>
      </div>

      <div style={{ marginBottom: 12 }}>
        <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>Status</span>
        <div style={{ display: "flex", gap: 6 }}>
          {["active", "paused"].map(s => (
            <span key={s} onClick={() => setForm(p => ({ ...p, status: s }))} style={{ fontSize: 12, padding: "5px 14px", borderRadius: 8, cursor: "pointer", background: form.status === s ? (s === "active" ? "rgba(46,204,113,0.2)" : "rgba(243,156,18,0.2)") : "rgba(8,13,26,0.5)", border: `1px solid ${form.status === s ? (s === "active" ? C.grn : C.yel) : C.bdr}`, color: form.status === s ? (s === "active" ? C.grn : C.yel) : C.mut, fontWeight: form.status === s ? 600 : 400 }}>
              {s === "active" ? "🟢 Ativo" : "🟡 Pausado"}
            </span>
          ))}
        </div>
      </div>

      <div style={{ display: "flex", gap: 8 }}>
        <Btn onClick={saveEdit} color={C.grn} small>Salvar</Btn>
        <Btn onClick={() => { setEditing(null); setShowAdd(false); }} color="rgba(30,48,80,0.6)" small>Cancelar</Btn>
      </div>
    </div>
  );

  const active = projects.filter(p => p.status === "active").length;

  return <>
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(4,1fr)", gap: 8, marginBottom: 14 }}>
      <KPI label="Projetos" value={projects.length} mob={mob} />
      <KPI label="Ativos" value={active} color={C.grn} mob={mob} />
      <KPI label="Pausados" value={projects.length - active} color={C.yel} mob={mob} />
      <KPI label="Total sites" value={projects.reduce((a, p) => a + p.sites.length, 0)} mob={mob} />
    </div>

    {(showAdd || editing) && projectFormJSX}

    {projects.map(p => (
      <Sec key={p.id} icon={p.status === "active" ? "🟢" : "🟡"} label={p.name} count={`${p.sites.length} sites · ${p.bms.length} BMs`} open={true}
        badge={{ t: p.status === "active" ? "Ativo" : "Pausado", bg: p.status === "active" ? "rgba(46,204,113,0.15)" : "rgba(243,156,18,0.15)", c: p.status === "active" ? C.grn : C.yel }}>

        <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr" : "1fr 1fr 1fr 1fr", gap: 12, marginBottom: 12 }}>
          <div>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>📡 Ad Manager</span>
            <span style={{ fontSize: 12, color: C.blu, fontWeight: 600 }}>{gamOptions.find(g => g.id === p.gam)?.name}</span>
          </div>
          <div>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>📘 BMs Facebook</span>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
              {p.bms.map(bid => <span key={bid} style={{ fontSize: 11, padding: "2px 8px", borderRadius: 6, background: "rgba(139,92,246,0.1)", color: "#a78bfa" }}>{bmOptions.find(b => b.id === bid)?.name}</span>)}
            </div>
          </div>
          <div>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>🌐 Sites</span>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
              {p.sites.map(s => <span key={s} style={{ fontSize: 11, padding: "2px 8px", borderRadius: 6, background: "rgba(93,173,226,0.1)", color: C.cyan, fontFamily: "monospace" }}>{s}</span>)}
            </div>
          </div>
          <div>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>💳 Contas de Anúncio</span>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
              {(p.adAccounts || []).map(function(accId) { var acc = adAccountOptions.find(function(a) { return String(a.id) === String(accId); }); return <span key={accId} style={{ fontSize: 11, padding: "2px 8px", borderRadius: 6, background: "rgba(243,156,18,0.1)", color: C.yel, fontFamily: "monospace" }}>{acc ? acc.name : accId}</span>; })}
              {(!p.adAccounts || p.adAccounts.length === 0) && <span style={{ fontSize: 11, color: C.mut }}>Nenhuma</span>}
            </div>
          </div>
        </div>

        <div style={{ display: "flex", gap: 6 }}>
          <Btn onClick={() => startEdit(p)} color={C.blu} small>Editar</Btn>
          <Btn onClick={() => { var updated = projects.map(x => x.id === p.id ? { ...x, status: x.status === "active" ? "paused" : "active" } : x); setProjects(updated); saveLS("operacoes", updated); }} color={p.status === "active" ? "rgba(243,156,18,0.3)" : C.grn} small>{p.status === "active" ? "Pausar" : "Ativar"}</Btn>
          <Btn onClick={() => { var updated = projects.filter(x => x.id !== p.id); setProjects(updated); saveLS("operacoes", updated); }} color="rgba(231,76,60,0.15)" small>Remover</Btn>
        </div>
      </Sec>
    ))}

    {!showAdd && !editing && <div style={{ textAlign: "center", paddingTop: 4 }}><Btn onClick={() => { setForm({ name: "", gam: 1, bms: [], sites: [], adAccounts: [], status: "active" }); setShowAdd(true); }} color={C.blu} small>+ Novo Projeto</Btn></div>}

    <InfoBox><span style={{ fontWeight: 600, color: C.blu }}>Operações:</span> Cada projeto combina 1 Ad Manager (GAM) com 1 ou mais BMs de Facebook e seus sites. O dashboard puxa receita do GAM e gasto do Facebook para calcular o P&L por projeto.</InfoBox>
    <SaveBar storageKey="operacoes" data={projects} mob={mob} />
  </>;
}

/* ========================================= */
/* ===== HOME DASHBOARD ==================== */
/* ========================================= */
function Home({ sites, mob, gamState, dismissedAlerts, setDismissedAlerts, period, dateFrom, dateTo, refreshKey, filterProject }) {
  const [apiDomains, setApiDomains] = useState([]);
  const [apiReport, setApiReport] = useState(null);
  const [swpTime, setSwpTime] = useState(null);
  const [loading, setLoading] = useState(true);
  const [homeOpsProjects, setHomeOpsProjects] = useState([]);
  const [dailyData, setDailyData] = useState({});
  const [expandedProj, setExpandedProj] = useState(null);
  const [tribArr, setTribArr] = useState([]);
  const [taxRateHome, setTaxRateHome] = useState(0);
  const [despesasHome, setDespesasHome] = useState([]);
  // ActiveView state
  const [avReport, setAvReport] = useState([]);
  const [avDomains, setAvDomains] = useState([]);
  const [avConnected, setAvConnected] = useState(false);
  const [avError, setAvError] = useState(null);
  const [avLatestHour, setAvLatestHour] = useState(null);
  const [avDailyData, setAvDailyData] = useState({});
  const [avLoading, setAvLoading] = useState(false);
  // Facebook spend state
  const [fbSpendByProject, setFbSpendByProject] = useState({});
  const [fbLeadsByProject, setFbLeadsByProject] = useState({});
  const [fbDailySpend, setFbDailySpend] = useState({});
  const [fbLoading, setFbLoading] = useState(false);
  const [fbAlerts, setFbAlerts] = useState([]);
  // Alert config from Configurações
  const [alertConfig, setAlertConfig] = useState(null);
  useEffect(() => {
    fetch("/api/store/alertConfig").then(r => r.json()).then(d => {
      if (d && d.value) setAlertConfig(d.value);
    }).catch(() => {});
  }, [refreshKey]);
  useEffect(() => {
    fetch("/api/store/tributacoes").then(r => r.json()).then(d => {
      if (d && d.value) {
        var v = d.value;
        if (Array.isArray(v)) setTribArr(v);
        else if (v.projects) { setTribArr(v.projects); if (v.taxRate !== undefined) setTaxRateHome(Number(v.taxRate) || 0); }
      }
    }).catch(() => {});
    fetch("/api/store/despesas").then(r => r.json()).then(d => {
      if (d && d.value && Array.isArray(d.value)) setDespesasHome(d.value);
    }).catch(() => {});
    fetch("/api/store/taxRate").then(r => r.json()).then(d => {
      if (d && d.value !== undefined && d.value !== null) setTaxRateHome(Number(d.value) || 0);
    }).catch(() => {});
  }, [refreshKey]);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        setDismissedAlerts(p => { var n = {...p}; delete n.swpOk; return n; });
        // SWP always fetches lastThirty — we filter by dateFrom/dateTo in realSites
        const swpDateParam = "lastThirty";
        fetch("/api/store/operacoes").then(r => r.json()).then(d => { if (d && d.value && Array.isArray(d.value)) setHomeOpsProjects(d.value); }).catch(() => {});

        // --- SendWebPush fetch ---
        const domRes = await fetch("/api/sendwebpush/domain");
        const doms = await domRes.json();
        if (Array.isArray(doms)) setApiDomains(doms.filter(d => d.url !== "redce.xyz"));
        // Fetch daily data (this is the source of truth for SWP)
        fetch("/api/sendwebpush/report?date=" + swpDateParam + "&dimensions=domain,date&metrics=revenue,impressions&custom_key_values=true&_t=" + Date.now()).then(r => r.json()).then(dd => {
          var raw = dd && dd.data ? dd.data : (Array.isArray(dd) ? dd : []);
          var byDomain = {};
          raw.filter(r => (r.domain || r.url) !== "redce.xyz").forEach(r => {
            var d = r.domain || r.url;
            if (!byDomain[d]) byDomain[d] = [];
            byDomain[d].push({ date: r.date, rev: Number(r.revenue) || 0, imp: Number(r.impressions) || 0 });
          });
          Object.values(byDomain).forEach(arr => arr.sort((a, b) => a.date > b.date ? 1 : -1));
          setDailyData(byDomain);
        }).catch(() => {});
        // Also fetch totals for quick display while daily loads
        const repRes = await fetch("/api/sendwebpush/report?date=" + swpDateParam + "&dimensions=domain&metrics=revenue,impressions,ecpm,clicks,ctr&custom_key_values=true&_t=" + Date.now());
        const rep = await repRes.json();
        const repData = rep && rep.data ? rep.data : (Array.isArray(rep) ? rep : []);
        setApiReport(repData.filter(r => (r.domain || r.url) !== "redce.xyz"));
        setSwpTime(new Date().toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" }));
      } catch (e) { setError(e.message); }
      finally { setLoading(false); }
    };
    fetchData();

    // --- ActiveView fetch (background, non-blocking, with retry) ---
    const fetchAV = async (attempt) => {
      if (!attempt) attempt = 0;
      try {
        // Reset AV state on first attempt to avoid stale data from previous period
        if (attempt === 0) {
          setAvReport([]); setAvConnected(false); setAvError(null); setAvLatestHour(null); setAvDailyData({}); setAvLoading(true);
          setDismissedAlerts(p => { var n = {...p}; delete n.avOk; delete n.avErr; return n; });
        }
        const amRes = await fetch("/api/store/admanagers");
        const amData = await amRes.json();
        const amItems = amData && amData.value ? amData.value : [];
        const avItem = amItems.find(i => i.type === "activeview" && i.fields && i.fields.apiKey && i.fields.networkCode && i.fields.domains);
        if (!avItem) { setAvLoading(false); return; }

        // Get domains from Operações projects only
        const opsRes = await fetch("/api/store/operacoes");
        const opsData = await opsRes.json();
        const opsProjects = opsData && opsData.value && Array.isArray(opsData.value) ? opsData.value : [];
        const projectDomains = opsProjects.flatMap(p => p.sites || []);
        const avAllDomains = [...new Set(avItem.fields.domains.split(",").map(s => s.trim()).filter(Boolean))];
        const avProjectDomains = avAllDomains.filter(d => projectDomains.includes(d));
        if (avProjectDomains.length === 0) { setAvConnected(true); setAvDomains([]); setAvLoading(false); return; }

        // Use dateFrom/dateTo directly — they are always correct from applyPeriod
        var sd = dateFrom, ed = dateTo;

        const avRes = await fetch("/api/activeview/aggregate?start_date=" + sd + "&end_date=" + ed + "&domains=" + avProjectDomains.join(","));
        const avData = await avRes.json();
        if (avData && !avData.error && avData.domains) {
          setAvConnected(true); setAvError(null);
          var avNorm = avData.domains.map(d => ({
            domain: d.domain, rev: d.rev, imp: d.imp, ecpm: d.imp > 0 ? (d.rev / d.imp) * 1000 : 0, source: "activeview"
          }));
          setAvReport(avNorm);
          setAvDomains(avNorm.map(e => e.domain));
          var avDaily = {};
          avData.domains.forEach(d => { if (d.daily) avDaily[d.domain] = d.daily; });
          setAvDailyData(avDaily);
          setAvLoading(false);
          if (avNorm.length > 0) {
            var nc = avItem.fields.networkCode;
            // Send today's local date for latest-hour check
            var localToday = new Date(); var localDateStr = localToday.getFullYear() + "-" + String(localToday.getMonth()+1).padStart(2,"0") + "-" + String(localToday.getDate()).padStart(2,"0");
            fetch("/api/activeview/latest-hour/" + nc + "/" + avNorm[0].domain + "?date=" + localDateStr).then(r => r.json()).then(hd => {
              if (hd && hd.response && hd.response.length > 0) {
                var maxHour = 0;
                hd.response.forEach(r => { var h = Number(r.HOUR || 0); if (h > maxHour) maxHour = h; });
                setAvLatestHour(maxHour > 0 ? maxHour + ":00h" : "processando dia " + localDateStr.split("-").reverse().join("/"));
              } else {
                setAvLatestHour("sem dados HOUR para " + localDateStr.split("-").reverse().join("/"));
              }
            }).catch(() => { setAvLatestHour("consultado às " + new Date().toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" })); });
          }
        } else {
          // Retry once after 3s on failure
          if (attempt < 1) { setTimeout(() => fetchAV(attempt + 1), 3000); return; }
          setAvError(avData.error || "Erro ao conectar ActiveView");
          setAvLoading(false);
        }
      } catch (avE) {
        // Retry once after 3s on network error
        if (attempt < 1) { setTimeout(() => fetchAV(attempt + 1), 3000); return; }
        setAvError(avE.message);
        setAvLoading(false);
      }
    };
    fetchAV(0);

    // --- Facebook spend fetch (reads BM tokens + project ad accounts) ---
    var fetchFBSpend = async function() {
      try {
        setFbLoading(true);
        var bmsRes = await fetch("/api/store/bms");
        var bmsData = await bmsRes.json();
        var bmsList = bmsData && bmsData.value && Array.isArray(bmsData.value) ? bmsData.value : [];
        var connectedBms = bmsList.filter(function(b) { return b.status === "connected" && b.accessToken; });
        if (connectedBms.length === 0) return;

        var opsRes = await fetch("/api/store/operacoes");
        var opsData = await opsRes.json();
        var opsList = opsData && opsData.value && Array.isArray(opsData.value) ? opsData.value : [];

        var spendByProject = {};
        var leadsByProject = {};
        var dailySpendByDomain = {};
        for (var pi = 0; pi < opsList.length; pi++) {
          var proj = opsList[pi];
          var projAdAccounts = proj.adAccounts || [];
          if (projAdAccounts.length === 0) continue;

          // Find which BM has the token for these ad accounts
          var token = null;
          for (var bi = 0; bi < connectedBms.length; bi++) {
            var bm = connectedBms[bi];
            var bmAccIds = (bm.adAccounts || []).map(function(a) { return String(a.id || a.account_id); });
            if (projAdAccounts.some(function(accId) { return bmAccIds.includes(String(accId)); })) {
              token = bm.accessToken;
              break;
            }
          }
          if (!token) continue;

          var totalSpend = 0;
          var totalLeads = 0;
          var dailySpendArr = [];
          for (var ai = 0; ai < projAdAccounts.length; ai++) {
            try {
              var accId = projAdAccounts[ai];
              // Get total spend + actions (leads)
              var insUrl = "/api/facebook/insights/" + accId + "?fields=spend,actions&level=account&since=" + dateFrom + "&until=" + dateTo;
              var insRes = await fetch(insUrl, { headers: { "x-fb-token": token } });
              var insData = await insRes.json();
              if (insData && insData.data && insData.data.length > 0) {
                totalSpend += Number(insData.data[0].spend) || 0;
                // Count leads: use offsite_conversion.fb_pixel_complete_registration (the "Registro concluído" result)
                var actions = insData.data[0].actions || [];
                var foundLeads = 0;
                var leadTypes = ["offsite_conversion.fb_pixel_complete_registration", "offsite_conversion.fb_pixel_lead", "onsite_conversion.lead_grouped"];
                actions.forEach(function(act) {
                  if (leadTypes.indexOf(act.action_type) >= 0) {
                    foundLeads += Number(act.value) || 0;
                  }
                });
                totalLeads += foundLeads;
              }
              var dailyUrl = "/api/facebook/insights/" + accId + "?fields=spend,actions&level=account&time_increment=1&since=" + dateFrom + "&until=" + dateTo;
              var dailyRes = await fetch(dailyUrl, { headers: { "x-fb-token": token } });
              var dailyData2 = await dailyRes.json();
              if (dailyData2 && dailyData2.data && Array.isArray(dailyData2.data)) {
                var dLeadTypes = ["offsite_conversion.fb_pixel_complete_registration", "offsite_conversion.fb_pixel_lead", "onsite_conversion.lead_grouped"];
                dailyData2.data.forEach(function(d) {
                  var dayLeads = 0;
                  (d.actions || []).forEach(function(act) {
                    if (dLeadTypes.indexOf(act.action_type) >= 0) {
                      dayLeads += Number(act.value) || 0;
                    }
                  });
                  dailySpendArr.push({ date: d.date_start, spend: Number(d.spend) || 0, leads: dayLeads });
                });
              }
            } catch (e) { /* skip failed account */ }
          }
          // Aggregate daily spend+leads by date (sum if multiple ad accounts)
          var dailyByDate = {};
          dailySpendArr.forEach(function(d) {
            if (!dailyByDate[d.date]) dailyByDate[d.date] = { spend: 0, leads: 0 };
            dailyByDate[d.date].spend += d.spend;
            dailyByDate[d.date].leads += d.leads || 0;
          });
          // Map spend+leads to project's domains
          (proj.sites || []).forEach(function(domain) {
            spendByProject[domain] = (spendByProject[domain] || 0) + totalSpend;
            leadsByProject[domain] = (leadsByProject[domain] || 0) + totalLeads;
            dailySpendByDomain[domain] = dailyByDate;
          });
        }
        setFbSpendByProject(spendByProject);
        setFbLeadsByProject(leadsByProject);
        setFbDailySpend(dailySpendByDomain);

        // Check for disapproved ads + account issues + BM health across all
        var alerts = [];
        var checkedAccounts = new Set();

        // BM health checks
        for (var bmi = 0; bmi < connectedBms.length; bmi++) {
          var cbm = connectedBms[bmi];
          // Token expiry check (if tokenType is not system, check age)
          if (cbm.tokenType !== "system" && cbm.tokenDate) {
            var tokenAge = Math.floor((Date.now() - new Date(cbm.tokenDate).getTime()) / 86400000);
            var daysLeft = 60 - tokenAge;
            if (daysLeft <= 10) alerts.push({ type: "bm_token", bmName: cbm.name, bmId: cbm.bmId, daysLeft: daysLeft, severity: daysLeft <= 5 ? "critical" : "warning" });
          }
          // Test BM access with a simple call
          try {
            var bmTestRes = await fetch("/api/facebook/insights/0?fields=spend&level=account&date_preset=today", { headers: { "x-fb-token": cbm.accessToken } });
            var bmTestData = await bmTestRes.json();
            if (bmTestData && bmTestData.error) {
              var errCode = bmTestData.error.code;
              var errMsg = bmTestData.error.message || "";
              // Code 190 = invalid/expired token, 10 = permission error, 100 = invalid params (OK)
              if (errCode === 190) alerts.push({ type: "bm_expired", bmName: cbm.name, bmId: cbm.bmId, msg: errMsg });
              else if (errCode === 10 || errCode === 200) alerts.push({ type: "bm_permission", bmName: cbm.name, bmId: cbm.bmId, msg: errMsg });
            }
          } catch(e) { /* network error, skip */ }
        }

        // Check ad accounts that belong to PROJECTS only (for Home relevance)
        for (var ci = 0; ci < opsList.length; ci++) {
          var cProj = opsList[ci];
          var cAccs = cProj.adAccounts || [];
          var cToken = null;
          var cBmName = "—";
          for (var cbi = 0; cbi < connectedBms.length; cbi++) {
            var cbm2 = connectedBms[cbi];
            var cbmIds = (cbm2.adAccounts || []).map(function(a) { return String(a.id || a.account_id); });
            if (cAccs.some(function(id) { return cbmIds.includes(String(id)); })) { cToken = cbm2.accessToken; cBmName = cbm2.name; break; }
          }
          if (!cToken) continue;
          for (var cai = 0; cai < cAccs.length; cai++) {
            var cAccId = String(cAccs[cai]);
            if (checkedAccounts.has(cAccId)) continue;
            checkedAccounts.add(cAccId);
            try {
              var accRes = await fetch("/api/facebook/account-status/" + cAccId, { headers: { "x-fb-token": cToken } });
              var accData = await accRes.json();
              if (accData && !accData.error && accData.account_status !== 1) {
                alerts.push({ type: "account", accId: cAccId, name: accData.name || cAccId, status: accData.account_status, reason: accData.disable_reason, project: cProj.name, bmName: cBmName });
              }
              var disRes = await fetch("/api/facebook/disapproved/" + cAccId, { headers: { "x-fb-token": cToken } });
              var disData = await disRes.json();
              if (disData && disData.data && disData.data.length > 0) {
                disData.data.forEach(function(ad) {
                  alerts.push({ type: "ad", accId: cAccId, adId: ad.id, adName: ad.name, status: ad.effective_status, project: cProj.name, bmName: cBmName, campaign: ad.adset && ad.adset.campaign ? ad.adset.campaign.name : "—", feedback: ad.ad_review_feedback });
                });
              }
            } catch(e) { /* skip */ }
          }
        }
        // Check FB Apps status
        try {
          var appsRes = await fetch("/api/store/fbapps");
          var appsData = await appsRes.json();
          var appsList = appsData && appsData.value && Array.isArray(appsData.value) ? appsData.value : [];
          appsList.forEach(function(app) {
            if (app.status === "rejected") alerts.push({ type: "app_rejected", appName: app.name, appId: app.appId, msg: "App rechazada por Facebook" });
            if (app.permissions) {
              Object.entries(app.permissions).forEach(function(entry) {
                if (entry[1] === "rejected") alerts.push({ type: "app_perm", appName: app.name, perm: entry[0], msg: "Permiso " + entry[0] + " rechazado" });
              });
            }
          });
        } catch(e) { /* skip */ }

        setFbAlerts(alerts);
      } catch (e) { /* FB spend optional */ }
      finally { setFbLoading(false); }
    };
    fetchFBSpend();
  }, [period, dateFrom, dateTo, refreshKey]);

  const realSites = useMemo(() => {
    var combined = {};
    var projectDomains = (homeOpsProjects || []).flatMap(p => p.sites || []);
    // SWP data from apiReport (loads fast, always available)
    if (apiReport && Array.isArray(apiReport)) {
      apiReport.forEach(r => {
        const domain = r.domain || r.url || "Unknown";
        combined[domain] = { domain, imp: Number(r.impressions) || 0, rev: Number(r.revenue) || 0, ecpm: Number(r.ecpm) || 0, swpRev: Number(r.revenue) || 0, avRev: 0 };
      });
    }
    // Override SWP totals from filtered dailyData when available (for accurate date filtering)
    if (dailyData && typeof dailyData === "object" && Object.keys(dailyData).length > 0) {
      Object.entries(dailyData).forEach(([domain, days]) => {
        if (domain === "Unknown") return;
        var filtered = days.filter(d => d.date >= dateFrom && d.date <= dateTo);
        var imp = filtered.reduce((a, d) => a + (d.imp || 0), 0);
        var rev = filtered.reduce((a, d) => a + (d.rev || 0), 0);
        combined[domain] = { domain, imp, rev, ecpm: imp > 0 ? (rev / imp) * 1000 : 0, swpRev: rev, avRev: (combined[domain] || {}).avRev || 0 };
      });
    }
    // Add/merge ActiveView data
    if (avReport && Array.isArray(avReport)) {
      avReport.forEach(r => {
        if (combined[r.domain]) {
          combined[r.domain].rev += r.rev;
          combined[r.domain].imp += r.imp;
          combined[r.domain].avRev = r.rev;
          combined[r.domain].ecpm = combined[r.domain].imp > 0 ? (combined[r.domain].rev / combined[r.domain].imp) * 1000 : 0;
        } else {
          combined[r.domain] = { domain: r.domain, imp: r.imp, rev: r.rev, ecpm: r.ecpm, swpRev: 0, avRev: r.rev };
        }
      });
    }
    // BUG1 FIX: Ensure ALL project domains appear even if APIs returned nothing
    (homeOpsProjects || []).forEach(p => {
      (p.sites || []).forEach(domain => {
        if (!combined[domain]) {
          combined[domain] = { domain, imp: 0, rev: 0, ecpm: 0, swpRev: 0, avRev: 0 };
        }
      });
    });
    // Compute yesterday's rev per domain for sort fallback when today is $0
    var yStr = (function() { var d = new Date(); d.setDate(d.getDate() - 1); return d.getFullYear() + "-" + String(d.getMonth()+1).padStart(2,"0") + "-" + String(d.getDate()).padStart(2,"0"); })();
    var seen = new Set();
    return Object.values(combined).filter(s => projectDomains.includes(s.domain) && !seen.has(s.domain) && seen.add(s.domain)).map(s => {
      const proj = homeOpsProjects.find(p => (p.sites || []).includes(s.domain));
      var spend = fbSpendByProject[s.domain] || 0;
      var leads = fbLeadsByProject[s.domain] || 0;
      var yRev = 0;
      if (dailyData && dailyData[s.domain]) { var yd = dailyData[s.domain].find(d => d.date === yStr); if (yd) yRev += yd.rev || 0; }
      if (avDailyData && avDailyData[s.domain]) { var yd2 = avDailyData[s.domain].find(d => d.date === yStr); if (yd2) yRev += yd2.rev || 0; }
      return { name: proj ? proj.name : s.domain, domain: s.domain, imp: s.imp, rev: s.rev, spend: spend, leads: leads, ecpm: s.ecpm, swpRev: s.swpRev || 0, avRev: s.avRev || 0, yesterdayRev: yRev };
    });
  }, [dailyData, avDailyData, apiReport, avReport, homeOpsProjects, dateFrom, dateTo, fbSpendByProject, fbLeadsByProject]);

  const displaySites = useMemo(() => {
    var base = realSites.length > 0 ? realSites : sites;
    if (filterProject === "all") return base;
    var proj = homeOpsProjects.find(p => String(p.id) === String(filterProject));
    if (!proj) return base;
    return base.filter(s => (proj.sites || []).includes(s.domain));
  }, [realSites, sites, filterProject, homeOpsProjects]);
  const allDailyData = useMemo(() => {
    var merged = {};
    // SWP daily — filter by dateFrom/dateTo
    Object.entries(dailyData).forEach(([k, v]) => {
      merged[k] = v.filter(d => d.date >= dateFrom && d.date <= dateTo);
    });
    // AV daily — already filtered by date range from server, but filter again for safety
    Object.entries(avDailyData).forEach(([k, v]) => {
      var filtered = v.filter(d => d.date >= dateFrom && d.date <= dateTo);
      if (!merged[k]) merged[k] = filtered;
      else {
        // Merge AV days into SWP days by summing per date
        var byDate = {};
        merged[k].forEach(d => { byDate[d.date] = { ...d }; });
        filtered.forEach(d => {
          if (byDate[d.date]) { byDate[d.date].rev += d.rev; byDate[d.date].imp += d.imp; }
          else { byDate[d.date] = { ...d }; }
        });
        merged[k] = Object.values(byDate).sort((a, b) => a.date > b.date ? 1 : -1);
      }
    });
    // Inject FB daily spend into merged data
    Object.entries(fbDailySpend).forEach(function(entry) {
      var domain = entry[0], spendByDate = entry[1];
      if (!merged[domain]) merged[domain] = [];
      var byDate = {};
      merged[domain].forEach(function(d) { byDate[d.date] = { ...d }; });
      Object.entries(spendByDate).forEach(function(se) {
        var date = se[0], val = se[1];
        var spendVal = typeof val === "object" ? (val.spend || 0) : (Number(val) || 0);
        var leadsVal = typeof val === "object" ? (val.leads || 0) : 0;
        if (byDate[date]) { byDate[date].spend = spendVal; byDate[date].leads = leadsVal; }
        else { byDate[date] = { date: date, rev: 0, imp: 0, spend: spendVal, leads: leadsVal }; }
      });
      merged[domain] = Object.values(byDate).sort(function(a, b) { return a.date > b.date ? 1 : -1; });
    });
    return merged;
  }, [dailyData, avDailyData, dateFrom, dateTo, fbDailySpend]);
  const periodDays = useMemo(() => Math.max(1, Math.round((new Date(dateTo) - new Date(dateFrom)) / 86400000) + 1), [dateFrom, dateTo]);
  const fixedMonthly = despesasHome.filter(e => e.recurrence === "monthly").reduce((a, e) => a + (e.value || 0), 0);
  const fixed = fixedMonthly * (periodDays / 30);
  // Build revShare map per project (by domain)
  const revShareByDomain = useMemo(() => {
    var map = {};
    (homeOpsProjects || []).forEach(proj => {
      var tribProj = tribArr.find(t => t.id === proj.id);
      var rs = tribProj ? (tribProj.revShare || 0) / 100 : 0;
      (proj.sites || []).forEach(site => { map[site] = rs; });
    });
    return map;
  }, [homeOpsProjects, tribArr]);
  const sc = useMemo(() => {
    var totalRev = displaySites.reduce(function(a, s) { return a + s.rev; }, 0);
    return displaySites.map(s => {
      var projRS = revShareByDomain[s.domain] || 0;
      const rs = s.rev * projRS;
      const tax = s.rev * taxRateHome / 100;
      const liq = s.rev - s.spend - rs - tax;
      const margin = s.spend > 0 ? (liq / s.spend) * 100 : (s.rev > 0 ? (liq / s.rev) * 100 : 0);
      const cpl = s.leads > 0 ? s.spend / s.leads : 0;
      return { ...s, rs, tax, liq, margin, cpl };
    });
  }, [displaySites, revShareByDomain, taxRateHome]);
  const tot = useMemo(() => {
    const imp = sc.reduce((a, s) => a + s.imp, 0), rev = sc.reduce((a, s) => a + s.rev, 0), spend = sc.reduce((a, s) => a + s.spend, 0), leads = sc.reduce((a, s) => a + s.leads, 0);
    const rs = sc.reduce((a, s) => a + s.rs, 0);
    const tax = rev * taxRateHome / 100;
    const gross = rev - spend - rs - tax;
    const liq = gross - fixed;
    const margin = spend > 0 ? (liq / spend) * 100 : (rev > 0 ? (liq / rev) * 100 : 0);
    const roi = margin;
    const ecpm = imp > 0 ? (rev / imp) * 1000 : 0;
    const cpl = leads > 0 ? spend / leads : 0;
    return { imp, rev, spend, leads, rs, tax, gross, liq, margin, roi, ecpm, cpl };
  }, [sc, taxRateHome, fixed]);
  const gc = mob ? "repeat(2,1fr)" : "repeat(4,1fr)";

  const [kpiConfig, setKpiConfig] = useState(null);
  useEffect(() => {
    fetch("/api/store/kpis").then(r => r.json()).then(d => {
      if (d && d.value && Array.isArray(d.value)) setKpiConfig(d.value);
    }).catch(() => {});
  }, [refreshKey]);

  const dismiss = (key) => {
    var upd = Object.assign({}, dismissedAlerts);
    upd[key] = Date.now();
    setDismissedAlerts(upd);
    try { localStorage.setItem("lum_dismiss", JSON.stringify(upd)); } catch(e) {}
  };
  var isDismissed = function(key) {
    var ts = dismissedAlerts[key];
    if (!ts) return false;
    if (ts === true) return true;
    return (Date.now() - ts) < 7 * 86400000;
  };

  // KPI mapping by ID — immune to browser translations or label changes
  var kpiById = {
    1: { v: $(tot.rev, "usd"), c: C.br, l: "Receita bruta" },
    2: { v: $(tot.imp, "int"), c: C.br, l: "Impressões" },
    3: { v: $(tot.spend, "usd"), c: C.br, l: "Gasto Facebook" },
    4: { v: $(tot.rs + tot.tax + fixed, "usd"), c: C.br, l: "Despesa total" },
    5: { v: $(tot.liq, "usd"), c: tot.liq >= 0 ? C.grn : C.red, l: "Líquido" },
    6: { v: $(tot.roi, "pct"), c: tot.roi >= 0 ? C.grn : C.red, l: tot.spend > 0 ? "ROI" : "Margem" },
    7: { v: $(tot.ecpm, "usd"), c: C.br, l: "ECPM" },
    8: { v: $(tot.cpl, "usd"), c: C.br, l: "CPL médio" },
    9: { v: $(tot.leads, "int"), c: C.br, l: "Total leads" },
    10: { v: $(tot.gross, "usd"), c: tot.gross >= 0 ? C.grn : C.red, l: "Margem bruta" },
    11: { v: $(tot.rs, "usd"), c: C.yel, l: "Rev Share" },
  };
  // activeKpis: ALWAYS use ID for value AND label — immune to translations/reorder bugs
  var activeKpis = kpiConfig ? kpiConfig.filter(function(k) { return k.enabled && kpiById[k.id]; }).map(function(k) {
    var m = kpiById[k.id];
    return { id: k.id, l: m.l, v: m.v, c: m.c };
  }) : [
    { id: 1, l: kpiById[1].l, v: kpiById[1].v, c: kpiById[1].c },
    { id: 2, l: kpiById[2].l, v: kpiById[2].v, c: kpiById[2].c },
    { id: 4, l: kpiById[4].l, v: kpiById[4].v, c: kpiById[4].c },
    { id: 3, l: kpiById[3].l, v: kpiById[3].v, c: kpiById[3].c },
    { id: 5, l: kpiById[5].l, v: kpiById[5].v, c: kpiById[5].c },
    { id: 6, l: kpiById[6].l, v: kpiById[6].v, c: kpiById[6].c },
    { id: 7, l: kpiById[7].l, v: kpiById[7].v, c: kpiById[7].c },
    { id: 8, l: kpiById[8].l, v: kpiById[8].v, c: kpiById[8].c },
  ];

  return <>
    <style>{`@keyframes spin{to{transform:rotate(360deg)}}`}</style>

    {/* === SWP Status (always first) === */}
    {loading ? (
      <div style={{ padding: mob ? "8px 12px" : "10px 14px", borderRadius: 10, marginBottom: 8, background: "rgba(43,126,201,0.08)", border: "1px solid rgba(43,126,201,0.2)", display: "flex", alignItems: "center", gap: 8 }}>
        <svg width="18" height="18" viewBox="0 0 20 20" style={{ flexShrink: 0 }}><rect width="20" height="20" rx="4" fill="#3b6fe0"/><path d="M10 4a4 4 0 0 0-4 4v2.5l-1 1.5v1h10v-1l-1-1.5V8a4 4 0 0 0-4-4zm-1.5 11a1.5 1.5 0 0 0 3 0h-3z" fill="#fff"/></svg>
        <span style={{ display: "inline-block", animation: "spin 1s linear infinite", width: 10, height: 10, border: "2px solid #3b82f6", borderTopColor: "transparent", borderRadius: "50%", flexShrink: 0 }} />
        <span style={{ fontSize: mob ? 12 : 13, color: "#3b82f6", fontWeight: 600 }}>SendWebPush cargando...</span>
      </div>
    ) : error ? (
      <div style={{ padding: mob ? "8px 12px" : "10px 14px", borderRadius: 10, background: "rgba(59,130,246,0.05)", border: "1px solid rgba(59,130,246,0.15)", marginBottom: 8 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <svg width="18" height="18" viewBox="0 0 20 20" style={{ flexShrink: 0, opacity: 0.5 }}><rect width="20" height="20" rx="4" fill="#3b6fe0"/><path d="M10 4a4 4 0 0 0-4 4v2.5l-1 1.5v1h10v-1l-1-1.5V8a4 4 0 0 0-4-4zm-1.5 11a1.5 1.5 0 0 0 3 0h-3z" fill="#fff"/></svg>
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: C.red, flexShrink: 0 }} />
          <span style={{ fontSize: mob ? 12 : 13, fontWeight: 600, color: C.red }}>SendWebPush desconectada</span>
        </div>
        <div style={{ fontSize: 10, color: C.mut, marginTop: 3, marginLeft: 26 }}>{error}</div>
      </div>
    ) : apiDomains.length > 0 && !dismissedAlerts?.swpOk ? (
      <div style={{ padding: mob ? "8px 12px" : "10px 14px", borderRadius: 10, background: "rgba(59,130,246,0.05)", border: "1px solid rgba(59,130,246,0.15)", marginBottom: 8, position: "relative" }}>
        <span onClick={function() { dismiss("swpOk"); }} style={{ position: "absolute", top: 6, right: 8, fontSize: 13, color: C.mut, cursor: "pointer", padding: "2px 4px" }}>✕</span>
        <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
          <svg width="18" height="18" viewBox="0 0 20 20" style={{ flexShrink: 0 }}><rect width="20" height="20" rx="4" fill="#3b6fe0"/><path d="M10 4a4 4 0 0 0-4 4v2.5l-1 1.5v1h10v-1l-1-1.5V8a4 4 0 0 0-4-4zm-1.5 11a1.5 1.5 0 0 0 3 0h-3z" fill="#fff"/></svg>
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: "#3b82f6", flexShrink: 0 }} />
          <span style={{ fontSize: mob ? 12 : 13, fontWeight: 600, color: "#3b82f6" }}>SendWebPush conectada — {apiDomains.length} domínios</span>
          {swpTime && <span style={{ fontSize: 10, color: C.mut }}>• Consultado às {swpTime}</span>}
        </div>
        <div style={{ fontSize: 10, color: C.mut, marginTop: 3, marginLeft: 26 }}>{apiDomains.map(function(d) { return d.url; }).join(", ")}</div>
      </div>
    ) : null}

    {/* === ActiveView Status (always second) === */}
    {avLoading ? (
      <div style={{ padding: mob ? "8px 12px" : "10px 14px", borderRadius: 10, background: "rgba(46,204,113,0.03)", border: "1px solid rgba(46,204,113,0.1)", marginBottom: 8, display: "flex", alignItems: "center", gap: 8 }}>
        <img src="https://activeview.io/favicon.ico" width="16" height="16" style={{ borderRadius: 3 }} onError={function(e) { e.target.style.display='none'; }} />
        <span style={{ display: "inline-block", width: 10, height: 10, border: "2px solid #2ecc71", borderTopColor: "transparent", borderRadius: "50%", animation: "spin 1s linear infinite", flexShrink: 0 }} />
        <span style={{ fontSize: mob ? 12 : 13, fontWeight: 600, color: "#2ecc71" }}>ActiveView cargando...</span>
      </div>
    ) : avError && !dismissedAlerts?.avErr ? (
      <div style={{ padding: mob ? "8px 12px" : "10px 14px", borderRadius: 10, background: "rgba(231,76,60,0.05)", border: "1px solid rgba(231,76,60,0.15)", marginBottom: 8, position: "relative" }}>
        <span onClick={function() { dismiss("avErr"); }} style={{ position: "absolute", top: 6, right: 8, fontSize: 13, color: C.mut, cursor: "pointer", padding: "2px 4px" }}>✕</span>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <img src="https://activeview.io/favicon.ico" width="16" height="16" style={{ borderRadius: 3, opacity: 0.5 }} onError={function(e) { e.target.style.display='none'; }} />
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: C.red, flexShrink: 0 }} />
          <span style={{ fontSize: mob ? 12 : 13, fontWeight: 600, color: C.red }}>ActiveView desconectado</span>
        </div>
        <div style={{ fontSize: 10, color: C.mut, marginTop: 3, marginLeft: 24 }}>{avError}</div>
      </div>
    ) : avConnected && !dismissedAlerts?.avOk ? (
      <div style={{ padding: mob ? "8px 12px" : "10px 14px", borderRadius: 10, background: "rgba(46,204,113,0.05)", border: "1px solid rgba(46,204,113,0.15)", marginBottom: 8, position: "relative" }}>
        <span onClick={function() { dismiss("avOk"); }} style={{ position: "absolute", top: 6, right: 8, fontSize: 13, color: C.mut, cursor: "pointer", padding: "2px 4px" }}>✕</span>
        <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
          <img src="https://activeview.io/favicon.ico" width="16" height="16" style={{ borderRadius: 3 }} onError={function(e) { e.target.style.display='none'; }} />
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: C.grn, flexShrink: 0 }} />
          <span style={{ fontSize: mob ? 12 : 13, fontWeight: 600, color: C.grn }}>ActiveView conectado — {avDomains.length} domínio{avDomains.length !== 1 ? "s" : ""}</span>
          {avLatestHour && <span style={{ fontSize: 10, color: C.mut }}>• GAM {avLatestHour}</span>}
        </div>
        <div style={{ fontSize: 10, color: C.mut, marginTop: 3, marginLeft: 24 }}>{avDomains.join(", ")}</div>
      </div>
    ) : null}

    {/* === Meta Status (always third) === */}
    {fbLoading && (
      <div style={{ padding: mob ? "8px 12px" : "10px 14px", borderRadius: 10, background: "rgba(24,119,242,0.03)", border: "1px solid rgba(24,119,242,0.1)", marginBottom: 8, display: "flex", alignItems: "center", gap: 8 }}>
        <svg width="16" height="16" viewBox="0 0 36 36" style={{ flexShrink: 0 }}><defs><linearGradient id="mg" x1="50%" x2="50%" y1="97.078%" y2="0%"><stop offset="0%" stopColor="#0062E0"/><stop offset="100%" stopColor="#19AFFF"/></linearGradient></defs><circle cx="18" cy="18" r="18" fill="url(#mg)"/><path d="M25.6 23.3l.9-5.3h-5.2v-3.5c0-1.5.7-2.9 3-2.9h2.3V7c0 0-2.1-.4-4.2-.4-4.3 0-7 2.6-7 7.2V18h-4.7v5.3h4.7v12.8c1 .1 1.9.2 2.9.2s2-.1 2.9-.2V23.3h4.3z" fill="#fff"/></svg>
        <span style={{ display: "inline-block", width: 10, height: 10, border: "2px solid #1877F2", borderTopColor: "transparent", borderRadius: "50%", animation: "spin 1s linear infinite", flexShrink: 0 }} />
        <span style={{ fontSize: mob ? 12 : 13, fontWeight: 600, color: "#1877F2" }}>Meta Ads cargando...</span>
      </div>
    )}

    {/* Delay alerts - respects alertConfig */}
    {(() => {
      var cfg = alertConfig || {};
      var showGam = cfg.gamDelay?.enabled !== false;
      var showSwp = cfg.swpDelay?.enabled !== false;
      var gamHours = cfg.gamDelay?.hours || 3;
      var swpHours = cfg.swpDelay?.hours || 3;
      var currentH = new Date().getHours();
      var avDelay = avLatestHour ? Math.max(0, currentH - parseInt(avLatestHour)) : null;
      var swpOk = apiReport && Array.isArray(apiReport) && apiReport.length > 0;
      var gamAlert = showGam && avDelay !== null && avDelay >= gamHours;
      var swpAlert = showSwp && !swpOk && !loading;
      if (!gamAlert && !swpAlert) return null;
      if (isDismissed("delayAlerts")) return null;
      return <div style={{ padding: mob ? "10px 12px" : "12px 16px", borderRadius: 12, background: "rgba(243,156,18,0.06)", border: "1px solid rgba(243,156,18,0.25)", marginBottom: 12, position: "relative" }}>
        <span onClick={() => dismiss("delayAlerts")} style={{ position: "absolute", top: 8, right: 10, fontSize: 14, color: C.mut, cursor: "pointer", lineHeight: 1, padding: "2px 4px" }}>✕</span>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: gamAlert && swpAlert ? 8 : 0 }}>
          <span style={{ fontSize: mob ? 16 : 18 }}>⏰</span>
          <span style={{ fontSize: mob ? 13 : 14, fontWeight: 700, color: C.yel }}>Alerta de delay</span>
        </div>
        {gamAlert && <div style={{ padding: "6px 10px", borderRadius: 6, background: "rgba(231,76,60,0.08)", marginBottom: 4, marginLeft: mob ? 0 : 26, display: "flex", alignItems: "center", gap: 8 }}>
          <img src="https://activeview.io/favicon.ico" width="14" height="14" style={{ borderRadius: 2 }} onError={e => e.target.style.display='none'} />
          <span style={{ fontSize: 12, color: C.red, fontWeight: 600 }}>GAM sin datos hace {avDelay}h</span>
          <span style={{ fontSize: 10, color: C.mut }}>· Alerta configurada: >{gamHours}h</span>
        </div>}
        {swpAlert && <div style={{ padding: "6px 10px", borderRadius: 6, background: "rgba(231,76,60,0.08)", marginLeft: mob ? 0 : 26, display: "flex", alignItems: "center", gap: 8 }}>
          <svg width="14" height="14" viewBox="0 0 20 20" style={{ flexShrink: 0 }}><rect width="20" height="20" rx="4" fill="#3b6fe0"/><path d="M10 4a4 4 0 0 0-4 4v2.5l-1 1.5v1h10v-1l-1-1.5V8a4 4 0 0 0-4-4zm-1.5 11a1.5 1.5 0 0 0 3 0h-3z" fill="#fff"/></svg>
          <span style={{ fontSize: 12, color: C.red, fontWeight: 600 }}>SWP sin datos de hoy</span>
          <span style={{ fontSize: 10, color: C.mut }}>· Alerta configurada: >{swpHours}h</span>
        </div>}
      </div>;
    })()}

    {/* Facebook alerts - respects alertConfig toggles */}
    {(() => {
      var cfg = alertConfig || {};
      var showRejected = cfg.fbRejected?.enabled !== false;
      var showAccount = cfg.fbAccountDisabled?.enabled !== false;
      var showBm = cfg.fbBmIssues?.enabled !== false;
      var accountAlerts = showAccount ? fbAlerts.filter(a => a.type === "account") : [];
      var adAlerts = showRejected ? fbAlerts.filter(a => a.type === "ad") : [];
      var bmAlerts = showBm ? fbAlerts.filter(a => a.type === "bm_token" || a.type === "bm_expired" || a.type === "bm_permission") : [];
      var appAlerts = showBm ? fbAlerts.filter(a => a.type === "app_rejected" || a.type === "app_perm") : [];
      var totalVisible = accountAlerts.length + adAlerts.length + bmAlerts.length + appAlerts.length;
      if (totalVisible === 0 || isDismissed("fbAlerts")) return null;
      return <div style={{ padding: mob ? "12px" : "14px 16px", borderRadius: 12, background: "rgba(231,76,60,0.08)", border: "2px solid rgba(231,76,60,0.35)", marginBottom: 12, position: "relative" }}>
        <span onClick={() => dismiss("fbAlerts")} style={{ position: "absolute", top: 8, right: 10, fontSize: 14, color: C.mut, cursor: "pointer", lineHeight: 1, padding: "2px 4px" }}>✕</span>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
          <svg width={mob ? "18" : "20"} height={mob ? "18" : "20"} viewBox="0 0 36 36" style={{ flexShrink: 0 }}><defs><linearGradient id="mg2" x1="50%" x2="50%" y1="97%" y2="0%"><stop offset="0%" stopColor="#0062E0"/><stop offset="100%" stopColor="#19AFFF"/></linearGradient></defs><circle cx="18" cy="18" r="18" fill="url(#mg2)"/><path d="M25.6 23.3l.9-5.3h-5.2v-3.5c0-1.5.7-2.9 3-2.9h2.3V7c0 0-2.1-.4-4.2-.4-4.3 0-7 2.6-7 7.2V18h-4.7v5.3h4.7v12.8c1 .1 1.9.2 2.9.2s2-.1 2.9-.2V23.3h4.3z" fill="#fff"/></svg>
          <span style={{ fontSize: mob ? 13 : 15, fontWeight: 800, color: "#e74c3c" }}>🚨 {totalVisible} alerta{totalVisible !== 1 ? "s" : ""} de Meta Ads</span>
        </div>
        {/* BM token warnings */}
        {bmAlerts.map((a, i) => (
          <div key={"bm" + i} style={{ padding: mob ? "6px 10px" : "8px 12px", marginBottom: 4, borderRadius: 8, background: a.type === "bm_expired" ? "rgba(231,76,60,0.12)" : "rgba(243,156,18,0.08)", border: "1px solid " + (a.type === "bm_expired" ? "rgba(231,76,60,0.25)" : "rgba(243,156,18,0.2)"), marginLeft: mob ? 0 : 28 }}>
            <div style={{ fontSize: mob ? 11 : 12, fontWeight: 700, color: a.type === "bm_expired" ? "#e74c3c" : C.yel }}>
              {a.type === "bm_expired" ? "🔑 Token expirado" : a.type === "bm_permission" ? "🔒 Sin permisos" : "🔑 Token expira pronto"}
            </div>
            <div style={{ fontSize: mob ? 10 : 11, color: C.txt, marginTop: 2 }}>BM: <span style={{ fontWeight: 600 }}>{a.bmName}</span> · {a.daysLeft !== undefined ? (a.daysLeft <= 0 ? "EXPIRADO" : "Expira en " + a.daysLeft + " día" + (a.daysLeft !== 1 ? "s" : "")) : ""}{a.severity === "critical" ? " · ⚠️ RENOVAR AHORA" : ""}</div>
          </div>
        ))}
        {/* App issues */}
        {appAlerts.map((a, i) => (
          <div key={"app" + i} style={{ padding: mob ? "6px 10px" : "8px 12px", marginBottom: 4, borderRadius: 8, background: "rgba(168,85,247,0.08)", border: "1px solid rgba(168,85,247,0.2)", marginLeft: mob ? 0 : 28 }}>
            <div style={{ fontSize: mob ? 11 : 12, fontWeight: 700, color: "#a855f7" }}>📱 {a.type === "app_rejected" ? "App rechazada" : "Permiso rechazado"}</div>
            <div style={{ fontSize: mob ? 10 : 11, color: C.txt, marginTop: 2 }}>App: <span style={{ fontWeight: 600 }}>{a.appName}</span> · {a.msg}</div>
          </div>
        ))}
        {/* Account issues — with BM name + account name + status */}
        {accountAlerts.map((a, i) => (
          <div key={"acc" + i} style={{ padding: mob ? "6px 10px" : "8px 12px", marginBottom: 4, borderRadius: 8, background: "rgba(231,76,60,0.1)", border: "1px solid rgba(231,76,60,0.2)", marginLeft: mob ? 0 : 28 }}>
            <div style={{ fontSize: mob ? 11 : 12, fontWeight: 700, color: "#e74c3c" }}>🚨 Cuenta de anuncio {a.status === 2 ? "DESACTIVADA" : a.status === 3 ? "NO APROBADA" : a.status === 7 ? "EN REVISIÓN" : "RESTRINGIDA"}</div>
            <div style={{ fontSize: mob ? 10 : 11, color: C.txt, marginTop: 2 }}>
              BM: <span style={{ fontWeight: 600 }}>{a.bmName || "—"}</span> → Cuenta: <span style={{ fontWeight: 600 }}>{a.name}</span> (act_{a.accId})
            </div>
            <div style={{ fontSize: mob ? 10 : 11, color: C.mut, marginTop: 1 }}>
              Proyecto: {a.project}{a.reason > 0 ? " · Razón: " + (a.reason === 1 ? "Violación de políticas" : a.reason === 2 ? "Actividad sospechosa" : a.reason === 3 ? "Pago rechazado" : "Código " + a.reason) : ""}
            </div>
          </div>
        ))}
        {/* Disapproved ads — with BM context */}
        {adAlerts.slice(0, mob ? 5 : 8).map((a, i) => (
          <div key={"ad" + i} style={{ padding: mob ? "5px 10px" : "6px 12px", marginBottom: 3, borderRadius: 6, background: "rgba(8,13,26,0.3)", border: "1px solid " + C.bdr, marginLeft: mob ? 0 : 28 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
              <span style={{ fontSize: mob ? 10 : 11, fontWeight: 700, color: a.status === "DISAPPROVED" ? "#e74c3c" : "#e67e22" }}>{a.status === "DISAPPROVED" ? "🚫" : "⚠️"} {a.adName}</span>
            </div>
            <div style={{ fontSize: mob ? 9 : 10, color: C.mut, marginTop: 1 }}>{a.bmName || ""} → {a.campaign} → {a.project}</div>
          </div>
        ))}
        {adAlerts.length > (mob ? 5 : 8) && <div style={{ fontSize: 11, color: C.mut, marginLeft: mob ? 0 : 28, marginTop: 4 }}>...y {adAlerts.length - (mob ? 5 : 8)} más. Ver en Campanhas.</div>}
      </div>;
    })()}

    <Sec icon="📊" label="KPIs" open={true}>
      {mob ? <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 7 }}>
        {activeKpis.map(function(k) { return (
          <div key={"kpi" + k.id} style={{ background: C.card, border: "1px solid " + C.bdr, borderRadius: 10, padding: "9px 12px" }}>
            <div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, marginBottom: 2 }}>{k.l}</div>
            <div style={{ fontSize: 17, fontWeight: 800, color: k.c, fontVariantNumeric: "tabular-nums", lineHeight: 1.15 }}>{k.v}</div>
          </div>
        ); })}
      </div> : <div style={{ display: "grid", gridTemplateColumns: "repeat(" + Math.min(activeKpis.length, 4) + ",1fr)", gap: 10 }}>
        {activeKpis.map(function(k) { return <KPI key={"kpi" + k.id} label={k.l} value={k.v} color={k.c !== C.br ? k.c : undefined} mob={mob} />; })}
      </div>}
    </Sec>

    {displaySites.length === 0 && !loading ? (
      <Sec icon="🌐" label="Sites" open={true}>
        <div style={{ padding: 30, textAlign: "center" }}>
          <div style={{ fontSize: 32, marginBottom: 10 }}>🌐</div>
          <div style={{ fontSize: 14, color: C.br, fontWeight: 600, marginBottom: 6 }}>Configure seus domínios</div>
          <div style={{ fontSize: 12, color: C.mut, maxWidth: 400, margin: "0 auto" }}>Vá em Ad Managers e configure seu token SendWebPush para ver dados reais de revenue e impressões. Os dados de gasto FB aparecerão quando conectar seus BMs de Facebook.</div>
        </div>
      </Sec>
    ) : displaySites.length === 0 && loading ? (
      <Sec icon="🌐" label="Projetos" open={true}>
        <div style={{ padding: 20, textAlign: "center", fontSize: 13, color: C.blu, display: "flex", alignItems: "center", justifyContent: "center", gap: 10 }}>
          <span style={{ display: "inline-block", animation: "spin 1s linear infinite", width: 14, height: 14, border: "2px solid currentColor", borderTopColor: "transparent", borderRadius: "50%" }} />
          Carregando projetos...
        </div>
      </Sec>
    ) : (
      <Sec icon="🌐" label="Projetos" count={displaySites.length} open={true}>
        {mob ? [...sc].sort((a, b) => (b.rev - a.rev) || ((b.yesterdayRev || 0) - (a.yesterdayRev || 0))).map((s, i) => {
          const isExp = expandedProj === s.name;
          const dayRows = (allDailyData[s.domain || s.name] || []);
          return <div key={i} style={{ background: isExp ? "rgba(36,120,181,0.06)" : "rgba(8,13,26,0.35)", border: `1px solid ${isExp ? "rgba(36,120,181,0.3)" : C.bdr}`, borderRadius: 12, marginBottom: 10, overflow: "hidden", transition: "border-color 0.2s" }}>
            {/* Header row */}
            <div onClick={() => setExpandedProj(isExp ? null : s.name)} style={{ padding: "14px 14px 12px", cursor: "pointer" }}>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
                  <span style={{ width: 8, height: 8, borderRadius: "50%", background: C.grn, flexShrink: 0 }} />
                  <span style={{ color: "#5dade2", fontFamily: "monospace", fontSize: 14, fontWeight: 700, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{s.name}</span>
                </div>
                <span style={{ color: C.mut, fontSize: 9, flexShrink: 0, marginLeft: 8, transform: isExp ? "rotate(0)" : "rotate(-90deg)", transition: "transform 0.2s" }}>▼</span>
              </div>
              {/* Main metrics */}
              <div style={{ display: "flex", alignItems: "flex-end" }}>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 1, marginBottom: 2 }}>Receita</div>
                  <div style={{ fontSize: 18, fontWeight: 800, color: C.br }}>{$(s.rev, "usd")}</div>
                </div>
                <div style={{ textAlign: "right", marginRight: 28 }}>
                  <div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 1, marginBottom: 2 }}>Líquido</div>
                  <div style={{ fontSize: 18, fontWeight: 800, color: s.liq >= 0 ? C.grn : C.red }}>{$(s.liq, "usd")}</div>
                </div>
                <div style={{ textAlign: "right" }}>
                  <div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 1, marginBottom: 2 }}>Margem</div>
                  <div style={{ fontSize: 18, fontWeight: 800, color: s.margin >= 0 ? C.grn : C.red }}>{$(s.margin, "pct")}</div>
                </div>
              </div>
              {/* Secondary metrics */}
              <div style={{ display: "flex", justifyContent: "space-between", marginTop: 10, paddingTop: 10, borderTop: "1px solid rgba(30,48,80,0.3)" }}>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 0.8 }}>Gasto Meta</div>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.red, marginTop: 2 }}>{$(s.spend, "usd")}</div>
                </div>
                <div style={{ flex: 1, textAlign: "center" }}>
                  <div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 0.8 }}>Imp.</div>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.txt, marginTop: 2 }}>{$(s.imp, "int")}</div>
                </div>
                <div style={{ flex: 1, textAlign: "right" }}>
                  <div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 0.8 }}>eCPM</div>
                  <div style={{ fontSize: 13, fontWeight: 600, color: C.txt, marginTop: 2 }}>{$(s.ecpm, "usd")}</div>
                </div>
              </div>
            </div>
            {/* Expanded daily */}
            {isExp && <div style={{ borderTop: `1px solid rgba(36,120,181,0.2)`, background: "rgba(8,13,26,0.4)" }}>
              <div style={{ padding: "12px 14px 8px", display: "flex", alignItems: "center", gap: 6 }}>
                <span style={{ fontSize: 13 }}>📅</span>
                <span style={{ fontSize: 12, color: C.blu, fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.8 }}>Detalhamento diário</span>
              </div>
              {dayRows.length > 0 ? <div style={{ overflowX: "auto", WebkitOverflowScrolling: "touch", padding: "0 0 12px" }}>
                <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 460 }}>
                  <thead><tr style={{ borderBottom: "1px solid rgba(30,48,80,0.4)" }}>
                    {["Data","eCPM","Imp.","Gasto Meta","Receita","Líquido","Margem"].map((h,hi) => (
                      <th key={hi} style={{ textAlign: hi === 0 ? "left" : "right", padding: "6px 8px", fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 0.8, fontWeight: 600 }}>{h}</th>
                    ))}
                  </tr></thead>
                  <tbody>{dayRows.map((d, j) => { var spend = d.spend || 0; var projRS = revShareByDomain[s.domain] || 0; var dayRS = d.rev * projRS; var dayTax = d.rev * taxRateHome / 100; var liq = d.rev - spend - dayRS - dayTax; var margin = spend > 0 ? (liq / spend) * 100 : (d.rev > 0 ? (liq / d.rev) * 100 : 0); return <tr key={j} style={{ borderBottom: j < dayRows.length - 1 ? "1px solid rgba(30,48,80,0.25)" : "none" }}>
                    <td style={{ padding: "8px 8px", fontSize: 12, color: C.blu, fontWeight: 600 }}>{d.date}</td>
                    <td style={{ textAlign: "right", padding: "8px 8px", fontSize: 12, color: "rgba(148,163,184,0.6)" }}>{$(d.imp > 0 ? (d.rev / d.imp) * 1000 : 0, "usd")}</td>
                    <td style={{ textAlign: "right", padding: "8px 8px", fontSize: 12, color: "rgba(148,163,184,0.6)" }}>{$(d.imp, "int")}</td>
                    <td style={{ textAlign: "right", padding: "8px 8px", fontSize: 12, color: C.red }}>{$(spend, "usd")}</td>
                    <td style={{ textAlign: "right", padding: "8px 8px", fontSize: 12, color: C.br, fontWeight: 600 }}>{$(d.rev, "usd")}</td>
                    <td style={{ textAlign: "right", padding: "8px 8px", fontSize: 12, color: liq >= 0 ? C.grn : C.red, fontWeight: 700 }}>{$(liq, "usd")}</td>
                    <td style={{ textAlign: "right", padding: "8px 8px", fontSize: 12, color: margin >= 0 ? C.grn : C.red, fontWeight: 700 }}>{$(margin, "pct")}</td>
                  </tr>; })}</tbody>
                </table>
              </div> : <div style={{ padding: "16px", textAlign: "center", fontSize: 12, color: C.mut }}>Carregando dados diários...</div>}
            </div>}
          </div>;
        }) : <>
          <table style={{ width: "100%", borderCollapse: "collapse" }}>
          <thead><tr style={{ borderBottom: "1px solid " + C.bdr }}>
            <th style={{ textAlign: "left", padding: "8px 12px", fontSize: 12, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Projeto</th>
            <th style={{ width: 65, textAlign: "right", padding: "8px", fontSize: 12, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>eCPM</th>
            <th style={{ width: 75, textAlign: "right", padding: "8px", fontSize: 12, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Imp.</th>
            <th style={{ width: 90, textAlign: "right", padding: "8px", fontSize: 12, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Gasto Meta</th>
            <th style={{ width: 90, textAlign: "right", padding: "8px", fontSize: 12, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Receita</th>
            <th style={{ width: 90, textAlign: "right", padding: "8px", fontSize: 12, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Líquido</th>
            <th style={{ width: 65, textAlign: "right", padding: "8px", fontSize: 12, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Margem</th>
          </tr></thead>
          <tbody>
          {[...sc].sort((a, b) => (b.rev - a.rev) || ((b.yesterdayRev || 0) - (a.yesterdayRev || 0))).map((s, i) => <React.Fragment key={i}>
            <tr onClick={() => setExpandedProj(expandedProj === s.name ? null : s.name)} style={{ cursor: "pointer", borderBottom: expandedProj === s.name ? "none" : (i < sc.length - 1 ? "1px solid " + C.bdr : "none") }}>
              <td style={{ padding: "14px 16px", fontSize: 15 }}><span style={{ display: "inline-block", width: 6, height: 6, borderRadius: "50%", background: C.grn, marginRight: 8 }} /><span style={{ fontWeight: 600 }}>{expandedProj === s.name ? "▼" : "▶"}</span> {s.name}</td>
              <td style={{ width: 75, textAlign: "right", padding: "12px 10px", fontSize: 14, color: "rgba(148,163,184,0.6)" }}>{$(s.ecpm, "usd")}</td>
              <td style={{ width: 80, textAlign: "right", padding: "12px 10px", fontSize: 14, color: "rgba(148,163,184,0.6)" }}>{$(s.imp, "int")}</td>
              <td style={{ width: 100, textAlign: "right", padding: "12px 10px", fontSize: 14, color: C.red }}>{$(s.spend, "usd")}</td>
              <td style={{ width: 90, textAlign: "right", padding: "10px 8px", fontSize: 12, fontWeight: 700, color: C.br }}>{$(s.rev, "usd")}</td>
              <td style={{ width: 100, textAlign: "right", padding: "12px 10px", fontSize: 15, fontWeight: 700, color: s.liq >= 0 ? C.grn : C.red }}>{$(s.liq, "usd")}</td>
              <td style={{ width: 75, textAlign: "right", padding: "12px 10px", fontSize: 15, fontWeight: 700, color: s.margin >= 0 ? C.grn : C.red }}>{$(s.margin, "pct")}</td>
            </tr>
            {expandedProj === s.name && <tr><td colSpan={7} style={{ padding: "0 12px 12px" }}>
              <div style={{ background: "rgba(8,13,26,0.5)", borderRadius: 8, padding: 10, border: "1px solid " + C.bdr }}>
                <div style={{ fontSize: 14, color: C.mut, fontWeight: 600, marginBottom: 8 }}>Detalhamento diário — {s.name}</div>
                <table style={{ width: "100%", borderCollapse: "collapse" }}>
                  <thead><tr style={{ borderBottom: "1px solid " + C.bdr }}>
                    <th style={{ textAlign: "left", padding: "8px 12px", fontSize: 12, color: C.mut }}>Data</th>
                    <th style={{ textAlign: "right", padding: "8px 10px", fontSize: 12, color: C.mut }}>eCPM</th>
                    <th style={{ textAlign: "right", padding: "8px 10px", fontSize: 12, color: C.mut }}>Imp.</th>
                    <th style={{ textAlign: "right", padding: "8px 10px", fontSize: 12, color: C.mut }}>Gasto Meta</th>
                    <th style={{ textAlign: "right", padding: "8px 10px", fontSize: 12, color: C.mut }}>Receita</th>
                    <th style={{ textAlign: "right", padding: "8px 10px", fontSize: 12, color: C.mut }}>Líquido</th>
                    <th style={{ textAlign: "right", padding: "8px 10px", fontSize: 12, color: C.mut }}>Margem</th>
                  </tr></thead>
                  <tbody>{(allDailyData[s.domain || s.name] || []).map((d, j) => { var spend = d.spend || 0; var projRS = revShareByDomain[s.domain] || 0; var dayRS = d.rev * projRS; var dayTax = d.rev * taxRateHome / 100; var liq = d.rev - spend - dayRS - dayTax; var margin = spend > 0 ? (liq / spend) * 100 : (d.rev > 0 ? (liq / d.rev) * 100 : 0); return <tr key={j} style={{ borderBottom: j < (allDailyData[s.domain || s.name] || []).length - 1 ? "1px solid rgba(30,48,80,0.3)" : "none" }}>
                    <td style={{ padding: "8px 12px", fontSize: 13, color: C.txt }}>{d.date}</td>
                    <td style={{ textAlign: "right", padding: "8px 10px", fontSize: 13, color: "rgba(148,163,184,0.6)" }}>{$(d.imp > 0 ? (d.rev / d.imp) * 1000 : 0, "usd")}</td>
                    <td style={{ textAlign: "right", padding: "8px 10px", fontSize: 13, color: "rgba(148,163,184,0.6)" }}>{$(d.imp, "int")}</td>
                    <td style={{ textAlign: "right", padding: "8px 10px", fontSize: 13, color: C.red }}>{$(spend, "usd")}</td>
                    <td style={{ textAlign: "right", padding: "8px 10px", fontSize: 13, color: C.br, fontWeight: 600 }}>{$(d.rev, "usd")}</td>
                    <td style={{ textAlign: "right", padding: "8px 10px", fontSize: 13, color: liq >= 0 ? C.grn : C.red, fontWeight: 600 }}>{$(liq, "usd")}</td>
                    <td style={{ textAlign: "right", padding: "8px 10px", fontSize: 13, color: margin >= 0 ? C.grn : C.red, fontWeight: 600 }}>{$(margin, "pct")}</td>
                  </tr>; })}</tbody>
                </table>
                {(!allDailyData[s.domain || s.name] || allDailyData[s.domain || s.name].length === 0) && <div style={{ fontSize: 11, color: C.mut, textAlign: "center", padding: 8 }}>Carregando dados diários...</div>}
              </div>
            </td></tr>}
          </React.Fragment>)}
          </tbody></table>
        </>}
      </Sec>
    )}
    <Sec icon="💵" label="P&L" open={true} badge={{ t: tot.liq >= 0 ? "PROFIT" : "LOSS", bg: tot.liq >= 0 ? "rgba(46,204,113,0.15)" : "rgba(231,76,60,0.15)", c: tot.liq >= 0 ? C.grn : C.red }}>
      {[{ l: "Receita bruta", v: $(tot.rev, "usd"), c: C.br, b: true }, { l: "(-) Gasto Facebook", v: $(tot.spend, "usd"), c: C.red }, { l: "(-) Rev Share", v: $(tot.rs, "usd"), c: C.yel }, { l: "(-) Impostos " + taxRateHome + "%", v: $(tot.tax, "usd"), c: C.yel }, { l: "= Lucro bruto", v: $(tot.gross, "usd"), c: tot.gross >= 0 ? C.grn : C.red, b: true, sep: true }, { l: "(-) Despesas fixas" + (periodDays < 30 ? " (" + periodDays + "d)" : ""), v: $(fixed, "usd"), c: C.yel }, { l: "= LÍQUIDO FINAL", v: $(tot.liq, "usd"), c: tot.liq >= 0 ? C.grn : C.red, b: true, sep: true, big: true }].map((r, i) => (
        <div key={i} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: r.big ? "12px 0" : "8px 0", borderTop: r.sep ? `1px solid ${C.bdr}` : "none", marginTop: r.sep ? 4 : 0 }}>
          <span style={{ color: r.b ? C.br : C.mut, fontWeight: r.b ? 600 : 400, fontSize: r.big ? 15 : 14 }}>{r.l}</span>
          <span style={{ color: r.c, fontWeight: r.b ? 700 : 500, fontSize: r.big ? 18 : 14, fontVariantNumeric: "tabular-nums" }}>{r.v}</span>
        </div>
      ))}
    </Sec>
  </>;
}

/* ===== PAGE: FACEBOOK APPS ===== */
/* ===== PAGE: FACEBOOK APPS ===== */
function PgFbApps({ mob }) {
  const STATUSES = { dev: { l: "Development", c: C.yel, bg: "rgba(243,156,18,0.15)" }, review: { l: "Em Review", c: C.blu, bg: "rgba(43,126,201,0.15)" }, approved: { l: "Aprovada (Live)", c: C.grn, bg: "rgba(46,204,113,0.15)" }, rejected: { l: "Rejeitada", c: C.red, bg: "rgba(231,76,60,0.15)" } };

  const [apps, setApps, saveApps] = useServerState("fbapps", [
    { id: 1, name: "Lumora360 Dashboard App", appId: "", appSecret: "", status: "dev", permissions: { ads_read: "pending", ads_management: "pending", business_management: "pending" }, bmsLinked: 6, notes: "App principal — conecta todos os BMs" },
  ]);
  const [showAdd, setShowAdd] = useState(false);
  const [newName, setNewName] = useState("");
  const [expandedSteps, setExpandedSteps] = useState({});
  const [expandedSubSteps, setExpandedSubSteps] = useState({});

  const upd = (id, f, v) => setApps(p => p.map(a => a.id === id ? { ...a, [f]: v } : a));
  const updPerm = (id, perm, val) => setApps(p => p.map(a => a.id === id ? { ...a, permissions: { ...a.permissions, [perm]: val } } : a));
  const toggleStep = (key) => setExpandedSteps(p => ({ ...p, [key]: !p[key] }));
  const toggleSub = (key) => setExpandedSubSteps(p => ({ ...p, [key]: !p[key] }));

  const submitReview = async (id) => {
    upd(id, "status", "review");
    await new Promise(r => setTimeout(r, 3000));
    upd(id, "status", "approved");
    const app = apps.find(a => a.id === id);
    Object.keys(app.permissions).forEach(p => updPerm(id, p, "approved"));
  };

  const add = () => {
    if (!newName.trim()) return;
    setApps(p => [...p, { id: Date.now(), name: newName, appId: "", appSecret: "", status: "dev", permissions: { ads_read: "pending", ads_management: "pending", business_management: "pending" }, bmsLinked: 0, notes: "Contingência" }]);
    setNewName(""); setShowAdd(false);
  };

  const approved = apps.filter(a => a.status === "approved").length;
  const permColors = { pending: C.yel, approved: C.grn, rejected: C.red };
  const permLabels = { pending: "Pendente", approved: "Aprovado", rejected: "Rejeitado" };

  const StepItem = ({ num, title, detail, subSteps, appId, section, color }) => {
    const key = `${appId}-${section}-${num}`;
    const isOpen = expandedSubSteps[key];
    return (
      <div style={{ borderBottom: `1px solid ${C.bdr}`, padding: "8px 0" }}>
        <div onClick={() => toggleSub(key)} style={{ display: "flex", gap: 10, cursor: "pointer", alignItems: "flex-start" }}>
          <span style={{ width: 24, height: 24, borderRadius: "50%", background: `${color}20`, color: color, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, fontWeight: 700, flexShrink: 0, marginTop: 1 }}>{num}</span>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 13, color: C.br, fontWeight: 600 }}>{title}</div>
            <div style={{ fontSize: 11, color: C.mut, marginTop: 2 }}>{detail}</div>
          </div>
          {subSteps && <span style={{ color: C.mut, fontSize: 10, transform: isOpen ? "rotate(90deg)" : "rotate(0)", transition: "transform 0.2s", flexShrink: 0, marginTop: 4 }}>▶</span>}
        </div>
        {isOpen && subSteps && (
          <div style={{ marginLeft: 34, marginTop: 8, padding: "10px 12px", background: "rgba(8,13,26,0.4)", borderRadius: 8, border: `1px solid ${C.bdr}` }}>
            {subSteps.map((sub, i) => (
              <div key={i} style={{ padding: "5px 0", borderBottom: i < subSteps.length - 1 ? `1px solid rgba(30,48,80,0.3)` : "none", fontSize: 12 }}>
                {sub.type === "tip" ? (
                  <div style={{ padding: "6px 10px", background: "rgba(46,204,113,0.08)", borderRadius: 6, border: "1px solid rgba(46,204,113,0.15)", color: C.grn, fontSize: 11 }}>
                    💡 {sub.text}
                  </div>
                ) : sub.type === "warn" ? (
                  <div style={{ padding: "6px 10px", background: "rgba(243,156,18,0.08)", borderRadius: 6, border: "1px solid rgba(243,156,18,0.15)", color: C.yel, fontSize: 11 }}>
                    ⚠️ {sub.text}
                  </div>
                ) : sub.type === "text" ? (
                  <div style={{ padding: "6px 10px", background: "rgba(43,126,201,0.08)", borderRadius: 6, border: "1px solid rgba(43,126,201,0.15)", color: C.blu, fontSize: 11, fontFamily: "monospace", whiteSpace: "pre-wrap" }}>
                    📝 Texto sugerido: "{sub.text}"
                  </div>
                ) : (
                  <div style={{ display: "flex", gap: 8 }}>
                    <span style={{ color: C.mut, flexShrink: 0 }}>•</span>
                    <span style={{ color: C.txt }}>{sub.text}</span>
                  </div>
                )}
              </div>
            ))}
          </div>
        )}
      </div>
    );
  };

  const CREATE_STEPS = [
    { num: 1, title: "Registre-se como desenvolvedor Meta", detail: "Pré-requisito para criar qualquer App", subs: [
      { text: "Acesse developers.facebook.com" },
      { text: "Faça login com a mesma conta do Facebook que é admin do seu BM" },
      { text: "Clique em 'Começar' ou 'Get Started'" },
      { text: "Aceite os termos de desenvolvedor e complete o registro" },
      { type: "tip", text: "Use sua conta pessoal principal — não crie contas fake, Meta pode bloquear" },
    ]},
    { num: 2, title: "Crie uma nova App", detail: "A App é o container que conecta à Marketing API", subs: [
      { text: "Clique em My Apps → Create App" },
      { text: "Na tela 'Add a use case', selecione: 'Other' → 'Business'" },
      { text: "Isso é OBRIGATÓRIO — só apps tipo Business podem usar Marketing API" },
      { text: "Dê um nome claro: ex 'Lumora360 Dashboard'" },
      { text: "Em Business Portfolio, selecione o BM que é provedor de tecnologia" },
      { text: "Clique Create App → confirme com sua senha" },
      { type: "warn", text: "Se selecionar tipo Consumer ou Gaming, NÃO vai ter acesso à Marketing API" },
    ]},
    { num: 3, title: "Adicione o produto Marketing API", detail: "Habilita os endpoints de anúncios", subs: [
      { text: "No painel da App, vá em Add Product (menu lateral)" },
      { text: "Encontre 'Marketing API' na lista" },
      { text: "Clique em 'Set Up'" },
      { text: "Pronto — agora a Marketing API aparece no menu lateral" },
      { type: "tip", text: "Após adicionar, você já pode gerar tokens de teste em Marketing API → Tools" },
    ]},
    { num: 4, title: "Copie as credenciais (App ID + App Secret)", detail: "Você vai precisar dessas credenciais no dashboard", subs: [
      { text: "Vá em Settings → Basic" },
      { text: "O App ID aparece no topo da página" },
      { text: "O App Secret está oculto — clique 'Show' e confirme com senha" },
      { text: "Copie ambos e cole nos campos acima nesta página" },
      { type: "warn", text: "NUNCA compartilhe o App Secret publicamente. Trate como uma senha." },
    ]},
    { num: 5, title: "Vincule a App ao seu Business Manager", detail: "Necessário para que a App acesse os ativos do BM", subs: [
      { text: "Vá em business.facebook.com → Configurações do Negócio" },
      { text: "Menu lateral → Contas → Apps" },
      { text: "Clique + Adicionar → Adicionar um App ID" },
      { text: "Cole o App ID da app que acabou de criar" },
      { text: "A App agora está vinculada ao BM" },
      { type: "tip", text: "Faça isso em CADA BM que quer conectar a esta App" },
    ]},
  ];

  const REVIEW_STEPS = [
    { num: 1, title: "Verifique o seu Business Manager", detail: "Obrigatório antes de pedir permissões avançadas", subs: [
      { text: "Vá em business.facebook.com → Configurações → Central de Segurança" },
      { text: "Inicie a 'Verificação de negócios'" },
      { text: "Envie documentos da empresa (CNPJ, contrato social, etc.)" },
      { text: "Meta analisa em 1-5 dias úteis" },
      { type: "tip", text: "Você disse que já tem a BM verificada como provedora de tecnologia — se sim, pule este passo!" },
    ]},
    { num: 2, title: "Acesse o painel de App Review", detail: "Onde você solicita as permissões", subs: [
      { text: "No painel da App em developers.facebook.com" },
      { text: "Menu lateral → App Review → Permissions and Features" },
      { text: "Você vai ver uma lista de todas as permissões disponíveis" },
      { text: "Cada permissão tem um botão 'Request' ou 'Get Advanced Access'" },
    ]},
    { num: 3, title: "Solicite 'Ads Management Standard Access'", detail: "Permissão principal — sem ela não funciona em produção", subs: [
      { text: "Procure 'Ads Management Standard Access' na lista" },
      { text: "Clique em 'Request'" },
      { text: "Isso abre o formulário de App Review" },
      { type: "warn", text: "Sem este tier, você só acessa suas próprias contas em modo Development — limitado a 600 calls/hora" },
    ]},
    { num: 4, title: "Solicite 'ads_read' — Advanced Access", detail: "Permite ler dados de campanhas, insights, métricas", subs: [
      { text: "Na mesma lista, procure 'ads_read'" },
      { text: "Clique em 'Get Advanced Access'" },
      { text: "Preencha a descrição de uso:" },
      { type: "text", text: "Our application is a publisher P&L dashboard that reads ad campaign performance data (spend, impressions, leads, CPC, CPL) to calculate ROI per project. We only READ data — we do not create, modify, or delete any campaigns. This is an internal business intelligence tool." },
      { type: "tip", text: "Seja específico sobre o que você lê e por quê. Meta gosta de ver que é read-only e para BI." },
    ]},
    { num: 5, title: "Solicite 'ads_management' — Advanced Access", detail: "Permite acesso completo a contas de anúncio", subs: [
      { text: "Procure 'ads_management' na lista" },
      { text: "Clique em 'Get Advanced Access'" },
      { text: "Preencha a descrição:" },
      { type: "text", text: "We use ads_management to access ad account insights, campaign structure, and spending data across multiple Business Managers. Our dashboard aggregates spend vs. revenue for publisher arbitrage operations. No campaign modifications are made via API." },
      { type: "tip", text: "Mesmo se você não vai criar campanhas via API, ads_management dá acesso completo às métricas." },
    ]},
    { num: 6, title: "Solicite 'business_management' (opcional mas recomendado)", detail: "Permite listar contas de anúncio e ativos do BM automaticamente", subs: [
      { text: "Procure 'business_management'" },
      { text: "Clique em 'Get Advanced Access'" },
      { type: "text", text: "We use business_management to programmatically list all ad accounts under each Business Manager, so our dashboard can automatically detect and sync connected accounts without manual configuration." },
      { type: "tip", text: "Com esta permissão, o dashboard detecta automaticamente as contas de anúncio de cada BM." },
    ]},
    { num: 7, title: "Prepare o material de apoio", detail: "Screenshots e documentação que aumentam chance de aprovação", subs: [
      { text: "Tire screenshots do seu dashboard mostrando onde os dados do FB aparecem" },
      { text: "Mostre a tela de KPIs com 'Gasto FB', 'CPL', 'Leads'" },
      { text: "Mostre a tela de BMs Facebook com as contas conectadas" },
      { text: "Grave um screencast de 1-2 minutos mostrando o fluxo (opcional mas ajuda MUITO)" },
      { text: "Tenha uma Privacy Policy publicada em URL pública (ex: bluegrid.media/privacy)" },
      { text: "Tenha Terms of Service publicados (ex: bluegrid.media/terms)" },
      { type: "tip", text: "Meta quer ver que é uma ferramenta real com interface. Quanto mais profissional parecer, melhor." },
      { type: "warn", text: "Sem Privacy Policy = rejeição automática. Use um gerador online se necessário." },
    ]},
    { num: 8, title: "Submeta e aguarde", detail: "Meta revisa em 1-7 dias úteis", subs: [
      { text: "Revise todas as informações do formulário" },
      { text: "Clique Submit" },
      { text: "Você recebe email de confirmação" },
      { text: "Status da App muda para 'Em Review'" },
      { text: "Meta pode pedir informações adicionais — responda rápido" },
      { type: "tip", text: "Se demorar mais de 7 dias, acesse a comunidade de desenvolvedores Meta e abra um ticket." },
    ]},
    { num: 9, title: "Aprovação → Modo Live", detail: "Quando aprovada, a App pode acessar qualquer conta autorizada", subs: [
      { text: "Você recebe email: 'Your app has been approved'" },
      { text: "Status muda de Development para Live" },
      { text: "Agora a App pode gerar tokens que acessam QUALQUER conta de anúncio que autorizar" },
      { text: "Vá em BMs Facebook no dashboard e use esta App para gerar tokens" },
      { text: "Rate limits aumentam: 190.000 + 400 × ads ativos por hora" },
      { type: "tip", text: "Crie mais Apps como contingência. Se Meta desabilitar uma, você tem backup." },
      { type: "warn", text: "Se rejeitada: leia o feedback, corrija, e reenvie. Rejeição NÃO é permanente." },
    ]},
  ];

  return <>
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(3,1fr)", gap: 8, marginBottom: 14 }}>
      <KPI label="Total Apps" value={apps.length} mob={mob} />
      <KPI label="Aprovadas" value={`${approved}/${apps.length}`} color={approved > 0 ? C.grn : C.yel} mob={mob} />
      <KPI label="BMs conectados" value={apps.reduce((a, ap) => a + ap.bmsLinked, 0)} mob={mob} />
    </div>

    {apps.map(app => {
      const st = STATUSES[app.status];
      return (
        <Sec key={app.id} icon={app.status === "approved" ? "🟢" : app.status === "review" ? "🔵" : app.status === "rejected" ? "🔴" : "🟡"} label={app.name} open={true}
          badge={{ t: st.l, bg: st.bg, c: st.c }}>

          {app.notes && <div style={{ fontSize: 12, color: C.mut, marginBottom: 10 }}>{app.notes}</div>}

          {/* App credentials */}
          <Inp label="App ID" value={app.appId} onChange={v => upd(app.id, "appId", v)} placeholder="1234567890123456" help="Settings → Basic" mob={mob} />
          <Inp label="App Secret" value={app.appSecret} onChange={v => upd(app.id, "appSecret", v)} placeholder="abc123def456..." pw help="Settings → Basic → Show" mob={mob} />

          {/* Permissions */}
          <div style={{ marginBottom: 12 }}>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 6 }}>Permissões necessárias</span>
            {Object.entries(app.permissions).map(([perm, status]) => (
              <div key={perm} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "6px 10px", marginBottom: 4, borderRadius: 8, background: "rgba(8,13,26,0.4)", border: `1px solid ${C.bdr}` }}>
                <div>
                  <span style={{ fontFamily: "monospace", fontSize: 12, color: C.txt }}>{perm}</span>
                  <span style={{ fontSize: 10, color: C.mut, marginLeft: 8 }}>
                    {perm === "ads_read" ? "Ler métricas e insights" : perm === "ads_management" ? "Acesso completo a contas" : "Listar ativos do BM"}
                  </span>
                </div>
                <span style={{ fontSize: 10, padding: "2px 8px", borderRadius: 6, background: `${permColors[status]}15`, color: permColors[status], fontWeight: 600 }}>{permLabels[status]}</span>
              </div>
            ))}
          </div>

          {/* Status flow */}
          <div style={{ marginBottom: 14 }}>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 6 }}>Fluxo de aprovação</span>
            <div style={{ display: "flex", gap: 4, alignItems: "center", flexWrap: "wrap" }}>
              {["dev", "review", "approved"].map((s, i) => (
                <div key={s} style={{ display: "flex", alignItems: "center", gap: 4 }}>
                  <span style={{ fontSize: 11, padding: "4px 10px", borderRadius: 8, background: app.status === s ? STATUSES[s].bg : "rgba(8,13,26,0.4)", border: `1px solid ${app.status === s ? STATUSES[s].c + "40" : C.bdr}`, color: app.status === s ? STATUSES[s].c : C.mut, fontWeight: app.status === s ? 600 : 400 }}>{STATUSES[s].l}</span>
                  {i < 2 && <span style={{ color: C.mut, fontSize: 10 }}>→</span>}
                </div>
              ))}
            </div>
          </div>

          {/* STEP 1: How to create */}
          <div style={{ marginBottom: 10 }}>
            <div onClick={() => toggleStep(`${app.id}-create`)} style={{ display: "flex", alignItems: "center", gap: 6, cursor: "pointer", fontSize: 13, color: C.blu, fontWeight: 600, padding: "8px 12px", background: "rgba(43,126,201,0.06)", borderRadius: 8, border: `1px solid rgba(43,126,201,0.15)` }}>
              <span style={{ transform: expandedSteps[`${app.id}-create`] ? "rotate(90deg)" : "rotate(0)", transition: "transform 0.2s" }}>▶</span>
              📱 Fase 1 — Criar a App ({CREATE_STEPS.length} passos)
            </div>
            {expandedSteps[`${app.id}-create`] && (
              <div style={{ padding: "8px 0 0 0" }}>
                {CREATE_STEPS.map(step => (
                  <StepItem key={step.num} num={step.num} title={step.title} detail={step.detail} subSteps={step.subs} appId={app.id} section="create" color={C.blu} />
                ))}
              </div>
            )}
          </div>

          {/* STEP 2: App Review */}
          <div style={{ marginBottom: 12 }}>
            <div onClick={() => toggleStep(`${app.id}-review`)} style={{ display: "flex", alignItems: "center", gap: 6, cursor: "pointer", fontSize: 13, color: "#a78bfa", fontWeight: 600, padding: "8px 12px", background: "rgba(139,92,246,0.06)", borderRadius: 8, border: `1px solid rgba(139,92,246,0.15)` }}>
              <span style={{ transform: expandedSteps[`${app.id}-review`] ? "rotate(90deg)" : "rotate(0)", transition: "transform 0.2s" }}>▶</span>
              📋 Fase 2 — App Review / Aprovação ({REVIEW_STEPS.length} passos)
            </div>
            {expandedSteps[`${app.id}-review`] && (
              <div style={{ padding: "8px 0 0 0" }}>
                {REVIEW_STEPS.map(step => (
                  <StepItem key={step.num} num={step.num} title={step.title} detail={step.detail} subSteps={step.subs} appId={app.id} section="review" color={"#a78bfa"} />
                ))}
              </div>
            )}
          </div>

          {/* Actions */}
          <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
            {app.status === "dev" && <Btn onClick={() => submitReview(app.id)} disabled={!app.appId} color="#a78bfa" small>📋 Submeter App Review</Btn>}
            {app.status === "review" && <span style={{ fontSize: 12, color: C.blu, display: "flex", alignItems: "center", gap: 6 }}><span style={{ display: "inline-block", animation: "spin 1s linear infinite", width: 12, height: 12, border: "2px solid currentColor", borderTopColor: "transparent", borderRadius: "50%" }} />Em análise pela Meta (1-7 dias)...</span>}
            {app.status === "approved" && <span style={{ fontSize: 12, color: C.grn, fontWeight: 600 }}>✓ App aprovada — modo Live ativo</span>}
            {app.status === "rejected" && <><Btn onClick={() => upd(app.id, "status", "dev")} color={C.yel} small>Corrigir e reenviar</Btn><span style={{ fontSize: 11, color: C.red }}>Leia o feedback da Meta</span></>}
            <Btn onClick={() => setApps(p => p.filter(x => x.id !== app.id))} color="rgba(231,76,60,0.15)" small>Remover</Btn>
          </div>
          <style>{`@keyframes spin{to{transform:rotate(360deg)}}`}</style>
        </Sec>
      );
    })}

    {showAdd ? (
      <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 12, padding: 16, marginBottom: 12 }}>
        <div style={{ fontSize: 13, fontWeight: 600, color: C.br, marginBottom: 10 }}>Nova Facebook App (contingência)</div>
        <Inp label="Nome da App" value={newName} onChange={v => setNewName(v)} placeholder="Ex: Lumora360 App 02" mob={mob} />
        <div style={{ display: "flex", gap: 8 }}><Btn onClick={add} color={C.grn} small>Criar</Btn><Btn onClick={() => setShowAdd(false)} color="rgba(30,48,80,0.6)" small>Cancelar</Btn></div>
      </div>
    ) : <div style={{ textAlign: "center", paddingTop: 4 }}><Btn onClick={() => setShowAdd(true)} color={C.blu} small>+ Nova App (contingência)</Btn></div>}

    <InfoBox>
      <span style={{ fontWeight: 600, color: "#3b82f6" }}>Resumo:</span> App → App Review → Aprovação → Gerar tokens nos BMs.
      <br />Tenha múltiplas Apps aprovadas como contingência. Sua BM verificada como provedora de tecnologia agiliza tudo.
      <br />Clique em cada passo acima para ver os detalhes e textos sugeridos para o App Review.
    </InfoBox>
    <SaveBar storageKey="fbapps" data={apps} mob={mob} />
  </>;
}

/* ========================================= */
/* ===== PAGE: DESPESAS FIXAS ============== */
/* ========================================= */
function PgDespesas({ mob }) {
  const [CATS, setCATS, saveCATS] = useServerState("despesas_cats", ["Servidores", "Ferramentas", "VPN / Proxies", "Equipe", "Software", "Outros"]);
  const [newCat, setNewCat] = useState("");
  const [editingCats, setEditingCats] = useState(false);
  const [projectNames, setProjectNames] = useState([]);
  useEffect(() => { 
    const local = loadLS("operacoes", []);
    if (local.length > 0) setProjectNames(local.map(p => p.name));
    fetch("/api/store/operacoes").then(r => r.json()).then(d => { if (d && d.value && Array.isArray(d.value)) setProjectNames(d.value.map(p => p.name)); }).catch(() => {}); 
  }, []);
  const PROJECTS = ["Global (todos)", ...projectNames];

  const [expenses, setExpenses, saveExpenses] = useServerState("despesas", []);

  const [showForm, setShowForm] = useState(false);
  const [editing, setEditing] = useState(null);
  const [form, setForm] = useState({ name: "", cat: "Servidores", value: "", recurrence: "monthly", project: "Global (todos)", month: "" });
  const [filterCat, setFilterCat] = useState("all");
  const [filterProject, setFilterProject] = useState("all");

  const startEdit = (e) => {
    setForm({ name: e.name, cat: e.cat, value: String(e.value), recurrence: e.recurrence, project: e.project, month: e.month });
    setEditing(e.id); setShowForm(true);
  };

  const save = () => {
    if (!form.name.trim() || !form.value) return;
    const data = { ...form, value: parseFloat(form.value) || 0 };
    if (editing) {
      setExpenses(p => p.map(e => e.id === editing ? { ...e, ...data } : e));
    } else {
      setExpenses(p => [...p, { id: Date.now(), ...data }]);
    }
    setEditing(null); setShowForm(false); setForm({ name: "", cat: CATS[0] || "Servidores", value: "", recurrence: "monthly", project: "Global (todos)", month: "" });
  };

  const remove = (id) => setExpenses(p => p.filter(e => e.id !== id));
  const cancel = () => { setEditing(null); setShowForm(false); setForm({ name: "", cat: "Servidores", value: "", recurrence: "monthly", project: "Global (todos)", month: "" }); };

  const filtered = expenses.filter(e => (filterCat === "all" || e.cat === filterCat) && (filterProject === "all" || e.project === filterProject));
  const monthlyTotal = expenses.filter(e => e.recurrence === "monthly").reduce((a, e) => a + e.value, 0);
  const onceTotal = expenses.filter(e => e.recurrence === "once").reduce((a, e) => a + e.value, 0);
  const globalTotal = expenses.filter(e => e.project === "Global (todos)" && e.recurrence === "monthly").reduce((a, e) => a + e.value, 0);
  const projectTotal = expenses.filter(e => e.project !== "Global (todos)" && e.recurrence === "monthly").reduce((a, e) => a + e.value, 0);

  const byCat = {};
  expenses.filter(e => e.recurrence === "monthly").forEach(e => { byCat[e.cat] = (byCat[e.cat] || 0) + e.value; });

  const byProject = {};
  expenses.forEach(e => { byProject[e.project] = (byProject[e.project] || 0) + e.value; });

  const fBrl = (v) => "R$ " + Number(v).toLocaleString("pt-BR", { minimumFractionDigits: 2, maximumFractionDigits: 2 });

  const catColors = { "Servidores": C.blu, "Ferramentas": "#a78bfa", "VPN / Proxies": C.yel, "Equipe": C.cyan, "Software": C.grn, "Outros": C.mut };

  return <>
    {/* KPIs */}
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(4,1fr)", gap: 8, marginBottom: 14 }}>
      <KPI label="Total mensal (fixo)" value={fBrl(monthlyTotal)} color={C.yel} mob={mob} />
      <KPI label="Pontuais este período" value={fBrl(onceTotal)} mob={mob} />
      <KPI label="Global" value={fBrl(globalTotal)} mob={mob} />
      <KPI label="Por projeto" value={fBrl(projectTotal)} mob={mob} />
    </div>

    {/* By category breakdown */}
    <Sec icon="📊" label="Resumo por categoria" open={true} count="mensal">
      {Object.entries(byCat).sort((a, b) => b[1] - a[1]).map(([cat, val], i) => (
        <div key={cat} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 0", borderBottom: i < Object.keys(byCat).length - 1 ? `1px solid ${C.bdr}` : "none" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <span style={{ width: 10, height: 10, borderRadius: 3, background: catColors[cat] || C.mut, flexShrink: 0 }} />
            <span style={{ fontSize: 13, color: C.br }}>{cat}</span>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <div style={{ width: mob ? 80 : 140, height: 6, background: "rgba(30,48,80,0.4)", borderRadius: 3, overflow: "hidden" }}>
              <div style={{ width: `${Math.min((val / monthlyTotal) * 100, 100)}%`, height: "100%", background: catColors[cat] || C.mut, borderRadius: 3 }} />
            </div>
            <span style={{ fontSize: 13, color: C.yel, fontWeight: 600, minWidth: 80, textAlign: "right" }}>{fBrl(val)}</span>
            <span style={{ fontSize: 11, color: C.mut, minWidth: 35, textAlign: "right" }}>{Math.round((val / monthlyTotal) * 100)}%</span>
          </div>
        </div>
      ))}
      <div style={{ display: "flex", justifyContent: "space-between", paddingTop: 8, borderTop: `2px solid ${C.bdr}`, marginTop: 4, fontSize: 14, fontWeight: 700 }}>
        <span style={{ color: C.br }}>Total mensal</span>
        <span style={{ color: C.yel }}>{fBrl(monthlyTotal)}</span>
      </div>
    </Sec>

    {/* By project breakdown */}
    <Sec icon="📂" label="Resumo por projeto" open={true}>
      {PROJECTS.map((proj, i) => {
        const projExpenses = expenses.filter(e => e.project === proj);
        const projMonthly = projExpenses.filter(e => e.recurrence === "monthly").reduce((a, e) => a + e.value, 0);
        const projOnce = projExpenses.filter(e => e.recurrence === "once").reduce((a, e) => a + e.value, 0);
        const projTotal = projMonthly + projOnce;
        if (projExpenses.length === 0) return null;
        return (
          <div key={proj} style={{ padding: "8px 0", borderBottom: i < PROJECTS.length - 1 ? `1px solid ${C.bdr}` : "none" }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <span style={{ fontSize: 12 }}>{proj === "Global (todos)" ? "🌍" : "📂"}</span>
                <span style={{ fontSize: 13, color: C.br, fontWeight: 600 }}>{proj}</span>
                <span style={{ fontSize: 11, color: C.mut }}>{projExpenses.length} itens</span>
              </div>
              <span style={{ fontSize: 13, color: C.yel, fontWeight: 700 }}>{fBrl(projTotal)}</span>
            </div>
            <div style={{ display: "flex", gap: 12, marginLeft: 28, fontSize: 11 }}>
              {projMonthly > 0 && <span style={{ color: C.blu }}>Mensal: {fBrl(projMonthly)}</span>}
              {projOnce > 0 && <span style={{ color: C.yel }}>Pontual: {fBrl(projOnce)}</span>}
            </div>
          </div>
        );
      })}
      <div style={{ display: "flex", justifyContent: "space-between", paddingTop: 8, borderTop: `2px solid ${C.bdr}`, marginTop: 4, fontSize: 14, fontWeight: 700 }}>
        <span style={{ color: C.br }}>Total geral</span>
        <span style={{ color: C.yel }}>{fBrl(monthlyTotal + onceTotal)}</span>
      </div>
    </Sec>

    {/* Filters */}
    <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 12 }}>
      <span onClick={() => setFilterCat("all")} style={{ fontSize: 11, padding: "4px 10px", borderRadius: 8, cursor: "pointer", background: filterCat === "all" ? "rgba(43,126,201,0.2)" : "rgba(8,13,26,0.5)", border: `1px solid ${filterCat === "all" ? C.blu : C.bdr}`, color: filterCat === "all" ? C.blu : C.mut }}>Todas categorias</span>
      {CATS.map(c => (
        <span key={c} onClick={() => setFilterCat(filterCat === c ? "all" : c)} style={{ fontSize: 11, padding: "4px 10px", borderRadius: 8, cursor: "pointer", background: filterCat === c ? `${catColors[c]}20` : "rgba(8,13,26,0.5)", border: `1px solid ${filterCat === c ? catColors[c] : C.bdr}`, color: filterCat === c ? catColors[c] : C.mut }}>
          {c}
        </span>
      ))}
    </div>
    <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 14 }}>
      <span onClick={() => setFilterProject("all")} style={{ fontSize: 11, padding: "4px 10px", borderRadius: 8, cursor: "pointer", background: filterProject === "all" ? "rgba(43,126,201,0.2)" : "rgba(8,13,26,0.5)", border: `1px solid ${filterProject === "all" ? C.blu : C.bdr}`, color: filterProject === "all" ? C.blu : C.mut }}>Todos projetos</span>
      {PROJECTS.map(p => (
        <span key={p} onClick={() => setFilterProject(filterProject === p ? "all" : p)} style={{ fontSize: 11, padding: "4px 10px", borderRadius: 8, cursor: "pointer", background: filterProject === p ? "rgba(93,173,226,0.2)" : "rgba(8,13,26,0.5)", border: `1px solid ${filterProject === p ? C.cyan : C.bdr}`, color: filterProject === p ? C.cyan : C.mut }}>
          {p}
        </span>
      ))}
    </div>

    {/* Add/Edit form */}
    {showForm && (
      <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 12, padding: 16, marginBottom: 12 }}>
        <div style={{ fontSize: 13, fontWeight: 600, color: C.br, marginBottom: 12 }}>{editing ? "Editar despesa" : "Nova despesa"}</div>
        <Inp label="Nome / descrição" value={form.name} onChange={v => setForm(p => ({ ...p, name: v }))} placeholder="Ex: DigitalOcean, Designer, Plugin X..." mob={mob} />
        <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr" : "1fr 1fr", gap: 8 }}>
          <Inp label="Valor (BRL)" value={form.value} onChange={v => setForm(p => ({ ...p, value: v }))} placeholder="Ex: 850.00" mob={mob} />
          <div style={{ marginBottom: 8 }}>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>Categoria</span>
            <select value={form.cat} onChange={e => setForm(p => ({ ...p, cat: e.target.value }))} style={{ width: "100%", padding: "7px 11px", borderRadius: 8, border: `1px solid ${C.bdr}`, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 12 }}>
              {CATS.map(c => <option key={c} value={c}>{c}</option>)}
            </select>
          </div>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr" : "1fr 1fr", gap: 8 }}>
          <div style={{ marginBottom: 8 }}>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 6 }}>Recorrência</span>
            <div style={{ display: "flex", gap: 6 }}>
              {[{ k: "monthly", l: "🔄 Mensal (todo mês)", c: C.blu }, { k: "once", l: "1️⃣ Pontual (só um mês)", c: C.yel }].map(r => (
                <span key={r.k} onClick={() => setForm(p => ({ ...p, recurrence: r.k }))} style={{ fontSize: 12, padding: "6px 12px", borderRadius: 8, cursor: "pointer", background: form.recurrence === r.k ? `${r.c}20` : "rgba(8,13,26,0.5)", border: `1px solid ${form.recurrence === r.k ? r.c : C.bdr}`, color: form.recurrence === r.k ? r.c : C.mut, fontWeight: form.recurrence === r.k ? 600 : 400, flex: 1, textAlign: "center" }}>{r.l}</span>
              ))}
            </div>
          </div>
          <div style={{ marginBottom: 8 }}>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 4 }}>Projeto</span>
            <select value={form.project} onChange={e => setForm(p => ({ ...p, project: e.target.value }))} style={{ width: "100%", padding: "7px 11px", borderRadius: 8, border: `1px solid ${C.bdr}`, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 12 }}>
              {PROJECTS.map(p => <option key={p} value={p}>{p}</option>)}
            </select>
          </div>
        </div>
        {form.recurrence === "once" && (
          <Inp label="Mês específico (YYYY-MM)" value={form.month} onChange={v => setForm(p => ({ ...p, month: v }))} placeholder="Ex: 2026-03" mob={mob} />
        )}
        <div style={{ display: "flex", gap: 8, marginTop: 4 }}>
          <Btn onClick={save} color={C.grn} small>Salvar</Btn>
          <Btn onClick={cancel} color="rgba(30,48,80,0.6)" small>Cancelar</Btn>
        </div>
      </div>
    )}

    {/* Expense list */}
    <Sec icon="📋" label="Despesas" count={filtered.length} open={true}>
      {filtered.length === 0 ? (
        <div style={{ padding: 16, textAlign: "center", color: C.mut, fontSize: 13 }}>Nenhuma despesa encontrada com os filtros selecionados.</div>
      ) : filtered.sort((a, b) => b.value - a.value).map((e, i) => (
        <div key={e.id} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: mob ? "10px 0" : "8px 0", borderBottom: i < filtered.length - 1 ? `1px solid ${C.bdr}` : "none", flexWrap: mob ? "wrap" : "nowrap", gap: mob ? 6 : 0 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8, flex: 1, minWidth: 0 }}>
            <span style={{ width: 8, height: 8, borderRadius: 3, background: catColors[e.cat] || C.mut, flexShrink: 0 }} />
            <div style={{ minWidth: 0 }}>
              <div style={{ fontSize: 13, color: C.br, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{e.name}</div>
              <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 2 }}>
                <span style={{ fontSize: 10, padding: "1px 6px", borderRadius: 4, background: `${catColors[e.cat]}15`, color: catColors[e.cat] }}>{e.cat}</span>
                <span style={{ fontSize: 10, padding: "1px 6px", borderRadius: 4, background: e.recurrence === "monthly" ? "rgba(43,126,201,0.1)" : "rgba(243,156,18,0.1)", color: e.recurrence === "monthly" ? C.blu : C.yel }}>{e.recurrence === "monthly" ? "Mensal" : `Pontual ${e.month}`}</span>
                {e.project !== "Global (todos)" && <span style={{ fontSize: 10, padding: "1px 6px", borderRadius: 4, background: "rgba(93,173,226,0.1)", color: C.cyan }}>{e.project}</span>}
              </div>
            </div>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 6, flexShrink: 0 }}>
            <span style={{ fontSize: 14, fontWeight: 600, color: C.yel, minWidth: 85, textAlign: "right" }}>{fBrl(e.value)}</span>
            <Btn onClick={() => startEdit(e)} color="rgba(43,126,201,0.2)" small>Editar</Btn>
            <Btn onClick={() => remove(e.id)} color="rgba(231,76,60,0.15)" small>✕</Btn>
          </div>
        </div>
      ))}
      <div style={{ display: "flex", justifyContent: "space-between", paddingTop: 8, borderTop: `1px solid ${C.bdr}`, marginTop: 4, fontSize: 13 }}>
        <span style={{ color: C.mut }}>Total filtrado ({filtered.length} itens)</span>
        <span style={{ color: C.yel, fontWeight: 700 }}>{fBrl(filtered.reduce((a, e) => a + e.value, 0))}</span>
      </div>
    </Sec>

    {/* Add button */}
    {!showForm && (
      <div style={{ textAlign: "center", paddingTop: 4 }}>
        <Btn onClick={() => { setForm({ name: "", cat: "Servidores", value: "", recurrence: "monthly", project: "Global (todos)", month: "" }); setEditing(null); setShowForm(true); }} color={C.blu} small>+ Nova despesa</Btn>
      </div>
    )}

    <InfoBox>
      <span style={{ fontWeight: 600, color: C.yel }}>Despesas em BRL:</span> Os valores são em Reais. No P&L do Dashboard, as despesas fixas são convertidas para USD usando a cotação do dia para calcular o líquido final.
      <br /><span style={{ fontWeight: 600, color: C.blu }}>Mensal:</span> Aparece automaticamente todo mês. <span style={{ fontWeight: 600, color: C.yel }}>Pontual:</span> Aparece só no mês especificado.
      <br /><span style={{ fontWeight: 600, color: C.cyan }}>Por projeto:</span> A despesa é contabilizada só no P&L daquele projeto. <span style={{ fontWeight: 600 }}>Global:</span> Dividida entre todos.
    </InfoBox>
    {editingCats && <div style={{ background: C.card, border: "1px solid " + C.bdr, borderRadius: 12, padding: 16, marginBottom: 12 }}>
      <div style={{ fontSize: 13, fontWeight: 600, color: C.br, marginBottom: 8 }}>Gerenciar categorias</div>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 6, marginBottom: 8 }}>
        {CATS.map(c => <span key={c} style={{ padding: "4px 10px", borderRadius: 8, background: "rgba(30,48,80,0.3)", color: C.txt, fontSize: 12, display: "flex", alignItems: "center", gap: 4 }}>{c} <span onClick={() => { setCATS(p => p.filter(x => x !== c)); saveLS("despesas_cats", CATS.filter(x => x !== c)); }} style={{ cursor: "pointer", color: C.red, fontWeight: 700 }}>×</span></span>)}
      </div>
      <div style={{ display: "flex", gap: 6 }}>
        <input value={newCat} onChange={e => setNewCat(e.target.value)} placeholder="Nova categoria..." style={{ padding: "5px 10px", borderRadius: 8, border: "1px solid " + C.bdr, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 12, flex: 1 }} />
        <Btn onClick={() => { if (newCat.trim()) { var nc = [...CATS, newCat.trim()]; setCATS(nc); saveLS("despesas_cats", nc); setNewCat(""); } }} color={C.grn} small>+ Adicionar</Btn>
      </div>
      <div style={{ marginTop: 8 }}><Btn onClick={() => setEditingCats(false)} color={C.mut} small>Fechar</Btn></div>
    </div>}
    <SaveBar storageKey="despesas" data={expenses} mob={mob} />
  </>;
}

/* ========================================= */
/* ===== PAGE: TRIBUTAÇÕES ================= */
/* ========================================= */
function PgTributacoes({ mob }) {
  const savedTribObj = loadLS("tributacoes", null);
  const [taxRate, setTaxRate, saveTaxRate] = useServerState("taxRate", (savedTribObj && savedTribObj.taxRate) ? savedTribObj.taxRate : 5);
  const [editingTax, setEditingTax] = useState(false);
  const [tempTax, setTempTax] = useState("5");
  const [period, setPeriod] = useState("30d");
  const [dateFrom, setDateFrom] = useState(() => { var d = new Date(); d.setDate(d.getDate() - 30); return d.getFullYear() + "-" + String(d.getMonth()+1).padStart(2,"0") + "-" + String(d.getDate()).padStart(2,"0"); });
  const [dateTo, setDateTo] = useState(() => { var d = new Date(); d.setDate(d.getDate() - 1); return d.getFullYear() + "-" + String(d.getMonth()+1).padStart(2,"0") + "-" + String(d.getDate()).padStart(2,"0"); });
  const [refreshKey, setRefreshKey] = useState(0);
  const [tribLoading, setTribLoading] = useState(false);

  // Sync taxRate from server (single source of truth)
  useEffect(() => {
    fetch("/api/store/tributacoes").then(r => r.json()).then(d => {
      if (d && d.value && d.value.taxRate !== undefined) {
        const serverRate = Number(d.value.taxRate) || 0;
        setTaxRate(serverRate);
        setTempTax(String(serverRate));
      }
    }).catch(() => {});
    fetch("/api/store/taxRate").then(r => r.json()).then(d => {
      if (d && d.value !== undefined && d.value !== null) {
        const serverRate = Number(d.value) || 0;
        setTaxRate(serverRate);
        setTempTax(String(serverRate));
      }
    }).catch(() => {});
  }, []);

  const applyPeriod = (k) => {
    setPeriod(k);
    const today = new Date();
    const fmt = d => d.getFullYear() + "-" + String(d.getMonth()+1).padStart(2,"0") + "-" + String(d.getDate()).padStart(2,"0");
    const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1);
    if (k === "y") { setDateFrom(fmt(yesterday)); setDateTo(fmt(yesterday)); }
    else if (k === "t") { setDateFrom(fmt(today)); setDateTo(fmt(today)); }
    else if (k === "7") { const w = new Date(yesterday); w.setDate(w.getDate() - 6); setDateFrom(fmt(w)); setDateTo(fmt(yesterday)); }
    else if (k === "m") { const first = new Date(today.getFullYear(), today.getMonth(), 1); setDateFrom(fmt(first)); setDateTo(fmt(today)); }
    else { const m = new Date(yesterday); m.setDate(m.getDate() - 29); setDateFrom(fmt(m)); setDateTo(fmt(yesterday)); }
  };

  const days = Math.max(1, Math.round((new Date(dateTo) - new Date(dateFrom)) / 86400000) + 1);
  const factor = days / 30;

  const [opsProjects, setOpsProjects, saveOpsProjects] = useServerState("operacoes", []);
  useEffect(() => { fetch("/api/store/operacoes").then(r => r.json()).then(d => { if (d && d.value && Array.isArray(d.value)) setOpsProjects(d.value); }).catch(() => {}); }, [refreshKey]);
  const tribData = loadLS("tributacoes", null);
  const savedRevShares = {};
  (Array.isArray(tribData) ? tribData : (tribData && tribData.projects ? tribData.projects : [])).forEach(p => { savedRevShares[p.id] = p.revShare || 0; });
  const [projects, setProjects] = useState(opsProjects.map(p => ({ id: p.id, name: p.name, revShare: savedRevShares[p.id] || 0, revenueBase: 0 })));
  useEffect(() => {
    if (opsProjects.length > 0) {
      setProjects(prev => {
        const prevMap = {};
        prev.forEach(p => { prevMap[p.id] = p.revShare || 0; });
        return opsProjects.map(p => ({ id: p.id, name: p.name, revShare: prevMap[p.id] || savedRevShares[p.id] || 0, revenueBase: 0 }));
      });
    }
  }, [opsProjects]);
  const [swpRevenue, setSwpRevenue] = useState({});
  const [avRevenue, setAvRevenue] = useState({});
  const [fbTribSpend, setFbTribSpend] = useState({});
  const [avTribLoading, setAvTribLoading] = useState(false);
  useEffect(() => {
    const swpDateParam = "lastThirty";
    setTribLoading(true);
    setAvTribLoading(true);

    // SWP daily data filtered by dateFrom/dateTo
    fetch("/api/sendwebpush/report?date=" + swpDateParam + "&dimensions=domain,date&metrics=revenue,impressions&custom_key_values=true&_t=" + Date.now())
      .then(r => r.json()).then(data => {
        const rep = data && data.data ? data.data : (Array.isArray(data) ? data : []);
        const byDomain = {};
        rep.filter(r => (r.domain || r.url) !== "redce.xyz").forEach(r => {
          var domain = r.domain || r.url;
          var date = r.date;
          if (date >= dateFrom && date <= dateTo) {
            byDomain[domain] = (byDomain[domain] || 0) + (Number(r.revenue) || 0);
          }
        });
        setSwpRevenue(byDomain);
      }).catch(() => {}).finally(() => setTribLoading(false));

    // ActiveView aggregate — fetch in parallel with retry
    const fetchTribAV = async (attempt) => {
      try {
        const avRes = await fetch("/api/activeview/aggregate?start_date=" + dateFrom + "&end_date=" + dateTo);
        const data = await avRes.json();
        if (data && !data.error && data.domains) {
          var byDomain = {};
          data.domains.forEach(d => { byDomain[d.domain] = d.rev || 0; });
          setAvRevenue(byDomain);
          setAvTribLoading(false);
        } else {
          if (attempt < 1) { setTimeout(() => fetchTribAV(attempt + 1), 3000); return; }
          setAvTribLoading(false);
        }
      } catch (e) {
        if (attempt < 1) { setTimeout(() => fetchTribAV(attempt + 1), 3000); return; }
        setAvTribLoading(false);
      }
    };
    fetchTribAV(0);

    // Facebook spend per project
    var fetchTribFB = async function() {
      try {
        var bmsRes = await fetch("/api/store/bms");
        var bmsData = await bmsRes.json();
        var bmsList = bmsData && bmsData.value && Array.isArray(bmsData.value) ? bmsData.value : [];
        var connectedBms = bmsList.filter(function(b) { return b.status === "connected" && b.accessToken; });
        if (connectedBms.length === 0) return;

        var opsRes2 = await fetch("/api/store/operacoes");
        var opsData2 = await opsRes2.json();
        var opsList2 = opsData2 && opsData2.value && Array.isArray(opsData2.value) ? opsData2.value : [];

        var spendMap = {};
        for (var i = 0; i < opsList2.length; i++) {
          var proj = opsList2[i];
          var accs = proj.adAccounts || [];
          if (accs.length === 0) continue;
          var token = null;
          for (var j = 0; j < connectedBms.length; j++) {
            var bm = connectedBms[j];
            var bmIds = (bm.adAccounts || []).map(function(a) { return String(a.id || a.account_id); });
            if (accs.some(function(id) { return bmIds.includes(String(id)); })) { token = bm.accessToken; break; }
          }
          if (!token) continue;
          var spend = 0;
          for (var k = 0; k < accs.length; k++) {
            try {
              var r = await fetch("/api/facebook/insights/" + accs[k] + "?fields=spend&level=account&since=" + dateFrom + "&until=" + dateTo, { headers: { "x-fb-token": token } });
              var d = await r.json();
              if (d && d.data && d.data.length > 0) spend += Number(d.data[0].spend) || 0;
            } catch (e) {}
          }
          (proj.sites || []).forEach(function(domain) { spendMap[domain] = (spendMap[domain] || 0) + spend; });
        }
        setFbTribSpend(spendMap);
      } catch (e) {}
    };
    fetchTribFB();
  }, [period, dateFrom, dateTo, refreshKey]);

  const pw = projects.map(p => {
    const opProj = opsProjects.find(op => op.id === p.id);
    const sites = opProj ? (opProj.sites || []) : [];
    const revenue = sites.reduce((sum, site) => sum + (swpRevenue[site] || 0) + (avRevenue[site] || 0), 0);
    const spend = sites.reduce((sum, site) => sum + (fbTribSpend[site] || 0), 0);
    return { ...p, revenue: Math.round(revenue * 100) / 100, spend: Math.round(spend * 100) / 100 };
  });

  const [editingRS, setEditingRS] = useState(null);
  const [tempRS, setTempRS] = useState("");
  const [filterTribProject, setFilterTribProject] = useState("all");

  const pwFiltered = filterTribProject === "all" ? pw : pw.filter(p => String(p.id) === String(filterTribProject));
  const totalRevenue = pwFiltered.reduce((a, p) => a + p.revenue, 0);
  const totalTax = totalRevenue * (taxRate / 100);
  const totalRS = pwFiltered.reduce((a, p) => a + p.revenue * (p.revShare / 100), 0);
  const totalDed = totalTax + totalRS;
  const afterDed = totalRevenue - totalDed;

  const fU = (v) => "$" + Number(v).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  const fP = (v) => Number(v).toFixed(1) + "%";
  const periods = [{ k: "y", l: "ontem" }, { k: "t", l: "hoje" }, { k: "7", l: "7 dias" }, { k: "30d", l: "30 dias" }, { k: "m", l: "este mês" }];

  const saveTax = () => { const v = parseFloat(tempTax); if (!isNaN(v) && v >= 0 && v <= 100) { setTaxRate(v); saveLS("taxRate", v); } setEditingTax(false); };
  const saveRS = (id) => { const v = parseFloat(tempRS); if (!isNaN(v) && v >= 0 && v <= 100) setProjects(p => p.map(pr => pr.id === id ? { ...pr, revShare: v } : pr)); setEditingRS(null); };

  const avgRS = pwFiltered.length > 0 ? pwFiltered.reduce((a, p) => a + p.revShare, 0) / pwFiltered.length : 0;
  const maxRev = Math.max(...pwFiltered.map(p => p.revenue), 1);

  return <>
    {/* Date filters */}
    <div style={{ display: "flex", alignItems: "center", gap: 5, flexWrap: "wrap", marginBottom: 8 }}>
      {periods.map(p => (
        <button key={p.k} onClick={() => applyPeriod(p.k)} style={{
          padding: mob ? "5px 8px" : "5px 14px", borderRadius: 20,
          border: period === p.k ? "none" : `1px solid ${C.bdr}`,
          background: period === p.k ? C.pill : "transparent",
          color: period === p.k ? "#fff" : C.mut,
          fontSize: mob ? 11 : 12, cursor: "pointer", fontWeight: period === p.k ? 700 : 400,
        }}>{p.l}</button>
      ))}
      <input type="date" value={dateFrom} onChange={e => { setDateFrom(e.target.value); setPeriod("c"); }} style={{ padding: mob ? "4px 6px" : "5px 10px", borderRadius: 8, border: `1px solid ${C.bdr}`, background: "rgba(11,18,37,0.7)", color: C.txt, fontSize: mob ? 10 : 12, colorScheme: "dark", maxWidth: mob ? 120 : "auto" }} />
      <input type="date" value={dateTo} onChange={e => { setDateTo(e.target.value); setPeriod("c"); }} style={{ padding: mob ? "4px 6px" : "5px 10px", borderRadius: 8, border: `1px solid ${C.bdr}`, background: "rgba(11,18,37,0.7)", color: C.txt, fontSize: mob ? 10 : 12, colorScheme: "dark", maxWidth: mob ? 120 : "auto" }} />
      <span style={{ fontSize: 11, color: C.mut }}>{dateFrom.split("-").reverse().join("/")} — {dateTo.split("-").reverse().join("/")} ({days} dias)</span>
      <Btn onClick={() => setRefreshKey(k => k + 1)} color={"#38bdf8"} small>{tribLoading || avTribLoading ? "⏳ Atualizando..." : "🔄 Atualizar"}</Btn>
    </div>

    {/* Project filter */}
    {pw.length > 1 && <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 12, alignItems: "center" }}>
      <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Filtrar:</span>
      <span onClick={() => setFilterTribProject("all")} style={{ fontSize: 11, padding: "5px 12px", borderRadius: 20, cursor: "pointer", background: filterTribProject === "all" ? C.blu : "transparent", border: "1px solid " + (filterTribProject === "all" ? C.blu : C.bdr), color: filterTribProject === "all" ? "#fff" : C.mut, fontWeight: filterTribProject === "all" ? 700 : 400 }}>Todos</span>
      {pw.map(p => <span key={p.id} onClick={() => setFilterTribProject(String(p.id))} style={{ fontSize: 11, padding: "5px 12px", borderRadius: 20, cursor: "pointer", background: String(filterTribProject) === String(p.id) ? C.blu : "transparent", border: "1px solid " + (String(filterTribProject) === String(p.id) ? C.blu : C.bdr), color: String(filterTribProject) === String(p.id) ? "#fff" : C.mut, fontWeight: String(filterTribProject) === String(p.id) ? 700 : 400 }}>{p.name}</span>)}
    </div>}

    {/* 3 compact cards with accent border */}
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr" : "1fr 1fr 1fr", gap: 10, marginBottom: 12 }}>
      <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 10, padding: "16px 20px", borderLeft: "3px solid rgba(43,126,201,0.6)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 6 }}>
          <span style={{ fontSize: 11, color: C.blu, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Receita bruta</span>
          <span style={{ fontSize: 11, color: C.mut }}>base</span>
        </div>
        <div style={{ fontSize: 21, fontWeight: 700, color: C.br, fontVariantNumeric: "tabular-nums" }}>{fU(totalRevenue)}</div>
      </div>
      <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 10, padding: "16px 20px", borderLeft: "3px solid rgba(231,76,60,0.6)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 6 }}>
          <span style={{ fontSize: 11, color: C.red, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Impostos</span>
          <span style={{ fontSize: 11, color: C.mut }}>{taxRate}%</span>
        </div>
        <div style={{ fontSize: 21, fontWeight: 700, color: C.red, fontVariantNumeric: "tabular-nums" }}>-{fU(totalTax)}</div>
      </div>
      <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 10, padding: "16px 20px", borderLeft: "3px solid rgba(243,156,18,0.6)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 6 }}>
          <span style={{ fontSize: 11, color: C.yel, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600 }}>Rev share</span>
          <span style={{ fontSize: 11, color: C.mut }}>média {fP(avgRS)}</span>
        </div>
        <div style={{ fontSize: 21, fontWeight: 700, color: C.yel, fontVariantNumeric: "tabular-nums" }}>-{fU(totalRS)}</div>
      </div>
    </div>

    {/* Proportion bar + result */}
    <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 10, padding: "14px 20px", marginBottom: 16 }}>
      <div style={{ height: 6, borderRadius: 3, overflow: "hidden", display: "flex", background: "rgba(30,48,80,0.3)", marginBottom: 10 }}>
        <div style={{ width: `${Math.max((afterDed / totalRevenue) * 100, 0)}%`, background: C.grn, borderRadius: "3px 0 0 3px", transition: "width 0.4s" }} />
        <div style={{ width: `${(totalTax / totalRevenue) * 100}%`, background: C.red, transition: "width 0.4s" }} />
        <div style={{ width: `${(totalRS / totalRevenue) * 100}%`, background: C.yel, borderRadius: "0 3px 3px 0", transition: "width 0.4s" }} />
      </div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <div style={{ display: "flex", gap: 12, fontSize: 11, color: C.mut }}>
          <span><span style={{ display: "inline-block", width: 7, height: 7, borderRadius: 2, background: C.grn, marginRight: 4 }} />{fP(Math.max((afterDed / totalRevenue) * 100, 0))} líquido</span>
          <span><span style={{ display: "inline-block", width: 7, height: 7, borderRadius: 2, background: C.red, marginRight: 4 }} />{fP((totalTax / totalRevenue) * 100)} imposto</span>
          <span><span style={{ display: "inline-block", width: 7, height: 7, borderRadius: 2, background: C.yel, marginRight: 4 }} />{fP((totalRS / totalRevenue) * 100)} rev share</span>
        </div>
        <div style={{ display: "flex", alignItems: "baseline", gap: 6 }}>
          <span style={{ fontSize: 11, color: C.mut }}>Líquido:</span>
          <span style={{ fontSize: 17, fontWeight: 700, color: afterDed >= 0 ? C.grn : C.red }}>{fU(afterDed)}</span>
        </div>
      </div>
    </div>

    {/* IMPOSTOS CONFIG */}
    <Sec icon="💰" label="Configurar impostos" open={true}>
      <div style={{ display: "flex", alignItems: "center", gap: 16, padding: "16px 0" }}>
        {editingTax ? (
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <input type="number" value={tempTax} onChange={e => setTempTax(e.target.value)} min="0" max="100" step="0.1"
              style={{ width: 80, padding: "10px 14px", borderRadius: 10, border: `2px solid ${C.blu}`, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 22, fontWeight: 700, textAlign: "center", outline: "none" }} />
            <span style={{ fontSize: 22, color: C.mut }}>%</span>
            <Btn onClick={saveTax} color={C.grn} small>Salvar</Btn>
            <Btn onClick={() => setEditingTax(false)} color="rgba(30,48,80,0.6)" small>Cancelar</Btn>
          </div>
        ) : (
          <div style={{ display: "flex", alignItems: "center", gap: 12, flex: 1 }}>
            <div style={{ width: 72, height: 72, borderRadius: 14, background: "rgba(231,76,60,0.1)", border: "1px solid rgba(231,76,60,0.2)", display: "flex", alignItems: "center", justifyContent: "center" }}>
              <span style={{ fontSize: 26, fontWeight: 800, color: C.red }}>{taxRate}%</span>
            </div>
            <div>
              <div style={{ fontSize: 14, fontWeight: 600, color: C.br }}>Alíquota única de impostos</div>
              <div style={{ fontSize: 12, color: C.mut }}>Aplicado sobre toda a receita bruta (ISS, PIS, COFINS, IRPJ, CSLL...)</div>
            </div>
            <Btn onClick={() => { setTempTax(String(taxRate)); setEditingTax(true); }} color="rgba(43,126,201,0.2)" small>Alterar</Btn>
          </div>
        )}
      </div>
    </Sec>

    {/* REVENUE SHARE PER PROJECT */}
    <Sec icon="🤝" label="Revenue share por projeto" open={true} count={pwFiltered.length + " projetos"}>
      <div style={{ fontSize: 12, color: C.mut, marginBottom: 14 }}>Porcentagem paga ao Ad Manager/parceiro. Cada projeto pode ter um % diferente.</div>

      {[...pwFiltered].sort((a, b) => b.revenue - a.revenue).map((p, i) => {
        const pRS = p.revenue * (p.revShare / 100);
        const pTax = p.revenue * (taxRate / 100);
        const pAfter = p.revenue - pRS - pTax;
        const isEditing = editingRS === p.id;
        const barW = totalRevenue > 0 ? (p.revenue / maxRev) * 100 : 0;

        return (
          <div key={p.id} style={{
            padding: "14px 16px", marginBottom: 10, borderRadius: 12,
            background: "rgba(8,13,26,0.35)", border: `1px solid ${C.bdr}`,
            transition: "all 0.2s",
          }}>
            {/* Header */}
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 10 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                <span style={{ fontSize: 13 }}>📂</span>
                <span style={{ fontSize: 14, fontWeight: 600, color: C.br }}>{p.name}</span>
              </div>
              {isEditing ? (
                <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                  <input type="number" value={tempRS} onChange={e => setTempRS(e.target.value)} min="0" max="100" step="0.5"
                    style={{ width: 60, padding: "5px 8px", borderRadius: 8, border: `2px solid ${C.yel}`, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 16, fontWeight: 700, textAlign: "center", outline: "none" }} />
                  <span style={{ color: C.mut }}>%</span>
                  <Btn onClick={() => saveRS(p.id)} color={C.grn} small>✓</Btn>
                  <Btn onClick={() => setEditingRS(null)} color="rgba(30,48,80,0.6)" small>✕</Btn>
                </div>
              ) : (
                <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <span style={{ fontSize: 20, fontWeight: 700, color: C.yel }}>{p.revShare}%</span>
                  <Btn onClick={() => { setEditingRS(p.id); setTempRS(String(p.revShare)); }} color="rgba(243,156,18,0.15)" small>Alterar</Btn>
                </div>
              )}
            </div>

            {/* Revenue bar */}
            <div style={{ marginBottom: 8 }}>
              <div style={{ height: 6, borderRadius: 3, overflow: "hidden", background: "rgba(30,48,80,0.3)", marginBottom: 4 }}>
                <div style={{ width: `${barW}%`, height: "100%", borderRadius: 3, background: "rgba(93,173,226,0.4)", transition: "width 0.4s" }} />
              </div>
            </div>

            {/* Metrics row */}
            <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(4,1fr)", gap: 8, fontSize: 12 }}>
              <div style={{ padding: "8px 10px", borderRadius: 8, background: "rgba(8,13,26,0.3)" }}>
                <div style={{ color: C.mut, fontSize: 10, textTransform: "uppercase", marginBottom: 2 }}>Receita</div>
                <div style={{ color: C.br, fontWeight: 600 }}>{fU(p.revenue)}</div>
              </div>
              <div style={{ padding: "8px 10px", borderRadius: 8, background: "rgba(231,76,60,0.06)" }}>
                <div style={{ color: C.mut, fontSize: 10, textTransform: "uppercase", marginBottom: 2 }}>Imposto ({taxRate}%)</div>
                <div style={{ color: C.red, fontWeight: 600 }}>-{fU(pTax)}</div>
              </div>
              <div style={{ padding: "8px 10px", borderRadius: 8, background: "rgba(243,156,18,0.06)" }}>
                <div style={{ color: C.mut, fontSize: 10, textTransform: "uppercase", marginBottom: 2 }}>Rev Share ({p.revShare}%)</div>
                <div style={{ color: C.yel, fontWeight: 600 }}>-{fU(pRS)}</div>
              </div>
              <div style={{ padding: "8px 10px", borderRadius: 8, background: "rgba(46,204,113,0.06)" }}>
                <div style={{ color: C.mut, fontSize: 10, textTransform: "uppercase", marginBottom: 2 }}>Após deduções</div>
                <div style={{ color: pAfter >= 0 ? C.grn : C.red, fontWeight: 600 }}>{fU(pAfter)}</div>
              </div>
            </div>
          </div>
        );
      })}

      {/* Totals */}
      <div style={{ padding: "14px 16px", borderRadius: 12, background: "rgba(8,13,26,0.5)", border: `1px solid ${C.bdr}`, marginTop: 4 }}>
        <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(4,1fr)", gap: 8, fontSize: 13 }}>
          <div><span style={{ color: C.mut, fontSize: 10, textTransform: "uppercase" }}>Total receita</span><div style={{ fontWeight: 700, color: C.br }}>{fU(totalRevenue)}</div></div>
          <div><span style={{ color: C.mut, fontSize: 10, textTransform: "uppercase" }}>Total impostos</span><div style={{ fontWeight: 700, color: C.red }}>-{fU(totalTax)}</div></div>
          <div><span style={{ color: C.mut, fontSize: 10, textTransform: "uppercase" }}>Total rev share</span><div style={{ fontWeight: 700, color: C.yel }}>-{fU(totalRS)}</div></div>
          <div><span style={{ color: C.mut, fontSize: 10, textTransform: "uppercase" }}>Total líquido</span><div style={{ fontWeight: 700, color: afterDed >= 0 ? C.grn : C.red }}>{fU(afterDed)}</div></div>
        </div>
      </div>
    </Sec>

    <InfoBox>
      <span style={{ fontWeight: 600, color: C.red }}>Impostos:</span> Alíquota única sobre receita bruta. Clique "Alterar" para mudar o %.
      <br /><span style={{ fontWeight: 600, color: C.yel }}>Revenue Share:</span> % pago ao parceiro/Ad Manager. Cada projeto tem seu próprio % conforme o acordo.
      <br />Ambos são descontados automaticamente no P&L do Dashboard.
    </InfoBox>
    <SaveBar storageKey="tributacoes" data={{ taxRate, projects }} mob={mob} />
  </>;
}

/* ========================================= */
/* ===== PAGE: USUÁRIOS ==================== */
/* ========================================= */
function PgUsuarios({ mob }) {
  const ROLES = [
    { id: "master", name: "Master", color: "#e74c3c", desc: "Acesso total — cria usuários, configura APIs, vê todos os dados", perms: ["Dashboard", "Operações", "Ad Managers", "BMs Facebook", "Campanhas", "Facebook Apps", "Despesas", "Tributações", "Usuários", "KPIs", "Configurações"] },
    { id: "admin", name: "Admin", color: "#f39c12", desc: "Gerencia operações e vê todos os dados, não configura APIs", perms: ["Dashboard", "Operações", "Campanhas", "Despesas", "Tributações", "KPIs", "Configurações"] },
    { id: "media", name: "Media Buyer", color: "#2ecc71", desc: "Vê campanhas, gastos e métricas de performance", perms: ["Dashboard", "Campanhas", "Operações", "KPIs"] },
    { id: "analyst", name: "Analista", color: "#3498db", desc: "Somente visualização — não edita nada", perms: ["Dashboard", "KPIs"] },
  ];

  const [users, setUsers, saveUsers] = useServerState("usuarios", [
    { id: 1, name: "Santiago Botero", email: "santiagobjdigital333@gmail.com", role: "master", status: "active", lastLogin: new Date().toISOString().slice(0, 16).replace("T", " "), createdAt: "2025-01-15", logins: 842 },
  ]);

  const [showForm, setShowForm] = useState(false);
  const [editing, setEditing] = useState(null);
  const [form, setForm] = useState({ name: "", email: "", password: "", role: "analyst" });
  const [showPerms, setShowPerms] = useState({});
  const [confirmRemove, setConfirmRemove] = useState(null);

  const isMaster = (u) => u.role === "master";

  const startEdit = (u) => {
    setForm({ name: u.name, email: u.email, password: "", role: u.role });
    setEditing(u.id); setShowForm(true);
  };

  const save = () => {
    if (!form.name.trim() || !form.email.trim()) return;
    if (editing) {
      setUsers(p => p.map(u => u.id === editing ? { ...u, name: form.name, email: form.email, role: u.role === "master" ? "master" : form.role, ...(form.password ? { password: form.password } : {}) } : u));
    } else {
      if (!form.password || form.password.length < 6) return;
      setUsers(p => [...p, { id: Date.now(), name: form.name, email: form.email, role: form.role, status: "active", lastLogin: "Nunca", createdAt: new Date().toISOString().slice(0, 10), logins: 0 }]);
    }
    setEditing(null); setShowForm(false); setForm({ name: "", email: "", password: "", role: "analyst" });
  };

  const cancel = () => { setEditing(null); setShowForm(false); setForm({ name: "", email: "", password: "", role: "analyst" }); };
  const toggleStatus = (id) => setUsers(p => p.map(u => u.id === id ? { ...u, status: u.status === "active" ? "inactive" : "active" } : u));
  const remove = (id) => {
    var u = users.find(x => x.id === id);
    if (u && u.role === "master") return;
    setUsers(p => p.filter(x => x.id !== id));
    setConfirmRemove(null);
  };

  const activeCount = users.filter(u => u.status === "active").length;
  const todayStr = new Date().toISOString().slice(0, 10);
  const roleColor = (r) => ROLES.find(rl => rl.id === r)?.color || C.mut;
  const roleName = (r) => ROLES.find(rl => rl.id === r)?.name || r;
  const initials = (name) => name.split(" ").map(w => w[0]).join("").slice(0, 2).toUpperCase();

  return <>
    {/* KPIs */}
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(4,1fr)", gap: 8, marginBottom: 14 }}>
      <KPI label="Total usuários" value={users.length} mob={mob} />
      <KPI label="Ativos" value={activeCount} color={C.grn} mob={mob} />
      <KPI label="Inativos" value={users.length - activeCount} color={users.length - activeCount > 0 ? C.yel : C.mut} mob={mob} />
      <KPI label="Online hoje" value={users.filter(u => u.lastLogin && u.lastLogin.startsWith(todayStr)).length} color={C.cyan} mob={mob} />
    </div>

    {/* Roles overview */}
    <Sec icon="🔑" label="Funções e permissões" count={ROLES.length + " funções"}>
      {ROLES.map((role, i) => (
        <div key={role.id} style={{ padding: "10px 0", borderBottom: i < ROLES.length - 1 ? `1px solid ${C.bdr}` : "none" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
            <span style={{ fontSize: 12, padding: "3px 10px", borderRadius: 6, background: `${role.color}15`, color: role.color, fontWeight: 700, borderLeft: `3px solid ${role.color}` }}>{role.name}</span>
            <span style={{ fontSize: 12, color: C.mut }}>{role.desc}</span>
          </div>
          <div style={{ display: "flex", gap: 4, flexWrap: "wrap", marginLeft: 2 }}>
            {role.perms.map(p => (
              <span key={p} style={{ fontSize: 10, padding: "2px 8px", borderRadius: 6, background: "rgba(43,126,201,0.08)", color: C.blu }}>{p}</span>
            ))}
          </div>
        </div>
      ))}
    </Sec>

    {/* Add/Edit form */}
    {showForm && (
      <div style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 12, padding: 18, marginBottom: 12 }}>
        <div style={{ fontSize: 14, fontWeight: 600, color: C.br, marginBottom: 14 }}>{editing ? "Editar usuário" : "Novo usuário"}</div>
        <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr" : "1fr 1fr", gap: 10 }}>
          <Inp label="Nome completo" value={form.name} onChange={v => setForm(p => ({ ...p, name: v }))} placeholder="Ex: João Silva" mob={mob} />
          <Inp label="Email" value={form.email} onChange={v => setForm(p => ({ ...p, email: v }))} placeholder="joao@bluegrid.media" mob={mob} />
        </div>
        <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr" : "1fr 1fr", gap: 10 }}>
          <Inp label={editing ? "Nueva contraseña (vacío = mantener)" : "Contraseña (mín. 6 caracteres)"} value={form.password} onChange={v => setForm(p => ({ ...p, password: v }))} placeholder={editing ? "••••••••" : "Mínimo 6 caracteres"} pw mob={mob} />
          <div style={{ marginBottom: 8 }}>
            <span style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, display: "block", marginBottom: 6 }}>Función</span>
            {editing && users.find(u => u.id === editing)?.role === "master" ? (
              <span style={{ fontSize: 12, padding: "7px 14px", borderRadius: 8, background: "rgba(231,76,60,0.15)", border: "1px solid #e74c3c", color: "#e74c3c", fontWeight: 600 }}>Master (no se puede cambiar)</span>
            ) : (
              <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
                {ROLES.filter(r => r.id !== "master").map(role => (
                  <span key={role.id} onClick={() => setForm(p => ({ ...p, role: role.id }))} style={{
                    fontSize: 12, padding: "7px 14px", borderRadius: 8, cursor: "pointer",
                    background: form.role === role.id ? `${role.color}20` : "rgba(8,13,26,0.5)",
                    border: `1px solid ${form.role === role.id ? role.color : C.bdr}`,
                    color: form.role === role.id ? role.color : C.mut,
                    fontWeight: form.role === role.id ? 600 : 400,
                  }}>{role.name}</span>
                ))}
              </div>
            )}
          </div>
        </div>
        <div style={{ display: "flex", gap: 8, marginTop: 4 }}>
          <Btn onClick={save} color={C.grn} small>{editing ? "Salvar alterações" : "Criar usuário"}</Btn>
          <Btn onClick={cancel} color="rgba(30,48,80,0.6)" small>Cancelar</Btn>
        </div>
      </div>
    )}

    {/* Users list */}
    <Sec icon="👥" label="Usuários" count={users.length} open={true}>
      {users.map((u, i) => {
        const rc = roleColor(u.role);
        const isPermsOpen = showPerms[u.id];
        const role = ROLES.find(r => r.id === u.role);
        return (
          <div key={u.id} style={{ padding: "14px 0", borderBottom: i < users.length - 1 ? `1px solid ${C.bdr}` : "none" }}>
            {/* User header */}
            <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 8 }}>
              {/* Avatar */}
              <div style={{ width: 40, height: 40, borderRadius: 10, background: `${rc}20`, border: `1px solid ${rc}30`, display: "flex", alignItems: "center", justifyContent: "center", fontWeight: 700, fontSize: 14, color: rc, flexShrink: 0 }}>
                {initials(u.name)}
              </div>
              {/* Info */}
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
                  <span style={{ fontSize: 14, fontWeight: 600, color: C.br }}>{u.name}</span>
                  <span style={{ fontSize: 10, padding: "2px 8px", borderRadius: 6, background: `${rc}15`, color: rc, fontWeight: 600, borderLeft: `2px solid ${rc}` }}>{roleName(u.role)}</span>
                  <SDot s={u.status === "active" ? "connected" : "disconnected"} />
                </div>
                <div style={{ fontSize: 12, color: C.mut, marginTop: 2 }}>{u.email}</div>
              </div>
              {/* Stats */}
              {!mob && (
                <div style={{ display: "flex", gap: 16, flexShrink: 0, fontSize: 11 }}>
                  <div style={{ textAlign: "center" }}>
                    <div style={{ color: C.mut }}>Último login</div>
                    <div style={{ color: C.txt, fontWeight: 500 }}>{u.lastLogin}</div>
                  </div>
                  <div style={{ textAlign: "center" }}>
                    <div style={{ color: C.mut }}>Logins</div>
                    <div style={{ color: C.txt, fontWeight: 500 }}>{u.logins}</div>
                  </div>
                  <div style={{ textAlign: "center" }}>
                    <div style={{ color: C.mut }}>Criado em</div>
                    <div style={{ color: C.txt, fontWeight: 500 }}>{u.createdAt}</div>
                  </div>
                </div>
              )}
            </div>

            {/* Mobile stats */}
            {mob && (
              <div style={{ display: "flex", gap: 12, fontSize: 11, color: C.mut, marginBottom: 8, marginLeft: 52 }}>
                <span>Login: {u.lastLogin.slice(0, 10)}</span>
                <span>{u.logins} logins</span>
              </div>
            )}

            {/* Permissions toggle */}
            <div style={{ marginLeft: 52 }}>
              <span onClick={() => setShowPerms(p => ({ ...p, [u.id]: !p[u.id] }))} style={{ fontSize: 11, color: C.blu, cursor: "pointer", display: "flex", alignItems: "center", gap: 4 }}>
                <span style={{ transform: isPermsOpen ? "rotate(90deg)" : "rotate(0)", transition: "transform 0.2s", fontSize: 8 }}>▶</span>
                Permissões ({role?.perms.length || 0} páginas)
              </span>
              {isPermsOpen && (
                <div style={{ display: "flex", gap: 4, flexWrap: "wrap", marginTop: 6 }}>
                  {role?.perms.map(p => (
                    <span key={p} style={{ fontSize: 10, padding: "2px 8px", borderRadius: 6, background: "rgba(46,204,113,0.1)", color: C.grn }}>✓ {p}</span>
                  ))}
                </div>
              )}
            </div>

            {/* Actions */}
            <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 8, marginLeft: 52 }}>
              <Btn onClick={() => startEdit(u)} color="rgba(43,126,201,0.2)" small>Editar</Btn>
              {!isMaster(u) && (
                <>
                  <Btn onClick={() => toggleStatus(u.id)} color={u.status === "active" ? "rgba(243,156,18,0.2)" : "rgba(46,204,113,0.2)"} small>
                    {u.status === "active" ? "Desativar" : "Ativar"}
                  </Btn>
                  {confirmRemove === u.id ? (
                    <>
                      <Btn onClick={() => remove(u.id)} color="rgba(231,76,60,0.3)" small>⚠ Confirmar</Btn>
                      <Btn onClick={() => setConfirmRemove(null)} color="rgba(30,48,80,0.4)" small>Cancelar</Btn>
                    </>
                  ) : (
                    <Btn onClick={() => setConfirmRemove(u.id)} color="rgba(231,76,60,0.15)" small>Remover</Btn>
                  )}
                </>
              )}
              {isMaster(u) && <span style={{ fontSize: 10, color: C.mut, alignSelf: "center" }}>Conta master — não pode ser removida</span>}
            </div>
          </div>
        );
      })}
    </Sec>

    {/* Add user button */}
    {!showForm && (
      <div style={{ textAlign: "center", paddingTop: 4 }}>
        <Btn onClick={() => { setForm({ name: "", email: "", password: "", role: "analyst" }); setEditing(null); setShowForm(true); }} color={C.blu} small>+ Novo usuário</Btn>
      </div>
    )}

    <InfoBox>
      <span style={{ fontWeight: 600, color: C.blu }}>Sistema de usuários:</span> O Master cria e gerencia todos os usuários. Cada função tem permissões específicas que controlam quais páginas o usuário pode acessar.
      <br /><span style={{ fontWeight: 600, color: C.red }}>Master:</span> Acesso total. <span style={{ fontWeight: 600, color: C.yel }}>Admin:</span> Operações + dados. <span style={{ fontWeight: 600, color: C.grn }}>Media Buyer:</span> Dashboard + campanhas. <span style={{ fontWeight: 600, color: C.blu }}>Analista:</span> Somente leitura.
      <br />Senhas são criptografadas no backend. O Master pode resetar a senha de qualquer usuário.
    </InfoBox>
    <SaveBar storageKey="usuarios" data={users} mob={mob} />
  </>;
}

/* ========================================= */
/* ========================================= */
/* ===== PAGE: KPIs ======================== */
/* ========================================= */
function PgKpis({ mob }) {
  const [kpis, setKpis, saveKpis] = useServerState("kpis", [
    { id: 1, label: "Receita bruta", enabled: true },
    { id: 2, label: "Impressões", enabled: true },
    { id: 3, label: "Gasto FB", enabled: true },
    { id: 4, label: "Despesa total", enabled: true },
    { id: 5, label: "Líquido", enabled: true },
    { id: 6, label: "ROI", enabled: true },
    { id: 7, label: "ECPM", enabled: true },
    { id: 8, label: "CPL médio", enabled: true },
    { id: 9, label: "Total leads", enabled: false },
    { id: 10, label: "Margem bruta", enabled: false },
    { id: 11, label: "Rev Share", enabled: false },
  ]);
  const [saved, setSaved] = useState(false);

  const move = (idx, dir) => {
    const n = [...kpis]; const t = idx + dir;
    if (t < 0 || t >= n.length) return;
    [n[idx], n[t]] = [n[t], n[idx]];
    setKpis(n); setSaved(false);
  };
  const toggle = (id) => { setKpis(p => p.map(k => k.id === id ? { ...k, enabled: !k.enabled } : k)); setSaved(false); };
  const save = () => { saveKpis(kpis); setSaved(true); setTimeout(() => setSaved(false), 3000); };
  const enabled = kpis.filter(k => k.enabled);

  return <>
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(3,1fr)", gap: 8, marginBottom: 14 }}>
      <KPI label="KPIs ativos" value={enabled.length} mob={mob} />
      <KPI label="Ocultos" value={kpis.length - enabled.length} color={C.mut} mob={mob} />
      <KPI label="Layout" value={enabled.length <= 4 ? "1 linha" : enabled.length <= 8 ? "2 linhas" : "3 linhas"} mob={mob} />
    </div>

    <Sec icon="⚙️" label="Ordem dos KPIs no Dashboard" count={enabled.length + " ativos"} open={true}>
      <div style={{ fontSize: 12, color: C.mut, marginBottom: 14 }}>Use ↑↓ para reordenar e o toggle para ativar/desativar. Os primeiros 4 ficam na linha 1, os próximos na linha 2.</div>

      {kpis.map((kpi, idx) => (
        <div key={kpi.id} style={{
          display: "flex", alignItems: "center", gap: 10, padding: "9px 12px", marginBottom: 5,
          borderRadius: 8, background: kpi.enabled ? "rgba(8,13,26,0.35)" : "rgba(8,13,26,0.15)",
          border: `1px solid ${kpi.enabled ? C.bdr : "rgba(30,48,80,0.2)"}`,
          opacity: kpi.enabled ? 1 : 0.45,
        }}>
          <span style={{ width: 22, height: 22, borderRadius: 6, background: kpi.enabled ? "rgba(43,126,201,0.15)" : "rgba(30,48,80,0.2)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, fontWeight: 700, color: kpi.enabled ? C.blu : C.mut, flexShrink: 0 }}>{idx + 1}</span>
          <span style={{ flex: 1, fontSize: 13, fontWeight: 500, color: kpi.enabled ? C.br : C.mut }}>{kpi.label}</span>
          <div style={{ display: "flex", gap: 2 }}>
            <span onClick={() => move(idx, -1)} style={{ width: 26, height: 26, borderRadius: 6, background: "rgba(30,48,80,0.3)", display: "flex", alignItems: "center", justifyContent: "center", cursor: idx > 0 ? "pointer" : "default", color: idx > 0 ? C.txt : "rgba(30,48,80,0.3)", fontSize: 12 }}>↑</span>
            <span onClick={() => move(idx, 1)} style={{ width: 26, height: 26, borderRadius: 6, background: "rgba(30,48,80,0.3)", display: "flex", alignItems: "center", justifyContent: "center", cursor: idx < kpis.length - 1 ? "pointer" : "default", color: idx < kpis.length - 1 ? C.txt : "rgba(30,48,80,0.3)", fontSize: 12 }}>↓</span>
          </div>
          <span onClick={() => toggle(kpi.id)} style={{
            width: 38, height: 20, borderRadius: 10, cursor: "pointer",
            background: kpi.enabled ? C.grn : "rgba(30,48,80,0.4)",
            display: "flex", alignItems: "center", padding: "0 2px",
            justifyContent: kpi.enabled ? "flex-end" : "flex-start",
          }}>
            <span style={{ width: 16, height: 16, borderRadius: "50%", background: "#fff" }} />
          </span>
        </div>
      ))}
    </Sec>

    {/* Preview */}
    <Sec icon="👁" label="Preview no Dashboard" open={true}>
      <div style={{ display: "grid", gridTemplateColumns: mob ? "repeat(2,1fr)" : "repeat(4,1fr)", gap: 6 }}>
        {enabled.map(k => (
          <div key={k.id} style={{ background: C.card, border: `1px solid ${C.bdr}`, borderRadius: 8, padding: "10px 12px" }}>
            <div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 1 }}>{k.label}</div>
            <div style={{ fontSize: 16, fontWeight: 700, color: C.br, marginTop: 3 }}>$0.00</div>
          </div>
        ))}
      </div>
    </Sec>

    {/* Save */}
    <div style={{ display: "flex", gap: 8, marginTop: 8, alignItems: "center" }}>
      <Btn onClick={save} color={C.grn}>{saved ? "✓ Salvo!" : "Salvar configuração"}</Btn>
      {saved && <span style={{ fontSize: 12, color: C.grn }}>Ordem salva com sucesso</span>}
    </div>

    <InfoBox>
      <span style={{ fontWeight: 600, color: C.blu }}>KPIs:</span> Configure quais métricas aparecem no Dashboard e em qual ordem. Os primeiros 4 ficam na primeira linha, os próximos na segunda.
    </InfoBox>
  </>;
}

/* ========================================= */
/* ===== PAGE: CAMPANHAS =================== */
/* ========================================= */
function PgCampanhas({ mob }) {
  const fU = (v) => "$" + Number(v).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  const fI = (v) => Number(v).toLocaleString("en-US");
  const fP = (v) => Number(v).toFixed(2) + "%";
  const fBudget = (v) => { var n = Number(v); return n > 0 ? "$" + (n / 100).toFixed(2) : "—"; };

  // Step flow: 1=BM, 2=Account, 3=Data
  const [step, setStep] = useState(1);
  const [campRefreshKey, setCampRefreshKey] = useState(0);
  const [campSearch, setCampSearch] = useState("");
  const [campSort, setCampSort] = useState({ key: "", dir: "desc" });
  const [adsetSort, setAdsetSort] = useState({ key: "", dir: "desc" });
  const [adSort, setAdSort] = useState({ key: "", dir: "desc" });

  const [bmsList, setBmsList] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [selectedBm, setSelectedBm] = useState(null);
  const [selectedAccount, setSelectedAccount] = useState(null);

  // Campaign data
  const [campaigns, setCampaigns] = useState([]);
  const [campaignInsights, setCampaignInsights] = useState({});
  const [loadingCampaigns, setLoadingCampaigns] = useState(false);

  // Drill-down
  const [expandedCampaign, setExpandedCampaign] = useState({});
  const [adsets, setAdsets] = useState({});
  const [loadingAdsets, setLoadingAdsets] = useState({});
  const [adsetInsights, setAdsetInsights] = useState({});
  const [expandedAdset, setExpandedAdset] = useState({});
  const [ads, setAds] = useState({});
  const [loadingAds, setLoadingAds] = useState({});
  const [adInsights, setAdInsights] = useState({});

  // Budget scheduling
  const [editingBudget, setEditingBudget] = useState(null);
  const [budgetValue, setBudgetValue] = useState("");
  const [scheduleDate, setScheduleDate] = useState("");
  const [scheduleTime, setScheduleTime] = useState("");
  const [useSchedule, setUseSchedule] = useState(false);
  const [savingBudget, setSavingBudget] = useState(false);
  const [budgetMsg, setBudgetMsg] = useState(null);
  const [scheduledJobs, setScheduledJobs] = useState([]);

  // Status toggling
  const [togglingStatus, setTogglingStatus] = useState({});
  const [lastUpdated, setLastUpdated] = useState(null);

  // Disapproved ads + account health (per-account, step 3)
  const [disapprovedAds, setDisapprovedAds] = useState([]);
  const [accountStatus, setAccountStatus] = useState(null);

  // Global rejected ads (all BMs, all accounts — shown in step 1/2/3)
  const [globalRejected, setGlobalRejected] = useState([]);
  const [globalRejLoading, setGlobalRejLoading] = useState(false);
  const [hiddenAds, setHiddenAds] = useState({});
  const [savedDismissed, setSavedDismissed] = useState([]);

  // Date range
  const [dateRange, setDateRange] = useState("today");
  const today = new Date();
  const fmt = (d) => d.toISOString().slice(0, 10);
  const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1);
  const sevenAgo = new Date(today); sevenAgo.setDate(today.getDate() - 7);
  const thirtyAgo = new Date(today); thirtyAgo.setDate(today.getDate() - 30);
  const monthStart = new Date(today.getFullYear(), today.getMonth(), 1);
  const dateRanges = {
    today: { since: fmt(today), until: fmt(today), label: "Hoje" },
    yesterday: { since: fmt(yesterday), until: fmt(yesterday), label: "Ontem" },
    last_7d: { since: fmt(sevenAgo), until: fmt(yesterday), label: "7 dias" },
    last_30d: { since: fmt(thirtyAgo), until: fmt(yesterday), label: "30 dias" },
    this_month: { since: fmt(monthStart), until: fmt(today), label: "Este mês" },
  };

  // Load BMs + global rejected ads
  useEffect(() => {
    // Load server-side dismissed list
    fetch("/api/store/dismissed_rejects").then(function(r) { return r.json(); }).then(function(d) {
      if (d && d.value && Array.isArray(d.value)) setSavedDismissed(d.value);
    }).catch(function() {});

    fetch("/api/store/bms").then(r => r.json()).then(d => {
      if (d && d.value && Array.isArray(d.value)) {
        var connected = d.value.filter(b => b.status === "connected" && b.accessToken);
        setBmsList(connected);

        // Fetch ALL rejected ads across ALL BMs
        if (connected.length > 0) {
          setGlobalRejLoading(true);
          var allRej = [];
          var proms = [];
          connected.forEach(function(bm) {
            (bm.adAccounts || []).forEach(function(acc) {
              var accId = acc.id || acc.account_id;
              proms.push(
                fetch("/api/facebook/disapproved/" + accId, { headers: { "x-fb-token": bm.accessToken } })
                  .then(function(r) { return r.json(); }).then(function(data) {
                    if (data && data.data) {
                      data.data.forEach(function(ad) {
                        allRej.push({ id: ad.id, name: ad.name, status: ad.effective_status, accId: accId, accName: acc.name || accId, bmName: bm.name,
                          campaign: ad.adset && ad.adset.campaign ? ad.adset.campaign.name : "—",
                          feedback: ad.ad_review_feedback });
                      });
                    }
                  }).catch(function() {})
              );
            });
          });
          Promise.all(proms).then(function() { setGlobalRejected(allRej); setGlobalRejLoading(false); });
        }
      }
      setLoading(false);
    }).catch(e => { setError(e.message); setLoading(false); });
  }, []);

  // Load scheduled jobs + auto-refresh every 30s
  useEffect(() => {
    var loadJobs = () => fetch("/api/scheduled-budgets").then(r => r.json()).then(d => { if (Array.isArray(d)) setScheduledJobs(d); }).catch(() => {});
    loadJobs();
    var interval = setInterval(loadJobs, 30000);
    return () => clearInterval(interval);
  }, []);

  // Fetch campaigns when account+date changes
  useEffect(() => {
    if (!selectedAccount || !selectedBm) return;
    var accId = selectedAccount.id || selectedAccount.account_id;
    if (!accId) return;
    setLoadingCampaigns(true);
    setCampaigns([]); setCampaignInsights({}); setExpandedCampaign({}); setAdsets({}); setExpandedAdset({}); setAds({}); setAdInsights({}); setError(null);
    setDisapprovedAds([]); setAccountStatus(null);
    var token = selectedBm.accessToken;

    // Fetch account status + disapproved ads in parallel
    fetch("/api/facebook/account-status/" + accId, { headers: { "x-fb-token": token } })
      .then(r => r.json()).then(d => { if (d && !d.error) setAccountStatus(d); }).catch(() => {});
    fetch("/api/facebook/disapproved/" + accId, { headers: { "x-fb-token": token } })
      .then(r => r.json()).then(d => { if (d && d.data) setDisapprovedAds(d.data); }).catch(() => {});

    fetch("/api/facebook/campaigns/" + accId, { headers: { "x-fb-token": token } })
      .then(r => r.json()).then(data => {
        if (data && data.data && Array.isArray(data.data)) {
          setCampaigns(data.data);
          var dr = dateRanges[dateRange] || dateRanges.today;
          data.data.forEach(camp => {
            fetch("/api/facebook/object-insights/" + camp.id + "?since=" + dr.since + "&until=" + dr.until + "&fields=spend,impressions,inline_link_clicks,cpc,inline_link_click_ctr,actions,cost_per_action_type", { headers: { "x-fb-token": token } })
              .then(r => r.json()).then(ins => {
                if (ins && ins.data && ins.data.length > 0) setCampaignInsights(prev => ({ ...prev, [camp.id]: ins.data[0] }));
              }).catch(() => {});
          });
        } else if (data && data.error) { setError(data.error.message || "Erro"); }
        setLoadingCampaigns(false);
        setLastUpdated(new Date());
      }).catch(e => { setError(e.message); setLoadingCampaigns(false); });
  }, [selectedAccount, selectedBm, dateRange, campRefreshKey]);

  var loadAdsets = (campaignId) => {
    if (adsets[campaignId]) return;
    setLoadingAdsets(prev => ({ ...prev, [campaignId]: true }));
    var token = selectedBm.accessToken;
    fetch("/api/facebook/adsets/" + campaignId, { headers: { "x-fb-token": token } })
      .then(r => r.json()).then(data => {
        if (data && data.data) {
          setAdsets(prev => ({ ...prev, [campaignId]: data.data }));
          var dr = dateRanges[dateRange] || dateRanges.today;
          data.data.forEach(as => {
            fetch("/api/facebook/object-insights/" + as.id + "?since=" + dr.since + "&until=" + dr.until + "&fields=spend,impressions,inline_link_clicks,cpc,inline_link_click_ctr,actions,cost_per_action_type", { headers: { "x-fb-token": token } })
              .then(r => r.json()).then(ins => { if (ins && ins.data && ins.data.length > 0) setAdsetInsights(prev => ({ ...prev, [as.id]: ins.data[0] })); }).catch(() => {});
          });
        }
        setLoadingAdsets(prev => ({ ...prev, [campaignId]: false }));
      }).catch(() => setLoadingAdsets(prev => ({ ...prev, [campaignId]: false })));
  };

  var loadAds = (adsetId) => {
    if (ads[adsetId]) return;
    setLoadingAds(prev => ({ ...prev, [adsetId]: true }));
    fetch("/api/facebook/ads/" + adsetId, { headers: { "x-fb-token": selectedBm.accessToken } })
      .then(r => r.json()).then(data => {
        if (data && data.data) {
          setAds(prev => ({ ...prev, [adsetId]: data.data }));
          var dr = dateRanges[dateRange] || dateRanges.today;
          data.data.forEach(ad => {
            fetch("/api/facebook/object-insights/" + ad.id + "?since=" + dr.since + "&until=" + dr.until + "&fields=spend,impressions,inline_link_clicks,cpc,inline_link_click_ctr,actions,cost_per_action_type", { headers: { "x-fb-token": selectedBm.accessToken } })
              .then(r => r.json()).then(ins => { if (ins && ins.data && ins.data.length > 0) setAdInsights(prev => ({ ...prev, [ad.id]: ins.data[0] })); }).catch(() => {});
          });
        }
        setLoadingAds(prev => ({ ...prev, [adsetId]: false }));
      }).catch(() => setLoadingAds(prev => ({ ...prev, [adsetId]: false })));
  };

  var toggleStatus = (objectId, currentStatus, type) => {
    var newStatus = currentStatus === "ACTIVE" ? "PAUSED" : "ACTIVE";
    setTogglingStatus(prev => ({ ...prev, [objectId]: true }));
    fetch("/api/facebook/update-status/" + objectId, {
      method: "POST", headers: { "Content-Type": "application/json", "x-fb-token": selectedBm.accessToken },
      body: JSON.stringify({ status: newStatus })
    }).then(r => r.json()).then(data => {
      if (data && !data.error) {
        var updater = prev => prev.map(c => c.id === objectId ? { ...c, status: newStatus } : c);
        if (type === "campaign") setCampaigns(updater);
        else if (type === "adset") setAdsets(prev => { var u = {}; Object.keys(prev).forEach(k => { u[k] = prev[k].map(a => a.id === objectId ? { ...a, status: newStatus } : a); }); return u; });
        else if (type === "ad") setAds(prev => { var u = {}; Object.keys(prev).forEach(k => { u[k] = prev[k].map(a => a.id === objectId ? { ...a, status: newStatus } : a); }); return u; });
      } else { alert("Erro: " + (data.error ? data.error.message : "Falha")); }
      setTogglingStatus(prev => ({ ...prev, [objectId]: false }));
    }).catch(e => { alert("Erro: " + e.message); setTogglingStatus(prev => ({ ...prev, [objectId]: false })); });
  };

  // Save budget — immediate or scheduled
  var saveBudgetEdit = () => {
    if (!editingBudget || !budgetValue) return;
    setSavingBudget(true); setBudgetMsg(null);
    if (useSchedule && scheduleDate && scheduleTime) {
      // Schedule for later
      // Build scheduled_at in Brazil time format (YYYY-MM-DDTHH:MM:SS) - no Z, server compares in Brazil TZ
      var scheduledAt = scheduleDate + "T" + scheduleTime + ":00";
      fetch("/api/scheduled-budgets", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ object_id: editingBudget.id, object_name: editingBudget.name, old_budget: Number(editingBudget.currentBudget) / 100, new_budget: Number(budgetValue), scheduled_at: scheduledAt, token: selectedBm.accessToken })
      }).then(r => r.json()).then(data => {
        if (data && data.ok) {
          setBudgetMsg("✓ Agendado para " + scheduleDate.split("-").reverse().join("/") + " às " + scheduleTime);
          fetch("/api/scheduled-budgets").then(r => r.json()).then(d => { if (Array.isArray(d)) setScheduledJobs(d); }).catch(() => {});
          setTimeout(() => { setEditingBudget(null); setBudgetMsg(null); setUseSchedule(false); setScheduleDate(""); setScheduleTime(""); }, 3000);
        } else { setBudgetMsg("✗ Erro ao agendar"); }
        setSavingBudget(false);
      }).catch(e => { setBudgetMsg("✗ " + e.message); setSavingBudget(false); });
    } else {
      // Immediate
      fetch("/api/facebook/update-budget/" + editingBudget.id, {
        method: "POST", headers: { "Content-Type": "application/json", "x-fb-token": selectedBm.accessToken },
        body: JSON.stringify({ daily_budget: budgetValue })
      }).then(r => r.json()).then(data => {
        if (data && !data.error) {
          var nc = Math.round(Number(budgetValue) * 100).toString();
          if (editingBudget.type === "campaign") setCampaigns(prev => prev.map(c => c.id === editingBudget.id ? { ...c, daily_budget: nc } : c));
          else setAdsets(prev => { var u = {}; Object.keys(prev).forEach(k => { u[k] = prev[k].map(a => a.id === editingBudget.id ? { ...a, daily_budget: nc } : a); }); return u; });
          setBudgetMsg("✓ Budget alterado agora!");
          setTimeout(() => { setEditingBudget(null); setBudgetMsg(null); }, 2500);
        } else { setBudgetMsg("✗ " + (data.error ? data.error.message : "Erro")); }
        setSavingBudget(false);
      }).catch(e => { setBudgetMsg("✗ " + e.message); setSavingBudget(false); });
    }
  };

  var deleteScheduledJob = (id) => {
    fetch("/api/scheduled-budgets/" + id, { method: "DELETE" }).then(() => {
      setScheduledJobs(prev => prev.filter(j => j.id !== id));
    }).catch(() => {});
  };
  var clearDoneJobs = () => {
    fetch("/api/scheduled-budgets/clear-done", { method: "DELETE" }).then(r => r.json()).then(d => {
      if (d && d.ok) setScheduledJobs(prev => prev.filter(j => j.status === "pending"));
    }).catch(() => {});
  };

  // Helpers
  var RESULT_TYPES = ["offsite_conversion.fb_pixel_complete_registration", "offsite_conversion.fb_pixel_lead", "onsite_conversion.lead_grouped", "lead"];
  var getLeads = (ins) => {
    if (!ins || !ins.actions) return 0;
    var t = 0; ins.actions.forEach(a => { if (RESULT_TYPES.indexOf(a.action_type) >= 0) t += Number(a.value) || 0; }); return t;
  };
  var getCPR = (ins) => {
    if (!ins || !ins.cost_per_action_type) { var leads = getLeads(ins); return leads > 0 ? (Number(ins.spend) || 0) / leads : 0; }
    var found = 0;
    ins.cost_per_action_type.forEach(a => { if (RESULT_TYPES.indexOf(a.action_type) >= 0 && Number(a.value) > 0) found = Number(a.value); });
    if (found > 0) return found;
    var leads = getLeads(ins); return leads > 0 ? (Number(ins.spend) || 0) / leads : 0;
  };

  // Shared sort helpers
  var getSortVal = function(ins, key, name) {
    if (!ins && key !== "name") return 0;
    if (key === "spend") return Number(ins.spend) || 0;
    if (key === "impressions") return Number(ins.impressions) || 0;
    if (key === "clicks") return Number(ins.inline_link_clicks) || 0;
    if (key === "ctr") return Number(ins.inline_link_click_ctr) || 0;
    if (key === "cpc") return Number(ins.cpc) || 0;
    if (key === "results") return getLeads(ins);
    if (key === "cpr") { var l = getLeads(ins); return l > 0 ? (Number(ins.spend) || 0) / l : 99999; }
    if (key === "name") return (name || "").toLowerCase();
    return 0;
  };
  var sortItems = function(items, insMap, st) {
    if (!st.key) return items;
    return items.slice().sort(function(a, b) {
      var vA = getSortVal(insMap[a.id], st.key, a.name);
      var vB = getSortVal(insMap[b.id], st.key, b.name);
      if (st.key === "name") return st.dir === "asc" ? (vA < vB ? -1 : 1) : (vA > vB ? -1 : 1);
      return st.dir === "desc" ? vB - vA : vA - vB;
    });
  };
  var SORT_OPTS = [{ k: "", l: "Original" }, { k: "spend", l: "Gasto" }, { k: "impressions", l: "Imp." }, { k: "clicks", l: "Clicks" }, { k: "ctr", l: "CTR" }, { k: "cpc", l: "CPC" }, { k: "results", l: "Result." }, { k: "cpr", l: "Costo/R" }, { k: "name", l: "Nombre" }];
  var SortPills = function({ sort, setSort, small }) {
    return <div style={{ display: "flex", gap: 3, flexWrap: "wrap", marginBottom: small ? 6 : 0 }}>
      {SORT_OPTS.map(function(s) {
        var active = sort.key === s.k;
        return <span key={s.k || "_orig"} onClick={function() { if (s.k === "") { setSort({ key: "", dir: "desc" }); } else { setSort(function(p) { return p.key === s.k ? { key: s.k, dir: p.dir === "desc" ? "asc" : "desc" } : { key: s.k, dir: "desc" }; }); } }} style={{ fontSize: small ? 9 : 10, padding: small ? "2px 6px" : "3px 8px", borderRadius: 6, cursor: "pointer", background: active ? (s.k === "" ? "rgba(46,204,113,0.15)" : "rgba(43,126,201,0.2)") : "rgba(8,13,26,0.3)", border: "1px solid " + (active ? (s.k === "" ? "rgba(46,204,113,0.3)" : "rgba(43,126,201,0.4)") : C.bdr), color: active ? (s.k === "" ? C.grn : C.blu) : C.mut, fontWeight: active ? 700 : 400 }}>{s.l} {active && s.k ? (sort.dir === "desc" ? "↓" : "↑") : ""}</span>;
      })}
    </div>;
  };

  var StatusDot = ({ status, effective }) => { var s = effective || status; return <span style={{ width: 8, height: 8, borderRadius: "50%", background: s === "ACTIVE" ? C.grn : s === "PAUSED" ? C.yel : s === "DISAPPROVED" ? "#e74c3c" : s === "WITH_ISSUES" ? "#e67e22" : C.red, display: "inline-block", flexShrink: 0 }} />; };
  var StatusLabel = ({ status, effective }) => { var s = effective || status; var isRejected = s === "DISAPPROVED" || s === "WITH_ISSUES"; return <span style={{ fontSize: 10, padding: "2px 8px", borderRadius: 10, background: (s === "ACTIVE" ? C.grn : s === "PAUSED" ? C.yel : "#e74c3c") + "20", color: s === "ACTIVE" ? C.grn : s === "PAUSED" ? C.yel : "#e74c3c", fontWeight: 600 }}>{s === "ACTIVE" ? "Ativo" : s === "PAUSED" ? "Pausado" : s === "DISAPPROVED" ? "🚫 Rechazado" : s === "WITH_ISSUES" ? "⚠️ Con problemas" : s}</span>; };
  var Spin = ({ s, c }) => <span style={{ display: "inline-block", animation: "spin 1s linear infinite", width: s || 14, height: s || 14, border: "2px solid " + (c || C.blu), borderTopColor: "transparent", borderRadius: "50%" }} />;

  // Metric row component
  var MetricRow = ({ ins, compact }) => {
    if (!ins) return <div style={{ fontSize: 11, color: C.mut, fontStyle: "italic" }}>Carregando métricas...</div>;
    var spend = Number(ins.spend) || 0, imp = Number(ins.impressions) || 0, clicks = Number(ins.inline_link_clicks) || 0;
    var ctr = Number(ins.inline_link_click_ctr) || 0, cpc = Number(ins.cpc) || 0, leads = getLeads(ins), cpr = getCPR(ins);
    var metrics = [
      { l: "Gasto", v: fU(spend), c: C.red, b: true },
      { l: "Impressões", v: fI(imp) },
      { l: "Clicks", v: fI(clicks) },
      { l: "CTR", v: fP(ctr) },
      { l: "CPC", v: fU(cpc) },
      { l: "Resultados", v: fI(leads), c: C.cyan, b: true },
      { l: "Custo/resultado", v: fU(cpr), c: C.br, b: true },
    ];
    var shown = compact ? metrics.filter((m, i) => i < 4) : metrics;
    return <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr 1fr" : "repeat(" + shown.length + ",1fr)", gap: mob ? 4 : 8 }}>
      {shown.map((m, mi) => <div key={mi}><div style={{ fontSize: 9, color: C.mut, textTransform: "uppercase", letterSpacing: 0.5 }}>{m.l}</div><div style={{ fontSize: compact ? 12 : (mob ? 13 : 14), fontWeight: m.b ? 700 : 500, color: m.c || C.txt }}>{m.v}</div></div>)}
    </div>;
  };

  // KPI totals
  var totalSpend = 0, totalLeads = 0, totalImp = 0, totalClicks = 0;
  campaigns.forEach(c => { var ins = campaignInsights[c.id]; if (ins) { totalSpend += Number(ins.spend) || 0; totalImp += Number(ins.impressions) || 0; totalClicks += Number(ins.inline_link_clicks) || 0; totalLeads += getLeads(ins); } });
  var avgCpr = totalLeads > 0 ? totalSpend / totalLeads : 0;

  // --- LOADING ---
  if (loading) return <div style={{ padding: 40, textAlign: "center" }}><Spin s={20} /> <span style={{ marginLeft: 10, color: C.blu, fontSize: 14 }}>Carregando BMs...</span></div>;

  // --- NO BMS ---
  if (bmsList.length === 0) return <Sec icon="📋" label="Campanhas" open={true}>
    <div style={{ padding: 30, textAlign: "center" }}>
      <div style={{ fontSize: 40, marginBottom: 12 }}>📋</div>
      <div style={{ fontSize: 15, color: C.br, fontWeight: 700, marginBottom: 8 }}>Nenhum BM conectado</div>
      <div style={{ fontSize: 12, color: C.mut, maxWidth: 380, margin: "0 auto" }}>Vá em <span style={{ color: C.blu, fontWeight: 600 }}>BMs Facebook</span> e conecte pelo menos um Business Manager para ver campanhas reais.</div>
    </div>
  </Sec>;

  // --- BUDGET MODAL ---
  var budgetModal = editingBudget && <div style={{ position: "fixed", inset: 0, zIndex: 200, display: "flex", alignItems: "center", justifyContent: "center" }}>
    <div onClick={() => { setEditingBudget(null); setBudgetMsg(null); setUseSchedule(false); }} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.6)" }} />
    <div style={{ position: "relative", background: C.card, border: "1px solid " + C.bdr, borderRadius: 16, padding: 24, width: mob ? "92%" : 420, zIndex: 201 }}>
      <div style={{ fontSize: 14, fontWeight: 700, color: C.br, marginBottom: 4 }}>Alterar orçamento diário</div>
      <div style={{ fontSize: 12, color: C.cyan, marginBottom: 6, fontFamily: "monospace" }}>{editingBudget.name}</div>
      <div style={{ fontSize: 11, color: C.mut, marginBottom: 12 }}>Atual: <span style={{ fontWeight: 600, color: C.br }}>{fBudget(editingBudget.currentBudget)}</span></div>

      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 14 }}>
        <span style={{ fontSize: 18, color: C.br, fontWeight: 700 }}>$</span>
        <input type="number" value={budgetValue} onChange={e => setBudgetValue(e.target.value)} placeholder="0.00" step="0.01" min="1"
          style={{ flex: 1, padding: "10px 14px", borderRadius: 8, border: "1px solid " + C.bdr, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 18, fontWeight: 700, outline: "none", fontFamily: "monospace" }} />
      </div>

      {/* Toggle: now vs scheduled */}
      <div style={{ display: "flex", gap: 8, marginBottom: 14 }}>
        <span onClick={() => setUseSchedule(false)} style={{ flex: 1, padding: "10px 14px", borderRadius: 8, cursor: "pointer", textAlign: "center", fontSize: 12, fontWeight: 600, background: !useSchedule ? "rgba(46,204,113,0.15)" : "rgba(8,13,26,0.4)", border: "1px solid " + (!useSchedule ? C.grn : C.bdr), color: !useSchedule ? C.grn : C.mut }}>⚡ Alterar agora</span>
        <span onClick={() => setUseSchedule(true)} style={{ flex: 1, padding: "10px 14px", borderRadius: 8, cursor: "pointer", textAlign: "center", fontSize: 12, fontWeight: 600, background: useSchedule ? "rgba(93,173,226,0.15)" : "rgba(8,13,26,0.4)", border: "1px solid " + (useSchedule ? C.cyan : C.bdr), color: useSchedule ? C.cyan : C.mut }}>🕐 Agendar mudança</span>
      </div>

      {useSchedule && <div style={{ marginBottom: 14 }}>
        <div style={{ fontSize: 10, color: C.mut, textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, marginBottom: 6 }}>Quando aplicar? (horário de Brasília)</div>
        <div style={{ display: "flex", gap: 8 }}>
          <input type="date" value={scheduleDate} onChange={e => setScheduleDate(e.target.value)} style={{ flex: 1, padding: "8px 10px", borderRadius: 8, border: "1px solid " + C.bdr, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 13, outline: "none", colorScheme: "dark" }} />
          <input type="time" value={scheduleTime} onChange={e => setScheduleTime(e.target.value)} style={{ width: 120, padding: "8px 10px", borderRadius: 8, border: "1px solid " + C.bdr, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 13, outline: "none", colorScheme: "dark" }} />
        </div>
        <div style={{ fontSize: 10, color: C.mut, marginTop: 6 }}>Horário de Brasília. O servidor verifica a cada 60s e aplica automaticamente. Limpa executados após 24h.</div>
      </div>}

      {budgetMsg && <div style={{ padding: "8px 12px", borderRadius: 8, marginBottom: 12, fontSize: 12, fontWeight: 600, background: budgetMsg.startsWith("✓") ? "rgba(46,204,113,0.1)" : "rgba(231,76,60,0.1)", border: "1px solid " + (budgetMsg.startsWith("✓") ? "rgba(46,204,113,0.3)" : "rgba(231,76,60,0.3)"), color: budgetMsg.startsWith("✓") ? C.grn : C.red }}>{budgetMsg}</div>}

      <div style={{ display: "flex", gap: 8 }}>
        <Btn onClick={saveBudgetEdit} disabled={savingBudget || !budgetValue || (useSchedule && (!scheduleDate || !scheduleTime))} color={useSchedule ? C.cyan : C.grn}>{savingBudget ? "Salvando..." : useSchedule ? "🕐 Agendar" : "⚡ Aplicar agora"}</Btn>
        <Btn onClick={() => { setEditingBudget(null); setBudgetMsg(null); setUseSchedule(false); }} color="rgba(30,48,80,0.6)">Cancelar</Btn>
      </div>
    </div>
  </div>;

  // --- Reject dismiss logic (no hooks here, just vars) ---
  var hideTemp = function(adId) { setHiddenAds(function(p) { var n = {}; for (var k in p) n[k] = p[k]; n[adId] = true; return n; }); };
  var hide7d = function(adId) {
    var upd = savedDismissed.concat([{ id: adId, ts: Date.now() }]);
    setSavedDismissed(upd);
    setHiddenAds(function(p) { var n = {}; for (var k in p) n[k] = p[k]; n[adId] = true; return n; });
    fetch("/api/store/dismissed_rejects", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ value: upd }) }).catch(function() {});
  };
  var weekAgo = Date.now() - 7 * 86400000;
  var dismissMap = {};
  savedDismissed.forEach(function(d) { if (d && d.ts > weekAgo) dismissMap[d.id] = true; });
  var visibleRej = globalRejected.filter(function(ad) { return !dismissMap[ad.id] && !hiddenAds[ad.id]; });

  var rejPanel = visibleRej.length > 0 ? (
    <div style={{ padding: mob ? "12px" : "14px 16px", borderRadius: 12, background: "rgba(231,76,60,0.06)", border: "1px solid rgba(231,76,60,0.25)", marginBottom: 14 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10, flexWrap: "wrap" }}>
        <svg width="18" height="18" viewBox="0 0 36 36" style={{ flexShrink: 0 }}><defs><linearGradient id="mgr" x1="50%" x2="50%" y1="97%" y2="0%"><stop offset="0%" stopColor="#0062E0"/><stop offset="100%" stopColor="#19AFFF"/></linearGradient></defs><circle cx="18" cy="18" r="18" fill="url(#mgr)"/><path d="M25.6 23.3l.9-5.3h-5.2v-3.5c0-1.5.7-2.9 3-2.9h2.3V7c0 0-2.1-.4-4.2-.4-4.3 0-7 2.6-7 7.2V18h-4.7v5.3h4.7v12.8c1 .1 1.9.2 2.9.2s2-.1 2.9-.2V23.3h4.3z" fill="#fff"/></svg>
        <span style={{ fontSize: mob ? 13 : 14, fontWeight: 800, color: "#e74c3c" }}>🚫 {visibleRej.length} anuncio{visibleRej.length !== 1 ? "s" : ""} rechazado{visibleRej.length !== 1 ? "s" : ""}</span>
        <span style={{ fontSize: 9, color: C.mut, marginLeft: "auto" }}>✕ oculta ahora · 🗑 oculta 7 días</span>
      </div>
      {visibleRej.map(function(ad, i) {
        var fb = ad.feedback && typeof ad.feedback === "object" ? Object.values(ad.feedback).flat().filter(function(v) { return typeof v === "string"; }).join(" · ") : "";
        return <div key={ad.id || i} style={{ display: "flex", alignItems: "flex-start", gap: 8, padding: mob ? "6px 8px" : "8px 10px", marginBottom: 3, borderRadius: 8, background: "rgba(8,13,26,0.35)", border: "1px solid " + C.bdr }}>
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: ad.status === "DISAPPROVED" ? "#e74c3c" : "#e67e22", flexShrink: 0, marginTop: 4 }} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12, fontWeight: 700, color: C.br, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{ad.name}</div>
            <div style={{ fontSize: 10, color: C.mut, marginTop: 2 }}>{ad.bmName} → {ad.accName} → {ad.campaign}</div>
            <div style={{ fontSize: 10, color: ad.status === "DISAPPROVED" ? "#e74c3c" : "#e67e22", fontWeight: 600, marginTop: 2 }}>
              {ad.status === "DISAPPROVED" ? "🚫 Rechazado" : "⚠️ Con problemas"}
              {fb && <span style={{ fontWeight: 400, color: C.mut }}> · {fb}</span>}
            </div>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 4, flexShrink: 0 }}>
            <span onClick={function() { hideTemp(ad.id); }} title="Ocultar ahora (vuelve al recargar)" style={{ fontSize: 14, color: C.mut, cursor: "pointer", padding: "2px 4px", lineHeight: 1 }}>✕</span>
            <span onClick={function() { hide7d(ad.id); }} title="Ocultar 7 días" style={{ fontSize: 12, color: C.mut, cursor: "pointer", padding: "2px 4px", lineHeight: 1 }}>🗑</span>
          </div>
        </div>;
      })}
    </div>
  ) : globalRejLoading ? (
    <div style={{ padding: "10px 14px", borderRadius: 10, background: "rgba(59,130,246,0.03)", border: "1px solid rgba(59,130,246,0.1)", marginBottom: 14, display: "flex", alignItems: "center", gap: 8 }}>
      <Spin s={10} /> <span style={{ fontSize: 12, color: C.blu }}>Verificando anuncios rechazados...</span>
    </div>
  ) : null;

  // --- STEP 1: CHOOSE BM ---
  if (step === 1) return <>
    {budgetModal}
    {rejPanel}
    <Sec icon="📘" label="Selecione o Business Manager" open={true}>
      <div style={{ fontSize: 12, color: C.mut, marginBottom: 14 }}>Escolha o BM que deseja gerenciar.</div>
      {bmsList.map(bm => (
        <div key={bm.id} onClick={() => { setSelectedBm(bm); if ((bm.adAccounts || []).length === 1) { setSelectedAccount(bm.adAccounts[0]); setStep(3); } else { setStep(2); } }} style={{
          display: "flex", alignItems: "center", gap: 12, padding: "14px 16px", marginBottom: 8, borderRadius: 10, cursor: "pointer",
          background: "rgba(8,13,26,0.4)", border: "1px solid " + C.bdr, transition: "all 0.15s"
        }}>
          <span style={{ width: 10, height: 10, borderRadius: "50%", background: C.grn, flexShrink: 0 }} />
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 14, fontWeight: 700, color: C.br }}>{bm.name}</div>
            <div style={{ fontSize: 11, color: C.mut }}>ID: {bm.bmId} · {(bm.adAccounts || []).length} contas · {bm.tokenType === "system" ? "Token permanente" : "Token 60 dias"}</div>
          </div>
          <span style={{ fontSize: 16, color: C.mut }}>→</span>
        </div>
      ))}
    </Sec>

    {/* Scheduled jobs */}
    {scheduledJobs.length > 0 && <Sec icon="🕐" label={"Budgets agendados (" + scheduledJobs.filter(j => j.status === "pending").length + " pendentes)"}>
      {scheduledJobs.map(j => {
        var schedParts = (j.scheduled_at || "").replace("T", " ").split(/[-: ]/);
        var schedStr = schedParts.length >= 5 ? schedParts[2] + "/" + schedParts[1] + "/" + schedParts[0] + " " + schedParts[3] + ":" + schedParts[4] : j.scheduled_at;
        return <div key={j.id} style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 12px", marginBottom: 6, borderRadius: 8, background: j.status === "pending" ? "rgba(243,156,18,0.04)" : j.status === "executed" ? "rgba(46,204,113,0.04)" : "rgba(231,76,60,0.04)", border: "1px solid " + C.bdr, flexWrap: "wrap" }}>
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: j.status === "pending" ? C.yel : j.status === "executed" ? C.grn : C.red, flexShrink: 0 }} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12, fontWeight: 600, color: C.br }}>{j.object_name || j.object_id}</div>
            <div style={{ fontSize: 11, color: C.mut }}>${Number(j.old_budget || 0).toFixed(2)} → <span style={{ color: C.grn, fontWeight: 600 }}>${Number(j.new_budget).toFixed(2)}</span> · Agendar: {schedStr} (BR) · {j.status === "pending" ? "⏳ Pendente" : j.status === "executed" ? "✅ " + (j.executed_at || "") : "❌ " + (j.result || "Erro")}</div>
          </div>
          <Btn onClick={() => deleteScheduledJob(j.id)} color="rgba(231,76,60,0.15)" small>✗</Btn>
        </div>;
      })}
      {scheduledJobs.some(j => j.status !== "pending") && <div style={{ textAlign: "right", marginTop: 6 }}><Btn onClick={clearDoneJobs} color="rgba(231,76,60,0.2)" small>🗑 Limpar executados</Btn></div>}
    </Sec>}
  </>;

  // --- STEP 2: CHOOSE ACCOUNT ---
  if (step === 2 && selectedBm) return <>
    {budgetModal}
    <div style={{ marginBottom: 14 }}>
      <span onClick={() => { setStep(1); setSelectedBm(null); setSelectedAccount(null); }} style={{ fontSize: 12, color: C.blu, cursor: "pointer", fontWeight: 600 }}>← Voltar aos BMs</span>
      <span style={{ fontSize: 12, color: C.mut, marginLeft: 10 }}>{selectedBm.name}</span>
    </div>
    <Sec icon="💳" label={"Contas de anúncio — " + selectedBm.name} count={(selectedBm.adAccounts || []).length} open={true}>
      <div style={{ fontSize: 12, color: C.mut, marginBottom: 14 }}>Selecione a conta de anúncio.</div>
      {(selectedBm.adAccounts || []).map(acc => {
        var accId = acc.id || acc.account_id;
        return <div key={accId} onClick={() => { setSelectedAccount(acc); setStep(3); }} style={{
          display: "flex", alignItems: "center", gap: 12, padding: "14px 16px", marginBottom: 8, borderRadius: 10, cursor: "pointer",
          background: "rgba(8,13,26,0.4)", border: "1px solid " + C.bdr
        }}>
          <span style={{ width: 10, height: 10, borderRadius: "50%", background: C.cyan, flexShrink: 0 }} />
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 14, fontWeight: 700, color: C.br }}>{acc.name || accId}</div>
            <div style={{ fontSize: 11, color: C.mut, fontFamily: "monospace" }}>act_{accId}</div>
          </div>
          <span style={{ fontSize: 16, color: C.mut }}>→</span>
        </div>;
      })}
    </Sec>
  </>;

  // --- STEP 3: CAMPAIGNS DATA ---
  return <>
    {budgetModal}
    {rejPanel}

    {/* Date range — TOP */}
    <div style={{ display: "flex", gap: 5, flexWrap: "wrap", marginBottom: 12, alignItems: "center" }}>
      {Object.entries(dateRanges).map(([k, v]) => (
        <button key={k} onClick={() => setDateRange(k)} style={{ padding: mob ? "7px 10px" : "5px 14px", borderRadius: 20, border: dateRange === k ? "none" : "1px solid " + C.bdr, background: dateRange === k ? C.pill : "transparent", color: dateRange === k ? "#fff" : C.mut, fontSize: mob ? 11 : 12, cursor: "pointer", fontWeight: dateRange === k ? 700 : 400 }}>{v.label}</button>
      ))}
      <button onClick={() => { setCampaigns([]); setCampaignInsights({}); setAdsets({}); setAdsetInsights({}); setAds({}); setAdInsights({}); setExpandedCampaign({}); setExpandedAdset({}); setCampRefreshKey(k => k + 1); }} style={{ padding: mob ? "7px 14px" : "7px 18px", borderRadius: 20, border: "none", background: "#e74c3c", color: "#fff", fontSize: mob ? 12 : 13, cursor: "pointer", fontWeight: 700 }}>🔄 Atualizar</button>
      {lastUpdated && <span style={{ fontSize: 11, color: C.mut, marginLeft: 4 }}>Actualizado: {lastUpdated.toLocaleTimeString("es-CO", { hour: "2-digit", minute: "2-digit", second: "2-digit" })}</span>}
    </div>

    {/* Breadcrumb */}
    <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 12, flexWrap: "wrap", fontSize: 12 }}>
      <span onClick={() => { setStep(1); setSelectedBm(null); setSelectedAccount(null); setCampaigns([]); }} style={{ color: C.blu, cursor: "pointer", fontWeight: 600 }}>BMs</span>
      <span style={{ color: C.mut }}>›</span>
      <span onClick={() => { setStep(2); setSelectedAccount(null); setCampaigns([]); }} style={{ color: C.blu, cursor: "pointer", fontWeight: 600 }}>{selectedBm.name}</span>
      <span style={{ color: C.mut }}>›</span>
      <span style={{ color: C.br, fontWeight: 700 }}>{selectedAccount.name || (selectedAccount.id || selectedAccount.account_id)}</span>
    </div>

    {/* KPIs */}
    <div style={{ display: "grid", gridTemplateColumns: mob ? "1fr 1fr" : "repeat(5,1fr)", gap: 8, marginBottom: 14 }}>
      <KPI label="Campanhas" value={campaigns.length} mob={mob} />
      <KPI label="Ativas" value={campaigns.filter(c => c.status === "ACTIVE").length} color={C.grn} mob={mob} />
      <KPI label="Gasto total" value={fU(totalSpend)} color={C.red} mob={mob} />
      <KPI label="Resultados" value={fI(totalLeads)} color={C.cyan} mob={mob} />
      <KPI label="Custo/resultado" value={fU(avgCpr)} mob={mob} />
    </div>

    {error && <div style={{ padding: "10px 14px", borderRadius: 10, background: "rgba(231,76,60,0.08)", border: "1px solid rgba(231,76,60,0.2)", marginBottom: 12, fontSize: 12, color: C.red }}>{error}</div>}

    {/* Account status alert */}
    {accountStatus && accountStatus.account_status !== 1 && (
      <div style={{ padding: "12px 16px", borderRadius: 12, background: "rgba(231,76,60,0.08)", border: "1px solid rgba(231,76,60,0.3)", marginBottom: 12 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
          <span style={{ fontSize: 18 }}>🚨</span>
          <span style={{ fontSize: 14, fontWeight: 800, color: "#e74c3c" }}>Cuenta de anuncio con restricciones</span>
        </div>
        <div style={{ fontSize: 12, color: C.txt, marginLeft: 26 }}>
          Status: <span style={{ fontWeight: 700, color: "#e74c3c" }}>{accountStatus.account_status === 2 ? "DESACTIVADA" : accountStatus.account_status === 3 ? "NO APROBADA" : accountStatus.account_status === 7 ? "PENDIENTE DE REVISIÓN" : accountStatus.account_status === 9 ? "EN PERIODO DE GRACIA" : "RESTRINGIDA (" + accountStatus.account_status + ")"}</span>
          {accountStatus.disable_reason > 0 && <span style={{ marginLeft: 8 }}>• Razón: {accountStatus.disable_reason === 1 ? "Violación de políticas" : accountStatus.disable_reason === 2 ? "Actividad sospechosa" : accountStatus.disable_reason === 3 ? "Pago rechazado" : "Código " + accountStatus.disable_reason}</span>}
        </div>
      </div>
    )}

    {/* Disapproved ads alert */}
    {disapprovedAds.length > 0 && (
      <div style={{ padding: "12px 16px", borderRadius: 12, background: "rgba(231,76,60,0.06)", border: "1px solid rgba(231,76,60,0.25)", marginBottom: 12 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }}>
          <span style={{ fontSize: 18 }}>🚫</span>
          <span style={{ fontSize: 14, fontWeight: 800, color: "#e74c3c" }}>{disapprovedAds.length} anuncio{disapprovedAds.length !== 1 ? "s" : ""} rechazado{disapprovedAds.length !== 1 ? "s" : ""}</span>
        </div>
        {disapprovedAds.map((ad, i) => {
          var campName = ad.adset && ad.adset.campaign ? ad.adset.campaign.name : "—";
          var adsetName = ad.adset ? ad.adset.name : "—";
          var feedback = ad.ad_review_feedback && typeof ad.ad_review_feedback === "object" ? Object.entries(ad.ad_review_feedback).map(([k,v]) => typeof v === "string" ? v : (Array.isArray(v) ? v.join(", ") : JSON.stringify(v))).join(" · ") : "";
          return <div key={ad.id || i} style={{ padding: "8px 10px", marginBottom: 4, borderRadius: 8, background: "rgba(8,13,26,0.3)", border: "1px solid " + C.bdr, marginLeft: 26 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 3, flexWrap: "wrap" }}>
              <span style={{ fontSize: 11, fontWeight: 700, color: "#e74c3c" }}>{ad.effective_status === "DISAPPROVED" ? "🚫 RECHAZADO" : "⚠️ CON PROBLEMAS"}</span>
              <span style={{ fontSize: 11, fontWeight: 600, color: C.br }}>{ad.name}</span>
            </div>
            <div style={{ fontSize: 10, color: C.mut }}>
              Campaña: <span style={{ color: C.txt }}>{campName}</span> → Conjunto: <span style={{ color: C.txt }}>{adsetName}</span>
            </div>
            {feedback && <div style={{ fontSize: 10, color: "#e67e22", marginTop: 3 }}>Motivo: {feedback}</div>}
          </div>;
        })}
      </div>
    )}

    {/* Campaigns with effective_status issues */}
    {campaigns.filter(c => c.effective_status && c.effective_status !== "ACTIVE" && c.effective_status !== "PAUSED" && c.effective_status !== "DELETED").length > 0 && disapprovedAds.length === 0 && (
      <div style={{ padding: "10px 14px", borderRadius: 10, background: "rgba(243,156,18,0.06)", border: "1px solid rgba(243,156,18,0.2)", marginBottom: 12 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ fontSize: 16 }}>⚠️</span>
          <span style={{ fontSize: 13, fontWeight: 700, color: C.yel }}>{campaigns.filter(c => c.effective_status && c.effective_status !== "ACTIVE" && c.effective_status !== "PAUSED" && c.effective_status !== "DELETED").length} campaña(s) con estado especial</span>
        </div>
        <div style={{ marginLeft: 24, marginTop: 4, fontSize: 11, color: C.mut }}>
          {campaigns.filter(c => c.effective_status && c.effective_status !== "ACTIVE" && c.effective_status !== "PAUSED" && c.effective_status !== "DELETED").map(c => <div key={c.id}><span style={{ color: C.txt, fontWeight: 600 }}>{c.name}</span>: <span style={{ color: "#e67e22" }}>{c.effective_status}</span></div>)}
        </div>
      </div>
    )}

    {loadingCampaigns && <div style={{ padding: 20, textAlign: "center", fontSize: 13, color: C.blu, display: "flex", alignItems: "center", justifyContent: "center", gap: 10 }}><Spin /> Carregando campanhas...</div>}

    {!loadingCampaigns && campaigns.length === 0 && !error && <Sec icon="📋" label="Campanhas" open={true}><div style={{ padding: 20, textAlign: "center", fontSize: 13, color: C.mut }}>Nenhuma campanha nesta conta.</div></Sec>}

    {/* CAMPAIGNS */}
    {campaigns.length > 0 && <Sec icon="📋" label={"Campanhas"} count={campaigns.length} open={true}>
      {/* Search + Sort */}
      <div style={{ marginBottom: 10 }}>
        <input type="text" value={campSearch} onChange={e => setCampSearch(e.target.value)} placeholder="🔍 Buscar campanha..." style={{ width: "100%", padding: "9px 14px", borderRadius: 10, border: "1px solid " + C.bdr, background: "rgba(8,13,26,0.6)", color: C.br, fontSize: 13, outline: "none", boxSizing: "border-box", marginBottom: 8 }} />
        <SortPills sort={campSort} setSort={setCampSort} />
      </div>
      {sortItems(campaigns.filter(camp => !campSearch || camp.name.toLowerCase().includes(campSearch.toLowerCase())), campaignInsights, campSort).map(camp => {
        var ins = campaignInsights[camp.id];
        var isExp = expandedCampaign[camp.id];

        return <div key={camp.id} style={{ marginBottom: 8 }}>
          <div style={{ background: isExp ? "rgba(36,120,181,0.06)" : "rgba(8,13,26,0.35)", border: "1px solid " + (isExp ? "rgba(36,120,181,0.3)" : C.bdr), borderRadius: isExp ? "12px 12px 0 0" : 12, padding: mob ? "12px" : "12px 16px" }}>
            {/* Header */}
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10, flexWrap: "wrap" }}>
              <StatusDot status={camp.status} effective={camp.effective_status} />
              <span onClick={() => { setExpandedCampaign(function(p) { var n = {}; for (var k in p) n[k] = p[k]; if (n[camp.id]) { delete n[camp.id]; } else { n[camp.id] = true; loadAdsets(camp.id); } return n; }); }} style={{ flex: 1, fontSize: 13, fontWeight: 700, color: C.br, cursor: "pointer", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 }}>{camp.name}</span>
              <StatusLabel status={camp.status} effective={camp.effective_status} />
              <span onClick={() => { setExpandedCampaign(function(p) { var n = {}; for (var k in p) n[k] = p[k]; if (n[camp.id]) { delete n[camp.id]; } else { n[camp.id] = true; loadAdsets(camp.id); } return n; }); }} style={{ color: C.mut, fontSize: 9, cursor: "pointer", transform: isExp ? "rotate(0)" : "rotate(-90deg)", transition: "transform 0.2s" }}>▼</span>
            </div>

            {/* Metrics */}
            <div style={{ marginBottom: 8 }}><MetricRow ins={ins} /></div>

            {/* Actions */}
            <div style={{ display: "flex", gap: 6, flexWrap: "wrap", alignItems: "center" }}>
              <Btn onClick={() => toggleStatus(camp.id, camp.status, "campaign")} disabled={!!togglingStatus[camp.id]} color={camp.status === "ACTIVE" ? "rgba(243,156,18,0.25)" : "rgba(46,204,113,0.25)"} small>
                {togglingStatus[camp.id] ? "⏳" : camp.status === "ACTIVE" ? "⏸ Pausar" : "▶ Ativar"}
              </Btn>
              {camp.daily_budget && <Btn onClick={() => { setEditingBudget({ id: camp.id, name: camp.name, currentBudget: camp.daily_budget, type: "campaign" }); setBudgetValue((Number(camp.daily_budget) / 100).toFixed(2)); setUseSchedule(false); setBudgetMsg(null); }} color="rgba(43,126,201,0.2)" small>💰 {fBudget(camp.daily_budget)}</Btn>}
              <Btn onClick={() => { setExpandedCampaign(function(p) { var n = {}; for (var k in p) n[k] = p[k]; if (n[camp.id]) { delete n[camp.id]; } else { n[camp.id] = true; loadAdsets(camp.id); } return n; }); }} color="rgba(93,173,226,0.15)" small>{isExp ? "▲ Fechar" : "▼ Conjuntos"}</Btn>
              {camp.objective && <span style={{ fontSize: 10, color: C.mut, fontStyle: "italic" }}>{camp.objective}</span>}
            </div>
          </div>

          {/* ADSETS */}
          {isExp && <div style={{ background: "rgba(36,120,181,0.03)", border: "1px solid rgba(36,120,181,0.15)", borderTop: "none", borderRadius: "0 0 12px 12px", padding: mob ? "8px" : "8px 16px 16px" }}>
            {loadingAdsets[camp.id] && <div style={{ padding: 14, textAlign: "center", fontSize: 12, color: C.blu }}><Spin s={12} /> Carregando conjuntos...</div>}

            {(adsets[camp.id] || []).length > 1 && !loadingAdsets[camp.id] && <SortPills sort={adsetSort} setSort={setAdsetSort} small />}

            {sortItems(adsets[camp.id] || [], adsetInsights, adsetSort).map(adset => {
              var asIns = adsetInsights[adset.id];
              var isAsExp = expandedAdset[adset.id];

              return <div key={adset.id} style={{ marginTop: 8 }}>
                <div style={{ background: isAsExp ? "rgba(139,92,246,0.06)" : "rgba(8,13,26,0.25)", border: "1px solid " + (isAsExp ? "rgba(139,92,246,0.25)" : C.bdr), borderRadius: isAsExp ? "10px 10px 0 0" : 10, padding: mob ? "10px" : "10px 14px" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap" }}>
                    <StatusDot status={adset.status} effective={adset.effective_status} />
                    <span onClick={() => { setExpandedAdset(function(p) { var n = {}; for (var k in p) n[k] = p[k]; if (n[adset.id]) { delete n[adset.id]; } else { n[adset.id] = true; loadAds(adset.id); } return n; }); }} style={{ flex: 1, fontSize: 12, fontWeight: 600, color: "#a78bfa", cursor: "pointer", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 }}>{adset.name}</span>
                    <StatusLabel status={adset.status} effective={adset.effective_status} />
                    <span onClick={() => { setExpandedAdset(function(p) { var n = {}; for (var k in p) n[k] = p[k]; if (n[adset.id]) { delete n[adset.id]; } else { n[adset.id] = true; loadAds(adset.id); } return n; }); }} style={{ color: C.mut, fontSize: 9, cursor: "pointer", transform: isAsExp ? "rotate(0)" : "rotate(-90deg)", transition: "transform 0.2s" }}>▼</span>
                  </div>
                  <div style={{ marginBottom: 8 }}><MetricRow ins={asIns} /></div>
                  <div style={{ display: "flex", gap: 5, flexWrap: "wrap", alignItems: "center" }}>
                    <Btn onClick={() => toggleStatus(adset.id, adset.status, "adset")} disabled={!!togglingStatus[adset.id]} color={adset.status === "ACTIVE" ? "rgba(243,156,18,0.2)" : "rgba(46,204,113,0.2)"} small>{togglingStatus[adset.id] ? "⏳" : adset.status === "ACTIVE" ? "⏸" : "▶"}</Btn>
                    {adset.daily_budget && <Btn onClick={() => { setEditingBudget({ id: adset.id, name: adset.name, currentBudget: adset.daily_budget, type: "adset" }); setBudgetValue((Number(adset.daily_budget) / 100).toFixed(2)); setUseSchedule(false); setBudgetMsg(null); }} color="rgba(43,126,201,0.15)" small>💰 {fBudget(adset.daily_budget)}</Btn>}
                    <Btn onClick={() => { setExpandedAdset(function(p) { var n = {}; for (var k in p) n[k] = p[k]; if (n[adset.id]) { delete n[adset.id]; } else { n[adset.id] = true; loadAds(adset.id); } return n; }); }} color="rgba(93,173,226,0.1)" small>{isAsExp ? "▲" : "▼ Anúncios"}</Btn>
                  </div>
                </div>

                {/* ADS */}
                {isAsExp && <div style={{ background: "rgba(139,92,246,0.02)", border: "1px solid rgba(139,92,246,0.12)", borderTop: "none", borderRadius: "0 0 10px 10px", padding: mob ? "6px" : "6px 12px 12px" }}>
                  {loadingAds[adset.id] && <div style={{ padding: 10, textAlign: "center", fontSize: 11, color: "#a78bfa" }}><Spin s={10} c="#a78bfa" /> Carregando anúncios...</div>}
                  {(ads[adset.id] || []).length > 1 && !loadingAds[adset.id] && <SortPills sort={adSort} setSort={setAdSort} small />}
                  {sortItems(ads[adset.id] || [], adInsights, adSort).map(ad => {
                    var adIns = adInsights[ad.id];
                    return <div key={ad.id} style={{ padding: "10px 12px", marginTop: 6, background: "rgba(8,13,26,0.3)", border: "1px solid " + C.bdr, borderRadius: 8 }}>
                      {/* Ad header */}
                      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }}>
                        {ad.creative && ad.creative.thumbnail_url && <img src={ad.creative.thumbnail_url} style={{ width: 36, height: 36, borderRadius: 6, objectFit: "cover", flexShrink: 0 }} />}
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                            <StatusDot status={ad.status} effective={ad.effective_status} />
                            <span style={{ fontSize: 11, fontWeight: 600, color: C.txt, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{ad.name}</span>
                          </div>
                          {ad.creative && ad.creative.body && <div style={{ fontSize: 10, color: C.mut, marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: mob ? 200 : 400 }}>{ad.creative.body}</div>}
                        </div>
                        <Btn onClick={() => toggleStatus(ad.id, ad.status, "ad")} disabled={!!togglingStatus[ad.id]} color={ad.status === "ACTIVE" ? "rgba(243,156,18,0.2)" : "rgba(46,204,113,0.2)"} small>{togglingStatus[ad.id] ? "⏳" : ad.status === "ACTIVE" ? "⏸" : "▶"}</Btn>
                      </div>
                      {/* Ad metrics */}
                      <MetricRow ins={adIns} />
                    </div>;
                  })}
                  {!loadingAds[adset.id] && (!ads[adset.id] || ads[adset.id].length === 0) && <div style={{ padding: 10, fontSize: 11, color: C.mut, textAlign: "center" }}>Nenhum anúncio</div>}
                </div>}
              </div>;
            })}
            {!loadingAdsets[camp.id] && (!adsets[camp.id] || adsets[camp.id].length === 0) && <div style={{ padding: 14, fontSize: 12, color: C.mut, textAlign: "center" }}>Nenhum conjunto nesta campanha</div>}
          </div>}
        </div>;
      })}
    </Sec>}

    {/* Scheduled budget changes */}
    {scheduledJobs.length > 0 && <Sec icon="🕐" label={"Agendamentos de budget (" + scheduledJobs.filter(j => j.status === "pending").length + " pendentes)"} open={scheduledJobs.some(j => j.status === "pending")}>
      {scheduledJobs.sort((a, b) => a.status === "pending" ? -1 : 1).map(j => {
        var schedParts = (j.scheduled_at || "").replace("T", " ").replace(".000Z", "").split(/[-: ]/);
        var schedStr = schedParts.length >= 5 ? schedParts[2] + "/" + schedParts[1] + "/" + schedParts[0] + " " + schedParts[3] + ":" + schedParts[4] : j.scheduled_at;
        return <div key={j.id} style={{ display: "flex", alignItems: "center", gap: 10, padding: "12px 14px", marginBottom: 6, borderRadius: 10, background: j.status === "pending" ? "rgba(243,156,18,0.05)" : j.status === "executed" ? "rgba(46,204,113,0.05)" : "rgba(231,76,60,0.05)", border: "1px solid " + (j.status === "pending" ? "rgba(243,156,18,0.2)" : j.status === "executed" ? "rgba(46,204,113,0.2)" : "rgba(231,76,60,0.2)"), flexWrap: "wrap" }}>
          <span style={{ width: 10, height: 10, borderRadius: "50%", background: j.status === "pending" ? C.yel : j.status === "executed" ? C.grn : C.red, flexShrink: 0 }} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 13, fontWeight: 700, color: C.br }}>{j.object_name || j.object_id}</div>
            <div style={{ fontSize: 12, marginTop: 3 }}>
              <span style={{ color: C.mut }}>Budget: </span>
              <span style={{ color: C.red, fontWeight: 600 }}>${Number(j.old_budget || 0).toFixed(2)}</span>
              <span style={{ color: C.mut }}> → </span>
              <span style={{ color: C.grn, fontWeight: 700 }}>${Number(j.new_budget).toFixed(2)}</span>
            </div>
            <div style={{ fontSize: 11, marginTop: 4, display: "flex", flexDirection: "column", gap: 2 }}>
              {j.created_at_br && <span style={{ color: C.mut }}>🕐 Programado em: <span style={{ color: C.txt }}>{j.created_at_br} (BR)</span></span>}
              <span style={{ color: C.cyan }}>📅 Agendar para: <span style={{ color: C.txt }}>{schedStr} (BR)</span></span>
              {j.status === "pending" && <span style={{ color: C.yel, fontWeight: 600 }}>⏳ Aguardando execução</span>}
              {j.status === "executed" && <span style={{ color: C.grn, fontWeight: 600 }}>✅ Executado em: {j.executed_at || ""} (BR)</span>}
              {j.status === "error" && <span style={{ color: C.red, fontWeight: 600 }}>❌ Erro em: {j.executed_at || ""} — {j.result || "Falha"}</span>}
            </div>
          </div>
          <Btn onClick={() => deleteScheduledJob(j.id)} color="rgba(231,76,60,0.2)" small>✗</Btn>
        </div>;
      })}
      {scheduledJobs.some(j => j.status !== "pending") && <div style={{ textAlign: "right", marginTop: 6 }}><Btn onClick={clearDoneJobs} color="rgba(231,76,60,0.2)" small>🗑 Limpar executados</Btn></div>}
    </Sec>}


    <InfoBox>
      <span style={{ fontWeight: 600, color: C.blu }}>Campanhas (API Real):</span> Dados da Facebook Marketing API.
      <br />• <span style={{ color: C.br }}>Métricas:</span> Gasto, Impressões, Clicks, CTR, CPC, Resultados, Custo/resultado
      <br />• <span style={{ color: C.br }}>Ações:</span> ⏸/▶ ativa/pausa | 💰 altera budget agora ou agenda para depois
      <br />• <span style={{ color: C.br }}>Drill-down:</span> Campanha → Conjuntos → Anúncios
      <br /><span style={{ fontWeight: 600, color: C.yel }}>Permissões:</span> <span style={{ fontFamily: "monospace", fontSize: 11 }}>ads_read + ads_management</span>
    </InfoBox>
  </>;
}

/* ========================================= */
/* ===== PAGE: CONFIGURAÇÕES =============== */
/* ========================================= */
/* ===== PAGE: CONFIGURAÇÕES =============== */
/* ========================================= */
function PgConfig({ mob }) {
  const [config, setConfig, saveConfig] = useServerState("alertConfig", {
    gamDelay: { enabled: true, hours: 3 },
    swpDelay: { enabled: true, hours: 3 },
    fbRejected: { enabled: true },
    fbAccountDisabled: { enabled: true },
    fbBmIssues: { enabled: true },
  });
  const [saved, setSaved] = useState(false);

  // Real-time delay status
  const [avLastHour, setAvLastHour] = useState(null);
  const [swpHasToday, setSwpHasToday] = useState(null);
  // Real FB alert data for preview
  const [rejectedCount, setRejectedCount] = useState(null);
  const [accountIssues, setAccountIssues] = useState(null);
  const [bmIssues, setBmIssues] = useState(null);

  useEffect(() => {
    // ActiveView latest hour
    fetch("/api/store/admanagers").then(r => r.json()).then(d => {
      if (!d || !d.value) return;
      var items = Array.isArray(d.value) ? d.value : [];
      var av = items.find(i => i.type === "activeview" && i.fields && i.fields.apiKey);
      if (!av || !av.fields.networkCode) return;
      var domains = (av.fields.domains || "").split(",").map(x => x.trim()).filter(Boolean);
      if (!domains.length) return;
      var today = new Date().toISOString().slice(0, 10);
      fetch("/api/activeview/latest-hour/" + av.fields.networkCode + "/" + domains[0] + "?date=" + today)
        .then(r => r.json()).then(hd => {
          if (hd && hd.response && hd.response.length > 0) {
            var maxH = 0;
            hd.response.forEach(r => { var h = Number(r.HOUR || 0); if (h > maxH) maxH = h; });
            setAvLastHour(maxH);
          }
        }).catch(() => {});
    }).catch(() => {});
    // SWP today check
    fetch("/api/sendwebpush/report?date=today&dimensions=domain&metrics=revenue&limit=1&_t=" + Date.now())
      .then(r => r.json()).then(d => {
        var rows = d && d.data ? d.data : [];
        setSwpHasToday(rows.length > 0);
      }).catch(() => setSwpHasToday(false));

    // FB data for previews
    fetch("/api/store/bms").then(r => r.json()).then(d => {
      var bms = d && d.value && Array.isArray(d.value) ? d.value.filter(b => b.status === "connected" && b.accessToken) : [];
      if (!bms.length) { setRejectedCount(0); setAccountIssues(0); setBmIssues(0); return; }
      var totalRejected = 0, totalAccIssues = 0, totalBmIssues = 0;
      var promises = [];
      // BM health
      bms.forEach(bm => {
        if (bm.tokenType !== "system" && bm.tokenDate) {
          var age = Math.floor((Date.now() - new Date(bm.tokenDate).getTime()) / 86400000);
          if (60 - age <= 10) totalBmIssues++;
        }
        // Check each account
        (bm.adAccounts || []).forEach(acc => {
          var accId = acc.id || acc.account_id;
          promises.push(
            fetch("/api/facebook/account-status/" + accId, { headers: { "x-fb-token": bm.accessToken } })
              .then(r => r.json()).then(data => { if (data && !data.error && data.account_status !== 1) totalAccIssues++; }).catch(() => {})
          );
          promises.push(
            fetch("/api/facebook/disapproved/" + accId, { headers: { "x-fb-token": bm.accessToken } })
              .then(r => r.json()).then(data => { if (data && data.data) totalRejected += data.data.length; }).catch(() => {})
          );
        });
      });
      // Apps
      promises.push(
        fetch("/api/store/fbapps").then(r => r.json()).then(data => {
          var apps = data && data.value && Array.isArray(data.value) ? data.value : [];
          apps.forEach(app => { if (app.status === "rejected") totalBmIssues++; });
        }).catch(() => {})
      );
      Promise.all(promises).then(() => { setRejectedCount(totalRejected); setAccountIssues(totalAccIssues); setBmIssues(totalBmIssues); });
    }).catch(() => {});
  }, []);

  var now = new Date();
  var currentH = now.getHours();
  var avDelay = avLastHour !== null ? Math.max(0, currentH - avLastHour) : null;
  var swpDelay = swpHasToday === true ? 0 : swpHasToday === false ? currentH : null;
  var gamBad = config.gamDelay && config.gamDelay.enabled && avDelay !== null && avDelay >= (config.gamDelay.hours || 3);
  var swpBad = config.swpDelay && config.swpDelay.enabled && swpDelay !== null && swpDelay >= (config.swpDelay.hours || 3);

  var upd = (key, field, val) => { setConfig(p => ({ ...p, [key]: { ...p[key], [field]: val } })); setSaved(false); };
  var save = () => { saveConfig(config); setSaved(true); setTimeout(() => setSaved(false), 3000); };

  const Toggle = ({ value, onChange }) => (
    <span onClick={() => onChange(!value)} style={{ width: 42, height: 22, borderRadius: 11, cursor: "pointer", background: value ? C.grn : "rgba(30,48,80,0.4)", display: "flex", alignItems: "center", padding: "0 3px", justifyContent: value ? "flex-end" : "flex-start", flexShrink: 0 }}>
      <span style={{ width: 16, height: 16, borderRadius: "50%", background: "#fff" }} />
    </span>
  );

  var AlertRow = ({ icon, label, desc, enabled, onToggle, status, children }) => (
    <div style={{ padding: "14px 16px", marginBottom: 8, borderRadius: 10, background: "rgba(8,13,26,0.35)", border: "1px solid " + C.bdr, opacity: enabled ? 1 : 0.4 }}>
      <div style={{ display: "flex", alignItems: mob ? "flex-start" : "center", justifyContent: "space-between", marginBottom: enabled && children ? 10 : 0, flexDirection: mob ? "column" : "row", gap: mob ? 8 : 0 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, flex: 1 }}>
          {icon}
          <div style={{ flex: 1 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
              <span style={{ fontSize: 13, fontWeight: 600, color: C.br }}>{label}</span>
              {status && enabled && <span style={{ fontSize: 10, padding: "2px 8px", borderRadius: 8, background: status.bad ? "rgba(231,76,60,0.12)" : "rgba(46,204,113,0.1)", color: status.bad ? "#e74c3c" : C.grn, fontWeight: 700 }}>{status.text}</span>}
            </div>
            {desc && <div style={{ fontSize: 10, color: C.mut, marginTop: 1 }}>{desc}</div>}
          </div>
        </div>
        <Toggle value={enabled} onChange={onToggle} />
      </div>
      {enabled && children}
    </div>
  );

  return <>
    {/* ALERTAS DE DELAY */}
    <Sec icon="🔔" label="Alertas de delay" open={true}>
      <div style={{ fontSize: 12, color: C.mut, marginBottom: 12 }}>Configura cuándo mostrar alerta de delay en el Dashboard.</div>
      <AlertRow icon={<img src="https://activeview.io/favicon.ico" width="16" height="16" style={{ borderRadius: 3 }} onError={e => e.target.style.display='none'} />} label="GAM (ActiveView)" desc="Alertar cuando GAM no tiene datos nuevos" enabled={config.gamDelay?.enabled !== false} onToggle={v => upd("gamDelay", "enabled", v)} status={avDelay === null ? { text: "Verificando...", bad: false } : gamBad ? { text: "⏰ delay " + avDelay + "h", bad: true } : { text: "✓ OK — " + avDelay + "h", bad: false }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
          <span style={{ fontSize: 12, color: C.mut }}>Alertar después de</span>
          <input type="number" value={config.gamDelay?.hours || 3} onChange={e => upd("gamDelay", "hours", parseInt(e.target.value) || 1)} min="1" max="24" style={{ width: 55, padding: "7px 10px", borderRadius: 8, border: "1px solid " + C.bdr, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 15, fontWeight: 600, textAlign: "center", outline: "none" }} />
          <span style={{ fontSize: 12, color: C.mut }}>horas</span>
        </div>
      </AlertRow>
      <AlertRow icon={<svg width="16" height="16" viewBox="0 0 20 20" style={{ flexShrink: 0 }}><rect width="20" height="20" rx="4" fill="#3b6fe0"/><path d="M10 4a4 4 0 0 0-4 4v2.5l-1 1.5v1h10v-1l-1-1.5V8a4 4 0 0 0-4-4zm-1.5 11a1.5 1.5 0 0 0 3 0h-3z" fill="#fff"/></svg>} label="SWP (SendWebPush)" desc="Alertar cuando SWP no tiene datos de hoy" enabled={config.swpDelay?.enabled !== false} onToggle={v => upd("swpDelay", "enabled", v)} status={swpDelay === null ? { text: "Verificando...", bad: false } : swpBad ? { text: "⏰ delay " + swpDelay + "h", bad: true } : { text: "✓ OK", bad: false }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
          <span style={{ fontSize: 12, color: C.mut }}>Alertar después de</span>
          <input type="number" value={config.swpDelay?.hours || 3} onChange={e => upd("swpDelay", "hours", parseInt(e.target.value) || 1)} min="1" max="24" style={{ width: 55, padding: "7px 10px", borderRadius: 8, border: "1px solid " + C.bdr, background: "rgba(8,13,26,0.8)", color: C.br, fontSize: 15, fontWeight: 600, textAlign: "center", outline: "none" }} />
          <span style={{ fontSize: 12, color: C.mut }}>horas</span>
        </div>
      </AlertRow>
    </Sec>

    {/* ALERTAS FACEBOOK */}
    <Sec icon="📱" label="Alertas de Meta Ads" open={true}>
      <div style={{ fontSize: 12, color: C.mut, marginBottom: 12 }}>Configura qué alertas de Facebook mostrar en el Dashboard y Campanhas.</div>
      <AlertRow icon={<span style={{ fontSize: 16 }}>🚫</span>} label="Anuncios rechazados" desc="Alerta cuando hay ads con status DISAPPROVED" enabled={config.fbRejected?.enabled !== false} onToggle={v => upd("fbRejected", "enabled", v)} status={rejectedCount === null ? { text: "Verificando...", bad: false } : rejectedCount > 0 ? { text: rejectedCount + " rechazado" + (rejectedCount !== 1 ? "s" : ""), bad: true } : { text: "✓ Sin rechazados", bad: false }} />
      <AlertRow icon={<span style={{ fontSize: 16 }}>🚨</span>} label="Cuenta desactivada" desc="Alerta cuando una cuenta de anuncio está restringida o desactivada" enabled={config.fbAccountDisabled?.enabled !== false} onToggle={v => upd("fbAccountDisabled", "enabled", v)} status={accountIssues === null ? { text: "Verificando...", bad: false } : accountIssues > 0 ? { text: accountIssues + " cuenta" + (accountIssues !== 1 ? "s" : "") + " con problemas", bad: true } : { text: "✓ Cuentas OK", bad: false }} />
      <AlertRow icon={<span style={{ fontSize: 16 }}>⚠️</span>} label="Problemas de BM / Apps" desc="Alerta cuando un Business Manager tiene problemas o un app pierde permisos" enabled={config.fbBmIssues?.enabled !== false} onToggle={v => upd("fbBmIssues", "enabled", v)} status={bmIssues === null ? { text: "Verificando...", bad: false } : bmIssues > 0 ? { text: bmIssues + " problema" + (bmIssues !== 1 ? "s" : ""), bad: true } : { text: "✓ BMs y Apps OK", bad: false }} />
    </Sec>

    {/* Save */}
    <div style={{ position: "sticky", bottom: 0, padding: "14px 20px", background: C.card, borderTop: "1px solid " + C.bdr, borderRadius: "12px 12px 0 0", display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 16 }}>
      <span style={{ fontSize: 12, color: saved ? C.grn : C.mut, fontWeight: saved ? 600 : 400 }}>{saved ? "✓ Configuraciones salvadas" : "Cambios sin salvar"}</span>
      <Btn onClick={save} color={C.grn}>{saved ? "✓ Salvo!" : "Salvar configuraciones"}</Btn>
    </div>
  </>;
}

/* ===== NAV & MAIN ===== */
const NAV = [
  { icon: "📊", k: "dash", l: "Dashboard" },
  { icon: "⚙️", k: "ops", l: "Operações" },
  { icon: "📡", k: "am", l: "Ad Managers" },
  { icon: "📘", k: "bms", l: "BMs Facebook" },
  { icon: "📋", k: "camp", l: "Campanhas" },
  { icon: "📁", k: "desp", l: "Despesas Fixas" },
  { icon: "💰", k: "trib", l: "Tributações" },
  { icon: "📱", k: "apps", l: "Facebook Apps" },
  { icon: "👥", k: "users", l: "Usuários" },
  { icon: "📈", k: "kpis", l: "KPIs" },
  { icon: "⚡", k: "cfg", l: "Configurações" },
];

/* ===== LOGIN PAGE ===== */
function LoginPage({ onLogin }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const handleLogin = async () => {
    if (!email.trim() || !password.trim()) { setError("Preencha email e senha"); return; }
    setLoading(true); setError("");
    await new Promise(r => setTimeout(r, 1200));
    if (email !== "santiagobjdigital333@gmail.com" || password !== "Botero12@") { setError("Email ou senha incorretos"); setLoading(false); return; }
    var ud = { email: email, name: email.split("@")[0] }; saveLS("user", ud); onLogin(ud);
  };

  return (
    <div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", background: "linear-gradient(135deg, #080d1a 0%, #0f1a30 50%, #14375a 100%)", padding: 20 }}>
      <div style={{ width: "100%", maxWidth: 400, background: "rgba(15,26,48,0.85)", backdropFilter: "blur(20px)", border: "1px solid rgba(30,48,80,0.5)", borderRadius: 20, padding: "40px 32px" }}>
        <div style={{ textAlign: "center", marginBottom: 30 }}>
          <svg width="80" height="80" viewBox="0 0 64 64" style={{ marginBottom: 8 }}><defs><linearGradient id="lgL" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stopColor="#00f5a0"/><stop offset="40%" stopColor="#00d4ff"/><stop offset="100%" stopColor="#7b2ff7"/></linearGradient><linearGradient id="lgP" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stopColor="#00f5a0"/><stop offset="50%" stopColor="#00d4ff"/><stop offset="100%" stopColor="#7b2ff7"/></linearGradient></defs><rect width="64" height="64" rx="14" fill="#060d1e"/><rect width="64" height="64" rx="14" fill="none" stroke="url(#lgL)" strokeWidth="0.5" opacity="0.3"/><circle cx="32" cy="32" r="22" fill="none" stroke="url(#lgL)" strokeWidth="1.8"/><circle cx="32" cy="32" r="15" fill="none" stroke="url(#lgL)" strokeWidth="0.6" opacity="0.3"/><path d="M14 32 L24 32 L27 22 L30 42 L33 18 L36 46 L39 25 L42 32 L50 32" fill="none" stroke="url(#lgP)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/><circle cx="32" cy="32" r="2" fill="#fff"/></svg>
        </div>
        <div style={{ marginBottom: 14 }}>
          <div style={{ fontSize: 10, color: "#4a5e78", textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, marginBottom: 4 }}>Email</div>
          <input type="email" value={email} onChange={e => setEmail(e.target.value)} autoFocus autoComplete="email" placeholder="seu@email.com" onKeyDown={e => e.key === "Enter" && handleLogin()}
            style={{ width: "100%", padding: "10px 14px", borderRadius: 10, border: "1px solid rgba(30,48,80,0.5)", background: "rgba(8,13,26,0.8)", color: "#e4eaf0", fontSize: 14, outline: "none", boxSizing: "border-box" }} />
        </div>
        <div style={{ marginBottom: 20 }}>
          <div style={{ fontSize: 10, color: "#4a5e78", textTransform: "uppercase", letterSpacing: 1, fontWeight: 600, marginBottom: 4 }}>Senha</div>
          <input type="password" value={password} onChange={e => setPassword(e.target.value)} placeholder="••••••••" onKeyDown={e => e.key === "Enter" && handleLogin()}
            style={{ width: "100%", padding: "10px 14px", borderRadius: 10, border: "1px solid rgba(30,48,80,0.5)", background: "rgba(8,13,26,0.8)", color: "#e4eaf0", fontSize: 14, outline: "none", boxSizing: "border-box" }} />
        </div>
        {error && <div style={{ padding: "8px 12px", borderRadius: 8, background: "rgba(231,76,60,0.1)", border: "1px solid rgba(231,76,60,0.3)", color: "#e74c3c", fontSize: 12, marginBottom: 14, textAlign: "center" }}>{error}</div>}
        <button onClick={handleLogin} disabled={loading} style={{ width: "100%", padding: "12px", borderRadius: 10, border: "none", background: loading ? "rgba(43,126,201,0.4)" : "linear-gradient(135deg, #2b7ec9, #3498db)", color: "#fff", fontSize: 14, fontWeight: 700, cursor: loading ? "wait" : "pointer" }}>
          {loading ? "Entrando..." : "Entrar"}
        </button>
        <div style={{ textAlign: "center", marginTop: 16, fontSize: 11, color: "#4a5e78" }}>
          <a href="/privacy" target="_blank" style={{ color: "#5dade2", textDecoration: "none" }}>Politica de Privacidade</a>
          <span style={{ margin: "0 8px" }}>•</span>
          <a href="/terms" target="_blank" style={{ color: "#5dade2", textDecoration: "none" }}>Termos de Uso</a>
        </div>
      </div>
    </div>
  );
}

function App() {
  const mob = useIsMobile();
  const [user, setUser] = useState(() => { try { var u = localStorage.getItem("bg_user"); return u ? JSON.parse(u) : null; } catch(e) { return null; } });
  const [pg, setPg] = useState(() => { try { var lp = localStorage.getItem("bg_lastPage"); if (lp) { localStorage.removeItem("bg_lastPage"); return lp; } } catch(e) {} return "dash"; });
  const [period, setPeriod] = useState("t");
  const [dateFrom, setDateFrom] = useState(() => { var d = new Date(); return d.getFullYear() + "-" + String(d.getMonth()+1).padStart(2,"0") + "-" + String(d.getDate()).padStart(2,"0"); });
  const [dateTo, setDateTo] = useState(() => { var d = new Date(); return d.getFullYear() + "-" + String(d.getMonth()+1).padStart(2,"0") + "-" + String(d.getDate()).padStart(2,"0"); });
  const [gamState, setGamState] = useState({ status: "idle", msg: "" });
  const [refreshKey, setRefreshKey] = useState(0);
  const [menuOpen, setMenuOpen] = useState(false);
  var _initD = {};
  try { var _ds = localStorage.getItem("lum_dismiss"); if (_ds) { var _dp = JSON.parse(_ds); if (_dp && typeof _dp === "object") _initD = _dp; } } catch(e) {}
  const [dismissedAlerts, setDismissedAlerts] = useState(_initD);
  const [dashFilterProject, setDashFilterProject] = useState("all");
  const [showDashFilter, setShowDashFilter] = useState(false);
  const [dashProjects, setDashProjects] = useState([]);

  const applyPeriod = useCallback((k) => {
    setPeriod(k);
    const today = new Date();
    const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1);
    const fmt = d => d.getFullYear() + "-" + String(d.getMonth()+1).padStart(2,"0") + "-" + String(d.getDate()).padStart(2,"0");
    if (k === "y") { setDateFrom(fmt(yesterday)); setDateTo(fmt(yesterday)); }
    else if (k === "t") { setDateFrom(fmt(today)); setDateTo(fmt(today)); }
    else if (k === "7") { const w = new Date(today); w.setDate(w.getDate() - 7); setDateFrom(fmt(w)); setDateTo(fmt(yesterday)); }
    else if (k === "m") { const first = new Date(today.getFullYear(), today.getMonth(), 1); setDateFrom(fmt(first)); setDateTo(fmt(today)); }
    else { const m = new Date(today); m.setDate(m.getDate() - 30); setDateFrom(fmt(m)); setDateTo(fmt(yesterday)); }
  }, []);

  const filteredSites = useMemo(() => [], [dateFrom, dateTo]);

  const updateGam = useCallback(async () => {
    setGamState({ status: "loading", msg: "Atualizando dados..." });
    setRefreshKey(k => k + 1);
    // Wait a bit for fetches to start, then clear loading after 5s max
    setTimeout(() => setGamState({ status: "idle", msg: "" }), 5000);
  }, []);

  const navigate = k => { setPg(k); setMenuOpen(false); if (k === "dash") setRefreshKey(r => r + 1); };
  useEffect(() => { fetch("/api/store/operacoes").then(r => r.json()).then(d => { if (d && d.value && Array.isArray(d.value)) setDashProjects(d.value); }).catch(() => {}); }, [refreshKey]);
  useEffect(() => { try { localStorage.setItem("bg_lastPage", pg); } catch(e) {} }, [pg]);
  const periods = [{ k: "y", l: "ontem" }, { k: "t", l: "hoje" }, { k: "7", l: "7 dias" }, { k: "30d", l: "30 dias" }, { k: "m", l: "este mês" }];
  const logout = () => { setUser(null); try { localStorage.removeItem("bg_user"); } catch(e) {} fetch("/api/store/user", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ value: null }) }); };

  if (!user) return <LoginPage onLogin={setUser} />;

  const renderPage = () => {
    switch (pg) {
      case "dash": return <Home sites={filteredSites} period={period} dateFrom={dateFrom} dateTo={dateTo} mob={mob} gamState={gamState} dismissedAlerts={dismissedAlerts} setDismissedAlerts={setDismissedAlerts} refreshKey={refreshKey} filterProject={dashFilterProject} />;
      case "am": return <PgAdManagers mob={mob} />;
      case "bms": return <PgBMs mob={mob} />;
      case "ops": return <PgOperacoes mob={mob} />;
      case "apps": return <PgFbApps mob={mob} />;
      case "desp": return <PgDespesas mob={mob} />;
      case "trib": return <PgTributacoes mob={mob} />;
      case "users": return <PgUsuarios mob={mob} />;
      case "kpis": return <PgKpis mob={mob} />;
      case "camp": return <PgCampanhas mob={mob} />;
      case "cfg": return <PgConfig mob={mob} />;
      default: return <Sec icon={NAV.find(n => n.k === pg)?.icon} label={NAV.find(n => n.k === pg)?.l} open={true}><div style={{ padding: 24, textAlign: "center", color: C.mut, fontSize: 13 }}>Em desenvolvimento.</div></Sec>;
    }
  };

  return (
    <div style={{ display: "flex", minHeight: "100vh", background: C.bg, color: C.txt, fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", fontSize: 14 }}>
      {!mob && (
        <aside style={{ width: 250, background: C.sb, borderRight: `1px solid ${C.bdr}`, flexShrink: 0, padding: "16px 0", display: "flex", flexDirection: "column" }}>
          <div style={{ padding: "0 14px 16px", borderBottom: `1px solid ${C.bdr}` }}>
            <svg width="42" height="42" viewBox="0 0 64 64"><defs><linearGradient id="slg" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stopColor="#00f5a0"/><stop offset="40%" stopColor="#00d4ff"/><stop offset="100%" stopColor="#7b2ff7"/></linearGradient><linearGradient id="slp" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stopColor="#00f5a0"/><stop offset="50%" stopColor="#00d4ff"/><stop offset="100%" stopColor="#7b2ff7"/></linearGradient></defs><rect width="64" height="64" rx="14" fill="#060d1e"/><circle cx="32" cy="32" r="22" fill="none" stroke="url(#slg)" strokeWidth="1.8"/><path d="M14 32 L24 32 L27 22 L30 42 L33 18 L36 46 L39 25 L42 32 L50 32" fill="none" stroke="url(#slp)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/><circle cx="32" cy="32" r="2" fill="#fff"/></svg>
          </div>
          <nav style={{ paddingTop: 6, flex: 1 }}>
            {NAV.map(item => { const a = pg === item.k; return <div key={item.k} onClick={() => navigate(item.k)} style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 18px", cursor: "pointer", fontSize: 14, fontWeight: a ? 600 : 400, color: a ? "#fff" : C.mut, background: a ? "rgba(36,120,181,0.22)" : "transparent", borderLeft: a ? "3px solid #3498db" : "3px solid transparent" }}><span style={{ width: 22, textAlign: "center", fontSize: 16 }}>{item.icon}</span> {item.l}</div>; })}
          </nav>
        </aside>
      )}
      {mob && menuOpen && (
        <div style={{ position: "fixed", inset: 0, zIndex: 100, display: "flex" }}>
          <div onClick={() => setMenuOpen(false)} style={{ position: "absolute", inset: 0, background: "rgba(0,0,0,0.6)" }} />
          <aside style={{ position: "relative", width: 260, background: C.sb, padding: "16px 0", zIndex: 101, overflowY: "auto", display: "flex", flexDirection: "column" }}>
            <div style={{ padding: "0 16px 16px", borderBottom: `1px solid ${C.bdr}`, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              <svg width="36" height="36" viewBox="0 0 64 64"><defs><linearGradient id="mlg" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stopColor="#00f5a0"/><stop offset="40%" stopColor="#00d4ff"/><stop offset="100%" stopColor="#7b2ff7"/></linearGradient><linearGradient id="mlp" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stopColor="#00f5a0"/><stop offset="50%" stopColor="#00d4ff"/><stop offset="100%" stopColor="#7b2ff7"/></linearGradient></defs><rect width="64" height="64" rx="14" fill="#060d1e"/><circle cx="32" cy="32" r="22" fill="none" stroke="url(#mlg)" strokeWidth="1.8"/><path d="M14 32 L24 32 L27 22 L30 42 L33 18 L36 46 L39 25 L42 32 L50 32" fill="none" stroke="url(#mlp)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/><circle cx="32" cy="32" r="2" fill="#fff"/></svg>
              <span onClick={() => setMenuOpen(false)} style={{ fontSize: 22, color: C.mut, cursor: "pointer", padding: "4px 6px" }}>✕</span>
            </div>
            <nav style={{ paddingTop: 8, flex: 1 }}>
              {NAV.map(item => { const a = pg === item.k; return <div key={item.k} onClick={() => navigate(item.k)} style={{ display: "flex", alignItems: "center", gap: 12, padding: "13px 18px", cursor: "pointer", fontSize: 15, fontWeight: a ? 600 : 400, color: a ? "#fff" : C.mut, background: a ? "rgba(36,120,181,0.22)" : "transparent", borderLeft: a ? "3px solid #3498db" : "3px solid transparent" }}>{item.icon} {item.l}</div>; })}
            </nav>
            <div style={{ padding: "16px 18px", borderTop: `1px solid ${C.bdr}` }}>
              <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 12 }}>
                <div style={{ width: 32, height: 32, borderRadius: "50%", background: "linear-gradient(135deg,#2b7ec9,#3498db)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 18 }}>🚀</div>
                <span style={{ fontSize: 13, color: C.txt }}>{user.name || user.email}</span>
              </div>
              <button onClick={() => { logout(); setMenuOpen(false); }} style={{ width: "100%", padding: "10px 16px", borderRadius: 8, border: "1px solid rgba(231,76,60,0.3)", background: "rgba(231,76,60,0.1)", color: "#e74c3c", fontSize: 14, fontWeight: 600, cursor: "pointer" }}>Sair da conta</button>
            </div>
          </aside>
        </div>
      )}
      <main style={{ flex: 1, minWidth: 0, overflow: "auto" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: mob ? "12px 16px" : "11px 24px", borderBottom: `1px solid ${C.bdr}`, gap: 8 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            {mob && <span onClick={() => setMenuOpen(true)} style={{ fontSize: 22, cursor: "pointer", color: C.txt, padding: "2px" }}>☰</span>}
            <h1 style={{ margin: 0, fontSize: mob ? 18 : 20, fontWeight: 700, color: C.br }}>{NAV.find(n => n.k === pg)?.l}</h1>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <div style={{ width: 30, height: 30, borderRadius: "50%", background: "linear-gradient(135deg,#2b7ec9,#3498db)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 16 }}>🚀</div>
            {!mob && <><span style={{ fontSize: 12 }}>{user.name || user.email}</span><button onClick={logout} style={{ padding: "3px 10px", borderRadius: 6, border: `1px solid ${C.bdr}`, background: "transparent", color: C.txt, fontSize: 11, cursor: "pointer" }}>Sair</button></>}
          </div>
        </div>
        <div style={{ padding: mob ? "14px 14px" : "14px 24px" }}>
          {pg === "dash" && <>
            <div style={{ display: "flex", alignItems: "center", gap: 5, flexWrap: "wrap", marginBottom: 8 }}>
              {periods.map(p => <button key={p.k} onClick={() => applyPeriod(p.k)} style={{ padding: mob ? "7px 10px" : "5px 14px", borderRadius: 20, border: period === p.k ? "none" : `1px solid ${C.bdr}`, background: period === p.k ? C.pill : "transparent", color: period === p.k ? "#fff" : C.mut, fontSize: mob ? 11 : 12, cursor: "pointer", fontWeight: period === p.k ? 700 : 400 }}>{p.l}</button>)}
              <input type="date" value={dateFrom} onChange={e => { setDateFrom(e.target.value); setPeriod("c"); }} style={{ padding: mob ? "6px 8px" : "5px 10px", borderRadius: 8, border: `1px solid ${C.bdr}`, background: "rgba(11,18,37,0.7)", color: C.txt, fontSize: mob ? 11 : 12, colorScheme: "dark", maxWidth: mob ? 130 : "auto" }} />
              <input type="date" value={dateTo} onChange={e => { setDateTo(e.target.value); setPeriod("c"); }} style={{ padding: mob ? "6px 8px" : "5px 10px", borderRadius: 8, border: `1px solid ${C.bdr}`, background: "rgba(11,18,37,0.7)", color: C.txt, fontSize: mob ? 11 : 12, colorScheme: "dark", maxWidth: mob ? 130 : "auto" }} />
            </div>
            <div style={{ display: "flex", gap: 8, marginBottom: showDashFilter ? 4 : 14, flexWrap: "wrap", alignItems: "center" }}>
              <button onClick={() => setShowDashFilter(p => !p)} style={{ padding: "7px 18px", borderRadius: 20, border: "none", background: dashFilterProject !== "all" ? C.blu : "rgba(43,126,201,0.8)", color: "#fff", fontSize: 13, cursor: "pointer", fontWeight: 700 }}>{dashFilterProject !== "all" ? (dashProjects.find(p => String(p.id) === String(dashFilterProject)) || {}).name : "Filtrar"}</button>
              {dashFilterProject !== "all" && <span onClick={() => setDashFilterProject("all")} style={{ fontSize: 11, color: C.blu, cursor: "pointer", fontWeight: 600 }}>✕</span>}
              <Btn onClick={updateGam} disabled={gamState.status === "loading"} color={"#e74c3c"}>{gamState.status === "loading" ? "⏳ Atualizando..." : "🔄 Atualizar"}</Btn>
              <span style={{ fontSize: 11, color: C.mut }}>{dateFrom.split("-").reverse().join("/")} — {dateTo.split("-").reverse().join("/")}</span>
            </div>
            {showDashFilter && <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 12, alignItems: "center" }}>
              <span onClick={() => { setDashFilterProject("all"); setShowDashFilter(false); }} style={{ fontSize: 11, padding: "5px 12px", borderRadius: 20, cursor: "pointer", background: dashFilterProject === "all" ? C.blu : "transparent", border: "1px solid " + (dashFilterProject === "all" ? C.blu : C.bdr), color: dashFilterProject === "all" ? "#fff" : C.mut, fontWeight: dashFilterProject === "all" ? 700 : 400 }}>Todos</span>
              {dashProjects.map(p => <span key={p.id} onClick={() => { setDashFilterProject(String(p.id)); setShowDashFilter(false); }} style={{ fontSize: 11, padding: "5px 12px", borderRadius: 20, cursor: "pointer", background: String(dashFilterProject) === String(p.id) ? C.blu : "transparent", border: "1px solid " + (String(dashFilterProject) === String(p.id) ? C.blu : C.bdr), color: String(dashFilterProject) === String(p.id) ? "#fff" : C.mut, fontWeight: String(dashFilterProject) === String(p.id) ? 700 : 400 }}>{p.name}</span>)}
            </div>}
          </>}
          {renderPage()}
        </div>
      </main>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(React.createElement(App));
