// ───────────────────────────────────────────────────────────────
// Busco Ops — Root app · v4
// Real Supabase auth + role-based access + impersonation + realtime
// ───────────────────────────────────────────────────────────────

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "orange",
  "density": "standard",
  "radius": "soft",
  "striping": "off"
}/*EDITMODE-END*/;

function PendingApprovalScreen({ user, onSignOut }) {
  return (
    <div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "IBM Plex Sans, sans-serif", padding: 24 }}>
      <div className="card" style={{ maxWidth: 420, textAlign: "center", padding: "32px 28px" }}>
        <div style={{ width: 48, height: 48, borderRadius: "50%", background: "var(--warn-50)", border: "1px solid var(--warn-100)", display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 16px" }}>
          <Icon name="lock" size={22} color="var(--warn-700)" />
        </div>
        <h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>{t("Waiting for approval")}</h2>
        <p style={{ fontSize: 13, color: "var(--muted)", marginTop: 10, lineHeight: 1.5 }}>
          {t("Your account")} (<b>{user.email}</b>) {t("has been created and is pending owner approval. You'll get access as soon as the owner approves it.")}
        </p>
        <button className="btn sm" style={{ marginTop: 20 }} onClick={onSignOut}>
          <Icon name="x" size={12} /> {t("Sign out")}
        </button>
      </div>
    </div>
  );
}

