/* global React, I, S */
/* Pamp — Admin portal */

const A_NAV = [
  { key: "dashboard", label: "Dashboard", icon: I.dashboard },
  { key: "users", label: "User management", icon: I.users },
  { key: "bookings", label: "Bookings", icon: I.bookings, badge: "84" },
  { key: "notifications", label: "Notifications", icon: I.bell },
  { key: "coupons", label: "Coupons", icon: I.coupon },
  { section: "Money" },
  { key: "payments", label: "Payment center", icon: I.card },
  { key: "wallets", label: "Wallets & payouts", icon: I.wallet },
  { key: "subscriptions", label: "Subscriptions", icon: I.crown },
  { section: "Insight" },
  { key: "reports", label: "Reports & analytics", icon: I.chart },
  { key: "support", label: "Support & help", icon: I.help, badge: "12" },
  { section: "System" },
  { key: "settings", label: "Settings", icon: I.settings },
];

function AdminApp({ collapsed, onToggle, onTheme, theme, onExit, session, onNavigate, currentPage }) {
  const page = currentPage || "dashboard";
  const setPage = onNavigate;
  const tok = session?.accessToken;

  return (
    <div className="shell" data-sidebar={collapsed ? "collapsed" : "expanded"}>
      <S.Sidebar
        items={A_NAV}
        current={page}
        onNav={setPage}
        collapsed={collapsed}
        footer={
          <button className="nav-item" onClick={onExit} style={{ width: "100%" }} data-tip="Sign out">
            <span className="ni-icon"><I.logout size={18} /></span>
            <span className="ni-label">Sign out</span>
          </button>
        }
      />
      <div className="main-col">
        <S.Topbar
          onToggleSidebar={onToggle}
          onTheme={onTheme}
          theme={theme}
          search="Search users, bookings, transactions…"
        />
        <main className="main-scroll">
          {page === "dashboard"     && <AdminDashboard tok={tok} session={session} />}
          {page === "users"         && <AdminUsers tok={tok} />}
          {page === "bookings"      && <AdminBookings tok={tok} />}
          {page === "wallets"       && <AdminWallets tok={tok} />}
          {page === "subscriptions" && <AdminSubscriptions tok={tok} />}
          {page === "payments"      && <AdminPayments tok={tok} />}
          {page === "reports"       && <AdminReports tok={tok} />}
          {page === "support"       && <AdminSupport tok={tok} />}
          {page === "coupons"       && <AdminCoupons tok={tok} />}
          {page === "notifications" && <AdminNotifications tok={tok} />}
          {page === "settings"      && <AdminSettings tok={tok} />}
        </main>
      </div>
    </div>
  );
}

/* ====================================================================
   ADMIN — DASHBOARD
   ==================================================================== */