// QOL: a small floating "back to top" button that appears once the page is
// scrolled down a bit — handy on the long Daily-log / Couriers lists, esp. on
// phones where there's no quick way back up.
function BackToTop() {
  const [show, setShow] = useState(false);
  useEffect(() => {
    const onScroll = () => setShow(window.scrollY > 500);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  if (!show) return null;
  return (
    <button
      className="back-to-top"
      title={t("Back to top")}
      aria-label={t("Back to top")}
      onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
    >
      <Icon name="up" size={18} />
    </button>
  );
}

function App() {
  // ── Auth + data state ──────────────────────────────────────
  const [user, setUser] = useState(null);                  // currently logged-in (or impersonated) user
  const [realUser, setRealUser] = useState(null);          // set while previewing another role
  const [authChecked, setAuthChecked] = useState(false);
  const [dataLoaded, setDataLoaded] = useState(false);
  const [dataVersion, setDataVersion] = useState(0);
  const [loadError, setLoadError] = useState(null);

  // ── UI state ───────────────────────────────────────────────
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [page, setPage] = useState(() => {
    // Honour the user's "Default landing screen" preference.
    const lbl = (window.BUSCO_PREFS && window.BUSCO_PREFS.landing) || "Overview";
    const sec = (window.SECTIONS || []).find((s) => s.label === lbl);
    return sec ? sec.id : "hub";
  });
  const [finUnlocked, setFinUnlocked] = useState(false);
  const [showHR, setShowHR] = useState(false);   // HR tab is hidden; revealed via buscoShowHR() in the console
  const [tourOpen, setTourOpen] = useState(false);
  const [toast, setToast] = useState(null);
  const [signInOpen, setSignInOpen] = useState(false);
  const [hubRange, setHubRange] = useState("today");
  const [syncing, setSyncing] = useState(false);
  const [workspace, setWorkspace] = useState(() => {
    // Restore the last-used workspace and apply its region BEFORE the first
    // data load, so a refresh doesn't silently reset to "All cities".
    try {
      const saved = localStorage.getItem("busco-workspace");
      const w = buscoAllWorkspaces().find((x) => x.id === saved);
      if (w) { window.BUSCO_REGION = w.id; return w; }
    } catch {}
    return WORKSPACES[0];
  });
  const [accountView, setAccountView] = useState(null);
  const showToast = (msg, kind = "success") => setToast({ msg, kind });

  // ── Role helpers ───────────────────────────────────────────
  const role = roleOf(user?.roleKey);
  const allowed = role.sections;
  const visibleSections = SECTIONS.filter((s) => allowed.includes(s.id));
  // HR is hidden by default — revealed for managers/owners via buscoShowHR() in the console.
  const HR_SECTION = { id: "hr", label: "HR & Procurement", icon: "briefcase" };
  const navSections = (showHR && role.manage) ? [...visibleSections, HR_SECTION] : visibleSections;
  const toAppUser = (u) => ({
    id: u.id, name: u.name, initials: u.initials, email: u.email,
    roleKey: u.roleKey, role: roleOf(u.roleKey).label,
  });

  const impersonate = (u) => {
    if (!realUser) setRealUser(user);
    setUser(toAppUser(u));
    showToast(`Now viewing as ${u.name} · ${roleOf(u.roleKey).label}`);
  };
  const exitPreview = () => {
    setUser(realUser); setRealUser(null);
    showToast("Back to your account");
  };

  // If active page isn't allowed for current role, jump to the first allowed one
  useEffect(() => {
    if (user && !allowed.includes(page) && !(showHR && page === "hr")) setPage(allowed[0] || "hub");
  }, [user?.roleKey]); // eslint-disable-line

  // Dev escape hatch: reveal the hidden HR & Procurement tab from the console
  // by typing  buscoShowHR()  — and  buscoHideHR()  to put it away again.
  // Also wires the full  busco.*  debug namespace (busco.help() to list it).
  useEffect(() => {
    window.buscoShowHR = () => { window.dispatchEvent(new CustomEvent("busco:hr", { detail: true }));  return "HR & Procurement tab revealed."; };
    window.buscoHideHR = () => { window.dispatchEvent(new CustomEvent("busco:hr", { detail: false })); return "HR & Procurement tab hidden."; };
    const h = (e) => {
      const on = e.detail !== false;
      setShowHR(on);
      if (on) setPage("hr"); else setPage((cur) => (cur === "hr" ? "hub" : cur));
    };
    window.addEventListener("busco:hr", h);

    // Guided tour — launched from the user menu, first-visit prompt, or busco.tour().
    const tourH = () => setTourOpen(true);
    window.addEventListener("busco:tour", tourH);

    // Custom workspace list changed → refresh the banner/chip.
    const wsH = () => setDataVersion((v) => v + 1);
    window.addEventListener("busco:workspaces", wsH);

    // Force a full re-render (used by language / number-format switches).
    window.buscoForceRender = () => setDataVersion((v) => v + 1);

    window.busco = {
      help() {
        console.log(
          "%cBusco dev console", "font-weight:bold;font-size:13px",
          "\n  busco.state()              → all loaded data {clients,couriers,entries,users}" +
          "\n  busco.user() / busco.role()→ your account / role + allowed sections" +
          "\n  busco.go('financial')      → jump to a tab (hub/log/clients/couriers/alerts/users/financial/hr)" +
          "\n  busco.showHR() / hideHR()  → reveal / hide the HR & Procurement tab" +
          "\n  busco.lang('ar' | 'en')    → switch language live (RTL flips instantly)" +
          "\n  busco.region('bahrain')    → scope data ('all', 'ksa' or 'bahrain')" +
          "\n  busco.numbers('1.234,5')   → change number format live ('1,234.5' / '1.234,5' / '1 234.5')" +
          "\n  busco.motion(true|false)   → toggle reduce-motion" +
          "\n  busco.invoice('Noon','2026-05') → build an invoice object" +
          "\n  busco.rates()              → quick client rate table (console.table-friendly)" +
          "\n  busco.parse(`...`)         → test the WhatsApp report parser" +
          "\n  busco.reload()             → re-fetch everything from Supabase" +
          "\n  Raw globals: CLIENTS, ENTRIES, COURIERS, CLIENT_ROWS, COURIER_ROWS, FINANCIALS, HR_REQUESTS, USERS, BUSCO_PREFS, buscoUser"
        );
        return "☝️ pick one";
      },
      state:  () => window.Store.getState(),
      user:   () => window.buscoUser,
      role:   () => window.roleOf(window.buscoUser?.roleKey),
      go:     (p) => { if (p === "hr") return window.buscoShowHR(); setPage(p); return `→ ${p}`; },
      showHR: () => window.buscoShowHR(),
      hideHR: () => window.buscoHideHR(),
      lang:   (c = "ar") => { window.buscoSetLang(c); window.buscoForceRender(); return `lang → ${c}`; },
      region: (r = "all") => { window.BUSCO_REGION = r; return window.buscoLoadAllData().then(() => { window.buscoForceRender(); return `region → ${r}`; }); },
      numbers:(fmt) => { window.buscoApplyPrefs({ ...window.BUSCO_PREFS, numberFmt: fmt }); window.buscoForceRender(); return `number format → ${fmt}`; },
      motion: (on = true) => { document.documentElement.setAttribute("data-reduce-motion", on ? "on" : ""); return on ? "motion reduced" : "motion on"; },
      invoice:(clientName, month) => window.buscoGenerateInvoice({ clientName, month }),
      rates:  () => (window.CLIENT_ROWS || []).map((c) => ({ client: c.name, rate: c.rate + "%", off: c.offloaded, del: c.delivered, ret: c.returned })),
      parse:  (text) => window.buscoParseTextReport(text),
      reload: () => window.buscoLoadAllData().then(() => { window.buscoForceRender(); return "reloaded ✓"; }),
      tour:   () => { window.dispatchEvent(new CustomEvent("busco:tour")); return "tour started"; },
    };
    console.log("%cBusco loaded — type busco.help() for dev commands.", "color:#E55A37;font-weight:bold");

    return () => { window.removeEventListener("busco:hr", h); window.removeEventListener("busco:tour", tourH); window.removeEventListener("busco:workspaces", wsH); };
  }, []);

  // Re-lock the Financial module whenever you navigate away — owner PIN must be
  // re-entered each time the page is opened.
  useEffect(() => {
    if (page !== "financial" && finUnlocked) setFinUnlocked(false);
  }, [page]); // eslint-disable-line

  // ── Resolve a Supabase auth user → an App user (with role) ─
  async function resolveAppUser(authUser) {
    const base = window.buscoUserFromAuth(authUser);
    // Look up role + saved account fields from user_profiles
    let roleKey = "warehouse";
    let displayName = base.name;
    let phone, lang, tz, status = "active";
    let notify_daily_digest, notify_critical_alerts, notify_weekly_summary;
    try {
      const profile = await window.buscoLoadMyRole();
      if (profile) {
        roleKey = profile.role_key || "warehouse";
        if (profile.name) displayName = profile.name;
        phone = profile.phone || undefined;
        lang  = profile.lang  || undefined;
        tz    = profile.tz    || undefined;
        status = profile.status || "active";
        notify_daily_digest    = profile.notify_daily_digest;
        notify_critical_alerts = profile.notify_critical_alerts;
        notify_weekly_summary  = profile.notify_weekly_summary;
      }
    } catch (e) {
      console.warn("Could not load role:", e);
    }
    return {
      id: base.id, email: base.email,
      name: displayName,
      initials: (displayName || base.email).split(/[\s._-]/).map(s => s[0]).join("").slice(0, 2).toUpperCase() || "BU",
      roleKey, role: roleOf(roleKey).label,
      phone, lang, tz, status,
      notify_daily_digest, notify_critical_alerts, notify_weekly_summary,
    };
  }

  // ── On mount: check session, load data ─────────────────────
  useEffect(() => {
    (async () => {
      try {
        const session = await window.buscoGetSession();
        if (session) {
          window.buscoUser = window.buscoUserFromAuth(session.user); // cache early so role lookup works
          const appUser = await resolveAppUser(session.user);
          window.buscoUser = appUser;
          setUser(appUser);
          await window.buscoLoadAllData();
          setDataLoaded(true);
          setDataVersion(v => v + 1);
        }
      } catch (e) {
        console.error("Initial load failed:", e);
        setLoadError(e?.message || String(e));
      } finally {
        setAuthChecked(true);
      }
    })();

    const { data: { subscription } } = window.supabaseClient.auth.onAuthStateChange(async (event, session) => {
      if (event === "SIGNED_IN" && session) {
        window.buscoUser = window.buscoUserFromAuth(session.user);
        const appUser = await resolveAppUser(session.user);
        window.buscoUser = appUser;
        setUser(appUser); setRealUser(null);
        try {
          await window.buscoLoadAllData();
          setDataLoaded(true);
          setDataVersion(v => v + 1);
        } catch (e) {
          console.error("Data load failed after sign-in:", e);
          setLoadError(e?.message || String(e));
        }
      } else if (event === "SIGNED_OUT") {
        setUser(null); setRealUser(null);
        window.buscoUser = null;
        setDataLoaded(false); setFinUnlocked(false);
      }
    });
    return () => subscription.unsubscribe();
  }, []);

  // ── Realtime sync ──────────────────────────────────────────
  useEffect(() => {
    if (!dataLoaded) return;
    let pending = false;
    const unsub = window.buscoSubscribeToChanges(async () => {
      if (pending) return;
      pending = true;
      try {
        await window.buscoLoadAllData();
        setDataVersion(v => v + 1);
      } catch (e) {
        console.error("Realtime refresh failed:", e);
      } finally {
        pending = false;
      }
    });
    return unsub;
  }, [dataLoaded]);

  // ── Apply user's saved language (sets html dir + lang attrs) ─
  useEffect(() => {
    window.buscoSetLang && window.buscoSetLang(user?.lang || "en");
  }, [user?.lang]);

  // ── Tweaks → HTML attributes for CSS theming ───────────────
  useEffect(() => {
    const r = document.documentElement;
    r.setAttribute("data-accent",   tw.accent === "orange" ? "" : tw.accent);
    r.setAttribute("data-density",  tw.density === "standard" ? "" : tw.density);
    r.setAttribute("data-radius",   tw.radius === "soft" ? "" : tw.radius);
    r.setAttribute("data-striping", tw.striping === "on" ? "on" : "");
  }, [tw.accent, tw.density, tw.radius, tw.striping]);

  // ── Cross-screen navigation events (banner "View clients" etc.) ─
  useEffect(() => {
    const h = (e) => setPage(e.detail);
    window.addEventListener("ops:nav", h);
    return () => window.removeEventListener("ops:nav", h);
  }, []);

  // ── Account-level modals ───────────────────────────────────
  useEffect(() => {
    const h = (e) => setAccountView(e.detail);
    window.addEventListener("ops:account", h);
    return () => window.removeEventListener("ops:account", h);
  }, []);

  // ── g + h/l/c/u/a/f quick nav ──────────────────────────────
  useEffect(() => {
    let last = 0; let prefix = false;
    const onKey = (e) => {
      const tag = e.target.tagName;
      if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
      if (e.key === "g" && Date.now() - last > 1500) { prefix = true; last = Date.now(); return; }
      if (prefix) {
        const map = { h: "hub", l: "log", c: "clients", u: "couriers", a: "alerts", f: "financial" };
        if (map[e.key] && allowed.includes(map[e.key])) setPage(map[e.key]);
        prefix = false;
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [allowed]);

  // QOL: jump back to the top when switching tabs (long pages otherwise keep
  // their scroll position from the previous tab).
  useEffect(() => { window.scrollTo({ top: 0, behavior: "auto" }); }, [page]);

  const syncNow = async () => {
    if (syncing) return;
    setSyncing(true);
    showToast("Refreshing from database…");
    try {
      await window.buscoLoadAllData();
      setDataVersion(v => v + 1);
      showToast("Synced");
    } catch (e) {
      showToast(e?.message || "Sync failed", "danger");
    } finally {
      setSyncing(false);
    }
  };

  const handleSignOut = async () => {
    try { await window.buscoSignOut(); showToast("Signed out"); }
    catch (e) { showToast(e?.message || "Sign-out failed", "danger"); }
  };

  // Switching workspace scopes all data to that region's cities, then reloads.
  const changeWorkspace = async (w) => {
    setWorkspace(w);
    window.BUSCO_REGION = w.id;
    try { localStorage.setItem("busco-workspace", w.id); } catch {}
    try {
      await window.buscoLoadAllData();
      setDataVersion(v => v + 1);
      showToast(`${w.label} — ${(window.ENTRIES || []).length} ${t("entries in view")}`);
    } catch (e) {
      showToast(e?.message || "Failed to switch workspace", "danger");
    }
  };

  // ── Auth / loading gates ───────────────────────────────────
  if (!authChecked) {
    return <div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "IBM Plex Sans, sans-serif", color: "var(--muted)" }}><span className="spinner" /> {t("Loading…")}</div>;
  }
  if (!user) {
    return (
      <SignInModal
        required
        onSignIn={async (u) => {
          // u came from real Supabase auth via buscoSignIn → buscoUserFromAuth
          const session = await window.buscoGetSession();
          if (!session) {
            setLoadError("Account created but no session — confirm your email first (or disable email confirmation in Supabase Auth).");
            return;
          }
          // Pre-cache so buscoLoadMyRole (inside resolveAppUser) can find us
          window.buscoUser = window.buscoUserFromAuth(session.user);
          const appUser = await resolveAppUser(session.user);
          window.buscoUser = appUser;
          setUser(appUser);
          try {
            await window.buscoLoadAllData();
            setDataLoaded(true);
            setDataVersion(v => v + 1);
          } catch (e) {
            console.error(e); setLoadError(e?.message || String(e));
          }
        }}
      />
    );
  }
  // Gate: new accounts must be approved by an owner before they get in.
  if (user.status === "pending") {
    return <PendingApprovalScreen user={user} onSignOut={handleSignOut} />;
  }
  if (!dataLoaded) {
    return (
      <div style={{ minHeight: "100vh", display: "flex", flexDirection: "column", gap: 12, alignItems: "center", justifyContent: "center", fontFamily: "IBM Plex Sans, sans-serif", color: "var(--muted)" }}>
        <span className="spinner" />
        <div>{t("Loading your data…")}</div>
        {loadError && <div style={{ color: "var(--crit-700)", fontSize: 12, maxWidth: 400, textAlign: "center" }}>{loadError}</div>}
      </div>
    );
  }

  // ── Page meta + actions ────────────────────────────────────
  const meta = {
    hub:       { title: t("Operations overview"),     crumbs: [new Date().toLocaleDateString("en-GB", { weekday: "long", day: "numeric", month: "long", year: "numeric" }), t("All operations")] },
    log:       { title: t("Operations · daily log"),   crumbs: [t("Manual entry"), t("Recent entries")] },
    clients:   { title: t("Client performance"),       crumbs: [`${(window.CLIENTS || []).length} ${t("active accounts") === "active accounts" ? "active accounts" : t("active accounts")}`, t("Monthly view")] },
    couriers:  { title: t("Courier directory"),        crumbs: [`${(window.COURIERS || []).length} ${t("active") === "active" ? "active" : t("active")}`, t("Performance & tiers")] },
    alerts:    { title: t("Alerts & rewards"),         crumbs: [t("Performance status"), t("Leaderboard")] },
    users:     { title: t("Users & roles"),            crumbs: [t("Team & access"), t("Admin")] },
    financial: { title: t("Financial"),                 crumbs: [t("Owner only"), new Date().toLocaleDateString("en-GB", { month: "long", year: "numeric" })] },
    hr:        { title: t("HR & Procurement"),          crumbs: [t("Hiring pipeline"), t("Procurement")] },
  }[page] || { title: t("Operations overview"), crumbs: [] };

  const actions = {
    hub: (<>
      <button className="btn primary sm" onClick={syncNow} disabled={syncing}>
        {syncing ? <span className="spinner" /> : <Icon name="refresh" size={12} color="#fff" />}
        {syncing ? t("Syncing…") : t("Sync now")}
      </button>
    </>),
    log: null, clients: null, couriers: null, users: null,
    alerts: (<>
      <button className="btn sm" data-tour="notify" onClick={async () => {
        const couriers = window.COURIER_ROWS || [];
        const clients  = window.CLIENT_ROWS  || [];
        const critical = couriers.filter((c) => c.offloaded > 0 && c.rate < 70);
        const warning  = couriers.filter((c) => c.offloaded > 0 && c.rate >= 70 && c.rate < 75);
        const flagCl   = clients.filter((c) => c.offloaded > 0 && c.rate < 75);
        if (!critical.length && !warning.length && !flagCl.length) {
          showToast("All systems green — nothing to notify");
          return;
        }
        const today = new Date().toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" });
        let text = `*Busco Ops Alert — ${today}*\n`;
        if (critical.length) {
          text += `\n_Critical couriers (<70%):_\n`;
          critical.forEach((c) => { text += `• ${c.name} — ${c.rate}%\n`; });
        }
        if (warning.length) {
          text += `\n_Warning couriers (70-75%):_\n`;
          warning.forEach((c) => { text += `• ${c.name} — ${c.rate}%\n`; });
        }
        if (flagCl.length) {
          text += `\n_Clients below 75%:_\n`;
          flagCl.forEach((c) => { text += `• ${c.name} — ${c.rate}%\n`; });
        }
        try {
          await navigator.clipboard.writeText(text);
          showToast("Alert summary copied — paste into the ops chat");
        } catch {
          showToast("Couldn't copy to clipboard", "danger");
        }
      }}><Icon name="send" size={12} /> {t("Notify ops")}</button>
    </>),
    financial: (<span className="badge badge-brand"><Icon name="lock" size={11} color="var(--b700)" /> {t("Owner access")}</span>),
  }[page] || null;

  return (
    <div className="app">
      <Header
        user={user}
        workspace={workspace}
        onWorkspaceChange={changeWorkspace}
        onRequestSignIn={() => setSignInOpen(true)}
        onSignOut={handleSignOut}
      />
      <SectionNav active={page} onChange={setPage} sections={navSections} />
      <PageBar title={meta.title} crumbs={meta.crumbs} actions={actions} />
      <div className="banner" style={{ background: "var(--b50)", borderColor: "var(--b100)", color: "var(--b700)", borderRadius: 0, padding: "6px 28px" }}>
        <Icon name="building" size={14} color="var(--b700)" />
        <div style={{ fontSize: 12 }}>
          {t("Viewing")} <b>{t(workspace.label)}</b> · {(window.ENTRIES || []).length} {t("entries in view")}
        </div>
        <div style={{ display: "flex", gap: 6, marginLeft: "auto", flexWrap: "wrap" }}>
          {buscoAllWorkspaces().filter((x) => x.id !== workspace.id).slice(0, 3).map((w) => (
            <button key={w.id} className="btn sm" onClick={() => changeWorkspace(w)}>
              {t(w.label)}
            </button>
          ))}
        </div>
      </div>
      {realUser &&
        <div className="banner" style={{ background: "var(--info-50)", borderColor: "var(--info-100)", color: "var(--info-700)", borderRadius: 0, padding: "10px 28px" }}>
          <Icon name="search" size={15} color="var(--info-700)" />
          <div>{t("Previewing as")} <b>{user.name}</b> · {t(role.label)} — {t("you only see what this role can access.")}</div>
          <button className="btn sm" style={{ marginLeft: "auto" }} onClick={exitPreview}>
            <Icon name="x" size={12} /> {t("Exit preview")}
          </button>
        </div>
      }
      <div className="content">
        {page === "hub"       && <HubScreen onToast={showToast} />}
        {page === "log"       && <DailyLogScreen onToast={showToast} />}
        {page === "clients"   && <ClientsScreen onToast={showToast} />}
        {page === "couriers"  && <CouriersScreen onToast={showToast} />}
        {page === "alerts"    && <AlertsScreen />}
        {page === "users"     && <UsersScreen user={user} onToast={showToast} onImpersonate={impersonate} />}
        {page === "financial" && <FinancialScreen unlocked={finUnlocked} setUnlocked={setFinUnlocked} onToast={showToast} />}
        {page === "hr"        && <HRScreen onToast={showToast} />}
      </div>
      <Toast msg={toast?.msg} kind={toast?.kind} onDone={() => setToast(null)} />
      <BackToTop />
      {!tourOpen && !realUser && <TourPrompt onStart={() => setTourOpen(true)} />}
      {tourOpen && <TourOverlay allowed={allowed} page={page} setPage={setPage} onClose={() => setTourOpen(false)} />}
      {signInOpen &&
        <SignInModal
          onClose={() => setSignInOpen(false)}
          onSignIn={async (u) => {
            const session = await window.buscoGetSession();
            if (!session) {
              showToast("No session — confirm your email first", "danger");
              return;
            }
            window.buscoUser = window.buscoUserFromAuth(session.user);
            const appUser = await resolveAppUser(session.user);
            setUser(appUser); window.buscoUser = appUser; setSignInOpen(false);
            showToast(`Welcome back, ${appUser.name.split(" ")[0]} · ${roleOf(appUser.roleKey).label}`);
          }}
        />
      }

      {accountView === "settings" &&
        <AccountSettingsModal
          user={user}
          onClose={() => setAccountView(null)}
          onToast={showToast}
          onSave={async (u) => {
            await window.buscoUpdateMyProfile(u);
            setUser((cur) => ({ ...(cur || {}), ...u }));
            const updated = { ...(window.buscoUser || {}), ...u };
            window.buscoUser = updated;
          }}
        />
      }
      {accountView === "preferences" &&
        <PreferencesModal onClose={() => setAccountView(null)} onToast={showToast} />
      }
      {accountView === "workspace" &&
        <WorkspaceModal
          workspace={workspace}
          onChange={changeWorkspace}
          onClose={() => setAccountView(null)}
          onToast={showToast}
        />
      }

      <TweaksPanel>
        <TweakSection label="Brand" />
        <TweakColor
          label="Accent"
          value={({ orange: "#E55A37", indigo: "#4F46E5", teal: "#0E9488", slate: "#334155" })[tw.accent]}
          options={["#E55A37", "#4F46E5", "#0E9488", "#334155"]}
          onChange={(v) => {
            const map = { "#E55A37": "orange", "#4F46E5": "indigo", "#0E9488": "teal", "#334155": "slate" };
            setTweak("accent", map[v] || "orange");
          }}
        />
        <TweakSection label="Layout" />
        <TweakRadio label="Density" value={tw.density} options={["compact", "standard", "comfortable"]} onChange={(v) => setTweak("density", v)} />
        <TweakRadio label="Corner radius" value={tw.radius} options={["sharp", "soft", "rounded"]} onChange={(v) => setTweak("radius", v)} />
        <TweakToggle label="Striped table rows" value={tw.striping === "on"} onChange={(v) => setTweak("striping", v ? "on" : "off")} />
      </TweaksPanel>
    </div>
  );
}

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