function AdminDashboard({ tok, session }) {
  const [stats, setStats] = React.useState(null);
  const firstName = (session?.profile?.full_name || "").split(" ")[0] || "there";

  React.useEffect(() => {
    let alive = true;
    SB.adminGetBookingStats(tok).then((s) => { if (alive) setStats(s); });
    return () => { alive = false; };
  }, [tok]);

  if (!stats) return <window.LoadingState />;

  const greeting = (() => {
    const h = new Date().getHours();
    if (h < 12) return "Good morning";
    if (h < 18) return "Good afternoon";
    return "Good evening";
  })();

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow="Overview · live data"
        title={`${greeting}, ${firstName}`}
        sub={`${stats.pending} pending bookings · ${stats.totalUsers} users on the platform.`}
        right={<>
          <S.Btn variant="outline" size="sm" icon={<I.calendar size={14} />}>This month</S.Btn>
          <S.Btn variant="outline" size="sm" icon={<I.download size={14} />}>Export</S.Btn>
        </>}
      />

      {/* hero metric grid */}
      <div className="grid-4" style={{ marginBottom: 20 }}>
        <S.Metric
          hero
          label="Total revenue"
          value={window.fmtMoney(stats.revenue)}
          delta={`${stats.completed} completed bookings`}
          spark={<S.Spark data={[8, 10, 9, 12, 14, 13, 16, 18, 17, 19, 22, 24]} color="oklch(80% 0.08 290)" width={120} height={36} />}
        />
        <S.Metric label="Active users" value={stats.totalUsers.toLocaleString()} delta={`${stats.recentBookings} recent`} deltaTone="pos" />
        <S.Metric label="Vendors" value={stats.totalVendors.toLocaleString()} delta="Active" deltaTone="pos" />
        <S.Metric label="Bookings" value={stats.totalBookings.toLocaleString()} delta={`${stats.pending} pending`} deltaTone={stats.pending > 0 ? "warn" : "pos"} />
      </div>

      {/* main grid */}
      <div className="grid-12" style={{ gap: 20 }}>
        {/* revenue chart */}
        <div className="card" style={{ gridColumn: "span 8" }}>
          <div className="row between" style={{ marginBottom: 8 }}>
            <div>
              <div className="eyebrow" style={{ marginBottom: 6 }}>Revenue</div>
              <div className="display" style={{ fontSize: 32, lineHeight: 1 }}>$1,424,820</div>
              <div className="row-tight" style={{ marginTop: 6 }}>
                <S.Chip tone="pos">+24.4%</S.Chip>
                <span className="muted tiny">vs Dec · $1.14M</span>
              </div>
            </div>
            <div className="row" style={{ gap: 6 }}>
              <div className="row-tight"><span className="dot" style={{ background: "var(--accent)" }} /> <span className="tiny muted">Gross</span></div>
              <div className="row-tight" style={{ marginLeft: 12 }}><span className="dot" style={{ background: "var(--ink-3)" }} /> <span className="tiny muted">Net</span></div>
              <span style={{ width: 1, height: 16, background: "var(--border)", margin: "0 8px" }} />
              <S.Btn variant="ghost" size="sm" iconRight={<I.chevD size={12} />}>Daily</S.Btn>
            </div>
          </div>
          <S.LineChart
            height={260}
            currency
            labels={["1 Jan", "5", "10", "15", "20", "25", "30 Jan"]}
            series={[
              { color: "var(--accent)", data: [42000, 51000, 48000, 62000, 58000, 71000, 84000] },
              { color: "var(--ink-3)", data: [38000, 44000, 41000, 52000, 49000, 58000, 67000], dashed: true },
            ]}
          />
        </div>

        {/* booking mix */}
        <div className="card" style={{ gridColumn: "span 4" }}>
          <div className="row between" style={{ marginBottom: 4 }}>
            <div className="h3">Booking mix</div>
            <S.IconBtn><I.ellipsis size={16} /></S.IconBtn>
          </div>
          <div className="muted tiny" style={{ marginBottom: 18 }}>By category, this month</div>

          <div className="row" style={{ justifyContent: "center", marginBottom: 18 }}>
            <S.Ring value={68} size={150} label="62.1k" sub="total bookings" stroke={14} />
          </div>

          <div className="col" style={{ gap: 10 }}>
            {[
              { label: "Hair & color", v: 38, n: "23.6k", c: "var(--accent)" },
              { label: "Nails", v: 24, n: "14.9k", c: "var(--ink)" },
              { label: "Spa & massage", v: 19, n: "11.8k", c: "var(--info)" },
              { label: "Barber", v: 12, n: "7.4k", c: "var(--warn)" },
              { label: "Other", v: 7, n: "4.4k", c: "var(--ink-3)" },
            ].map((r, i) => (
              <div key={i} className="row" style={{ gap: 10 }}>
                <span className="dot" style={{ background: r.c }} />
                <span style={{ flex: 1, fontSize: 13 }}>{r.label}</span>
                <span className="mono tiny muted">{r.v}%</span>
                <span className="mono" style={{ fontSize: 12, width: 50, textAlign: "right" }}>{r.n}</span>
              </div>
            ))}
          </div>
        </div>

        {/* vendor leaderboard */}
        <div className="card card-flush" style={{ gridColumn: "span 8" }}>
          <div className="row between" style={{ padding: "22px 22px 14px" }}>
            <div>
              <div className="h3">Top vendors</div>
              <div className="muted tiny" style={{ marginTop: 4 }}>Ranked by net revenue, last 30 days</div>
            </div>
            <div className="row" style={{ gap: 8 }}>
              <S.Btn variant="ghost" size="sm" icon={<I.filter size={12} />}>Filter</S.Btn>
              <S.Btn variant="outline" size="sm">View all</S.Btn>
            </div>
          </div>
          <table className="tbl">
            <thead>
              <tr>
                <th style={{ width: 36 }}>#</th>
                <th>Vendor</th>
                <th>Bookings</th>
                <th>Rating</th>
                <th>Capacity</th>
                <th className="col-num">Net</th>
                <th style={{ width: 60 }} />
              </tr>
            </thead>
            <tbody>
              {VENDORS.map((v, i) => (
                <tr key={v.name}>
                  <td className="mono muted">{String(i + 1).padStart(2, "0")}</td>
                  <td>
                    <div className="row-tight">
                      <S.Avatar name={v.name} size="sm" />
                      <div>
                        <div style={{ fontWeight: 500 }}>{v.name}</div>
                        <div className="muted tiny">{v.city} · {v.cat}</div>
                      </div>
                    </div>
                  </td>
                  <td className="mono">{v.bookings.toLocaleString()}</td>
                  <td><div className="row-tight"><I.star size={12} color="var(--warn)" /> {v.rating}</div></td>
                  <td style={{ width: 140 }}>
                    <div className="row-tight" style={{ gap: 8 }}>
                      <div className="bar" style={{ flex: 1 }}><span style={{ width: `${v.cap}%`, background: v.cap > 90 ? "var(--neg)" : v.cap > 70 ? "var(--warn)" : "var(--pos)" }} /></div>
                      <span className="mono tiny" style={{ width: 32 }}>{v.cap}%</span>
                    </div>
                  </td>
                  <td className="col-num mono" style={{ fontWeight: 500 }}>${v.net.toLocaleString()}</td>
                  <td><S.IconBtn><I.chevR size={14} /></S.IconBtn></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>

        {/* activity feed */}
        <div className="card" style={{ gridColumn: "span 4" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div className="h3">Live activity</div>
            <S.Chip tone="pos" icon={<span className="dot dot-pos" style={{ animation: "pulse 1.6s infinite" }} />}>live</S.Chip>
          </div>
          <div className="col" style={{ gap: 14 }}>
            {ACTIVITY.map((a, i) => (
              <div key={i} className="row-tight" style={{ alignItems: "flex-start" }}>
                <span style={{
                  width: 28, height: 28, borderRadius: 8, flexShrink: 0,
                  background: a.tone === "pos" ? "var(--pos-soft)" : a.tone === "warn" ? "var(--warn-soft)" : "var(--accent-soft)",
                  color: a.tone === "pos" ? "var(--pos)" : a.tone === "warn" ? "var(--warn)" : "var(--accent-ink)",
                  display: "flex", alignItems: "center", justifyContent: "center",
                }}>{a.icon}</span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13 }}>{a.text}</div>
                  <div className="muted tiny" style={{ marginTop: 2 }}>{a.time}</div>
                </div>
              </div>
            ))}
          </div>
        </div>

        {/* payouts queue */}
        <div className="card" style={{ gridColumn: "span 5" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div>
              <div className="h3">Payout queue</div>
              <div className="muted tiny" style={{ marginTop: 4 }}>84 vendors · clears tonight 11:00 PM UTC</div>
            </div>
            <S.Btn variant="outline" size="sm">Review all</S.Btn>
          </div>
          <div className="display" style={{ fontSize: 40, letterSpacing: "-0.03em", marginBottom: 4 }}>$284,910</div>
          <div className="muted tiny" style={{ marginBottom: 18 }}>Total amount staged</div>

          <div className="col" style={{ gap: 10 }}>
            {[
              { name: "Maison Color & Co.", amount: 8420, ago: "Queued 12m ago", tone: "ready" },
              { name: "Atelier Nails", amount: 6210, ago: "Queued 38m ago", tone: "ready" },
              { name: "Forest Spa", amount: 14820, ago: "Manual review", tone: "review" },
              { name: "Cut & Co Barber", amount: 3920, ago: "Queued 1h ago", tone: "ready" },
            ].map((p, i) => (
              <div key={i} className="row" style={{ padding: "10px 12px", border: "1px solid var(--border)", borderRadius: 10 }}>
                <S.Avatar name={p.name} size="sm" />
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 13, fontWeight: 500 }}>{p.name}</div>
                  <div className="muted tiny">{p.ago}</div>
                </div>
                <div style={{ textAlign: "right" }}>
                  <div className="mono" style={{ fontSize: 13, fontWeight: 500 }}>${p.amount.toLocaleString()}</div>
                  <S.Chip tone={p.tone === "review" ? "warn" : "pos"}>{p.tone === "review" ? "Review" : "Ready"}</S.Chip>
                </div>
              </div>
            ))}
          </div>
        </div>

        {/* health */}
        <div className="card" style={{ gridColumn: "span 4" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div className="h3">Platform health</div>
            <S.Chip tone="pos">All systems go</S.Chip>
          </div>
          <div className="row" style={{ justifyContent: "center", marginBottom: 14 }}>
            <S.Gauge value={94} size={170} label="94%" sub="composite SLO" />
          </div>
          <div className="col" style={{ gap: 10 }}>
            {[
              { l: "API latency p99", v: "182 ms", t: "pos" },
              { l: "Payments success", v: "99.97%", t: "pos" },
              { l: "Search index lag", v: "1.2s", t: "warn" },
              { l: "Webhook delivery", v: "99.84%", t: "pos" },
            ].map((h) => (
              <div key={h.l} className="row between">
                <span className="muted tiny">{h.l}</span>
                <span className="row-tight"><span className={`dot dot-${h.t}`} /><span className="mono tiny">{h.v}</span></span>
              </div>
            ))}
          </div>
        </div>

        {/* support */}
        <div className="card" style={{ gridColumn: "span 3" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div className="h3">Support</div>
            <S.IconBtn><I.arrowR size={14} /></S.IconBtn>
          </div>
          <div className="display" style={{ fontSize: 40 }}>12</div>
          <div className="muted tiny">Open tickets</div>
          <div className="divider" style={{ margin: "16px 0" }} />
          <div className="col" style={{ gap: 8 }}>
            <div className="row between"><span className="tiny">Urgent</span><span className="row-tight"><span className="dot dot-neg" /><span className="mono tiny">2</span></span></div>
            <div className="row between"><span className="tiny">In progress</span><span className="row-tight"><span className="dot dot-warn" /><span className="mono tiny">7</span></span></div>
            <div className="row between"><span className="tiny">Waiting</span><span className="row-tight"><span className="dot" style={{ background: "var(--ink-4)" }} /><span className="mono tiny">3</span></span></div>
          </div>
          <div className="muted tiny" style={{ marginTop: 14, lineHeight: 1.5 }}>
            Median first response <strong style={{ color: "var(--ink)" }}>4m 12s</strong>
          </div>
        </div>
      </div>

      <style dangerouslySetInnerHTML={{ __html: "@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}" }} />
    </div>
  );
}

const VENDORS = [
  { name: "Maison Color & Co.", city: "Paris", cat: "Hair & color", bookings: 1840, rating: 4.9, cap: 92, net: 84210 },
  { name: "Atelier Nails", city: "Brooklyn", cat: "Nails", bookings: 1420, rating: 4.8, cap: 88, net: 62180 },
  { name: "Forest Spa", city: "Reykjavík", cat: "Spa", bookings: 980, rating: 4.9, cap: 76, net: 58420 },
  { name: "Cut & Co Barber", city: "Berlin", cat: "Barber", bookings: 2100, rating: 4.7, cap: 95, net: 38210 },
  { name: "Glow Skin Studio", city: "Lisbon", cat: "Facials", bookings: 820, rating: 4.9, cap: 71, net: 34180 },
];

const ACTIVITY = [
  { tone: "pos", icon: <I.check size={14} />, text: "New vendor Maison Color & Co. approved", time: "2m ago" },
  { tone: "accent", icon: <I.card size={14} />, text: "Payout batch #2418 queued · $284,910 across 84 vendors", time: "12m ago" },
  { tone: "pos", icon: <I.users size={14} />, text: "1,420 new client accounts in the last hour", time: "34m ago" },
  { tone: "warn", icon: <I.help size={14} />, text: "Urgent ticket from Forest Spa — payout review", time: "1h ago" },
  { tone: "accent", icon: <I.coupon size={14} />, text: "Coupon WELLNESS25 redeemed 218 times today", time: "2h ago" },
];

/* ====================================================================
   ADMIN — USERS
   ==================================================================== */
function AdminUsers({ tok }) {
  const toast = window.useToast();
  const [tab, setTab] = React.useState("clients");
  const [selected, setSelected] = React.useState(null);
  const [inviteOpen, setInviteOpen] = React.useState(false);
  const [searchInput, setSearchInput] = React.useState("");
  const search = window.useDebounce(searchInput, 250);
  const [profiles, setProfiles] = React.useState(null);
  const [vendors, setVendors]   = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    let alive = true;
    setProfiles(null); setVendors(null);
    Promise.all([
      SB.adminGetAllProfiles(tok),
      SB.adminGetAllVendors(tok),
    ]).then(([p, v]) => {
      if (!alive) return;
      setProfiles(p || []);
      setVendors(v || []);
    });
    return () => { alive = false; };
  }, [tok, reloadKey]);

  if (profiles === null || vendors === null) {
    return <div className="page-enter"><window.LoadingState /></div>;
  }

  // Shape rows for the active tab
  const clients = profiles.filter(p => p.role === "user").map(p => ({
    id: p.id,
    name: p.full_name || p.email || "—",
    email: p.email || "",
    city: p.city || "—",
    phone: p.phone || "",
    bookings: p.bookings_count || 0,
    ltv: p.lifetime_value || 0,
    status: p.is_banned ? "Banned" : (p.last_seen_at && (Date.now() - new Date(p.last_seen_at).getTime()) > 90*24*3600*1000) ? "Dormant" : "Active",
    joined: window.fmtDate(p.created_at),
    verified: !!p.email_confirmed_at,
    tier: p.tier || "—",
    _raw: p,
  }));

  const vendorRows = vendors.map(v => ({
    id: v.id,
    name: v.business_name || "—",
    email: v.contact_email || v.owner_email || "",
    city: v.city || "—",
    category: v.category || "—",
    plan: v.plan_tier || "Starter",
    bookings: v.total_bookings || 0,
    netMtd: v.net_mtd || 0,
    status: v.is_active === false ? "Suspended" : "Active",
    joined: window.fmtDate(v.created_at),
    verified: !!v.verified_at,
    _raw: v,
  }));

  const staff = profiles.filter(p => p.role === "admin").map(p => ({
    id: p.id,
    name: p.full_name || p.email || "—",
    email: p.email || "",
    role: p.admin_role || "Admin",
    lastActive: p.last_seen_at ? window.fmtDate(p.last_seen_at) : "—",
    status: p.is_banned ? "Suspended" : "Active",
    joined: window.fmtDate(p.created_at),
    _raw: p,
  }));

  const filtered = (rows) => {
    if (!search) return rows;
    const q = search.toLowerCase();
    return rows.filter(r =>
      (r.name || "").toLowerCase().includes(q) ||
      (r.email || "").toLowerCase().includes(q) ||
      (r.city || "").toLowerCase().includes(q)
    );
  };

  const data = filtered(tab === "clients" ? clients : tab === "vendors" ? vendorRows : staff);
  const tabCounts = { clients: clients.length, vendors: vendorRows.length, staff: staff.length };
  const total = clients.length + vendorRows.length + staff.length;

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow={`People · ${total.toLocaleString()} total`}
        title="User management"
        sub="Clients, vendors, and platform staff in one place."
        right={<>
          <S.Btn variant="outline" size="sm" icon={<I.filter size={14} />}>Filter</S.Btn>
          <S.Btn variant="outline" size="sm" icon={<I.download size={14} />}>Export CSV</S.Btn>
          <S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={() => setInviteOpen(true)}>Invite user</S.Btn>
        </>}
      />

      <div className="row" style={{ gap: 0, borderBottom: "1px solid var(--border)", marginBottom: 20 }}>
        {[
          { k: "clients", l: "Clients", n: tabCounts.clients },
          { k: "vendors", l: "Vendors", n: tabCounts.vendors },
          { k: "staff",   l: "Platform staff", n: tabCounts.staff },
        ].map(t => (
          <button key={t.k} onClick={() => setTab(t.k)}
            style={{
              padding: "12px 18px", fontSize: 13, fontWeight: 500,
              color: tab === t.k ? "var(--ink)" : "var(--ink-3)",
              borderBottom: `2px solid ${tab === t.k ? "var(--ink)" : "transparent"}`,
              marginBottom: -1,
            }}>
            {t.l} <span className="mono tiny muted" style={{ marginLeft: 4 }}>{t.n.toLocaleString()}</span>
          </button>
        ))}
      </div>

      <div className="card card-flush">
        <div className="row" style={{ padding: 16, gap: 10 }}>
          <S.Input
            icon={<I.search size={15} />}
            placeholder="Search by name, email, or city…"
            style={{ flex: 1, maxWidth: 360 }}
            value={searchInput}
            onChange={(e) => setSearchInput(e.target.value)}
          />
          <div className="spacer" />
          <span className="muted tiny">{data.length} {data.length === 1 ? "result" : "results"} · sorted by signup ↓</span>
        </div>
        {data.length === 0 ? (
          <window.EmptyState
            icon={<I.users size={24} />}
            title={search ? "No matches" : `No ${tab} yet`}
            sub={search ? "Try a different search term." : "They'll appear here as they sign up."}
          />
        ) : (
          <table className="tbl">
            <thead>
              <tr>
                <th style={{ width: 30 }}><input type="checkbox" /></th>
                <th>{tab === "vendors" ? "Vendor" : tab === "staff" ? "Staff member" : "Client"}</th>
                {tab === "vendors" ? <>
                  <th>Category</th>
                  <th>Plan</th>
                  <th>Bookings</th>
                  <th>Net (mtd)</th>
                </> : tab === "staff" ? <>
                  <th>Role</th>
                  <th>Email</th>
                  <th>Last active</th>
                  <th />
                </> : <>
                  <th>City</th>
                  <th>Bookings</th>
                  <th>Lifetime value</th>
                </>}
                <th>Status</th>
                <th>Joined</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {data.map((u) => (
                <tr key={u.id} onClick={() => setSelected({ ...u, _kind: tab })} style={{ cursor: "pointer" }}>
                  <td onClick={(e) => e.stopPropagation()}><input type="checkbox" /></td>
                  <td>
                    <div className="row-tight">
                      <S.Avatar name={u.name} size="sm" />
                      <div>
                        <div style={{ fontWeight: 500 }}>{u.name}</div>
                        <div className="muted tiny">{u.email}</div>
                      </div>
                    </div>
                  </td>
                  {tab === "vendors" ? <>
                    <td>{u.category}</td>
                    <td><S.Chip tone={u.plan === "Atelier" ? "accent" : u.plan === "Studio" ? "info" : ""}>{u.plan}</S.Chip></td>
                    <td className="mono">{u.bookings.toLocaleString()}</td>
                    <td className="mono">{window.fmtMoney(u.netMtd)}</td>
                  </> : tab === "staff" ? <>
                    <td><S.Chip tone="accent">{u.role}</S.Chip></td>
                    <td className="mono muted tiny">{u.email}</td>
                    <td className="muted tiny">{u.lastActive}</td>
                    <td />
                  </> : <>
                    <td>{u.city}</td>
                    <td className="mono">{u.bookings}</td>
                    <td className="mono">{window.fmtMoney(u.ltv)}</td>
                  </>}
                  <td><S.Chip tone={u.status === "Active" ? "pos" : u.status === "Dormant" ? "warn" : "neg"}>{u.status}</S.Chip></td>
                  <td className="mono muted">{u.joined}</td>
                  <td><S.IconBtn><I.chevR size={14} /></S.IconBtn></td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      <UserDetailModal user={selected} onClose={() => setSelected(null)} />
      <InviteUserModal
        open={inviteOpen}
        onClose={() => setInviteOpen(false)}
        defaultRole={tab === "vendors" ? "vendor" : "client"}
        onCreated={() => { setReloadKey(k => k + 1); toast.success("User created"); }}
      />
    </div>
  );
}

/* ----------------------------- INVITE USER MODAL ------------------- */
function InviteUserModal({ open, onClose, defaultRole = "client", onCreated }) {
  const toast = window.useToast();
  const [data, setData] = React.useState({ name: "", email: "", phone: "", role: defaultRole, password: "" });
  const [errors, setErrors] = React.useState({});
  const [busy, setBusy] = React.useState(false);
  React.useEffect(() => { if (open) setData(d => ({ ...d, role: defaultRole })); }, [open, defaultRole]);
  const set = (k, v) => { setData(d => ({ ...d, [k]: v })); setErrors(e => ({ ...e, [k]: undefined })); };
  const reset = () => { setData({ name: "", email: "", phone: "", role: defaultRole, password: "" }); setErrors({}); };

  const submit = async () => {
    const e = {};
    if (!data.name.trim()) e.name = "Full name is required.";
    if (!data.email.trim()) e.email = "Email is required.";
    else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) e.email = "Enter a valid email address.";
    if (data.phone && !/^[+\d\s()-]{7,}$/.test(data.phone)) e.phone = "Enter a valid phone number.";
    if (!data.password || data.password.length < 8) e.password = "Password must be at least 8 characters.";
    setErrors(e);
    if (Object.keys(e).length > 0) return;

    setBusy(true);
    try {
      // Map UI role -> DB role
      // SB layer expects "business" for vendor accounts (it also creates the vendor_profiles row).
      const dbRole = data.role === "vendor" ? "business" : data.role === "admin" ? "admin" : "user";
      const result = await SB.adminAddUser({
        email: data.email.trim(),
        password: data.password,
        role: dbRole,
        fullName: data.name.trim(),
      });
      if (!result.ok) {
        toast.error(result.message || "Couldn't create user");
        return;
      }
      onCreated?.();
      onClose();
      reset();
    } catch (err) {
      toast.error(err.message || "Couldn't create user");
    } finally {
      setBusy(false);
    }
  };

  return (
    <window.M.Modal open={open} onClose={() => { onClose(); reset(); }} size="lg"
      icon={<I.users />} title="Invite a new user"
      subtitle="Create the account directly. They'll receive a confirmation email and can sign in immediately."
      footer={<>
        <S.Btn variant="ghost" onClick={() => { onClose(); reset(); }} disabled={busy}>Cancel</S.Btn>
        <S.Btn variant="primary" iconRight={<I.arrowR size={14} />} onClick={submit} disabled={busy}>
          {busy ? "Creating…" : "Create user"}
        </S.Btn>
      </>}
    >
      <window.M.FormGrid>
        <window.M.Field full label="Account type">
          <window.M.RadioCards value={data.role} onChange={(v) => set("role", v)}
            options={[
              { value: "client", label: "Client", desc: "Books and pays for services" },
              { value: "vendor", label: "Vendor", desc: "Runs a studio on Pamp" },
            ]} />
        </window.M.Field>
        <window.M.Field full label="Full name" error={errors.name}>
          <window.M.TextField value={data.name} onChange={(v) => set("name", v)} placeholder="Jordan Lee" />
        </window.M.Field>
        <window.M.Field label="Email" error={errors.email}>
          <window.M.TextField icon={<I.mail size={14} />} value={data.email} onChange={(v) => set("email", v)} placeholder="jordan@example.com" />
        </window.M.Field>
        <window.M.Field label="Temporary password" error={errors.password} hint="Min 8 characters. They can change it on first login.">
          <window.M.TextField type="password" icon={<I.lock size={14} />} value={data.password} onChange={(v) => set("password", v)} placeholder="At least 8 characters" />
        </window.M.Field>
        <window.M.Field full label="Phone number" hint="Optional." error={errors.phone}>
          <window.M.TextField icon={<I.phone size={14} />} value={data.phone} onChange={(v) => set("phone", v)} placeholder="+1 555 0142" />
        </window.M.Field>
      </window.M.FormGrid>
    </window.M.Modal>
  );
}

/* ----------------------------- USER DETAIL MODAL ------------------- */
function UserDetailModal({ user, onClose }) {
  if (!user) return null;
  const isVendor = user._kind === "vendors";
  const isStaff = user._kind === "staff";
  return (
    <window.M.Modal open={!!user} onClose={onClose} size="lg">
      <div style={{ padding: 28, paddingTop: 8 }}>
        <div className="row" style={{ gap: 18, marginBottom: 22 }}>
          <S.Avatar name={user.name} size="xl" />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="row-tight">
              <div className="display" style={{ fontSize: 24, letterSpacing: "-0.02em" }}>{user.name}</div>
              {user.verified && <span style={{ width: 16, height: 16, borderRadius: 999, background: "var(--accent)", color: "oklch(20% 0.10 145)", display: "inline-flex", alignItems: "center", justifyContent: "center" }}><I.check size={10} /></span>}
            </div>
            <div className="muted tiny" style={{ marginTop: 4 }}>{user.email} · ID #{user.id}</div>
            <div className="row-tight" style={{ marginTop: 10, gap: 6 }}>
              <S.Chip tone={user.status === "Active" ? "pos" : user.status === "Dormant" ? "warn" : "neg"}>{user.status}</S.Chip>
              {isVendor && <S.Chip tone={user.plan === "Atelier" ? "accent" : "info"}>{user.plan} plan</S.Chip>}
              {!isVendor && !isStaff && user.tier && <S.Chip tone={user.tier === "Platinum" ? "accent" : user.tier === "Gold" ? "warn" : ""}>{user.tier} tier</S.Chip>}
              {isStaff && <S.Chip tone="accent">{user.role}</S.Chip>}
            </div>
          </div>
          <button onClick={onClose} className="icon-btn"><I.x size={18} /></button>
        </div>

        {!isStaff && (
          <div className="grid-3" style={{ marginBottom: 20 }}>
            <ClientStat label={isVendor ? "Bookings (life)" : "Bookings"} value={isVendor ? user.bookings.toLocaleString() : user.bookings} />
            <ClientStat label={isVendor ? "Net MTD" : "Lifetime spend"} value={`$${(isVendor ? user.netMtd : user.ltv).toLocaleString()}`} />
            <ClientStat label="Joined" value={user.joined.split(",")[0]} />
          </div>
        )}

        <div className="card" style={{ padding: 18, marginBottom: 14 }}>
          <div className="eyebrow" style={{ marginBottom: 14 }}>Contact</div>
          <div className="grid-2" style={{ gap: 14 }}>
            <ClientField icon={<I.mail size={14} />} label="Email" value={user.email} />
            {user.phone && <ClientField icon={<I.phone size={14} />} label="Phone" value={user.phone} />}
            {user.city && <ClientField icon={<I.location size={14} />} label="Location" value={user.city} />}
            {isVendor && <ClientField icon={<I.store size={14} />} label="Category" value={user.category} />}
            {isStaff && <ClientField icon={<I.clock size={14} />} label="Last active" value={user.lastActive} />}
          </div>
        </div>

        {!isStaff && (
          <div className="card" style={{ padding: 18, marginBottom: 14 }}>
            <div className="eyebrow" style={{ marginBottom: 14 }}>Recent activity</div>
            <div className="col" style={{ gap: 8 }}>
              {[
                { d: "Today", t: isVendor ? "Payout queued · $4,820" : "Booked Maison Color · $184", tone: "pos" },
                { d: "Yesterday", t: isVendor ? "3 new bookings" : "Top-up · $100", tone: "info" },
                { d: "Jan 28", t: isVendor ? "Subscription renewed (Atelier)" : "Forest Spa · $142", tone: "info" },
              ].map((r, i) => (
                <div key={i} className="row between" style={{ padding: "8px 0" }}>
                  <span className="row-tight"><span className={`dot dot-${r.tone}`} /><span style={{ fontSize: 13 }}>{r.t}</span></span>
                  <span className="muted tiny">{r.d}</span>
                </div>
              ))}
            </div>
          </div>
        )}

        <div className="card" style={{ padding: 18 }}>
          <div className="eyebrow" style={{ marginBottom: 12 }}>Admin actions</div>
          <div className="row" style={{ gap: 8, flexWrap: "wrap" }}>
            <S.Btn variant="outline" size="sm" icon={<I.mail size={12} />}>Send message</S.Btn>
            <S.Btn variant="outline" size="sm" icon={<I.coupon size={12} />}>Issue credit</S.Btn>
            {!isStaff && <S.Btn variant="outline" size="sm" icon={<I.export size={12} />}>Impersonate</S.Btn>}
            {isVendor && <S.Btn variant="outline" size="sm" icon={<I.check size={12} />}>Force verify</S.Btn>}
            <S.Btn variant="outline" size="sm" icon={<I.clock size={12} />}>Reset password</S.Btn>
            <S.Btn variant="outline" size="sm" style={{ color: "var(--warn)", borderColor: "var(--warn)" }}>Suspend</S.Btn>
            <S.Btn variant="outline" size="sm" style={{ color: "var(--neg)", borderColor: "var(--neg)" }}>Ban</S.Btn>
          </div>
        </div>
      </div>

      <div className="modal-foot">
        <span className="muted tiny">{isVendor ? `Vendor · ${user.plan}` : isStaff ? `Platform staff · ${user.role}` : "Client"} · joined {user.joined}</span>
        <div className="spacer" />
        <S.Btn variant="ghost" onClick={onClose}>Close</S.Btn>
        <S.Btn variant="primary" iconRight={<I.arrowR size={14} />}>Open profile</S.Btn>
      </div>
    </window.M.Modal>
  );
}

function ClientStat({ label, value }) {
  return (
    <div style={{ padding: 16, background: "var(--surface-2)", borderRadius: 12 }}>
      <div className="muted tiny">{label}</div>
      <div className="display" style={{ fontSize: 22, marginTop: 4 }}>{value}</div>
    </div>
  );
}
function ClientField({ icon, label, value }) {
  return (
    <div>
      <div className="muted tiny row-tight" style={{ marginBottom: 4 }}>{icon}{label}</div>
      <div style={{ fontSize: 13.5 }}>{value}</div>
    </div>
  );
}

/* ====================================================================
   ADMIN — BOOKINGS
   ==================================================================== */
function AdminBookings({ tok }) {
  const toast = window.useToast();
  const [scheduleOpen, setScheduleOpen] = React.useState(false);
  const [bookings, setBookings] = React.useState(null);
  const [searchInput, setSearchInput] = React.useState("");
  const search = window.useDebounce(searchInput, 250);
  const [statusFilter, setStatusFilter] = React.useState("all");
  const [selected, setSelected] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    let alive = true;
    setBookings(null);
    SB.adminGetAllBookings(tok).then((rows) => {
      if (!alive) return;
      setBookings(rows || []);
    });
    return () => { alive = false; };
  }, [tok, reloadKey]);

  if (bookings === null) {
    return <div className="page-enter"><window.LoadingState /></div>;
  }

  // Stats computed from real data
  const stats = {
    scheduled:  bookings.filter(b => b.status === "confirmed" || b.status === "pending").length,
    completed:  bookings.filter(b => b.status === "completed").length,
    cancelled:  bookings.filter(b => b.status === "cancelled").length,
    noShow:     bookings.filter(b => b.status === "no_show").length,
  };

  // Filter
  let filtered = bookings;
  if (statusFilter !== "all") filtered = filtered.filter(b => b.status === statusFilter);
  if (search) {
    const q = search.toLowerCase();
    filtered = filtered.filter(b => {
      const client = (b.client?.full_name || b.client?.email || "").toLowerCase();
      const vendor = (b.vendor?.business_name || "").toLowerCase();
      const service = (b.service?.name || "").toLowerCase();
      return client.includes(q) || vendor.includes(q) || service.includes(q) || (b.id || "").toLowerCase().includes(q);
    });
  }

  const statusToneMap = {
    confirmed: "pos", completed: "pos",
    pending: "warn", in_progress: "info",
    cancelled: "neg", no_show: "neg",
  };

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow={`${bookings.length.toLocaleString()} bookings · all time`}
        title="Bookings"
        sub="Every appointment across the network, in real time."
        right={<>
          <S.Btn variant="outline" size="sm" icon={<I.filter size={14} />}>Filter</S.Btn>
          <S.Btn variant="outline" size="sm" icon={<I.export size={14} />}>Export</S.Btn>
          <S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={() => setScheduleOpen(true)}>Schedule</S.Btn>
        </>}
      />

      <div className="grid-4" style={{ marginBottom: 24 }}>
        <S.Metric label="Scheduled"     value={stats.scheduled.toLocaleString()}  delta="Pending + Confirmed" />
        <S.Metric label="Completed"     value={stats.completed.toLocaleString()}  delta="Lifetime" deltaTone="pos" />
        <S.Metric label="Cancellations" value={stats.cancelled.toLocaleString()}  deltaTone={stats.cancelled > 0 ? "warn" : "pos"} />
        <S.Metric label="No-shows"      value={stats.noShow.toLocaleString()}     deltaTone={stats.noShow > 0 ? "neg" : "pos"} />
      </div>

      <div className="card card-flush">
        <div className="row" style={{ padding: 16, gap: 10 }}>
          <S.Input
            icon={<I.search size={15} />}
            placeholder="Search by client, vendor, service, ID…"
            style={{ flex: 1, maxWidth: 360 }}
            value={searchInput}
            onChange={(e) => setSearchInput(e.target.value)}
          />
          <select
            className="text-input"
            style={{ width: 160 }}
            value={statusFilter}
            onChange={(e) => setStatusFilter(e.target.value)}
          >
            <option value="all">All statuses</option>
            <option value="pending">Pending</option>
            <option value="confirmed">Confirmed</option>
            <option value="in_progress">In progress</option>
            <option value="completed">Completed</option>
            <option value="cancelled">Cancelled</option>
            <option value="no_show">No show</option>
          </select>
          <div className="spacer" />
          <span className="muted tiny">{filtered.length} of {bookings.length}</span>
        </div>

        {filtered.length === 0 ? (
          <window.EmptyState
            icon={<I.bookings size={24} />}
            title="No bookings"
            sub={search || statusFilter !== "all" ? "Try a different filter." : "Bookings will appear here as they come in."}
          />
        ) : (
          <table className="tbl">
            <thead>
              <tr>
                <th>ID</th>
                <th>Client</th>
                <th>Vendor</th>
                <th>Service</th>
                <th>When</th>
                <th>Status</th>
                <th className="col-num">Total</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {filtered.map((b) => {
                const clientName  = b.client?.full_name || b.client?.email || "—";
                const vendorName  = b.vendor?.business_name || "—";
                const serviceName = b.service?.name || "—";
                const shortId = "PB-" + (b.id || "").slice(0, 8).toUpperCase();
                return (
                  <tr key={b.id} onClick={() => setSelected(b)} style={{ cursor: "pointer" }}>
                    <td className="mono muted">{shortId}</td>
                    <td><div className="row-tight"><S.Avatar name={clientName} size="sm" />{clientName}</div></td>
                    <td>{vendorName}</td>
                    <td>{serviceName}</td>
                    <td>
                      <div className="mono tiny">{window.fmtDate(b.booking_date)}</div>
                      <div className="muted tiny">{window.fmtTime(b.start_time)}</div>
                    </td>
                    <td><S.Chip tone={statusToneMap[b.status] || "info"}>{window.statusLabel(b.status)}</S.Chip></td>
                    <td className="col-num mono">{window.fmtMoney(b.total_price)}</td>
                    <td><S.IconBtn><I.chevR size={14} /></S.IconBtn></td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>

      <BookingDetailModal
        booking={selected}
        onClose={() => setSelected(null)}
        tok={tok}
        onUpdated={() => { setSelected(null); setReloadKey(k => k + 1); toast.success("Booking updated"); }}
      />
      <ScheduleBookingModal
        open={scheduleOpen}
        onClose={() => setScheduleOpen(false)}
        tok={tok}
        onCreated={() => { setScheduleOpen(false); setReloadKey(k => k + 1); toast.success("Booking created"); }}
      />
    </div>
  );
}

/* ----------------------------- BOOKING DETAIL MODAL --------------- */
function BookingDetailModal({ booking, onClose, tok, onUpdated }) {
  const toast = window.useToast();
  const [busy, setBusy] = React.useState(false);
  const [newStatus, setNewStatus] = React.useState(booking?.status || "pending");
  React.useEffect(() => { setNewStatus(booking?.status || "pending"); }, [booking?.id, booking?.status]);
  if (!booking) return null;

  const clientName = booking.client?.full_name || booking.client?.email || "—";
  const vendorName = booking.vendor?.business_name || "—";
  const serviceName = booking.service?.name || "—";
  const shortId = "PB-" + (booking.id || "").slice(0, 8).toUpperCase();

  const save = async () => {
    if (newStatus === booking.status) { onClose(); return; }
    setBusy(true);
    try {
      const r = await SB.adminUpdateBookingStatus(booking.id, newStatus, tok);
      if (!r.ok) { toast.error(r.message || "Update failed"); return; }
      onUpdated?.();
    } finally {
      setBusy(false);
    }
  };

  return (
    <window.M.Modal open={!!booking} onClose={onClose} size="lg"
      icon={<I.bookings />} title={`Booking ${shortId}`} subtitle={`${clientName} → ${vendorName}`}
      footer={<>
        <S.Btn variant="ghost" onClick={onClose} disabled={busy}>Close</S.Btn>
        <S.Btn variant="primary" onClick={save} disabled={busy}>{busy ? "Saving…" : "Save changes"}</S.Btn>
      </>}
    >
      <div className="grid-2" style={{ gap: 14 }}>
        <ClientField icon={<I.users size={14} />} label="Client" value={clientName} />
        <ClientField icon={<I.store size={14} />} label="Vendor" value={vendorName} />
        <ClientField icon={<I.scissors size={14} />} label="Service" value={serviceName} />
        <ClientField icon={<I.calendar size={14} />} label="Date" value={window.fmtDate(booking.booking_date)} />
        <ClientField icon={<I.clock size={14} />} label="Time" value={window.fmtTime(booking.start_time)} />
        <ClientField icon={<I.card size={14} />} label="Total" value={window.fmtMoney(booking.total_price)} />
      </div>

      <div className="form-field" style={{ marginTop: 22 }}>
        <label>Update status</label>
        <select className="text-input" value={newStatus} onChange={(e) => setNewStatus(e.target.value)}>
          <option value="pending">Pending</option>
          <option value="confirmed">Confirmed</option>
          <option value="in_progress">In progress</option>
          <option value="completed">Completed</option>
          <option value="cancelled">Cancelled</option>
          <option value="no_show">No show</option>
        </select>
      </div>

      {booking.notes && (
        <div style={{ marginTop: 16 }}>
          <div className="muted tiny" style={{ marginBottom: 6 }}>Notes</div>
          <div style={{ fontSize: 13, padding: 12, background: "var(--surface-2)", borderRadius: 10 }}>{booking.notes}</div>
        </div>
      )}
    </window.M.Modal>
  );
}

function ScheduleBookingModal({ open, onClose, tok, onCreated }) {
  const toast = window.useToast();
  const [step, setStep] = React.useState(1);
  const [clients, setClients] = React.useState([]);
  const [vendors, setVendors] = React.useState([]);
  const [services, setServices] = React.useState([]);
  const [busy, setBusy] = React.useState(false);
  const [data, setData] = React.useState({
    clientId: "", vendorId: "", serviceId: "",
    date: "", time: "", duration: 60, price: 0, status: "pending", notes: "",
  });
  const set = (k, v) => setData(d => ({ ...d, [k]: v }));
  const reset = () => {
    setStep(1);
    setData({ clientId: "", vendorId: "", serviceId: "", date: "", time: "", duration: 60, price: 0, status: "pending", notes: "" });
  };

  React.useEffect(() => {
    if (!open) return;
    Promise.all([SB.adminGetAllProfiles(tok), SB.adminGetAllVendors(tok)]).then(([p, v]) => {
      setClients((p || []).filter(x => x.role === "user"));
      setVendors(v || []);
    });
  }, [open, tok]);

  React.useEffect(() => {
    if (!data.vendorId) { setServices([]); return; }
    SB.adminGetServicesForVendor(data.vendorId, tok).then((s) => setServices(s || []));
  }, [data.vendorId, tok]);

  // Auto-fill price/duration when service selected
  React.useEffect(() => {
    if (!data.serviceId) return;
    const svc = services.find(s => s.id === data.serviceId);
    if (svc) {
      setData(d => ({ ...d, price: Number(svc.price || 0), duration: Number(svc.duration_mins || 60) }));
    }
  }, [data.serviceId, services]);

  const submit = async () => {
    if (!data.clientId)  { toast.error("Pick a client"); return; }
    if (!data.vendorId)  { toast.error("Pick a vendor"); return; }
    if (!data.serviceId) { toast.error("Pick a service"); return; }
    if (!data.date || !data.time) { toast.error("Date and time are required"); return; }
    const dur = parseInt(data.duration, 10);
    if (!dur || dur <= 0) { toast.error("Duration must be > 0"); return; }
    const [hh, mm] = data.time.split(":").map(Number);
    const endMin = hh * 60 + mm + dur;
    const endTime = `${String(Math.floor(endMin / 60) % 24).padStart(2, "0")}:${String(endMin % 60).padStart(2, "0")}`;

    setBusy(true);
    try {
      const r = await SB.adminCreateBooking({
        client_id: data.clientId,
        vendor_id: data.vendorId,
        service_id: data.serviceId,
        booking_date: data.date,
        start_time: data.time,
        end_time: endTime,
        total_price: Number(data.price) || 0,
        status: data.status,
        notes: data.notes || null,
      }, tok);
      if (!r.ok) { toast.error(r.message || "Couldn't create booking"); return; }
      onCreated?.();
      reset();
    } finally {
      setBusy(false);
    }
  };

  const next = () => {
    if (step === 1) {
      if (!data.clientId)  { toast.error("Pick a client"); return; }
      if (!data.vendorId)  { toast.error("Pick a vendor"); return; }
      if (!data.serviceId) { toast.error("Pick a service"); return; }
    }
    if (step === 2) {
      if (!data.date || !data.time) { toast.error("Date and time are required"); return; }
    }
    setStep(step + 1);
  };

  const clientLabel = clients.find(c => c.id === data.clientId);
  const vendorLabel = vendors.find(v => v.id === data.vendorId);
  const serviceLabel = services.find(s => s.id === data.serviceId);

  return (
    <window.M.Modal open={open} onClose={() => { onClose(); reset(); }} size="lg"
      icon={<I.calendar />} title="Schedule appointment"
      subtitle="Book on behalf of a client."
      footer={<>
        <div className="row-tight" style={{ flex: 1 }}>
          {[1, 2, 3].map(s => (
            <div key={s} style={{ flex: 1, height: 4, borderRadius: 999, background: step >= s ? "var(--accent)" : "var(--surface-3)" }} />
          ))}
        </div>
        {step > 1 && <S.Btn variant="ghost" onClick={() => setStep(step - 1)} disabled={busy}>Back</S.Btn>}
        {step < 3 ? (
          <S.Btn variant="primary" iconRight={<I.arrowR size={14} />} onClick={next}>Continue</S.Btn>
        ) : (
          <S.Btn variant="primary" iconRight={<I.check size={14} />} onClick={submit} disabled={busy}>
            {busy ? "Creating…" : "Confirm booking"}
          </S.Btn>
        )}
      </>}
    >
      {step === 1 && <window.M.FormGrid>
        <window.M.Field full label="Client">
          <select className="text-input" value={data.clientId} onChange={(e) => set("clientId", e.target.value)}>
            <option value="">Select a client…</option>
            {clients.map(c => (
              <option key={c.id} value={c.id}>{c.full_name || "—"} · {c.email}</option>
            ))}
          </select>
        </window.M.Field>
        <window.M.Field full label="Vendor">
          <select className="text-input" value={data.vendorId} onChange={(e) => { set("vendorId", e.target.value); set("serviceId", ""); }}>
            <option value="">Select a vendor…</option>
            {vendors.map(v => (
              <option key={v.id} value={v.id}>{v.business_name}</option>
            ))}
          </select>
        </window.M.Field>
        <window.M.Field full label="Service">
          <select className="text-input" value={data.serviceId} onChange={(e) => set("serviceId", e.target.value)} disabled={!data.vendorId}>
            <option value="">{data.vendorId ? "Select a service…" : "Pick a vendor first"}</option>
            {services.map(s => (
              <option key={s.id} value={s.id}>{s.name} · {window.fmtMoney(s.price)} · {s.duration_mins}min</option>
            ))}
          </select>
        </window.M.Field>
      </window.M.FormGrid>}

      {step === 2 && <window.M.FormGrid>
        <window.M.Field label="Date">
          <input className="text-input" type="date" value={data.date} onChange={(e) => set("date", e.target.value)} />
        </window.M.Field>
        <window.M.Field label="Start time">
          <input className="text-input" type="time" value={data.time} onChange={(e) => set("time", e.target.value)} />
        </window.M.Field>
        <window.M.Field label="Duration (minutes)">
          <input className="text-input" type="number" min="15" step="15" value={data.duration} onChange={(e) => set("duration", e.target.value)} />
        </window.M.Field>
        <window.M.Field label="Total price">
          <input className="text-input" type="number" min="0" step="0.01" value={data.price} onChange={(e) => set("price", e.target.value)} />
        </window.M.Field>
        <window.M.Field full label="Status">
          <window.M.Segmented value={data.status} onChange={(v) => set("status", v)}
            options={[
              { value: "pending", label: "Pending" },
              { value: "confirmed", label: "Confirmed" },
            ]} />
        </window.M.Field>
        <window.M.Field full label="Notes (optional)">
          <window.M.Textarea value={data.notes} onChange={(v) => set("notes", v)} placeholder="Anything the vendor should know…" />
        </window.M.Field>
      </window.M.FormGrid>}

      {step === 3 && <div>
        <div className="eyebrow" style={{ marginBottom: 14 }}>Review &amp; confirm</div>
        <div className="card" style={{ padding: 18, background: "var(--surface-2)" }}>
          <ReviewRow label="Client" value={clientLabel ? (clientLabel.full_name || clientLabel.email) : "—"} />
          <ReviewRow label="Vendor" value={vendorLabel ? vendorLabel.business_name : "—"} />
          <ReviewRow label="Service" value={serviceLabel ? serviceLabel.name : "—"} />
          <ReviewRow label="When" value={`${data.date || "—"} · ${data.time || "—"}`} />
          <ReviewRow label="Duration" value={`${data.duration} min`} />
          <ReviewRow label="Total" value={window.fmtMoney(data.price)} />
          <ReviewRow label="Status" value={window.statusLabel(data.status)} />
          {data.notes && <ReviewRow label="Notes" value={data.notes} />}
        </div>
        <div className="row-tight" style={{ marginTop: 16, padding: 14, background: "var(--accent-soft)", color: "var(--accent-ink)", borderRadius: 10, fontSize: 13 }}>
          <I.mail size={14} /> The client will receive a confirmation email.
        </div>
      </div>}
    </window.M.Modal>
  );
}

function ReviewRow({ label, value }) {
  return (
    <div className="row between" style={{ padding: "8px 0", borderTop: "1px solid var(--border)" }}>
      <span className="muted tiny">{label}</span>
      <span style={{ fontSize: 13, fontWeight: 500, textAlign: "right", maxWidth: "60%" }}>{value}</span>
    </div>
  );
}

/* ====================================================================
   ADMIN — WALLETS & PAYOUTS
   ==================================================================== */
function AdminWallets({ tok }) {
  const toast = window.useToast();
  const [wallets, setWallets] = React.useState(null);
  const [payouts, setPayouts] = React.useState(null);
  const [txns, setTxns] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);
  const [adjustVendor, setAdjustVendor] = React.useState(null);
  const [showPendingOnly, setShowPendingOnly] = React.useState(false);

  React.useEffect(() => {
    let alive = true;
    setWallets(null); setPayouts(null); setTxns(null);
    Promise.all([
      SB.adminGetVendorWallets(tok),
      SB.adminGetAllPayoutRequests(tok),
      SB.adminGetTransactions(tok),
    ]).then(([w, p, t]) => {
      if (!alive) return;
      setWallets(w || []);
      setPayouts(p || []);
      setTxns(t || []);
    });
    return () => { alive = false; };
  }, [tok, reloadKey]);

  const reload = () => setReloadKey(k => k + 1);

  if (wallets === null || payouts === null || txns === null) {
    return <div className="page-enter"><window.LoadingState /></div>;
  }

  const totalEarnings  = wallets.reduce((s, w) => s + Number(w.total_earnings || 0), 0);
  const totalBalance   = wallets.reduce((s, w) => s + Number(w.balance || 0), 0);
  const pending        = payouts.filter(p => p.status === "pending");
  const approved       = payouts.filter(p => p.status === "approved" || p.status === "paid");
  const pendingAmount  = pending.reduce((s, p) => s + Number(p.amount || 0), 0);
  const completedAmt   = approved.reduce((s, p) => s + Number(p.amount || 0), 0);

  const visiblePayouts = showPendingOnly ? pending : payouts;

  const processPayout = async (id, decision) => {
    const verb = decision === "approved" ? "approve" : "decline";
    if (!confirm(`Are you sure you want to ${verb} this payout?`)) return;
    const r = await SB.adminProcessPayout(id, decision, tok);
    if (!r.ok) { toast.error(r.message || "Action failed"); return; }
    toast.success(`Payout ${decision}`);
    reload();
  };

  // Build a simple 12-week revenue series from transactions
  const now = Date.now();
  const weekMs = 7 * 24 * 60 * 60 * 1000;
  const weekRevenue = Array(12).fill(0);
  const weekLabels = [];
  for (let i = 11; i >= 0; i--) {
    const d = new Date(now - i * weekMs);
    weekLabels.push(d.toLocaleDateString("en-US", { month: "short", day: "numeric" }));
  }
  txns.forEach(t => {
    const ageWeeks = Math.floor((now - new Date(t.created_at).getTime()) / weekMs);
    if (ageWeeks >= 0 && ageWeeks < 12 && Number(t.amount) > 0) {
      weekRevenue[11 - ageWeeks] += Number(t.amount);
    }
  });

  return (
    <div className="page-enter">
      <S.PageHead eyebrow="Money · live data" title="Wallets & payouts"
        sub="Vendor balances, payout pipeline, and transaction ledger."
        right={<>
          <S.Btn variant="outline" size="sm" icon={<I.download size={14} />}>Export ledger</S.Btn>
        </>}
      />

      <div className="grid-4" style={{ marginBottom: 24 }}>
        <S.Metric hero label="Total earnings"  value={window.fmtMoney(totalEarnings)} delta={`${wallets.length} vendors`} />
        <S.Metric label="Wallet balances"      value={window.fmtMoney(totalBalance)}  delta="Across all vendors" />
        <S.Metric label="Pending payouts"      value={window.fmtMoney(pendingAmount)} delta={`${pending.length} requests`} deltaTone={pending.length > 0 ? "warn" : "pos"} />
        <S.Metric label="Completed payouts"    value={window.fmtMoney(completedAmt)}  delta={`${approved.length} processed`} deltaTone="pos" />
      </div>

      <div className="grid-12" style={{ marginBottom: 24 }}>
        <div className="card" style={{ gridColumn: "span 8" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div className="h3">Revenue · last 12 weeks</div>
          </div>
          <S.LineChart
            height={260}
            currency
            labels={weekLabels}
            series={[{ color: "var(--accent)", data: weekRevenue }]}
          />
        </div>

        <div className="card" style={{ gridColumn: "span 4" }}>
          <div className="h3" style={{ marginBottom: 4 }}>Pending payouts</div>
          <div className="muted tiny" style={{ marginBottom: 18 }}>Awaiting admin approval</div>
          <div className="display" style={{ fontSize: 44, letterSpacing: "-0.03em" }}>{window.fmtMoney(pendingAmount)}</div>
          <div className="muted tiny" style={{ marginBottom: 18 }}>across {pending.length} {pending.length === 1 ? "vendor" : "vendors"}</div>
          {pending.length > 0 && (
            <S.Btn variant="primary" size="sm" onClick={() => setShowPendingOnly(true)} style={{ width: "100%" }}>
              Review pending
            </S.Btn>
          )}
        </div>
      </div>

      {/* VENDOR WALLETS */}
      <div className="card card-flush" style={{ marginBottom: 24 }}>
        <div className="row between" style={{ padding: "22px 22px 14px" }}>
          <div>
            <div className="h3">Vendor wallets</div>
            <div className="muted tiny" style={{ marginTop: 4 }}>Balances, earnings, and manual adjustments.</div>
          </div>
          <span className="muted tiny">{wallets.length} vendors</span>
        </div>
        {wallets.length === 0 ? (
          <window.EmptyState icon={<I.wallet size={24} />} title="No vendor wallets" sub="They appear once vendors complete their first booking." />
        ) : (
          <table className="tbl">
            <thead>
              <tr>
                <th>Vendor</th>
                <th className="col-num">Balance</th>
                <th className="col-num">Total earnings</th>
                <th className="col-num">Pending payout</th>
                <th>Status</th>
                <th style={{ width: 140 }} />
              </tr>
            </thead>
            <tbody>
              {wallets.map(w => (
                <tr key={w.vendor_id}>
                  <td>
                    <div className="row-tight">
                      <S.Avatar name={w.business_name || "—"} size="sm" />
                      <div>
                        <div style={{ fontWeight: 500 }}>{w.business_name || "—"}</div>
                        <div className="muted tiny">{w.owner_name || ""}</div>
                      </div>
                    </div>
                  </td>
                  <td className="col-num mono" style={{ fontWeight: 500 }}>{window.fmtMoney(w.balance)}</td>
                  <td className="col-num mono">{window.fmtMoney(w.total_earnings)}</td>
                  <td className="col-num mono" style={{ color: w.pending_payout > 0 ? "var(--warn)" : undefined }}>
                    {window.fmtMoney(w.pending_payout)}
                  </td>
                  <td>
                    <S.Chip tone={w.pending_payout > 0 ? "warn" : w.balance > 0 ? "pos" : ""}>
                      {w.pending_payout > 0 ? "Pending payout" : w.balance > 0 ? "Active" : "Empty"}
                    </S.Chip>
                  </td>
                  <td>
                    <S.Btn variant="ghost" size="sm" icon={<I.edit size={12} />} onClick={() => setAdjustVendor(w)}>Adjust</S.Btn>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      {/* PAYOUT REQUESTS */}
      <div className="card card-flush" style={{ marginBottom: 24 }}>
        <div className="row between" style={{ padding: "22px 22px 14px" }}>
          <div>
            <div className="h3">Payout requests</div>
            <div className="muted tiny" style={{ marginTop: 4 }}>Approve or decline vendor payout requests.</div>
          </div>
          <div className="row-tight">
            <S.Chip tone="warn">{pending.length} pending</S.Chip>
            <S.Btn variant="ghost" size="sm" onClick={() => setShowPendingOnly(s => !s)}>
              {showPendingOnly ? "Show all" : "Pending only"}
            </S.Btn>
          </div>
        </div>
        {visiblePayouts.length === 0 ? (
          <window.EmptyState icon={<I.transfer size={24} />} title={showPendingOnly ? "No pending payouts" : "No payout requests yet"} />
        ) : (
          <table className="tbl">
            <thead>
              <tr>
                <th>Vendor</th>
                <th>Requested</th>
                <th>Method</th>
                <th className="col-num">Amount</th>
                <th>Status</th>
                <th style={{ width: 200 }} />
              </tr>
            </thead>
            <tbody>
              {visiblePayouts.map((p) => (
                <tr key={p.id}>
                  <td>
                    <div className="row-tight">
                      <S.Avatar name={p.vendor?.business_name || "—"} size="sm" />
                      <div>
                        <div style={{ fontWeight: 500 }}>{p.vendor?.business_name || "—"}</div>
                        <div className="muted tiny">{p.vendor?.owner_name || ""}</div>
                      </div>
                    </div>
                  </td>
                  <td className="mono muted">{window.fmtDate(p.requested_at)}</td>
                  <td><div className="row-tight tiny"><I.card size={12} />{p.method || "Bank"}</div></td>
                  <td className="col-num mono" style={{ fontWeight: 500 }}>{window.fmtMoney(p.amount)}</td>
                  <td><S.Chip tone={window.statusTone(p.status)}>{window.statusLabel(p.status)}</S.Chip></td>
                  <td>
                    {p.status === "pending" ? (
                      <div className="row-tight">
                        <S.Btn variant="outline" size="sm" style={{ borderColor: "var(--pos)", color: "var(--pos)" }} icon={<I.check size={12} />} onClick={() => processPayout(p.id, "approved")}>Approve</S.Btn>
                        <S.Btn variant="ghost" size="sm" style={{ color: "var(--neg)" }} onClick={() => processPayout(p.id, "declined")}>Decline</S.Btn>
                      </div>
                    ) : (
                      <span className="muted tiny">{p.processed_at ? `Processed ${window.fmtDate(p.processed_at)}` : ""}</span>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      {/* TRANSACTION LEDGER */}
      <div className="card card-flush">
        <div className="row between" style={{ padding: "22px 22px 14px" }}>
          <div className="h3">Transaction history</div>
          <span className="muted tiny">{txns.length} entries</span>
        </div>
        {txns.length === 0 ? (
          <window.EmptyState icon={<I.payment size={24} />} title="No transactions yet" />
        ) : (
          <table className="tbl">
            <thead>
              <tr><th>Reference</th><th>Type</th><th>Status</th><th>Date</th><th className="col-num">Amount</th></tr>
            </thead>
            <tbody>
              {txns.slice(0, 50).map((t) => {
                const amt = Number(t.amount || 0);
                const ref = t.reference || `TXN-${(t.id || "").slice(0, 8).toUpperCase()}`;
                return (
                  <tr key={t.id}>
                    <td className="mono muted">{ref}</td>
                    <td style={{ textTransform: "capitalize" }}>{(t.type || "").replace(/_/g, " ")}</td>
                    <td><S.Chip tone={window.statusTone(t.status)}>{window.statusLabel(t.status)}</S.Chip></td>
                    <td className="mono muted">{window.fmtDate(t.created_at)}</td>
                    <td className="col-num mono" style={{ color: amt < 0 ? "var(--neg)" : "var(--pos)", fontWeight: 500 }}>
                      {amt < 0 ? "−" : "+"}{window.fmtMoney(Math.abs(amt))}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>

      <AdjustWalletModal
        vendor={adjustVendor}
        onClose={() => setAdjustVendor(null)}
        tok={tok}
        onSaved={() => { setAdjustVendor(null); reload(); toast.success("Wallet adjusted"); }}
      />
    </div>
  );
}

function AdjustWalletModal({ vendor, onClose, tok, onSaved }) {
  const toast = window.useToast();
  const [type, setType] = React.useState("credit");
  const [amount, setAmount] = React.useState("");
  const [notes, setNotes] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  React.useEffect(() => { if (vendor) { setType("credit"); setAmount(""); setNotes(""); } }, [vendor?.vendor_id]);
  if (!vendor) return null;

  const submit = async () => {
    const amt = parseFloat(amount);
    if (!amt || amt <= 0) { toast.error("Amount must be > 0"); return; }
    setBusy(true);
    try {
      const r = await SB.adminAdjustWallet({ vendorId: vendor.vendor_id, amount: amt, type, notes }, tok);
      if (!r.ok) { toast.error(r.message || "Adjustment failed"); return; }
      onSaved?.();
    } finally {
      setBusy(false);
    }
  };

  return (
    <window.M.Modal open={!!vendor} onClose={onClose}
      icon={<I.wallet />} title={`Adjust wallet — ${vendor.business_name || "—"}`}
      subtitle="Manually credit or debit a vendor's wallet. Logged in the transaction ledger."
      footer={<>
        <S.Btn variant="ghost" onClick={onClose} disabled={busy}>Cancel</S.Btn>
        <S.Btn variant="primary" onClick={submit} disabled={busy}>{busy ? "Saving…" : "Save adjustment"}</S.Btn>
      </>}
    >
      <div className="row" style={{ gap: 14, padding: "8px 0 16px" }}>
        <div className="card" style={{ flex: 1, padding: 14, background: "var(--surface-2)" }}>
          <div className="muted tiny">Current balance</div>
          <div className="display" style={{ fontSize: 22, marginTop: 4 }}>{window.fmtMoney(vendor.balance)}</div>
        </div>
        <div className="card" style={{ flex: 1, padding: 14, background: "var(--surface-2)" }}>
          <div className="muted tiny">Total earnings</div>
          <div className="display" style={{ fontSize: 22, marginTop: 4 }}>{window.fmtMoney(vendor.total_earnings)}</div>
        </div>
      </div>
      <window.M.FormGrid>
        <window.M.Field full label="Adjustment type">
          <window.M.Segmented value={type} onChange={setType} options={[
            { value: "credit", label: "Credit (add funds)" },
            { value: "debit",  label: "Debit (remove funds)" },
          ]} />
        </window.M.Field>
        <window.M.Field full label="Amount">
          <input className="text-input" type="number" min="0" step="0.01" value={amount} onChange={(e) => setAmount(e.target.value)} placeholder="0.00" />
        </window.M.Field>
        <window.M.Field full label="Reason / notes" hint="Recorded in the transaction history.">
          <window.M.Textarea value={notes} onChange={setNotes} placeholder="Why is this adjustment being made?" />
        </window.M.Field>
      </window.M.FormGrid>
    </window.M.Modal>
  );
}

/* ====================================================================
   ADMIN — SUBSCRIPTIONS
   ==================================================================== */
function AdminSubscriptions({ tok }) {
  const toast = window.useToast();
  const [tab, setTab] = React.useState("clients");
  const [planFormOpen, setPlanFormOpen] = React.useState(false);
  const [editingPlan, setEditingPlan] = React.useState(null);
  const [confirmDelete, setConfirmDelete] = React.useState(null);
  const [plans, setPlans] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    let alive = true;
    setPlans(null);
    SB.adminGetPlans(tok).then((p) => { if (alive) setPlans(p || []); });
    return () => { alive = false; };
  }, [tok, reloadKey]);

  const reload = () => setReloadKey(k => k + 1);

  if (plans === null) return <div className="page-enter"><window.LoadingState /></div>;

  // audience filter: 'user' plans on clients tab, 'vendor' on vendors tab
  const audience = tab === "clients" ? "user" : "vendor";
  const visible = plans.filter(p => (p.audience || "user") === audience);

  const openNew  = () => { setEditingPlan(null); setPlanFormOpen(true); };
  const openEdit = (p) => { setEditingPlan(p); setPlanFormOpen(true); };

  const togglePlanStatus = async (p) => {
    const r = await SB.adminUpdatePlan(p.id, { is_active: !(p.is_active !== false) }, tok);
    if (!r.ok) { toast.error(r.message || "Update failed"); return; }
    toast.success("Plan updated");
    reload();
  };
  const deletePlan = async () => {
    const r = await SB.adminDeletePlan(confirmDelete.id, tok);
    if (!r.ok) { toast.error(r.message || "Delete failed"); setConfirmDelete(null); return; }
    toast.success("Plan deleted");
    setConfirmDelete(null);
    reload();
  };
  const savePlan = async (next) => {
    const features = (next.features || "").split("\n").map(f => f.trim()).filter(Boolean);
    const payload = {
      name: next.name,
      price: next.price === "" ? null : parseFloat(next.price),
      duration: next.duration,
      audience,
      features,
    };
    const r = editingPlan
      ? await SB.adminUpdatePlan(editingPlan.id, payload, tok)
      : await SB.adminCreatePlan(payload, tok);
    if (!r.ok) { toast.error(r.message || "Save failed"); return; }
    toast.success(editingPlan ? "Plan updated" : "Plan created");
    setPlanFormOpen(false);
    reload();
  };

  const activePlans = visible.filter(p => p.is_active !== false);

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow={`${tab === "clients" ? "Client" : "Vendor"} plans · ${activePlans.length} active`}
        title="Subscriptions"
        sub="Manage Pamp plans for clients and vendors — pricing, features, and lifecycle."
        right={<>
          <S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={openNew}>New plan</S.Btn>
        </>}
      />

      <div className="grid-4" style={{ marginBottom: 20 }}>
        <S.Metric hero label={tab === "clients" ? "Client plans" : "Vendor plans"} value={activePlans.length.toString()} delta={`${visible.length - activePlans.length} inactive`} />
        <S.Metric label="Plan tiers" value={visible.length.toString()} />
        <S.Metric label="Free tier" value={visible.find(p => Number(p.price) === 0) ? "Yes" : "No"} />
        <S.Metric label="Most expensive" value={visible.length ? window.fmtMoney(Math.max(...visible.map(p => Number(p.price) || 0))) : "—"} />
      </div>

      {/* Segmented tabs */}
      <div className="row" style={{ marginBottom: 20 }}>
        <div className="segmented">
          <button className={tab === "clients" ? "active" : ""} onClick={() => setTab("clients")}>
            Clients <span className="muted" style={{ marginLeft: 6, fontSize: 11 }}>{plans.filter(p => (p.audience || "user") === "user").length}</span>
          </button>
          <button className={tab === "vendors" ? "active" : ""} onClick={() => setTab("vendors")}>
            Vendors <span className="muted" style={{ marginLeft: 6, fontSize: 11 }}>{plans.filter(p => p.audience === "vendor").length}</span>
          </button>
        </div>
      </div>

      {visible.length === 0 ? (
        <window.EmptyState
          icon={<I.coupon size={24} />}
          title={`No ${tab === "clients" ? "client" : "vendor"} plans yet`}
          sub="Create your first plan to start charging subscriptions."
          action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={openNew}>New plan</S.Btn>}
        />
      ) : (
        <div className="card card-flush">
          <table className="tbl">
            <thead>
              <tr>
                <th style={{ width: "22%" }}>Plan</th>
                <th>Price</th>
                <th>Duration</th>
                <th style={{ width: "44%" }}>Features</th>
                <th>Status</th>
                <th style={{ width: 140 }} />
              </tr>
            </thead>
            <tbody>
              {visible.map((p) => {
                const features = Array.isArray(p.features) ? p.features : (p.features ? Object.values(p.features) : []);
                const isActive = p.is_active !== false;
                return (
                  <tr key={p.id}>
                    <td>
                      <div className="row-tight" style={{ gap: 10 }}>
                        <span style={{
                          width: 36, height: 36, borderRadius: 10, flexShrink: 0,
                          background: "var(--surface-3)",
                          color: "var(--ink-2)",
                          display: "flex", alignItems: "center", justifyContent: "center",
                        }}>
                          {tab === "clients" ? <I.crown size={16} /> : <I.store size={16} />}
                        </span>
                        <div>
                          <div style={{ fontWeight: 500 }}>{p.name}</div>
                          <div className="muted tiny" style={{ marginTop: 2 }}>{p.id.slice(0, 8).toUpperCase()}</div>
                        </div>
                      </div>
                    </td>
                    <td>
                      <div style={{ fontWeight: 500 }}>
                        {p.price === null ? "Custom" : Number(p.price) === 0 ? "Free" : window.fmtMoney(p.price)}
                        {p.price !== null && Number(p.price) > 0 && <span className="muted" style={{ fontWeight: 400 }}> /{p.duration === "Annual" ? "yr" : "mo"}</span>}
                      </div>
                    </td>
                    <td className="muted">{p.duration || "—"}</td>
                    <td>
                      <div className="row" style={{ gap: 6, flexWrap: "wrap" }}>
                        {features.slice(0, 3).map((f, i) => (
                          <span key={i} className="chip" style={{ height: 22, fontSize: 11 }}>{f}</span>
                        ))}
                        {features.length > 3 && <span className="muted tiny">+{features.length - 3} more</span>}
                      </div>
                    </td>
                    <td><S.Chip tone={isActive ? "pos" : ""}>{isActive ? "Active" : "Inactive"}</S.Chip></td>
                    <td>
                      <div className="row-tight" style={{ gap: 4, justifyContent: "flex-end" }}>
                        <S.IconBtn title="Edit" onClick={() => openEdit(p)}><I.edit size={15} /></S.IconBtn>
                        <S.IconBtn title={isActive ? "Deactivate" : "Activate"} onClick={() => togglePlanStatus(p)}>
                          {isActive ? <I.eyeOff size={15} /> : <I.eye size={15} />}
                        </S.IconBtn>
                        <S.IconBtn title="Delete" onClick={() => setConfirmDelete(p)}><I.trash size={15} /></S.IconBtn>
                      </div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      <PlanFormModal
        open={planFormOpen}
        plan={editingPlan}
        audience={tab}
        onClose={() => setPlanFormOpen(false)}
        onSave={savePlan}
      />
      <window.M.ConfirmModal
        open={!!confirmDelete}
        onClose={() => setConfirmDelete(null)}
        onConfirm={deletePlan}
        title={`Delete ${confirmDelete?.name}?`}
        body="This will remove the plan. Existing subscribers won't be affected, but new sign-ups can no longer pick it."
        confirmLabel="Delete plan"
        danger
        icon={<I.trash />}
      />
    </div>
  );
}

function PlanFormModal({ open, plan, audience, onClose, onSave }) {
  const [data, setData] = React.useState({ name: "", price: "", duration: "Monthly", features: "" });
  React.useEffect(() => {
    if (open) setData(plan ? {
      name: plan.name, price: plan.price === null ? "" : String(plan.price),
      duration: plan.duration || "Monthly",
      features: (Array.isArray(plan.features) ? plan.features : (plan.features ? Object.values(plan.features) : [])).join("\n"),
    } : { name: "", price: "", duration: "Monthly", features: "" });
  }, [open, plan]);
  const set = (k, v) => setData(d => ({ ...d, [k]: v }));
  const submit = () => {
    onSave({
      name: data.name || "Untitled",
      price: data.price === "" ? null : Number(data.price),
      period: "mo",
      duration: data.duration,
      features: data.features.split("\n").map(s => s.trim()).filter(Boolean),
    });
  };
  return (
    <window.M.Modal open={open} onClose={onClose} size="lg"
      icon={<I.crown />} title={plan ? `Edit ${plan.name}` : `Create ${audience === "clients" ? "client" : "vendor"} plan`}
      subtitle={plan ? "Changes apply to new subscribers immediately." : "Define pricing, duration, and what's included."}
      footer={<>
        <S.Btn variant="ghost" onClick={onClose}>Cancel</S.Btn>
        <S.Btn variant="primary" iconRight={<I.check size={14} />} onClick={submit}>{plan ? "Save changes" : "Create plan"}</S.Btn>
      </>}
    >
      <window.M.FormGrid>
        <window.M.Field label="Plan name">
          <window.M.TextField value={data.name} onChange={(v) => set("name", v)} placeholder="e.g. Gold" />
        </window.M.Field>
        <window.M.Field label="Price (USD)" hint="Leave blank for custom pricing.">
          <window.M.TextField value={data.price} onChange={(v) => set("price", v)} placeholder="49" />
        </window.M.Field>
        <window.M.Field full label="Duration">
          <window.M.Segmented value={data.duration} onChange={(v) => set("duration", v)}
            options={[
              { value: "Monthly", label: "Monthly" },
              { value: "Annual", label: "Annual" },
              { value: "Annual contract", label: "Custom contract" },
            ]} />
        </window.M.Field>
        <window.M.Field full label="Features" hint="One feature per line.">
          <window.M.Textarea rows={6} value={data.features} onChange={(v) => set("features", v)} placeholder={"Reduced fees · 3.5%\nCustom branding\nPriority support"} />
        </window.M.Field>
      </window.M.FormGrid>
    </window.M.Modal>
  );
}

/* ====================================================================
   STUBS — payments / reports / support / coupons / notifs / settings
   ==================================================================== */
function AdminPayments({ tok }) {
  const [stats, setStats] = React.useState(null);
  const [txns, setTxns] = React.useState(null);
  const [searchInput, setSearchInput] = React.useState("");
  const search = window.useDebounce(searchInput, 250);
  const [typeFilter, setTypeFilter] = React.useState("all");

  React.useEffect(() => {
    let alive = true;
    setStats(null); setTxns(null);
    Promise.all([SB.adminGetPaymentStats(tok), SB.adminGetTransactions(tok)]).then(([s, t]) => {
      if (!alive) return;
      setStats(s); setTxns(t || []);
    });
  }, [tok]);

  if (stats === null || txns === null) return <div className="page-enter"><window.LoadingState /></div>;

  // Filter
  let filtered = txns;
  if (typeFilter !== "all") filtered = filtered.filter(t => t.type === typeFilter);
  if (search) {
    const q = search.toLowerCase();
    filtered = filtered.filter(t =>
      ((t.reference || "").toLowerCase().includes(q)) ||
      ((t.type || "").toLowerCase().includes(q)) ||
      String(t.amount || "").includes(q)
    );
  }

  const today = new Date(); today.setHours(0,0,0,0);
  const todayTxns = txns.filter(t => new Date(t.created_at) >= today);
  const captures  = txns.filter(t => Number(t.amount) > 0 && (t.status === "completed" || t.status === "captured"));
  const captureTotal = captures.reduce((s, t) => s + Number(t.amount), 0);
  const todayCaptureTotal = todayTxns.filter(t => Number(t.amount) > 0).reduce((s, t) => s + Number(t.amount), 0);
  const successRate = txns.length === 0 ? 100 : (txns.filter(t => t.status === "completed" || t.status === "captured" || t.status === "approved").length / txns.length * 100);
  const avgTicket = captures.length ? captureTotal / captures.length : 0;

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow="Payment center · all rails"
        title="Payment center"
        sub="Every transaction across the platform."
        right={null}
      />

      <div className="grid-4" style={{ marginBottom: 24 }}>
        <S.Metric hero label="Captures today" value={window.fmtMoney(todayCaptureTotal)} delta={`${todayTxns.length} entries`} />
        <S.Metric label="All-time volume" value={window.fmtMoney(captureTotal)} delta={`${captures.length} captures`} deltaTone="pos" />
        <S.Metric label="Success rate" value={`${successRate.toFixed(1)}%`} deltaTone={successRate > 95 ? "pos" : "warn"} />
        <S.Metric label="Avg. ticket" value={window.fmtMoney(avgTicket)} />
      </div>

      <div className="card card-flush">
        <div className="row" style={{ padding: 16, gap: 10 }}>
          <S.Input
            icon={<I.search size={15} />}
            placeholder="Search by reference, type, amount…"
            style={{ flex: 1, maxWidth: 360 }}
            value={searchInput}
            onChange={(e) => setSearchInput(e.target.value)}
          />
          <select className="text-input" style={{ width: 200 }} value={typeFilter} onChange={(e) => setTypeFilter(e.target.value)}>
            <option value="all">All types</option>
            <option value="booking_fee">Booking fee</option>
            <option value="payout">Payout</option>
            <option value="refund">Refund</option>
            <option value="withdrawal">Withdrawal</option>
          </select>
          <div className="spacer" />
          <span className="muted tiny">{filtered.length} of {txns.length}</span>
        </div>
        {filtered.length === 0 ? (
          <window.EmptyState icon={<I.payment size={24} />} title="No transactions match" sub="Try a different filter." />
        ) : (
          <table className="tbl">
            <thead>
              <tr><th>Reference</th><th>Type</th><th>Status</th><th>Date</th><th className="col-num">Amount</th></tr>
            </thead>
            <tbody>
              {filtered.slice(0, 100).map(t => {
                const ref = t.reference || `TXN-${(t.id || "").slice(0, 8).toUpperCase()}`;
                const amt = Number(t.amount || 0);
                return (
                  <tr key={t.id}>
                    <td className="mono muted">{ref}</td>
                    <td style={{ textTransform: "capitalize" }}>{(t.type || "").replace(/_/g, " ")}</td>
                    <td><S.Chip tone={window.statusTone(t.status)}>{window.statusLabel(t.status)}</S.Chip></td>
                    <td className="mono muted">{window.fmtDate(t.created_at)}</td>
                    <td className="col-num mono" style={{ color: amt < 0 ? "var(--neg)" : "var(--pos)", fontWeight: 500 }}>
                      {amt < 0 ? "−" : "+"}{window.fmtMoney(Math.abs(amt))}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

function AdminReports({ tok }) {
  const [range, setRange] = React.useState("90d");
  const [report, setReport] = React.useState(null);

  React.useEffect(() => {
    let alive = true;
    setReport(null);
    SB.adminGetReports(tok).then((r) => {
      if (!alive) return;
      setReport(r);
    });
    return () => { alive = false; };
  }, [tok, range]);

  if (!report) return <div className="page-enter"><window.LoadingState /></div>;

  // Build trailing-N labels for charts
  const dayLabels = [];
  for (let i = 6; i >= 0; i--) {
    const d = new Date(Date.now() - i * 24 * 60 * 60 * 1000);
    dayLabels.push(d.toLocaleDateString("en-US", { weekday: "short" }));
  }
  const weekLabels = [];
  for (let i = 6; i >= 0; i--) {
    const d = new Date(Date.now() - i * 7 * 24 * 60 * 60 * 1000);
    weekLabels.push(d.toLocaleDateString("en-US", { month: "short", day: "numeric" }));
  }

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow="Live platform data"
        title="Reports & analytics"
        sub="Health, growth, and revenue across users, vendors, and bookings."
        right={<>
          <div className="row-tight" style={{ background: "var(--surface-3)", padding: 3, borderRadius: 999 }}>
            {[{ k: "7d", l: "7d" }, { k: "30d", l: "30d" }, { k: "90d", l: "90d" }].map(r => (
              <button key={r.k} onClick={() => setRange(r.k)}
                className={`btn btn-sm ${range === r.k ? "btn-primary" : "btn-ghost"}`}>{r.l}</button>
            ))}
          </div>
          <S.Btn variant="outline" size="sm" icon={<I.download size={14} />}>Export</S.Btn>
        </>}
      />

      {/* hero KPI strip — real numbers */}
      <div className="grid-4" style={{ marginBottom: 24 }}>
        <S.Metric hero label="Total revenue"  value={window.fmtMoney(report.totalRevenue)} delta={`${window.fmtMoney(report.revenue7d)} last 7d`} />
        <S.Metric label="Total bookings"      value={report.totalBookings.toLocaleString()} delta={`+${report.newBookings7d} this week`} deltaTone="pos" />
        <S.Metric label="Active users"        value={report.totalUsers.toLocaleString()} delta={`+${report.newUsers7d} this week`} deltaTone="pos" />
        <S.Metric label="Active vendors"      value={report.totalVendors.toLocaleString()} delta={`${report.activeVendors} live`} deltaTone="pos" />
      </div>

      <div className="grid-12" style={{ marginBottom: 24 }}>
        {/* Booking trends - last 7 days */}
        <div className="card" style={{ gridColumn: "span 8" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div>
              <div className="eyebrow">Booking activity</div>
              <div className="h3" style={{ marginTop: 4 }}>Bookings per day · last 7 days</div>
            </div>
          </div>
          <S.BarChart
            height={260}
            labels={dayLabels}
            data={report.dayBuckets}
            color="var(--accent)"
          />
        </div>

        {/* Top vendors */}
        <div className="card" style={{ gridColumn: "span 4" }}>
          <div className="eyebrow" style={{ marginBottom: 4 }}>Performance</div>
          <div className="h3" style={{ marginBottom: 18 }}>Top vendors</div>
          {report.topVendors.length === 0 ? (
            <div className="muted tiny" style={{ padding: "32px 0", textAlign: "center" }}>No vendor data yet</div>
          ) : (
            <div className="col" style={{ gap: 14 }}>
              {report.topVendors.map((v, i) => {
                const max = Math.max(1, report.topVendors[0].total_reviews || 1);
                const pct = ((v.total_reviews || 0) / max) * 100;
                return (
                  <div key={v.id}>
                    <div className="row between" style={{ marginBottom: 4 }}>
                      <span style={{ fontSize: 13, fontWeight: 500 }}>{v.business_name}</span>
                      <span className="mono tiny muted">★{(v.rating || 0).toFixed(1)} · {v.total_reviews || 0}</span>
                    </div>
                    <div className="bar"><span style={{ width: `${pct}%`, background: i === 0 ? "var(--accent)" : "var(--accent-soft)" }} /></div>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>

      <div className="grid-12" style={{ marginBottom: 24 }}>
        {/* Revenue trend - last 7 days */}
        <div className="card" style={{ gridColumn: "span 6" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div>
              <div className="eyebrow">Revenue</div>
              <div className="h3" style={{ marginTop: 4 }}>Daily revenue · last 7 days</div>
            </div>
          </div>
          <S.LineChart
            height={220}
            currency
            labels={dayLabels}
            series={[{ color: "var(--accent)", data: report.revenueDayBuckets }]}
          />
        </div>

        {/* User growth */}
        <div className="card" style={{ gridColumn: "span 6" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div>
              <div className="eyebrow">Growth</div>
              <div className="h3" style={{ marginTop: 4 }}>New users · last 7 weeks</div>
            </div>
          </div>
          <S.BarChart
            height={220}
            labels={weekLabels}
            data={report.weekBuckets}
            color="var(--accent-soft)"
          />
        </div>
      </div>

      <div className="grid-12" style={{ marginBottom: 24 }}>
        {/* Top services */}
        <div className="card" style={{ gridColumn: "span 6" }}>
          <div className="eyebrow" style={{ marginBottom: 4 }}>Demand</div>
          <div className="h3" style={{ marginBottom: 18 }}>Most booked services</div>
          {report.topServices.length === 0 ? (
            <div className="muted tiny" style={{ padding: "32px 0", textAlign: "center" }}>No service bookings yet</div>
          ) : (
            <div className="col" style={{ gap: 14 }}>
              {report.topServices.map((s, i) => {
                const max = Math.max(1, report.topServices[0].count || 1);
                const pct = (s.count / max) * 100;
                return (
                  <div key={s.id}>
                    <div className="row between" style={{ marginBottom: 4 }}>
                      <span style={{ fontSize: 13, fontWeight: 500 }}>{s.name}</span>
                      <span className="mono tiny muted">{s.count} {s.count === 1 ? "booking" : "bookings"}</span>
                    </div>
                    <div className="bar"><span style={{ width: `${pct}%`, background: i === 0 ? "var(--accent)" : "var(--accent-soft)" }} /></div>
                  </div>
                );
              })}
            </div>
          )}
        </div>

        {/* Vendor growth */}
        <div className="card" style={{ gridColumn: "span 6" }}>
          <div className="row between" style={{ marginBottom: 18 }}>
            <div>
              <div className="eyebrow">Growth</div>
              <div className="h3" style={{ marginTop: 4 }}>New vendors · last 7 weeks</div>
            </div>
          </div>
          <S.BarChart
            height={220}
            labels={weekLabels}
            data={report.vendorWeekBuckets}
            color="var(--accent)"
          />
        </div>
      </div>

      {/* Recent transactions */}
      <div className="card card-flush">
        <div className="row between" style={{ padding: "22px 22px 14px" }}>
          <div className="h3">Recent transactions</div>
          <span className="muted tiny">{report.recentTransactions.length} entries</span>
        </div>
        {report.recentTransactions.length === 0 ? (
          <window.EmptyState icon={<I.payment size={24} />} title="No transactions yet" />
        ) : (
          <table className="tbl">
            <thead>
              <tr><th>Reference</th><th>Type</th><th>Status</th><th>Date</th><th className="col-num">Amount</th></tr>
            </thead>
            <tbody>
              {report.recentTransactions.map(t => {
                const ref = t.reference || `TXN-${(t.id || "").slice(0, 8).toUpperCase()}`;
                const amt = Number(t.amount || 0);
                return (
                  <tr key={t.id}>
                    <td className="mono muted">{ref}</td>
                    <td style={{ textTransform: "capitalize" }}>{(t.type || "").replace(/_/g, " ")}</td>
                    <td><S.Chip tone={window.statusTone(t.status)}>{window.statusLabel(t.status)}</S.Chip></td>
                    <td className="mono muted">{window.fmtDate(t.created_at)}</td>
                    <td className="col-num mono" style={{ color: amt < 0 ? "var(--neg)" : "var(--pos)", fontWeight: 500 }}>
                      {amt < 0 ? "−" : "+"}{window.fmtMoney(Math.abs(amt))}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}
function FunnelChart({ steps }) {
  const max = steps[0].count;
  return (
    <div className="col" style={{ gap: 10 }}>
      {steps.map((s, i) => (
        <div key={i}>
          <div className="row between" style={{ marginBottom: 4 }}>
            <span style={{ fontSize: 13 }}>{s.label}</span>
            <span className="row-tight">
              <span className="mono tiny" style={{ fontWeight: 500 }}>{s.count.toLocaleString()}</span>
              <span className="mono tiny muted">· {s.rate.toFixed(1)}%</span>
            </span>
          </div>
          <div style={{ height: 10, background: "var(--surface-3)", borderRadius: 6, overflow: "hidden" }}>
            <div style={{
              width: `${(s.count / max) * 100}%`, height: "100%",
              background: i === 0 ? "var(--accent)" : i === steps.length - 1 ? "var(--ink)" : "var(--accent-soft)",
              transition: "width 0.5s ease",
            }} />
          </div>
        </div>
      ))}
    </div>
  );
}

function DistRow({ label, pct, c }) {
  return (
    <div>
      <div className="row between" style={{ marginBottom: 4 }}>
        <span className="tiny">{label}</span>
        <span className="mono tiny">{pct}%</span>
      </div>
      <div className="bar"><span style={{ width: `${pct}%`, background: c }} /></div>
    </div>
  );
}

function CohortGrid() {
  const months = ["Aug", "Sep", "Oct", "Nov", "Dec", "Jan"];
  const data = [
    [100, 64, 52, 44, 38, 34],
    [100, 68, 56, 48, 42, null],
    [100, 70, 58, 50, null, null],
    [100, 72, 60, null, null, null],
    [100, 74, null, null, null, null],
    [100, null, null, null, null, null],
  ];
  return (
    <div>
      <div className="row" style={{ gap: 4, marginBottom: 4 }}>
        <div style={{ width: 80 }} />
        {months.map((m, i) => <div key={m} style={{ flex: 1, textAlign: "center" }} className="mono tiny muted">M{i}</div>)}
      </div>
      {data.map((row, i) => (
        <div key={i} className="row" style={{ gap: 4, marginBottom: 4 }}>
          <div style={{ width: 80 }} className="mono tiny muted">{months[i]} ’25</div>
          {row.map((v, j) => (
            <div key={j} style={{
              flex: 1, height: 40, borderRadius: 6, display: "flex", alignItems: "center", justifyContent: "center",
              background: v == null ? "var(--surface-3)" : `oklch(${95 - v * 0.5}% ${0.04 + v * 0.001} 290)`,
              color: v == null ? "var(--ink-4)" : v > 60 ? "white" : "var(--ink)",
              fontSize: 12, fontFamily: "var(--font-mono)",
            }}>{v == null ? "—" : `${v}%`}</div>
          ))}
        </div>
      ))}
    </div>
  );
}

function AdminSupport({ tok }) {
  const toast = window.useToast();
  const [filter, setFilter] = React.useState("all");
  const [selected, setSelected] = React.useState(null);
  const [tickets, setTickets] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    let alive = true;
    setTickets(null);
    SB.adminGetTickets(null, tok).then((t) => {
      if (!alive) return;
      setTickets(t || []);
    });
    return () => { alive = false; };
  }, [tok, reloadKey]);

  const reload = () => setReloadKey(k => k + 1);

  if (tickets === null) {
    return <div className="page-enter"><window.LoadingState /></div>;
  }

  // Derived counts
  const counts = {
    all:         tickets.length,
    open:        tickets.filter(t => t.status === "open").length,
    in_progress: tickets.filter(t => t.status === "in_progress").length,
    resolved:    tickets.filter(t => t.status === "resolved" || t.status === "closed").length,
    urgent:      tickets.filter(t => t.priority === "urgent").length,
  };

  // Filter
  let filtered = tickets;
  if (filter === "open")        filtered = tickets.filter(t => t.status === "open");
  if (filter === "in_progress") filtered = tickets.filter(t => t.status === "in_progress");
  if (filter === "resolved")    filtered = tickets.filter(t => t.status === "resolved" || t.status === "closed");
  if (filter === "urgent")      filtered = tickets.filter(t => t.priority === "urgent");

  const priorityTone = (p) => p === "urgent" ? "neg" : p === "high" ? "warn" : p === "low" ? "" : "info";

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow={`Inbox · ${counts.open} open${counts.urgent ? ` · ${counts.urgent} urgent` : ""}`}
        title="Support & help"
        sub="Tickets from clients and vendors."
        right={<>
          <S.Btn variant="outline" size="sm" icon={<I.refresh size={14} />} onClick={reload}>Refresh</S.Btn>
        </>}
      />

      <div className="grid-4" style={{ marginBottom: 24 }}>
        <S.Metric hero label="Open tickets"    value={counts.open.toString()}        delta="Awaiting response" deltaTone={counts.open > 0 ? "warn" : "pos"} />
        <S.Metric label="In progress"          value={counts.in_progress.toString()} delta="Active conversations" />
        <S.Metric label="Resolved"             value={counts.resolved.toString()}    delta="Lifetime" deltaTone="pos" />
        <S.Metric label="Urgent"               value={counts.urgent.toString()}      delta="High priority" deltaTone={counts.urgent > 0 ? "neg" : "pos"} />
      </div>

      <div style={{ display: "grid", gridTemplateColumns: selected ? "1fr 420px" : "1fr", gap: 20, alignItems: "flex-start" }}>
        <div className="card card-flush">
          <div className="row" style={{ padding: 16, gap: 8, borderBottom: "1px solid var(--border)", flexWrap: "wrap" }}>
            {[
              { k: "all",         l: "All",         n: counts.all },
              { k: "open",        l: "Open",        n: counts.open },
              { k: "in_progress", l: "In progress", n: counts.in_progress },
              { k: "resolved",    l: "Resolved",    n: counts.resolved },
              { k: "urgent",      l: "Urgent",      n: counts.urgent },
            ].map(f => (
              <button key={f.k} onClick={() => setFilter(f.k)}
                className={`btn btn-sm ${filter === f.k ? "btn-primary" : "btn-outline"}`}>
                {f.l} <span className="mono tiny" style={{ marginLeft: 4, opacity: 0.6 }}>{f.n}</span>
              </button>
            ))}
          </div>

          {filtered.length === 0 ? (
            <window.EmptyState icon={<I.ticket size={24} />} title="No tickets here" sub="Filter clear, or no one's reaching out right now." />
          ) : (
            <table className="tbl">
              <thead>
                <tr>
                  <th>Ticket</th>
                  <th>From</th>
                  <th>Subject</th>
                  <th>Priority</th>
                  <th>Status</th>
                  <th>Created</th>
                  <th />
                </tr>
              </thead>
              <tbody>
                {filtered.map((t) => {
                  const fromName = t.author?.full_name || t.user_name || t.author?.email || t.user_email || "Anonymous";
                  const fromRole = t.author?.role || "user";
                  const shortId = "TKT-" + (t.id || "").slice(0, 8).toUpperCase();
                  return (
                    <tr key={t.id} onClick={() => setSelected(t)} style={{ cursor: "pointer", background: selected?.id === t.id ? "var(--accent-soft)" : undefined }}>
                      <td className="mono muted">{shortId}</td>
                      <td>
                        <div className="row-tight">
                          <S.Avatar name={fromName} size="sm" />
                          <div>
                            <div style={{ fontWeight: 500, fontSize: 13 }}>{fromName}</div>
                            <div className="muted tiny" style={{ textTransform: "capitalize" }}>{fromRole}</div>
                          </div>
                        </div>
                      </td>
                      <td>
                        <div style={{ fontWeight: 500 }}>{t.subject}</div>
                        <div className="muted tiny" style={{ maxWidth: 280, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{t.body}</div>
                      </td>
                      <td><S.Chip tone={priorityTone(t.priority)} style={{ textTransform: "capitalize" }}>{t.priority || "normal"}</S.Chip></td>
                      <td><S.Chip tone={window.statusTone(t.status)}>{window.statusLabel(t.status)}</S.Chip></td>
                      <td className="muted tiny">{window.fmtDate(t.created_at)}</td>
                      <td><S.IconBtn><I.chevR size={14} /></S.IconBtn></td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          )}
        </div>

        {selected && <TicketDetail
          ticket={selected}
          tok={tok}
          onClose={() => setSelected(null)}
          onChanged={() => { reload(); }}
        />}
      </div>
    </div>
  );
}

function TicketDetail({ ticket, tok, onClose, onChanged }) {
  const toast = window.useToast();
  const [replies, setReplies] = React.useState([]);
  const [body, setBody] = React.useState("");
  const [priority, setPriority] = React.useState(ticket.priority || "normal");
  const [busy, setBusy] = React.useState(false);

  React.useEffect(() => {
    setPriority(ticket.priority || "normal");
    setBody("");
    SB.adminGetTicketReplies(ticket.id, tok).then((r) => setReplies(r || []));
  }, [ticket?.id, tok]);

  const fromName  = ticket.author?.full_name || ticket.user_name || ticket.author?.email || ticket.user_email || "Anonymous";
  const fromRole  = ticket.author?.role || "user";
  const shortId   = "TKT-" + (ticket.id || "").slice(0, 8).toUpperCase();
  const isResolved = ticket.status === "resolved" || ticket.status === "closed";
  const priorityTone = (p) => p === "urgent" ? "neg" : p === "high" ? "warn" : p === "low" ? "" : "info";

  const sendReply = async () => {
    if (!body.trim()) { toast.error("Type a reply first"); return; }
    setBusy(true);
    try {
      const r = await SB.adminReplyTicket(ticket.id, body.trim(), tok);
      if (!r.ok) { toast.error(r.message || "Couldn't send"); return; }
      const fresh = await SB.adminGetTicketReplies(ticket.id, tok);
      setReplies(fresh || []);
      setBody("");
      toast.success("Reply sent");
      onChanged?.();
    } finally {
      setBusy(false);
    }
  };

  const updateStatus = async (newStatus) => {
    setBusy(true);
    try {
      const r = await SB.adminUpdateTicketStatus(ticket.id, newStatus, tok);
      if (!r.ok) { toast.error(r.message || "Update failed"); return; }
      toast.success(newStatus === "resolved" ? "Marked resolved" : "Reopened");
      onChanged?.();
      onClose();
    } finally {
      setBusy(false);
    }
  };

  const updatePriority = async (newPriority) => {
    setPriority(newPriority);
    const r = await SB.adminUpdateTicketPriority(ticket.id, newPriority, tok);
    if (!r.ok) { toast.error(r.message || "Update failed"); return; }
    toast.success("Priority updated");
    onChanged?.();
  };

  return (
    <div className="card" style={{ padding: 0, position: "sticky", top: 0 }}>
      <div style={{ padding: 22, borderBottom: "1px solid var(--border)" }}>
        <div className="row between">
          <div className="eyebrow">{shortId}</div>
          <S.IconBtn onClick={onClose}><I.x size={14} /></S.IconBtn>
        </div>
        <div className="display" style={{ fontSize: 18, marginTop: 8, letterSpacing: "-0.015em", lineHeight: 1.25 }}>{ticket.subject}</div>
        <div className="row" style={{ marginTop: 12, gap: 6 }}>
          <S.Chip tone={priorityTone(priority)} style={{ textTransform: "capitalize" }}>{priority}</S.Chip>
          <S.Chip tone={window.statusTone(ticket.status)}>{window.statusLabel(ticket.status)}</S.Chip>
        </div>
      </div>

      <div style={{ padding: 22, borderBottom: "1px solid var(--border)" }}>
        <div className="eyebrow" style={{ marginBottom: 10 }}>From</div>
        <div className="row" style={{ gap: 12 }}>
          <S.Avatar name={fromName} size="lg" />
          <div style={{ flex: 1 }}>
            <div style={{ fontWeight: 500 }}>{fromName}</div>
            <div className="muted tiny" style={{ textTransform: "capitalize" }}>{fromRole}</div>
          </div>
        </div>
      </div>

      <div style={{ padding: 22, borderBottom: "1px solid var(--border)" }}>
        <div className="eyebrow" style={{ marginBottom: 10 }}>Priority</div>
        <select className="text-input" value={priority} onChange={(e) => updatePriority(e.target.value)} disabled={busy}>
          <option value="low">Low</option>
          <option value="normal">Normal</option>
          <option value="high">High</option>
          <option value="urgent">Urgent</option>
        </select>
      </div>

      <div style={{ padding: 22, borderBottom: "1px solid var(--border)" }}>
        <div className="eyebrow" style={{ marginBottom: 10 }}>Thread · {1 + replies.length} {1 + replies.length === 1 ? "message" : "messages"}</div>
        <div className="ticket-thread">
          <div className="ticket-msg user">
            <div className="ticket-msg-meta">{fromName} · {window.fmtDate(ticket.created_at)}</div>
            {ticket.body}
          </div>
          {replies.map((r) => {
            const isAdmin = r.author_role === "admin";
            const author = r.author?.full_name || r.author?.email || (isAdmin ? "Admin" : "User");
            return (
              <div key={r.id} className={`ticket-msg ${isAdmin ? "admin" : "user"}`}>
                <div className="ticket-msg-meta">{author}{isAdmin ? " · Admin" : ""} · {window.fmtDate(r.created_at)}</div>
                {r.body}
              </div>
            );
          })}
        </div>
      </div>

      <div style={{ padding: 22 }}>
        {!isResolved && (
          <textarea className="text-input" rows={4} placeholder="Reply to this ticket…"
            value={body} onChange={(e) => setBody(e.target.value)} disabled={busy} />
        )}
        <div className="row" style={{ marginTop: 10, gap: 6 }}>
          <div className="spacer" />
          {isResolved ? (
            <S.Btn variant="outline" size="sm" icon={<I.refresh size={12} />} onClick={() => updateStatus("open")} disabled={busy}>
              Reopen ticket
            </S.Btn>
          ) : <>
            <S.Btn variant="outline" size="sm" onClick={() => updateStatus("resolved")} disabled={busy}>Mark resolved</S.Btn>
            <S.Btn variant="primary" size="sm" iconRight={<I.send size={12} />} onClick={sendReply} disabled={busy}>
              {busy ? "Sending…" : "Send reply"}
            </S.Btn>
          </>}
        </div>
      </div>
    </div>
  );
}

function AdminCoupons({ tok }) {
  const toast = window.useToast();
  const [open, setOpen] = React.useState(false);
  const [editing, setEditing] = React.useState(null);
  const [coupons, setCoupons] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    let alive = true;
    setCoupons(null);
    SB.adminGetCoupons(tok).then((c) => { if (alive) setCoupons(c || []); });
    return () => { alive = false; };
  }, [tok, reloadKey]);

  const reload = () => setReloadKey(k => k + 1);

  if (coupons === null) return <div className="page-enter"><window.LoadingState /></div>;

  const active = coupons.filter(c => c.is_active !== false && (!c.expires_at || new Date(c.expires_at) > new Date()));
  const totalUses = coupons.reduce((s, c) => s + (c.uses_count || 0), 0);

  const deleteCoupon = async (c) => {
    if (!confirm(`Delete coupon ${c.code}?`)) return;
    const r = await SB.adminDeleteCoupon(c.id, tok);
    if (!r.ok) { toast.error(r.message || "Delete failed"); return; }
    toast.success("Coupon deleted");
    reload();
  };

  return (
    <div className="page-enter">
      <S.PageHead eyebrow={`${active.length} active · ${coupons.length} total`} title="Coupons" sub="Promo codes and discount campaigns."
        right={<>
          <S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={() => { setEditing(null); setOpen(true); }}>Create coupon</S.Btn>
        </>}
      />

      <div className="grid-4" style={{ marginBottom: 24 }}>
        <S.Metric hero label="Total redemptions" value={totalUses.toLocaleString()} delta={`${active.length} active codes`} />
        <S.Metric label="Active campaigns" value={active.length.toString()} />
        <S.Metric label="Total campaigns" value={coupons.length.toString()} />
        <S.Metric label="Expired / inactive" value={(coupons.length - active.length).toString()} deltaTone="" />
      </div>

      {coupons.length === 0 ? (
        <window.EmptyState
          icon={<I.coupon size={24} />}
          title="No coupons yet"
          sub="Create your first promo code to start running campaigns."
          action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={() => { setEditing(null); setOpen(true); }}>Create coupon</S.Btn>}
        />
      ) : (
        <div className="grid-3">
          {coupons.map((c) => {
            const isExpired = c.expires_at && new Date(c.expires_at) < new Date();
            const isInactive = c.is_active === false || isExpired;
            const tone = isInactive ? "" : c.discount_type === "percent" ? "accent" : "pos";
            const usePct = c.usage_limit ? (((c.uses_count || 0) / c.usage_limit) * 100) : null;
            return (
              <div key={c.id} className="card" style={{ padding: 22, opacity: isInactive ? 0.65 : 1 }}>
                <div className="row between">
                  <S.Chip tone={tone}>{c.code}</S.Chip>
                  <div className="row-tight">
                    <S.IconBtn onClick={() => { setEditing(c); setOpen(true); }}><I.edit size={14} /></S.IconBtn>
                    <S.IconBtn onClick={() => deleteCoupon(c)}><I.trash size={14} /></S.IconBtn>
                  </div>
                </div>
                <div className="display" style={{ fontSize: 36, marginTop: 16, letterSpacing: "-0.03em" }}>
                  {c.discount_type === "percent" ? `${c.discount_value}%` : window.fmtMoney(c.discount_value)}
                  <span className="muted" style={{ fontSize: 12, fontWeight: 400, marginLeft: 8 }}>off</span>
                </div>
                <div style={{ fontSize: 13, marginTop: 6, color: "var(--ink-2)" }}>{c.description || c.code}</div>
                <div className="divider" style={{ margin: "16px 0" }} />
                <div className="row between mono tiny muted" style={{ marginBottom: 6 }}>
                  <span>{(c.uses_count || 0).toLocaleString()} redeemed</span>
                  <span>of {c.usage_limit ? c.usage_limit.toLocaleString() : "∞"}</span>
                </div>
                {usePct !== null && (
                  <div className="bar"><span style={{ width: `${Math.min(100, usePct)}%` }} /></div>
                )}
                {isExpired && <div className="tiny muted" style={{ marginTop: 10, fontStyle: "italic" }}>Expired {window.fmtDate(c.expires_at)}</div>}
                {c.is_active === false && !isExpired && <div className="tiny muted" style={{ marginTop: 10, fontStyle: "italic" }}>Disabled</div>}
              </div>
            );
          })}
        </div>
      )}

      <CreateCouponModal
        open={open}
        coupon={editing}
        onClose={() => { setOpen(false); setEditing(null); }}
        tok={tok}
        onSaved={() => { setOpen(false); setEditing(null); reload(); toast.success(editing ? "Coupon updated" : "Coupon created"); }}
      />
    </div>
  );
}

function CreateCouponModal({ open, coupon, onClose, tok, onSaved }) {
  const toast = window.useToast();
  const isEdit = !!coupon;
  const [busy, setBusy] = React.useState(false);
  const [data, setData] = React.useState({
    code: "", description: "", discount_type: "percent", discount_value: "",
    usage_limit: "", expires_at: "", is_active: true,
  });

  React.useEffect(() => {
    if (open && coupon) {
      setData({
        code: coupon.code || "",
        description: coupon.description || "",
        discount_type: coupon.discount_type || "percent",
        discount_value: coupon.discount_value?.toString() || "",
        usage_limit: coupon.usage_limit?.toString() || "",
        expires_at: coupon.expires_at ? coupon.expires_at.slice(0, 10) : "",
        is_active: coupon.is_active !== false,
      });
    } else if (open) {
      setData({ code: "", description: "", discount_type: "percent", discount_value: "", usage_limit: "", expires_at: "", is_active: true });
    }
  }, [open, coupon?.id]);

  const set = (k, v) => setData(d => ({ ...d, [k]: v }));

  const submit = async () => {
    if (!data.code.trim()) { toast.error("Code is required"); return; }
    const val = parseFloat(data.discount_value);
    if (!val || val <= 0) { toast.error("Discount value must be > 0"); return; }
    if (data.discount_type === "percent" && val > 100) { toast.error("Percent must be ≤ 100"); return; }

    setBusy(true);
    try {
      const payload = {
        code: data.code.trim().toUpperCase(),
        description: data.description.trim() || null,
        discount_type: data.discount_type,
        discount_value: val,
        usage_limit: data.usage_limit ? parseInt(data.usage_limit, 10) : null,
        expires_at: data.expires_at || null,
        is_active: data.is_active,
      };
      const r = isEdit
        ? await SB.adminUpdateCoupon(coupon.id, payload, tok)
        : await SB.adminCreateCoupon(payload, tok);
      if (!r.ok) { toast.error(r.message || "Save failed"); return; }
      onSaved?.();
    } finally {
      setBusy(false);
    }
  };

  return (
    <window.M.Modal open={open} onClose={onClose} size="lg"
      icon={<I.coupon />}
      title={isEdit ? `Edit ${coupon?.code}` : "Create coupon"}
      subtitle={isEdit ? "Update the discount or limits." : "Define the discount, audience, and limits."}
      footer={<>
        <S.Btn variant="ghost" onClick={onClose} disabled={busy}>Cancel</S.Btn>
        <S.Btn variant="primary" iconRight={<I.check size={14} />} onClick={submit} disabled={busy}>
          {busy ? "Saving…" : isEdit ? "Save changes" : "Create coupon"}
        </S.Btn>
      </>}
    >
      <window.M.FormGrid>
        <window.M.Field label="Code" hint="Letters/numbers. Auto-uppercased.">
          <window.M.TextField value={data.code} onChange={(v) => set("code", v.toUpperCase())} placeholder="e.g. SPRING25" />
        </window.M.Field>
        <window.M.Field label="Description" hint="Shown to clients at checkout.">
          <window.M.TextField value={data.description} onChange={(v) => set("description", v)} placeholder="25% off your first booking" />
        </window.M.Field>
        <window.M.Field full label="Discount type">
          <window.M.Segmented value={data.discount_type} onChange={(v) => set("discount_type", v)}
            options={[{ value: "percent", label: "Percentage off" }, { value: "fixed", label: "Fixed amount off" }]} />
        </window.M.Field>
        <window.M.Field label={`Value (${data.discount_type === "percent" ? "%" : "$"})`}>
          <input className="text-input" type="number" min="0" step={data.discount_type === "percent" ? "1" : "0.01"} value={data.discount_value} onChange={(e) => set("discount_value", e.target.value)} placeholder={data.discount_type === "percent" ? "25" : "10.00"} />
        </window.M.Field>
        <window.M.Field label="Usage limit" hint="Blank = unlimited.">
          <input className="text-input" type="number" min="1" value={data.usage_limit} onChange={(e) => set("usage_limit", e.target.value)} placeholder="1000" />
        </window.M.Field>
        <window.M.Field label="Expires on" hint="Blank = no expiry.">
          <input className="text-input" type="date" value={data.expires_at} onChange={(e) => set("expires_at", e.target.value)} />
        </window.M.Field>
        <window.M.Field label="Status">
          <window.M.Checkbox checked={data.is_active} onChange={(v) => set("is_active", v)} label="Active (clients can use this code)" />
        </window.M.Field>
      </window.M.FormGrid>
    </window.M.Modal>
  );
}

function AdminNotifications({ tok }) {
  const toast = window.useToast();
  const [tab, setTab] = React.useState("history");
  const [open, setOpen] = React.useState(false);
  const [scheduleMode, setScheduleMode] = React.useState(false);
  const [broadcasts, setBroadcasts] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  React.useEffect(() => {
    let alive = true;
    setBroadcasts(null);
    SB.adminGetBroadcasts(tok).then((b) => { if (alive) setBroadcasts(b || []); });
    return () => { alive = false; };
  }, [tok, reloadKey]);

  const reload = () => setReloadKey(k => k + 1);

  if (broadcasts === null) return <div className="page-enter"><window.LoadingState /></div>;

  const totalSent = broadcasts.reduce((s, b) => s + (b.recipient_count || 0), 0);

  return (
    <div className="page-enter">
      <S.PageHead
        eyebrow={`${broadcasts.length} broadcasts · ${totalSent.toLocaleString()} recipients`}
        title="Notifications"
        sub="Send in-app notifications to clients, vendors, and segments."
        right={<>
          <S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={() => { setScheduleMode(false); setOpen(true); }}>Send notification</S.Btn>
        </>}
      />

      <div className="grid-4" style={{ marginBottom: 24 }}>
        <S.Metric hero label="Total broadcasts" value={broadcasts.length.toString()} delta={`${totalSent.toLocaleString()} delivered`} />
        <S.Metric label="In the last 30 days" value={broadcasts.filter(b => (Date.now() - new Date(b.created_at).getTime()) < 30*24*3600*1000).length.toString()} />
        <S.Metric label="Recipients reached" value={totalSent.toLocaleString()} deltaTone="pos" />
        <S.Metric label="Most recent" value={broadcasts[0] ? window.fmtDate(broadcasts[0].created_at) : "—"} />
      </div>

      <div className="row" style={{ gap: 0, borderBottom: "1px solid var(--border)", marginBottom: 20 }}>
        {[{ k: "history", l: "Sent" }, { k: "automated", l: "Automated" }].map(t => (
          <button key={t.k} onClick={() => setTab(t.k)}
            style={{
              padding: "12px 18px", fontSize: 13, fontWeight: 500,
              color: tab === t.k ? "var(--ink)" : "var(--ink-3)",
              borderBottom: `2px solid ${tab === t.k ? "var(--ink)" : "transparent"}`,
              marginBottom: -1,
            }}>{t.l}</button>
        ))}
      </div>

      {tab === "history" ? (
        broadcasts.length === 0 ? (
          <window.EmptyState
            icon={<I.bell size={24} />}
            title="No notifications sent yet"
            sub="Send your first broadcast to reach users."
            action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />} onClick={() => setOpen(true)}>Send notification</S.Btn>}
          />
        ) : (
          <div className="card card-flush">
            <table className="tbl">
              <thead>
                <tr>
                  <th>Title</th>
                  <th>Audience</th>
                  <th>Channels</th>
                  <th className="col-num">Recipients</th>
                  <th>Sent</th>
                </tr>
              </thead>
              <tbody>
                {broadcasts.map((n) => (
                  <tr key={n.id}>
                    <td>
                      <div style={{ fontWeight: 500 }}>{n.title}</div>
                      <div className="muted tiny" style={{ marginTop: 2, maxWidth: 360, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{n.body}</div>
                    </td>
                    <td><S.Chip>{window.statusLabel(n.audience || "all")}</S.Chip></td>
                    <td>
                      <div className="row-tight" style={{ gap: 4 }}>
                        <span title="In-app" style={{ width: 26, height: 26, borderRadius: 7, fontSize: 10, fontWeight: 600, background: "var(--surface-3)", color: "var(--ink-2)", display: "inline-flex", alignItems: "center", justifyContent: "center" }}>
                          <I.bell size={12} />
                        </span>
                      </div>
                    </td>
                    <td className="col-num mono">{(n.recipient_count || 0).toLocaleString()}</td>
                    <td className="muted tiny">{window.fmtDate(n.created_at)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )
      ) : (
        <div className="card" style={{ padding: 22 }}>
          <window.DemoBanner feature="automated notification triggers" />
          <div className="muted" style={{ fontSize: 13 }}>
            Automated triggers (welcome, booking confirmation, payout sent) fire from the email/notification pipeline,
            not the admin broadcast UI. They're live in the backend; this tab will surface their delivery stats once
            metrics are wired in a later phase.
          </div>
        </div>
      )}

      <SendNotificationModal
        open={open}
        onClose={() => setOpen(false)}
        tok={tok}
        onSent={() => { setOpen(false); reload(); toast.success("Broadcast sent"); }}
      />
    </div>
  );
}

function SendNotificationModal({ open, onClose, tok, onSent }) {
  const toast = window.useToast();
  const [busy, setBusy] = React.useState(false);
  const [data, setData] = React.useState({
    audience: "all_users", title: "", body: "",
  });
  React.useEffect(() => { if (open) setData({ audience: "all_users", title: "", body: "" }); }, [open]);
  const set = (k, v) => setData(d => ({ ...d, [k]: v }));

  const submit = async () => {
    if (!data.title.trim()) { toast.error("Title is required"); return; }
    if (!data.body.trim())  { toast.error("Message body is required"); return; }
    setBusy(true);
    try {
      const r = await SB.adminBroadcastNotification({
        title: data.title.trim(),
        body: data.body.trim(),
        audience: data.audience,
        channel: "in-app",
      }, tok);
      if (!r.ok) { toast.error(r.message || "Broadcast failed"); return; }
      onSent?.();
    } finally {
      setBusy(false);
    }
  };

  return (
    <window.M.Modal open={open} onClose={onClose} size="lg"
      icon={<I.bell />} title="Send notification"
      subtitle="Compose and send to a segment immediately. Delivered in-app."
      footer={<>
        <S.Btn variant="ghost" onClick={onClose} disabled={busy}>Cancel</S.Btn>
        <S.Btn variant="primary" iconRight={<I.send size={14} />} onClick={submit} disabled={busy}>
          {busy ? "Sending…" : "Send now"}
        </S.Btn>
      </>}
    >
      <window.M.FormGrid>
        <window.M.Field full label="Audience" hint="Who should receive this notification?">
          <window.M.RadioCards value={data.audience} onChange={(v) => set("audience", v)}
            options={[
              { value: "all_users",   label: "All clients", desc: "Every client account" },
              { value: "all_vendors", label: "All vendors", desc: "Every vendor account" },
              { value: "all",         label: "Everyone",    desc: "Clients and vendors" },
            ]} />
        </window.M.Field>

        <window.M.Field full label="Title">
          <window.M.TextField value={data.title} onChange={(v) => set("title", v)} placeholder="Short, scannable headline" />
        </window.M.Field>
        <window.M.Field full label="Body">
          <window.M.Textarea value={data.body} onChange={(v) => set("body", v)} placeholder="Write what you want them to know." rows={5} />
        </window.M.Field>
      </window.M.FormGrid>
    </window.M.Modal>
  );
}

function ChannelTile({ checked, onClick, icon, label, hint }) {
  return (
    <button type="button" onClick={onClick} className="radio-card" data-checked={checked}
      style={{ flex: 1, flexDirection: "column", alignItems: "flex-start", padding: 14 }}>
      <div className="row between" style={{ width: "100%", marginBottom: 6 }}>
        <span style={{ color: checked ? "var(--accent-ink)" : "var(--ink-3)", display: "inline-flex" }}>{React.cloneElement(icon, { size: 16 })}</span>
        <span className="cb-box" data-checked={checked}>{checked && <I.check size={12} />}</span>
      </div>
      <div style={{ fontSize: 13, fontWeight: 500 }}>{label}</div>
      <div className="muted tiny">{hint}</div>
    </button>
  );
}

const SettingsContext = React.createContext({ values: {}, setValue: () => {}, save: () => {}, dirty: false, busy: false });

function AdminSettings({ tok }) {
  const toast = window.useToast();
  const [tab, setTab] = React.useState("general");
  const [values, setValues] = React.useState(null);
  const [original, setOriginal] = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  React.useEffect(() => {
    let alive = true;
    setValues(null);
    SB.adminGetSettings(tok).then((s) => {
      if (!alive) return;
      const v = s || {};
      setValues(v);
      setOriginal(JSON.stringify(v));
    });
    return () => { alive = false; };
  }, [tok]);

  if (values === null) return <div className="page-enter"><window.LoadingState /></div>;

  const dirty = JSON.stringify(values) !== original;
  const setValue = (k, v) => setValues(curr => ({ ...curr, [k]: v }));

  const save = async () => {
    setBusy(true);
    try {
      // Diff and save changed only
      const orig = JSON.parse(original || "{}");
      const changes = [];
      Object.keys(values).forEach(k => {
        if (JSON.stringify(values[k]) !== JSON.stringify(orig[k])) {
          changes.push([k, values[k]]);
        }
      });
      let okAll = true;
      for (const [k, v] of changes) {
        const r = await SB.adminSetSetting(k, v, tok);
        if (!r.ok) { toast.error(`Failed to save ${k}: ${r.message || ""}`); okAll = false; break; }
      }
      if (okAll && changes.length > 0) {
        toast.success(`Saved ${changes.length} setting${changes.length === 1 ? "" : "s"}`);
        setOriginal(JSON.stringify(values));
      } else if (changes.length === 0) {
        toast.info("Nothing to save");
      }
    } finally {
      setBusy(false);
    }
  };

  const ctx = { values, setValue, save, dirty, busy };

  return (
    <SettingsContext.Provider value={ctx}>
      <div className="page-enter">
        <S.PageHead
          eyebrow="Platform · global settings"
          title="Settings"
          sub="Branding, regions, security, billing, integrations & audit."
          right={<>
            <S.Btn variant="ghost" size="sm" onClick={() => { setValues(JSON.parse(original)); }} disabled={!dirty || busy}>Discard</S.Btn>
            <S.Btn variant="primary" size="sm" icon={<I.check size={14} />} onClick={save} disabled={!dirty || busy}>
              {busy ? "Saving…" : "Save changes"}
            </S.Btn>
          </>}
        />

        <div style={{ display: "grid", gridTemplateColumns: "240px 1fr", gap: 28, alignItems: "flex-start" }}>
          <aside className="card" style={{ padding: 8, position: "sticky", top: 0 }}>
            <nav className="col" style={{ gap: 2 }}>
              {[
                { section: "Platform" },
                { k: "general", l: "General", ic: I.settings },
                { k: "branding", l: "Branding", ic: I.sparkle },
                { k: "regions", l: "Regions & taxes", ic: I.location },
                { k: "fees", l: "Fees & pricing", ic: I.coupon },
                { section: "People" },
                { k: "team", l: "Admin team", ic: I.staff },
                { k: "roles", l: "Roles & permissions", ic: I.users },
                { section: "Security" },
                { k: "security", l: "Security policies", ic: I.help },
                { k: "session", l: "Sessions & devices", ic: I.panel },
                { k: "audit", l: "Audit log", ic: I.list },
                { section: "Billing" },
                { k: "billing", l: "Billing & invoices", ic: I.card },
                { section: "Developer" },
                { k: "integrations", l: "Integrations", ic: I.export },
                { k: "api", l: "API & webhooks", ic: I.chart },
              ].map((s, i) => {
                if (s.section) return <div key={`s${i}`} style={{
                  fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.12em",
                  textTransform: "uppercase", color: "var(--ink-4)",
                  padding: "14px 12px 6px",
                }}>{s.section}</div>;
                const Ic = s.ic;
                const active = tab === s.k;
                return (
                  <button key={s.k} onClick={() => setTab(s.k)}
                    className={`nav-item${active ? " active" : ""}`}
                    style={{ width: "100%", justifyContent: "flex-start" }}>
                    <span className="ni-icon"><Ic size={16} /></span>
                    <span className="ni-label">{s.l}</span>
                  </button>
                );
              })}
            </nav>
          </aside>

          <div>
            {tab === "general" && <SettingsGeneral />}
            {tab === "branding" && <SettingsBranding />}
            {tab === "regions" && <SettingsRegions />}
            {tab === "fees" && <SettingsFees />}
            {tab === "team" && <SettingsTeam />}
            {tab === "roles" && <SettingsRoles />}
            {tab === "security" && <SettingsSecurity />}
            {tab === "session" && <SettingsSessions />}
            {tab === "audit" && <SettingsAudit />}
            {tab === "billing" && <SettingsBilling />}
            {tab === "integrations" && <SettingsIntegrations />}
            {tab === "api" && <SettingsApi />}
          </div>
        </div>
      </div>
    </SettingsContext.Provider>
  );
}

function ASCard({ title, sub, children, action }) {
  return (
    <div className="card" style={{ padding: 28, marginBottom: 18 }}>
      <div className="row between" style={{ marginBottom: 20 }}>
        <div>
          <div className="h2" style={{ fontSize: 22 }}>{title}</div>
          {sub && <div className="muted" style={{ fontSize: 13, marginTop: 6 }}>{sub}</div>}
        </div>
        {action}
      </div>
      {children}
    </div>
  );
}

function ASRow({ label, hint, children, full }) {
  return (
    <div style={{
      display: "grid",
      gridTemplateColumns: full ? "1fr" : "220px 1fr",
      gap: 18, alignItems: "flex-start",
      padding: "14px 0", borderTop: "1px solid var(--border)",
    }}>
      <div>
        <div style={{ fontSize: 13, fontWeight: 500 }}>{label}</div>
        {hint && <div className="muted tiny" style={{ marginTop: 4 }}>{hint}</div>}
      </div>
      <div>{children}</div>
    </div>
  );
}

function ASToggle({ defaultOn, hint }) {
  const [on, setOn] = React.useState(!!defaultOn);
  return (
    <div className="row" style={{ gap: 14 }}>
      <button onClick={() => setOn(!on)} style={{
        width: 38, height: 22, borderRadius: 999,
        background: on ? "var(--accent)" : "var(--surface-3)",
        position: "relative", transition: "background 0.2s",
        border: "1px solid var(--border)",
      }}>
        <span style={{
          position: "absolute", top: 1, left: on ? 17 : 1, width: 18, height: 18, borderRadius: 999,
          background: "white", transition: "left 0.2s", boxShadow: "0 1px 3px rgba(0,0,0,0.20)",
        }} />
      </button>
      {hint && <span className="muted tiny">{hint}</span>}
    </div>
  );
}

function SettingsGeneral() {
  const { values, setValue } = React.useContext(SettingsContext);
  return (
    <ASCard title="General" sub="Core platform settings every page inherits from.">
      <ASRow label="Platform name">
        <S.Input value={values.platform_name || ""} onChange={(e) => setValue("platform_name", e.target.value)} style={{ maxWidth: 320 }} placeholder="Pamp" />
      </ASRow>
      <ASRow label="Public website" hint="Used in footer links and outbound emails.">
        <S.Input value={values.public_url || ""} onChange={(e) => setValue("public_url", e.target.value)} style={{ maxWidth: 320 }} placeholder="pamp.app" />
      </ASRow>
      <ASRow label="Support email" hint="Replies to this address surface in the Support inbox.">
        <S.Input icon={<I.mail size={14} />} value={values.support_email || ""} onChange={(e) => setValue("support_email", e.target.value)} style={{ maxWidth: 320 }} placeholder="hello@pamp.app" />
      </ASRow>
      <ASRow label="Default timezone">
        <select className="text-input" style={{ maxWidth: 320 }} value={values.timezone || "Africa/Accra"} onChange={(e) => setValue("timezone", e.target.value)}>
          <option value="Africa/Accra">Africa/Accra (GMT)</option>
          <option value="UTC">UTC · Coordinated</option>
          <option value="Europe/London">Europe/London</option>
          <option value="America/New_York">America/New_York</option>
          <option value="America/Los_Angeles">America/Los_Angeles</option>
          <option value="Asia/Singapore">Asia/Singapore</option>
        </select>
      </ASRow>
      <ASRow label="Currency">
        <select className="text-input" style={{ maxWidth: 320 }} value={values.currency || "USD"} onChange={(e) => setValue("currency", e.target.value)}>
          <option value="USD">USD · US Dollar</option>
          <option value="GHS">GHS · Ghanaian Cedi</option>
          <option value="EUR">EUR · Euro</option>
          <option value="GBP">GBP · British Pound</option>
        </select>
      </ASRow>
      <ASRow label="Booking fee %" hint="Platform commission on each booking.">
        <input className="text-input" type="number" min="0" max="100" step="0.1"
          style={{ maxWidth: 320 }}
          value={values.booking_fee_pct ?? 10}
          onChange={(e) => setValue("booking_fee_pct", parseFloat(e.target.value) || 0)} />
      </ASRow>
    </ASCard>
  );
}

function SettingsBranding() {
  const { values, setValue } = React.useContext(SettingsContext);
  return (
    <>
      <ASCard title="Brand identity" sub="What appears across the app, emails, and receipts.">
        <ASRow label="Logo URL" hint="Public URL to your logo. Shown on landing + auth pages.">
          <S.Input value={values.logo_url || ""} onChange={(e) => setValue("logo_url", e.target.value)} style={{ maxWidth: 420 }} placeholder="https://yourdomain.com/logo.png" />
        </ASRow>
        {values.logo_url && (
          <ASRow label="Preview">
            <div className="row" style={{ gap: 12, alignItems: "center" }}>
              <img src={values.logo_url} alt="Logo preview" style={{ width: 56, height: 56, borderRadius: 14, objectFit: "cover" }} onError={(e) => { e.target.style.display = "none"; }} />
              <div className="muted tiny">Renders 56×56 in nav, scales on landing.</div>
            </div>
          </ASRow>
        )}
        <ASRow label="Email signature" hint="Appended to every transactional email.">
          <textarea className="text-input" rows={3}
            value={values.email_signature || ""}
            onChange={(e) => setValue("email_signature", e.target.value)}
            placeholder="— The Pamp team · pamp.app · unsubscribe" />
        </ASRow>
      </ASCard>
    </>
  );
}

function SettingsRegions() {
  return (
    <ASCard
      title="Regions & taxes"
      sub="Where Pamp operates and how money is collected."
      action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />}>Add region</S.Btn>}
    >
      <table className="tbl" style={{ marginTop: -10 }}>
        <thead>
          <tr>
            <th>Region</th>
            <th>Currency</th>
            <th>Tax rate</th>
            <th>Tax authority</th>
            <th>Status</th>
            <th />
          </tr>
        </thead>
        <tbody>
          {[
            { r: "United States", c: "USD", t: "Pass-through", a: "State sales tax", s: "Live", st: "pos" },
            { r: "United Kingdom", c: "GBP", t: "20% VAT", a: "HMRC · GB142180", s: "Live", st: "pos" },
            { r: "European Union", c: "EUR", t: "21% VAT (avg)", a: "Per country · OSS", s: "Live", st: "pos" },
            { r: "Canada", c: "CAD", t: "5% GST + HST", a: "CRA", s: "Live", st: "pos" },
            { r: "Australia", c: "AUD", t: "10% GST", a: "ATO", s: "Pending", st: "warn" },
            { r: "Japan", c: "JPY", t: "10% consumption", a: "NTA", s: "Draft", st: "info" },
          ].map((r) => (
            <tr key={r.r}>
              <td style={{ fontWeight: 500 }}>{r.r}</td>
              <td className="mono">{r.c}</td>
              <td>{r.t}</td>
              <td className="muted tiny">{r.a}</td>
              <td><S.Chip tone={r.st}>{r.s}</S.Chip></td>
              <td><S.IconBtn><I.ellipsis size={16} /></S.IconBtn></td>
            </tr>
          ))}
        </tbody>
      </table>
    </ASCard>
  );
}

function SettingsFees() {
  return (
    <ASCard title="Fees & pricing" sub="Default platform fees per vendor plan.">
      {[
        { plan: "Starter", fee: "5.0%", subs: "Free" },
        { plan: "Studio", fee: "3.5%", subs: "$49 /mo" },
        { plan: "Atelier", fee: "2.4%", subs: "$149 /mo" },
        { plan: "Enterprise", fee: "Custom", subs: "Custom" },
      ].map((p) => (
        <ASRow key={p.plan} label={p.plan} hint={`Subscription · ${p.subs}`}>
          <div className="row" style={{ gap: 12 }}>
            <S.Input value={p.fee} onChange={() => { }} style={{ maxWidth: 140 }} />
            <span className="muted tiny" style={{ alignSelf: "center" }}>per booking · taken from vendor net</span>
          </div>
        </ASRow>
      ))}
      <ASRow label="Refund handling" hint="What happens to platform fees when bookings are refunded.">
        <window.M.RadioCards value="prorate" onChange={() => { }} options={[
          { value: "prorate", label: "Pro-rate fees", desc: "Refund a proportional slice of the fee with each refund." },
          { value: "keep", label: "Keep fees", desc: "Vendor absorbs the platform fee on refund." },
          { value: "release", label: "Release fees", desc: "Pamp returns the fee in full." },
        ]} />
      </ASRow>
    </ASCard>
  );
}

function SettingsTeam() {
  return (
    <ASCard
      title="Admin team"
      sub="People with access to this dashboard."
      action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />}>Invite admin</S.Btn>}
    >
      <table className="tbl" style={{ marginTop: -10 }}>
        <thead>
          <tr><th>Member</th><th>Role</th><th>2FA</th><th>Last active</th><th /></tr>
        </thead>
        <tbody>
          {[
            { n: "Mira Johnson", e: "mira.j@pamp.app", r: "Owner", t: true, l: "Online now" },
            { n: "Eli Rosenberg", e: "eli.r@pamp.app", r: "Support lead", t: true, l: "12m ago" },
            { n: "Olu Adeyemi", e: "olu.a@pamp.app", r: "Finance", t: true, l: "1h ago" },
            { n: "Sasha Ivanov", e: "sasha.i@pamp.app", r: "Trust & safety", t: false, l: "Yesterday" },
          ].map((m) => (
            <tr key={m.e}>
              <td>
                <div className="row-tight">
                  <S.Avatar name={m.n} size="sm" />
                  <div>
                    <div style={{ fontWeight: 500 }}>{m.n}</div>
                    <div className="muted tiny">{m.e}</div>
                  </div>
                </div>
              </td>
              <td><S.Chip tone="accent">{m.r}</S.Chip></td>
              <td>{m.t ? <S.Chip tone="pos">Enabled</S.Chip> : <S.Chip tone="warn">Not set</S.Chip>}</td>
              <td className="muted tiny">{m.l}</td>
              <td><S.IconBtn><I.ellipsis size={16} /></S.IconBtn></td>
            </tr>
          ))}
        </tbody>
      </table>
    </ASCard>
  );
}

function SettingsRoles() {
  const matrix = [
    { area: "Users", o: true, s: true, f: false, t: true },
    { area: "Bookings", o: true, s: true, f: true, t: true },
    { area: "Payments", o: true, s: false, f: true, t: false },
    { area: "Payouts", o: true, s: false, f: true, t: false },
    { area: "Coupons", o: true, s: true, f: false, t: false },
    { area: "Support", o: true, s: true, f: false, t: true },
    { area: "Reports", o: true, s: true, f: true, t: true },
    { area: "Settings", o: true, s: false, f: false, t: false },
  ];
  const Cell = ({ v }) => v ? <I.check size={14} color="var(--pos)" /> : <I.x size={14} color="var(--ink-4)" />;
  return (
    <ASCard title="Roles & permissions" sub="What each admin role can see and change.">
      <table className="tbl" style={{ marginTop: -10 }}>
        <thead>
          <tr><th>Area</th><th>Owner</th><th>Support</th><th>Finance</th><th>Trust & safety</th></tr>
        </thead>
        <tbody>
          {matrix.map(r => (
            <tr key={r.area}>
              <td style={{ fontWeight: 500 }}>{r.area}</td>
              <td><Cell v={r.o} /></td>
              <td><Cell v={r.s} /></td>
              <td><Cell v={r.f} /></td>
              <td><Cell v={r.t} /></td>
            </tr>
          ))}
        </tbody>
      </table>
    </ASCard>
  );
}

function SettingsSecurity() {
  return (
    <ASCard title="Security policies" sub="How admins log in and stay safe.">
      <ASRow label="Require 2FA for admins" hint="All admins must enable an authenticator app.">
        <ASToggle defaultOn />
      </ASRow>
      <ASRow label="Single sign-on (SAML)" hint="Use your identity provider for admin login.">
        <ASToggle defaultOn />
      </ASRow>
      <ASRow label="IP allowlist" hint="Only requests from listed CIDR ranges can sign in.">
        <ASToggle />
      </ASRow>
      <ASRow label="Session timeout">
        <window.M.Segmented value="30" onChange={() => { }}
          options={[{ value: "15", label: "15 min" }, { value: "30", label: "30 min" }, { value: "60", label: "1 hr" }, { value: "8h", label: "8 hrs" }]} />
      </ASRow>
      <ASRow label="Password policy" hint="Minimum strength for new admin passwords.">
        <window.M.Segmented value="strong" onChange={() => { }}
          options={[{ value: "basic", label: "Basic" }, { value: "strong", label: "Strong" }, { value: "fips", label: "FIPS" }]} />
      </ASRow>
      <ASRow label="Auto-lock dormant admins" hint="Disable accounts inactive for over 60 days.">
        <ASToggle defaultOn />
      </ASRow>
    </ASCard>
  );
}

function SettingsSessions() {
  return (
    <ASCard title="Active admin sessions" sub="Sign anyone out if a device looks unfamiliar.">
      <table className="tbl" style={{ marginTop: -10 }}>
        <thead><tr><th>Member</th><th>Device</th><th>Location</th><th>Last seen</th><th /></tr></thead>
        <tbody>
          {[
            { n: "Mira Johnson", d: "MacBook Pro · Chrome", l: "San Francisco, US", t: "Online now" },
            { n: "Mira Johnson", d: "iPhone 15 · Safari", l: "San Francisco, US", t: "4h ago" },
            { n: "Eli Rosenberg", d: "MacBook Air · Safari", l: "Berlin, DE", t: "12m ago" },
            { n: "Olu Adeyemi", d: "Linux · Firefox", l: "Lagos, NG", t: "1h ago" },
          ].map((s, i) => (
            <tr key={i}>
              <td>{s.n}</td>
              <td className="muted">{s.d}</td>
              <td className="muted tiny">{s.l}</td>
              <td className="mono tiny">{s.t}</td>
              <td><S.Btn variant="ghost" size="sm" style={{ color: "var(--neg)" }}>Sign out</S.Btn></td>
            </tr>
          ))}
        </tbody>
      </table>
      <div className="row" style={{ marginTop: 16 }}>
        <div className="spacer" />
        <S.Btn variant="outline" size="sm" style={{ color: "var(--neg)", borderColor: "var(--neg)" }}>Sign out all other sessions</S.Btn>
      </div>
    </ASCard>
  );
}

function SettingsAudit() {
  return (
    <ASCard
      title="Audit log"
      sub="Every sensitive admin action, with who and when."
      action={<S.Btn variant="outline" size="sm" icon={<I.download size={12} />}>Export CSV</S.Btn>}
    >
      <table className="tbl" style={{ marginTop: -10 }}>
        <thead><tr><th>When</th><th>Member</th><th>Action</th><th>Target</th><th>IP</th></tr></thead>
        <tbody>
          {[
            { t: "2m ago", n: "Mira Johnson", a: "Authorized transfer", o: "Operating → Payroll · $148,420", ip: "73.118.221.42" },
            { t: "12m ago", n: "Olu Adeyemi", a: "Approved payout", o: "PR-9239 · Atelier Nails", ip: "102.89.10.18" },
            { t: "1h ago", n: "Eli Rosenberg", a: "Refund issued", o: "PB-28405 · $142", ip: "82.220.190.4" },
            { t: "3h ago", n: "Sasha Ivanov", a: "Suspended user", o: "Client #6 · Olivia Wright", ip: "203.0.113.42" },
            { t: "Yesterday", n: "Mira Johnson", a: "Updated branding", o: "Primary accent · #86D694", ip: "73.118.221.42" },
            { t: "Yesterday", n: "Olu Adeyemi", a: "Created coupon", o: "WELLNESS25", ip: "102.89.10.18" },
          ].map((r, i) => (
            <tr key={i}>
              <td className="mono tiny">{r.t}</td>
              <td>{r.n}</td>
              <td><S.Chip>{r.a}</S.Chip></td>
              <td className="muted tiny">{r.o}</td>
              <td className="mono tiny muted">{r.ip}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </ASCard>
  );
}

function SettingsBilling() {
  return (
    <>
      <ASCard title="Billing" sub="How you pay for Pamp infrastructure & services.">
        <div className="grid-3" style={{ gap: 14, marginBottom: 8 }}>
          <div style={{ padding: 18, borderRadius: 14, background: "var(--ink)", color: "var(--bg)", position: "relative", overflow: "hidden", minHeight: 130 }}>
            <div style={{ position: "absolute", inset: 0, opacity: 0.4, background: "radial-gradient(circle at 90% 20%, var(--accent), transparent 60%)" }} />
            <div style={{ position: "relative" }}>
              <div className="eyebrow" style={{ color: "oklch(75% 0.02 145)" }}>Plan</div>
              <div className="display" style={{ fontSize: 28, marginTop: 6 }}>Enterprise</div>
              <div className="muted tiny" style={{ color: "oklch(75% 0.02 145)", marginTop: 4 }}>Renews Jan 1, 2027</div>
            </div>
          </div>
          <div style={{ padding: 18, borderRadius: 14, border: "1px solid var(--border)", minHeight: 130 }}>
            <div className="eyebrow">Monthly cost</div>
            <div className="display" style={{ fontSize: 28, marginTop: 6 }}>$4,800</div>
            <div className="muted tiny">Includes 50k MAU</div>
          </div>
          <div style={{ padding: 18, borderRadius: 14, border: "1px solid var(--border)", minHeight: 130 }}>
            <div className="eyebrow">Card on file</div>
            <div style={{ fontSize: 18, marginTop: 6, fontWeight: 500 }}>Visa ····4218</div>
            <div className="muted tiny">Expires 11/27</div>
          </div>
        </div>
      </ASCard>
      <ASCard title="Invoices" sub="Receipts from your last twelve months.">
        <table className="tbl" style={{ marginTop: -10 }}>
          <thead><tr><th>Date</th><th>Period</th><th>Amount</th><th>Status</th><th /></tr></thead>
          <tbody>
            {[
              { d: "Feb 1, 2026", p: "Jan 2026", a: 4800, s: "Paid", st: "pos" },
              { d: "Jan 1, 2026", p: "Dec 2025", a: 4800, s: "Paid", st: "pos" },
              { d: "Dec 1, 2025", p: "Nov 2025", a: 4800, s: "Paid", st: "pos" },
              { d: "Nov 1, 2025", p: "Oct 2025", a: 4800, s: "Paid", st: "pos" },
            ].map(r => (
              <tr key={r.d}>
                <td className="mono">{r.d}</td>
                <td className="muted">{r.p}</td>
                <td className="mono">${r.a.toLocaleString()}</td>
                <td><S.Chip tone={r.st}>{r.s}</S.Chip></td>
                <td><S.IconBtn><I.download size={14} /></S.IconBtn></td>
              </tr>
            ))}
          </tbody>
        </table>
      </ASCard>
    </>
  );
}

function SettingsIntegrations() {
  const items = [
    { n: "Stripe", d: "Payments, payouts, disputes", on: true, c: "var(--info)" },
    { n: "Twilio", d: "SMS reminders & confirmations", on: true, c: "var(--neg)" },
    { n: "SendGrid", d: "Transactional email delivery", on: true, c: "var(--ink)" },
    { n: "Segment", d: "Event pipeline to analytics tools", on: true, c: "var(--accent)" },
    { n: "Slack", d: "Ops alerts to #pamp-ops", on: true, c: "var(--warn)" },
    { n: "Zendesk", d: "Mirror support tickets", on: false, c: "var(--info)" },
    { n: "Google Calendar", d: "Sync appointments to calendars", on: true, c: "var(--pos)" },
    { n: "Datadog", d: "Logs & traces from API", on: true, c: "var(--accent-ink)" },
  ];
  return (
    <ASCard
      title="Integrations"
      sub="Third-party services connected to Pamp."
      action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />}>Add integration</S.Btn>}
    >
      <div className="grid-2" style={{ gap: 12 }}>
        {items.map(i => (
          <div key={i.n} className="row" style={{ padding: 16, borderRadius: 12, border: "1px solid var(--border)", gap: 14 }}>
            <div style={{
              width: 40, height: 40, borderRadius: 10, background: "var(--surface-2)",
              display: "flex", alignItems: "center", justifyContent: "center",
              color: i.c, fontFamily: "var(--font-display)", fontSize: 18, fontWeight: 600,
            }}>{i.n[0]}</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>{i.n}</div>
              <div className="muted tiny">{i.d}</div>
            </div>
            <div className="row-tight">
              <S.Chip tone={i.on ? "pos" : ""}>{i.on ? "Connected" : "Off"}</S.Chip>
              <S.IconBtn><I.chevR size={14} /></S.IconBtn>
            </div>
          </div>
        ))}
      </div>
    </ASCard>
  );
}

function SettingsApi() {
  return (
    <>
      <ASCard
        title="API keys"
        sub="Server-to-server credentials. Treat like passwords."
        action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />}>Create key</S.Btn>}
      >
        <table className="tbl" style={{ marginTop: -10 }}>
          <thead><tr><th>Label</th><th>Token</th><th>Scopes</th><th>Created</th><th>Last used</th><th /></tr></thead>
          <tbody>
            {[
              { n: "Production · core", t: "sk_live_•••••••••2418", s: "All", c: "Jan 14, 2024", l: "12m ago" },
              { n: "Mobile read-only", t: "pk_live_•••••••••8210", s: "Read", c: "Mar 02, 2024", l: "2m ago" },
              { n: "Internal · CI", t: "sk_test_•••••••••4218", s: "Sandbox", c: "Aug 11, 2024", l: "1h ago" },
            ].map((k, i) => (
              <tr key={i}>
                <td style={{ fontWeight: 500 }}>{k.n}</td>
                <td className="mono tiny muted">{k.t}</td>
                <td><S.Chip>{k.s}</S.Chip></td>
                <td className="mono tiny muted">{k.c}</td>
                <td className="muted tiny">{k.l}</td>
                <td><S.IconBtn><I.ellipsis size={16} /></S.IconBtn></td>
              </tr>
            ))}
          </tbody>
        </table>
      </ASCard>

      <ASCard
        title="Webhooks"
        sub="Where Pamp posts realtime events."
        action={<S.Btn variant="primary" size="sm" icon={<I.plus size={14} />}>Add endpoint</S.Btn>}
      >
        <div className="col" style={{ gap: 10 }}>
          {[
            { u: "https://api.maisoncolor.fr/pamp/hook", ev: ["booking.created", "booking.cancelled"], s: "Live", st: "pos" },
            { u: "https://hooks.zapier.com/hooks/catch/12/pamp", ev: ["payout.sent"], s: "Live", st: "pos" },
            { u: "https://internal.pamp.app/webhook/audit", ev: ["audit.*"], s: "Failing", st: "neg" },
          ].map((w, i) => (
            <div key={i} className="row" style={{ padding: 14, border: "1px solid var(--border)", borderRadius: 12, gap: 14 }}>
              <I.chart size={16} color="var(--ink-3)" />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div className="mono tiny" style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{w.u}</div>
                <div className="row-tight" style={{ marginTop: 4 }}>
                  {w.ev.map(e => <span key={e} className="chip" style={{ height: 20, fontSize: 10.5 }}>{e}</span>)}
                </div>
              </div>
              <S.Chip tone={w.st}>{w.s}</S.Chip>
              <S.IconBtn><I.ellipsis size={16} /></S.IconBtn>
            </div>
          ))}
        </div>
      </ASCard>
    </>
  );
}

window.AdminApp = AdminApp;
