// Vanday DAM — settings (account, users, fields, billing)
function SettingsSidebar({ section, setSection }) {
  const features = (typeof window.useVandayFeatures === "function")
    ? window.useVandayFeatures()
    : null;
  // Only workspace admins may see the Workspace, Plan, and Admin settings.
  // Non-admin members (editor/contributor/viewer) get just their personal
  // settings. Default to admin BEFORE /api/me loads so an admin doesn't see
  // their menu briefly collapse on first paint.
  const isWsAdmin = features ? features.isWorkspaceAdmin === true : true;
  // Beta hides most admin/account surfaces. The settings panel itself stays
  // accessible — just with a much smaller menu. Each item below is gated on
  // a specific feature flag so dev mode shows the full prototype.
  const allItems = [
    { group: "Personal", items: [
      { id: "profile",     name: "Profile",       icon: <IcUsers size={15} />, show: true },
      { id: "notifs",      name: "Notifications", icon: <IcBell size={15} />,  show: !features || features.notifications },
    ]},
    { group: "Workspace", items: [
      { id: "workspace",   name: "Members & invites", icon: <IcUsers size={15} />, show: isWsAdmin },
    ]},
    { group: "Account", items: [
      { id: "usage",    name: "Usage",    icon: <IcGrid size={15} />,  show: !features || features.usageBilling },
      { id: "plan",     name: "Plan",     icon: <IcCard size={15} />,  show: isWsAdmin },
      { id: "billing",  name: "Billing",  icon: <IcCard size={15} />,  show: !features || features.usageBilling },
      { id: "branding", name: "Branding", icon: <IcImage size={15} />, show: !features || features.branding },
    ]},
    { group: "Admin", items: [
      { id: "users",        name: "Users & permissions", icon: <IcUsers size={15} />, show: isWsAdmin },
      { id: "projects",     name: "Projects",         icon: <IcFolder size={15} />,   show: isWsAdmin && (!features || features.projects) },
      { id: "fields",       name: "Fields",           icon: <IcTag size={15} />,      show: isWsAdmin },
      { id: "workflow",     name: "Workflow labels",  icon: <IcEye size={15} />,      show: isWsAdmin },
      { id: "integrations", name: "Integrations",     icon: <IcLink size={15} />,     show: isWsAdmin /* unified hub: social + storage + design tools, one page */ },
      { id: "api",          name: "API & webhooks",   icon: <IcExternal size={15} />, show: isWsAdmin && (!features || features.apiKeys || features.webhooks) },
      { id: "audit",        name: "Audit log",        icon: <IcEye size={15} />,      show: isWsAdmin && (!features || features.audit) },
      { id: "security",     name: "Content security", icon: <IcShield size={15} />,   show: isWsAdmin && (!features || features.contentSecurity) },
      // Admin-only: toggle paid-tier feature flags per beta account.
      { id: "flags",        name: "Feature flags",    icon: <IcSettings size={15} />, show: features?.isAdmin === true },
    ]},
  ];
  const sections = allItems
    .map((g) => ({ ...g, items: g.items.filter((i) => i.show) }))
    .filter((g) => g.items.length > 0);

  return (
    <aside className="sidebar">
      {sections.map((s) => (
        <React.Fragment key={s.group}>
          <div className="sidebar-header">
            <span className="sidebar-title">{s.group}</span>
          </div>
          <div className="sidebar-section">
            {s.items.map((i) => (
              <button
                key={i.id}
                className={`sidebar-item ${section === i.id ? "active" : ""}`}
                onClick={() => setSection(i.id)}
              >
                <span className="ic">{i.icon}</span>
                {i.name}
              </button>
            ))}
          </div>
        </React.Fragment>
      ))}
      <div className="rail-spacer" />
      <div style={{ padding: "14px 18px", fontSize: 12, color: "var(--text-faint)", borderTop: "1px solid var(--border)" }}>
        Legal notices
      </div>
    </aside>
  );
}

// Settings → Workspace. During the beta every account has a single workspace
// and can't create additional ones — multiple workspaces are a planned
// feature. Member management lives under "Users & permissions". This section
// just sets expectations with a "coming soon" message.
function WorkspaceSection() {
  const me = (typeof window.useVandayMe === "function") ? window.useVandayMe() : null;
  const features = (typeof window.useVandayFeatures === "function") ? window.useVandayFeatures() : null;
  const isWsAdmin = features ? features.isWorkspaceAdmin === true : true;
  const currentName = (me && me.org && me.org.name) || "";

  const [name, setName] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [saved, setSaved] = React.useState(false);
  const [seeded, setSeeded] = React.useState(false);

  // Hydrate the field from /api/me once it loads.
  React.useEffect(() => {
    if (currentName && !seeded) { setName(currentName); setSeeded(true); }
  }, [currentName, seeded]);

  const dirty = name.trim().replace(/\s+/g, " ") !== currentName && name.trim() !== "";
  const saveName = async () => {
    const next = name.trim().replace(/\s+/g, " ");
    if (!next || busy) return;
    setBusy(true);
    setSaved(false);
    try {
      await window.VandayAPI.setOrgName(next);
      if (window.VandayMe) await window.VandayMe.fetchMe();
      setSaved(true);
      setTimeout(() => setSaved(false), 2500);
    } catch (e) {
      const code = (e && e.data && e.data.error) || e.message || "";
      window.alert(
        code.includes("name_too_long") ? "That name is too long — keep it under 60 characters."
          : code.includes("bad_name") ? "Please enter a workspace name."
            : code.includes("not_admin") ? "Only a workspace admin can rename the workspace."
              : `Couldn't save the name: ${e.message || "error"}`,
      );
    } finally {
      setBusy(false);
    }
  };

  return (
    <div style={{ maxWidth: 820 }}>
      <h1 className="settings-h1">Workspaces</h1>
      <p className="settings-sub" style={{ marginBottom: 20 }}>
        Manage the workspaces your account belongs to.
      </p>

      <div className="section-card" style={{ marginBottom: 18 }}>
        <div style={{ fontWeight: 600, fontSize: 14, marginBottom: 4 }}>Workspace name</div>
        <p className="settings-sub" style={{ margin: "0 0 14px" }}>
          {isWsAdmin
            ? "Shown in the top-left of the app and in the breadcrumb."
            : "The name shown in the top-left of the app. Only a workspace admin can change it."}
        </p>
        <div style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
          <input
            type="text"
            value={name}
            onChange={(e) => setName(e.target.value)}
            maxLength={60}
            disabled={!isWsAdmin || busy}
            placeholder="e.g. Vanday Studio"
            style={{
              flex: 1, minWidth: 240,
              padding: "9px 12px", borderRadius: 8,
              border: "1px solid var(--border)", background: "var(--surface)",
              color: "var(--text)", fontSize: 14, fontFamily: "inherit",
            }}
          />
          {isWsAdmin && (
            <button className="btn accent" disabled={!dirty || busy} onClick={saveName}>
              {busy ? "Saving…" : saved ? "Saved" : "Save"}
            </button>
          )}
        </div>
      </div>

      <div
        className="section-card"
        style={{ padding: 40, textAlign: "center" }}
      >
        <div style={{
          width: 56, height: 56, borderRadius: 14, margin: "0 auto 16px",
          background: "var(--accent-soft)", color: "var(--accent)",
          display: "grid", placeItems: "center",
        }}><IcSparkles size={24} /></div>
        <div style={{ fontSize: 15, fontWeight: 600, marginBottom: 6 }}>
          Multiple workspaces are coming soon
        </div>
        <p style={{ fontSize: 13, color: "var(--text-muted)", maxWidth: 460, margin: "0 auto", lineHeight: 1.55 }}>
          For now you have a single workspace on the free beta plan. The ability
          to create and switch between additional workspaces will arrive with
          paid plans. To invite teammates to your current workspace, head to
          <strong> Users &amp; permissions</strong>.
        </p>
      </div>
    </div>
  );
}

// Pull a human-readable message out of a Clerk error (or anything else).
function clerkErrText(e) {
  if (e && Array.isArray(e.errors) && e.errors[0]) {
    return e.errors[0].longMessage || e.errors[0].message || "Something went wrong.";
  }
  return (e && e.message) || "Something went wrong.";
}

// Profile — a custom, Vanday-styled account panel whose controls write back
// to Clerk's client SDK (window.Clerk.user). Name, avatar, password and
// two-factor all persist for real. Falls back to read-only rows when Clerk
// isn't present (e.g. the static prototype).
function ProfileSection() {
  const [, force] = React.useReducer((x) => x + 1, 0);
  const [hasClerk, setHasClerk] = React.useState(!!window.Clerk);

  // Wait for Clerk to finish loading, then re-render on any user change so
  // the rows reflect saved edits without a refresh.
  React.useEffect(() => {
    if (!window.Clerk) {
      const onReady = () => { setHasClerk(true); force(); };
      window.addEventListener("clerk-ready", onReady);
      return () => window.removeEventListener("clerk-ready", onReady);
    }
    setHasClerk(true);
    let unsub;
    try { unsub = window.Clerk.addListener(() => force()); } catch {}
    return () => { try { unsub && unsub(); } catch {} };
  }, [hasClerk]);

  const user = (window.Clerk && window.Clerk.user) || null;
  const sessionUser = window.VandaySession ? window.VandaySession.getActiveUser() : null;
  const role = sessionUser ? sessionUser.role : null;
  // Deleting the account also tears down the whole workspace, so only a
  // workspace admin may do it. Invited members can't delete a workspace that
  // isn't theirs — an admin removes them instead. Default to true while /api/me
  // loads (solo/personal users are admins of their own workspace).
  const features = (typeof window.useVandayFeatures === "function") ? window.useVandayFeatures() : null;
  const isWsAdmin = features ? features.isWorkspaceAdmin === true : true;

  // ----- editable name -----
  const [editingName, setEditingName] = React.useState(false);
  const [firstName, setFirstName] = React.useState("");
  const [lastName, setLastName] = React.useState("");
  const [nameBusy, setNameBusy] = React.useState(false);
  const startEditName = () => {
    setFirstName(user ? (user.firstName || "") : "");
    setLastName(user ? (user.lastName || "") : "");
    setEditingName(true);
  };
  const saveName = async () => {
    if (!user) return;
    setNameBusy(true);
    try {
      await user.update({ firstName: firstName.trim(), lastName: lastName.trim() });
      setEditingName(false);
    } catch (e) { window.alert(clerkErrText(e)); }
    setNameBusy(false);
  };

  // ----- avatar -----
  const fileRef = React.useRef(null);
  const [avatarBusy, setAvatarBusy] = React.useState(false);
  const onPickPhoto = async (e) => {
    const file = e.target.files && e.target.files[0];
    e.target.value = "";
    if (!file || !user) return;
    setAvatarBusy(true);
    try { await user.setProfileImage({ file }); }
    catch (err) { window.alert(clerkErrText(err)); }
    setAvatarBusy(false);
  };

  // ----- password -----
  const [pwOpen, setPwOpen] = React.useState(false);
  const [curPw, setCurPw] = React.useState("");
  const [newPw, setNewPw] = React.useState("");
  const [confirmPw, setConfirmPw] = React.useState("");
  const [pwBusy, setPwBusy] = React.useState(false);
  const [pwMsg, setPwMsg] = React.useState(null); // { ok, text }
  const passwordEnabled = !!(user && user.passwordEnabled);
  const submitPassword = async () => {
    if (!user) return;
    setPwMsg(null);
    if (newPw.length < 8) { setPwMsg({ ok: false, text: "Use at least 8 characters." }); return; }
    if (newPw !== confirmPw) { setPwMsg({ ok: false, text: "The two passwords don't match." }); return; }
    setPwBusy(true);
    try {
      const params = { newPassword: newPw, signOutOfOtherSessions: false };
      if (passwordEnabled) params.currentPassword = curPw;
      await user.updatePassword(params);
      setPwMsg({ ok: true, text: passwordEnabled ? "Password updated." : "Password set." });
      setCurPw(""); setNewPw(""); setConfirmPw("");
      setTimeout(() => { setPwOpen(false); setPwMsg(null); }, 1200);
    } catch (e) { setPwMsg({ ok: false, text: clerkErrText(e) }); }
    setPwBusy(false);
  };

  // ----- two-factor (TOTP) -----
  const totpEnabled = !!(user && user.totpEnabled);
  const [totp, setTotp] = React.useState(null); // { secret, uri } during setup
  const [totpCode, setTotpCode] = React.useState("");
  const [twoFABusy, setTwoFABusy] = React.useState(false);
  const [twoFAMsg, setTwoFAMsg] = React.useState(null);
  const beginTotp = async () => {
    if (!user) return;
    setTwoFABusy(true); setTwoFAMsg(null);
    try {
      const t = await user.createTOTP();
      setTotp({ secret: t.secret, uri: t.uri });
    } catch (e) { setTwoFAMsg({ ok: false, text: clerkErrText(e) }); }
    setTwoFABusy(false);
  };
  const verifyTotp = async () => {
    if (!user) return;
    setTwoFABusy(true); setTwoFAMsg(null);
    try {
      await user.verifyTOTP({ code: totpCode.trim() });
      setTotp(null); setTotpCode("");
      setTwoFAMsg({ ok: true, text: "Two-factor authentication is on." });
    } catch (e) { setTwoFAMsg({ ok: false, text: clerkErrText(e) }); }
    setTwoFABusy(false);
  };
  const disableTotp = async () => {
    if (!user) return;
    if (!window.confirm("Turn off two-factor authentication?")) return;
    setTwoFABusy(true); setTwoFAMsg(null);
    try { await user.disableTOTP(); setTwoFAMsg(null); }
    catch (e) { setTwoFAMsg({ ok: false, text: clerkErrText(e) }); }
    setTwoFABusy(false);
  };

  // Display values.
  const fullName = user ? (user.fullName || [user.firstName, user.lastName].filter(Boolean).join(" ") || "—")
    : (sessionUser ? sessionUser.name : "—");
  const email = user ? (user.primaryEmailAddress && user.primaryEmailAddress.emailAddress) || "—"
    : (sessionUser ? sessionUser.email : "—");
  const initials = (fullName && fullName !== "—")
    ? fullName.split(/[\s._-]+/).filter(Boolean).slice(0, 2).map((s) => s[0].toUpperCase()).join("")
    : "?";
  const hasImage = !!(user && user.hasImage && user.imageUrl);

  const inputStyle = {
    width: "100%", background: "var(--surface)", border: "1px solid var(--border)",
    borderRadius: 8, padding: "9px 11px", fontSize: 13, outline: "none",
  };

  // ----- delete account (destructive, irreversible) -----
  const [delOpen, setDelOpen] = React.useState(false);
  const [delText, setDelText] = React.useState("");
  const [delBusy, setDelBusy] = React.useState(false);
  const [delErr, setDelErr] = React.useState(null);
  const delReady = delText.trim().toUpperCase() === "DELETE";
  const confirmDelete = async () => {
    if (!delReady) return;
    setDelBusy(true); setDelErr(null);
    try {
      await window.VandayAPI.deleteAccount();
      // Everything is gone server-side, including the Clerk login. Sign out
      // locally and bounce to the home/sign-in screen.
      try { if (window.Clerk) await window.Clerk.signOut(); } catch {}
      window.location.href = "/";
    } catch (e) {
      setDelErr((e && e.message) || "Could not delete your account. Please try again.");
      setDelBusy(false);
    }
  };

  return (
    <div style={{ maxWidth: 820 }}>
      <h1 className="settings-h1">Profile</h1>
      <p className="settings-sub">Your account details — changes save to your sign-in.</p>

      <div className="section-card">
        {/* Avatar */}
        <div style={{ display: "flex", gap: 22, alignItems: "center", marginBottom: 22 }}>
          <div style={{
            width: 64, height: 64, borderRadius: 16, overflow: "hidden",
            background: (sessionUser && sessionUser.color) || "var(--accent)", color: "white",
            display: "grid", placeItems: "center", fontWeight: 600, fontSize: 22,
            backgroundImage: hasImage ? `url(${user.imageUrl})` : undefined,
            backgroundSize: "cover", backgroundPosition: "center",
          }}>{hasImage ? "" : initials}</div>
          <div>
            <input ref={fileRef} type="file" accept="image/png,image/jpeg" style={{ display: "none" }} onChange={onPickPhoto} />
            <button className="btn" disabled={!user || avatarBusy} onClick={() => fileRef.current && fileRef.current.click()}>
              {avatarBusy ? "Uploading…" : "Upload photo"}
            </button>
            <div style={{ fontSize: 12, color: "var(--text-faint)", marginTop: 6 }}>PNG or JPG, up to 5 MB.</div>
          </div>
        </div>

        {/* Full name */}
        <div className="row">
          <div>
            <div className="row-label">Full name</div>
            <div className="row-sub">Shown to teammates on comments and activity.</div>
          </div>
          {editingName ? (
            <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap", justifyContent: "flex-end" }}>
              <input style={{ ...inputStyle, width: 130 }} placeholder="First" value={firstName} onChange={(e) => setFirstName(e.target.value)} />
              <input style={{ ...inputStyle, width: 130 }} placeholder="Last" value={lastName} onChange={(e) => setLastName(e.target.value)} />
              <button className="btn sm" onClick={() => setEditingName(false)} disabled={nameBusy}>Cancel</button>
              <button className="btn accent sm" onClick={saveName} disabled={nameBusy}>{nameBusy ? "Saving…" : "Save"}</button>
            </div>
          ) : (
            <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
              <span className="row-value">{fullName}</span>
              {user && <button className="btn sm" onClick={startEditName}>Edit</button>}
            </div>
          )}
        </div>

        {/* Email */}
        <div className="row">
          <div>
            <div className="row-label">Email</div>
            <div className="row-sub">Used for sign-in and notifications.</div>
          </div>
          <div className="row-value">{email}</div>
        </div>

        {/* Role */}
        {role && (
          <div className="row">
            <div>
              <div className="row-label">Role</div>
              <div className="row-sub">Your workspace permissions.</div>
            </div>
            <div className="row-value">{role}</div>
          </div>
        )}

        {/* Password */}
        <div className="row" style={{ alignItems: pwOpen ? "flex-start" : "center" }}>
          <div>
            <div className="row-label">Password</div>
            <div className="row-sub">{passwordEnabled ? "Change the password you sign in with." : "No password set — you sign in with a connected account. Add one as a backup."}</div>
          </div>
          {!pwOpen ? (
            <button className="btn sm" disabled={!user} onClick={() => { setPwOpen(true); setPwMsg(null); }}>
              {passwordEnabled ? "Change" : "Set password"}
            </button>
          ) : (
            <div style={{ display: "flex", flexDirection: "column", gap: 8, width: 280 }}>
              {passwordEnabled && (
                <input type="password" autoComplete="current-password" style={inputStyle} placeholder="Current password" value={curPw} onChange={(e) => setCurPw(e.target.value)} />
              )}
              <input type="password" autoComplete="new-password" style={inputStyle} placeholder="New password" value={newPw} onChange={(e) => setNewPw(e.target.value)} />
              <input type="password" autoComplete="new-password" style={inputStyle} placeholder="Confirm new password" value={confirmPw} onChange={(e) => setConfirmPw(e.target.value)} />
              {pwMsg && <div style={{ fontSize: 12, color: pwMsg.ok ? "var(--ok, #2e7d52)" : "var(--accent, #c8553d)" }}>{pwMsg.text}</div>}
              <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
                <button className="btn sm" onClick={() => { setPwOpen(false); setPwMsg(null); setCurPw(""); setNewPw(""); setConfirmPw(""); }} disabled={pwBusy}>Cancel</button>
                <button className="btn accent sm" onClick={submitPassword} disabled={pwBusy}>{pwBusy ? "Saving…" : "Save password"}</button>
              </div>
            </div>
          )}
        </div>

        {/* Two-factor */}
        <div className="row" style={{ alignItems: (totp || twoFAMsg) ? "flex-start" : "center" }}>
          <div>
            <div className="row-label">Two-factor authentication</div>
            <div className="row-sub">{totpEnabled ? "On — an authenticator app code is required at sign-in." : "Add a one-time code from an authenticator app for extra security."}</div>
            {twoFAMsg && <div style={{ fontSize: 12, marginTop: 6, color: twoFAMsg.ok ? "var(--ok, #2e7d52)" : "var(--accent, #c8553d)" }}>{twoFAMsg.text}</div>}
            {totp && (
              <div style={{ marginTop: 12, padding: 12, background: "var(--surface-sunken)", border: "1px solid var(--border)", borderRadius: 10, maxWidth: 360 }}>
                <div style={{ fontSize: 12.5, color: "var(--text-muted)", marginBottom: 8 }}>
                  In your authenticator app (Google Authenticator, Authy, 1Password…), add an account and enter this key:
                </div>
                <div style={{ fontFamily: "var(--font-mono)", fontSize: 13, letterSpacing: "0.04em", wordBreak: "break-all", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 8, padding: "8px 10px", marginBottom: 10 }}>
                  {totp.secret}
                </div>
                <input style={inputStyle} placeholder="Enter the 6-digit code" value={totpCode} onChange={(e) => setTotpCode(e.target.value)} />
                <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 8 }}>
                  <button className="btn sm" onClick={() => { setTotp(null); setTotpCode(""); }} disabled={twoFABusy}>Cancel</button>
                  <button className="btn accent sm" onClick={verifyTotp} disabled={twoFABusy || totpCode.trim().length < 6}>{twoFABusy ? "Verifying…" : "Verify & turn on"}</button>
                </div>
              </div>
            )}
          </div>
          {!totp && (
            totpEnabled ? (
              <button className="btn sm" disabled={!user || twoFABusy} onClick={disableTotp}>{twoFABusy ? "…" : "Turn off"}</button>
            ) : (
              <button className="btn sm" disabled={!user || twoFABusy} onClick={beginTotp}>{twoFABusy ? "…" : "Set up"}</button>
            )
          )}
        </div>
      </div>

      {/* Danger zone — permanent account + workspace deletion. Admins only:
          a non-admin member can't tear down a workspace they don't own. */}
      {isWsAdmin && (
      <div
        className="section-card"
        style={{ marginTop: 18, borderColor: "color-mix(in oklch, var(--accent, #c8553d) 35%, var(--border))" }}
      >
        <div className="row" style={{ borderBottom: "none" }}>
          <div>
            <div className="row-label" style={{ color: "var(--accent, #c8553d)" }}>Delete account</div>
            <div className="row-sub" style={{ maxWidth: 460 }}>
              Permanently delete your account and workspace — every image, crop,
              folder and share, plus any teammates' access. This cannot be
              undone and nothing can be recovered.
            </div>
          </div>
          <button
            className="btn sm"
            style={{
              borderColor: "var(--accent, #c8553d)",
              color: "var(--accent, #c8553d)",
              fontWeight: 600,
            }}
            onClick={() => { setDelOpen(true); setDelText(""); setDelErr(null); }}
          >
            Delete account
          </button>
        </div>
      </div>
      )}

      {delOpen && (
        <div
          role="dialog"
          aria-modal="true"
          aria-labelledby="vanday-delete-title"
          style={{
            position: "fixed", inset: 0, zIndex: 10000,
            background: "rgba(8, 12, 22, 0.55)",
            display: "grid", placeItems: "center", padding: 24,
            backdropFilter: "blur(4px)",
          }}
          onClick={(e) => { if (e.target === e.currentTarget && !delBusy) setDelOpen(false); }}
        >
          <div style={{
            background: "var(--surface, #fff)", color: "var(--text, #111)",
            width: "100%", maxWidth: 460, borderRadius: 14,
            boxShadow: "0 20px 60px rgba(0,0,0,0.25)", padding: "26px 26px 22px",
          }}>
            <div id="vanday-delete-title" style={{ fontSize: 17, fontWeight: 700, marginBottom: 8, color: "var(--accent, #c8553d)" }}>
              Delete your account?
            </div>
            <p style={{ fontSize: 13.5, lineHeight: 1.55, color: "var(--text-muted)", margin: "0 0 16px" }}>
              This permanently deletes your account and workspace — every image,
              crop, folder and share, and it removes any teammates you've invited.
              <strong> Everything will be gone and cannot be recovered.</strong>
            </p>
            <label style={{ fontSize: 12.5, fontWeight: 600, display: "block", marginBottom: 6 }}>
              Type <span style={{ fontFamily: "var(--font-mono)" }}>DELETE</span> to confirm
            </label>
            <input
              autoFocus
              value={delText}
              onChange={(e) => setDelText(e.target.value)}
              onKeyDown={(e) => { if (e.key === "Enter" && delReady && !delBusy) confirmDelete(); }}
              placeholder="DELETE"
              style={{
                width: "100%", background: "var(--surface)", border: "1px solid var(--border)",
                borderRadius: 8, padding: "9px 11px", fontSize: 13, outline: "none",
                fontFamily: "var(--font-mono)", letterSpacing: "0.06em",
              }}
            />
            {delErr && (
              <div style={{ fontSize: 12, color: "var(--accent, #c8553d)", marginTop: 8 }}>{delErr}</div>
            )}
            <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 18 }}>
              <button className="btn" onClick={() => setDelOpen(false)} disabled={delBusy}>Cancel</button>
              <button
                className="btn"
                onClick={confirmDelete}
                disabled={!delReady || delBusy}
                style={{
                  background: delReady ? "var(--accent, #c8553d)" : "var(--surface-sunken)",
                  color: delReady ? "white" : "var(--text-faint)",
                  border: "none", fontWeight: 600,
                  cursor: delReady && !delBusy ? "pointer" : "not-allowed",
                }}
              >
                {delBusy ? "Deleting…" : "Permanently delete"}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// Format a millisecond timestamp as a short relative time ("3d ago").
function relTime(ms) {
  if (!ms) return "—";
  const s = Math.max(0, (Date.now() - ms) / 1000);
  if (s < 60) return "just now";
  if (s < 3600) return `${Math.floor(s / 60)}m ago`;
  if (s < 86400) return `${Math.floor(s / 3600)}h ago`;
  if (s < 86400 * 30) return `${Math.floor(s / 86400)}d ago`;
  return new Date(ms).toLocaleDateString();
}

// Admin permissions manager. Fetches real workspace access from the server:
// the member roster with per-user roles, plus the company-domain auto-join
// rule. Each member's role can be changed inline (persists via PATCH); the
// domain rule is configured below (persists via PUT). Non-admins see a
// read-only view.
function UsersSection() {
  const [data, setData] = React.useState(null);
  const [err, setErr] = React.useState(null);
  const [busyId, setBusyId] = React.useState(null);

  // Beta seat cap (owner + invites combined). Read from the server so the UI
  // matches what's actually enforced on POST /api/org/invites.
  const limits = (typeof window.useVandayLimits === "function") ? window.useVandayLimits() : null;
  const seatCap = limits?.maxSeats ?? 3;

  // Domain-rule form state, hydrated from the server on load.
  const [drEnabled, setDrEnabled] = React.useState(false);
  const [drDomain, setDrDomain] = React.useState("");
  const [drRole, setDrRole] = React.useState("viewer");
  const [drBusy, setDrBusy] = React.useState(false);
  const [drSaved, setDrSaved] = React.useState(false);

  // Invite form state.
  const [invEmail, setInvEmail] = React.useState("");
  const [invRole, setInvRole] = React.useState("editor");
  const [invBusy, setInvBusy] = React.useState(false);
  const [invNote, setInvNote] = React.useState(null); // { ok, text }

  const load = React.useCallback(() => {
    window.VandayAPI.getOrgAccess()
      .then((d) => {
        setData(d);
        const r = d.domainRule || {};
        setDrEnabled(!!r.enabled);
        setDrDomain(r.domain || d.suggestedDomain || "");
        setDrRole(r.role || "viewer");
      })
      .catch((e) => setErr(e.message || "Failed to load"));
  }, []);
  React.useEffect(() => { load(); }, [load]);

  if (err) {
    return (
      <>
        <h1 className="settings-h1">Users &amp; permissions</h1>
        <p className="settings-sub" style={{ color: "var(--danger, oklch(0.6 0.18 25))" }}>Couldn't load workspace access: {err}</p>
      </>
    );
  }
  if (!data) {
    return (
      <>
        <h1 className="settings-h1">Users &amp; permissions</h1>
        <p className="settings-sub">Loading…</p>
      </>
    );
  }

  const { myRole, isAdmin, isPersonal, roles, members } = data;
  const invites = data.invites || [];
  // Seats in use = current members + outstanding (unaccepted) invites.
  const pendingCount = invites.filter((iv) => !iv.acceptedAt).length;
  const seatsUsed = members.length + pendingCount;
  const seatsFull = seatsUsed >= seatCap;
  const roleOptions = roles.map((r) => ({ value: r.id, label: r.label }));
  const roleLabel = (id) => (roles.find((r) => r.id === id) || {}).label || id;

  const sendInvite = async () => {
    const email = invEmail.trim().toLowerCase();
    if (!email || invBusy) return;
    setInvBusy(true);
    setInvNote(null);
    try {
      const res = await window.VandayAPI.inviteUser(email, invRole);
      setData((d) => ({ ...d, invites: [res.invite, ...(d.invites || []).filter((i) => i.id !== res.invite.id)] }));
      setInvEmail("");
      setInvNote(res.emailSent
        ? { ok: true, text: `Invite email sent to ${email}.` }
        : { ok: false, text: `${email} was added to pending invites, but the invite email couldn't be sent (${res.emailReason || "email not configured"}). They can still join by signing up with this email.` });
    } catch (e) {
      const code = (e && e.data && e.data.error) || e.message || "";
      window.alert(
        code.includes("seat_limit_reached") ? (e.data && e.data.message) || `Your beta workspace is limited to ${seatCap} people.`
          : code.includes("already_member") ? "That person is already in this workspace."
            : code.includes("bad_email") ? "That doesn't look like a valid email address."
              : `Couldn't send the invite: ${e.message || "error"}`,
      );
    } finally {
      setInvBusy(false);
    }
  };
  const revokeInvite = async (id) => {
    try {
      await window.VandayAPI.revokeInvite(id);
      setData((d) => ({ ...d, invites: (d.invites || []).filter((i) => i.id !== id) }));
    } catch (e) {
      window.alert(`Couldn't revoke: ${e.message || "error"}`);
    }
  };

  const changeRole = async (userId, role) => {
    setBusyId(userId);
    try {
      await window.VandayAPI.setMemberRole(userId, role);
      setData((d) => ({ ...d, members: d.members.map((m) => m.id === userId ? { ...m, role } : m) }));
    } catch (e) {
      window.alert(
        e.message && e.message.includes("last_admin")
          ? "You can't remove the last admin — promote someone else first."
          : e.message && e.message.includes("owner_must_stay_admin")
            ? "The workspace owner must stay an admin."
            : `Couldn't change role: ${e.message || "error"}`,
      );
    } finally {
      setBusyId(null);
    }
  };

  const removeMember = async (m) => {
    const fullName = (m.name || "").trim();
    const who = fullName || (m.email || "").split("@")[0] || "this person";
    if (!window.confirm(`Remove ${who} from the workspace? They'll lose access immediately.`)) return;
    setBusyId(m.id);
    try {
      await window.VandayAPI.removeMember(m.id);
      setData((d) => ({ ...d, members: d.members.filter((x) => x.id !== m.id) }));
    } catch (e) {
      const code = (e && e.data && e.data.error) || e.message || "";
      window.alert(
        code.includes("cannot_remove_admin")
          ? "Admins can't remove each other. Change their role to something other than admin first."
          : code.includes("cannot_remove_owner")
            ? "The workspace owner can't be removed."
            : `Couldn't remove this person: ${e.message || "error"}`,
      );
    } finally {
      setBusyId(null);
    }
  };

  const saveDomainRule = async () => {
    setDrBusy(true);
    setDrSaved(false);
    try {
      const res = await window.VandayAPI.setDomainRule({ enabled: drEnabled, domain: drDomain.trim(), role: drRole });
      const r = res.domainRule || {};
      setDrEnabled(!!r.enabled);
      if (r.domain) setDrDomain(r.domain);
      if (r.role) setDrRole(r.role);
      setDrSaved(true);
      setTimeout(() => setDrSaved(false), 2500);
    } catch (e) {
      window.alert(
        e.message && e.message.includes("bad_domain")
          ? "That doesn't look like a valid domain (e.g. acme.com)."
          : `Couldn't save the rule: ${e.message || "error"}`,
      );
    } finally {
      setDrBusy(false);
    }
  };

  return (
    <>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 20, marginBottom: 28 }}>
        <div>
          <h1 className="settings-h1">Users &amp; permissions</h1>
          <p className="settings-sub" style={{ marginBottom: 0 }}>
            {isAdmin
              ? "Give each person a role that decides what they can do across the workspace."
              : "View who has access to this workspace."}
          </p>
        </div>
      </div>

      {isPersonal && (
        <div className="section-card" style={{ display: "flex", gap: 10, alignItems: "flex-start" }}>
          <IcInfo size={16} />
          <div style={{ fontSize: 13, color: "var(--text-muted)" }}>
            This is your personal workspace. Turn on the company-domain rule below to let teammates join automatically when they sign up with your company email.
          </div>
        </div>
      )}

      <div className="section-card" style={{ padding: 0, overflow: "hidden" }}>
        <div style={{ padding: "14px 16px", display: "flex", alignItems: "center", gap: 8, borderBottom: "1px solid var(--border)" }}>
          <span style={{ fontWeight: 600, fontSize: 14 }}>People</span>
          <span style={{ marginLeft: "auto", fontSize: 12, color: "var(--text-muted)" }}>
            {members.length} {members.length === 1 ? "person" : "people"}
          </span>
        </div>
        <table className="table">
          <thead>
            <tr>
              <th>User</th>
              <th>Email</th>
              <th>Role</th>
              <th>Last active</th>
              {isAdmin && <th></th>}
            </tr>
          </thead>
          <tbody>
            {members.map((m) => {
              // Prefer the person's real name; fall back to the email's local
              // part. Never surface the opaque user id.
              const fullName = (m.name || "").trim();
              const emailLocal = (m.email || "").split("@")[0];
              const display = fullName || emailLocal || "Team member";
              const initials = (
                fullName
                  ? fullName.split(/\s+/).map((w) => w[0]).slice(0, 2).join("")
                  : display.slice(0, 2)
              ).toUpperCase();
              return (
                <tr key={m.id}>
                  <td>
                    <span className="pill-user" style={{ background: "transparent", padding: 0 }}>
                      <span className="av" style={{ width: 24, height: 24, fontSize: 11 }}>{initials}</span>
                      <span style={{ marginLeft: 8 }}>
                        {display}
                        {m.isSelf && <span style={{ color: "var(--text-faint)", fontWeight: 400 }}> (you)</span>}
                        {m.isOwner && <span className="role-pill" style={{ marginLeft: 6 }}>Owner</span>}
                      </span>
                    </span>
                  </td>
                  <td style={{ color: "var(--text-muted)", fontFamily: "var(--font-mono)", fontSize: 12 }}>{m.email}</td>
                  <td>
                    {isAdmin && !m.isOwner ? (
                      <RoleSelect
                        value={m.role}
                        disabled={busyId === m.id}
                        options={roleOptions}
                        onChange={(r) => changeRole(m.id, r)}
                      />
                    ) : (
                      <span className="role-pill">{roleLabel(m.role)}</span>
                    )}
                  </td>
                  <td style={{ color: "var(--text-muted)" }}>{relTime(m.lastSeenAt)}</td>
                  {isAdmin && (
                    <td style={{ textAlign: "right" }}>
                      {!m.isOwner && !m.isSelf && m.role !== "admin" && (
                        <button
                          type="button"
                          className="btn ghost sm"
                          disabled={busyId === m.id}
                          onClick={() => removeMember(m)}
                          style={{ color: "var(--accent, #c8553d)" }}
                        >
                          Remove
                        </button>
                      )}
                    </td>
                  )}
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {/* Invite people */}
      {isAdmin && (
        <div className="section-card">
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, flexWrap: "wrap" }}>
            <div style={{ fontWeight: 600, fontSize: 14 }}>Invite people</div>
            <span style={{
              fontSize: 12, fontWeight: 600,
              color: seatsFull ? "var(--accent, #c8553d)" : "var(--text-muted)",
              background: "var(--surface-sunken)", border: "1px solid var(--border)",
              borderRadius: 999, padding: "3px 10px", whiteSpace: "nowrap",
            }}>
              {seatsUsed} of {seatCap} seats used
            </span>
          </div>
          <p className="settings-sub" style={{ margin: "2px 0 0" }}>
            {seatsFull
              ? `Your beta workspace is limited to ${seatCap} people. Remove a member or revoke a pending invite to add someone new.`
              : "Invite a teammate by email and pick their role. They'll join this workspace automatically the first time they sign in with that email — just share the app link with them."}
          </p>
          <div style={{ display: "flex", gap: 12, alignItems: "flex-end", marginTop: 14, flexWrap: "wrap" }}>
            <div style={{ display: "grid", gap: 4, flex: 1, minWidth: 220 }}>
              <label style={{ fontSize: 12, color: "var(--text-muted)" }}>Email address</label>
              <div className="search" style={{ width: "100%" }}>
                <input
                  type="email"
                  placeholder="teammate@company.com"
                  value={invEmail}
                  disabled={invBusy || seatsFull}
                  onChange={(e) => setInvEmail(e.target.value)}
                  onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); sendInvite(); } }}
                />
              </div>
            </div>
            <div style={{ display: "grid", gap: 4 }}>
              <label style={{ fontSize: 12, color: "var(--text-muted)" }}>Role</label>
              <RoleSelect value={invRole} disabled={invBusy || seatsFull} options={roleOptions} onChange={setInvRole} />
            </div>
            <button className="btn accent" disabled={!invEmail.trim() || invBusy || seatsFull} onClick={sendInvite}>
              <IcPlus size={14} /> {invBusy ? "Inviting…" : "Send invite"}
            </button>
          </div>

          {invNote && (
            <div style={{
              marginTop: 12, fontSize: 13, lineHeight: 1.5,
              color: invNote.ok ? "oklch(0.5 0.13 150)" : "var(--text-muted)",
            }}>
              {invNote.ok ? "✓ " : "⚠ "}{invNote.text}
            </div>
          )}

          {invites.length > 0 && (
            <div style={{ marginTop: 16 }}>
              <div style={{ fontSize: 12, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--text-faint)", fontWeight: 500, marginBottom: 8 }}>
                Pending invites
              </div>
              <div style={{ display: "grid", gap: 6 }}>
                {invites.map((iv) => (
                  <div key={iv.id} style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 12px", border: "1px solid var(--border)", borderRadius: 8 }}>
                    <IcClock size={14} />
                    <span style={{ fontFamily: "var(--font-mono)", fontSize: 13 }}>{iv.email}</span>
                    <span className="role-pill">{roleLabel(iv.role)}</span>
                    <span style={{ marginLeft: "auto", fontSize: 12, color: "var(--text-faint)" }}>invited {relTime(iv.createdAt)}</span>
                    <button className="btn ghost sm" onClick={() => revokeInvite(iv.id)} title="Revoke invite"><IcClose size={14} /></button>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>
      )}

      {/* Role legend */}
      <div className="section-card">
        <div style={{ fontWeight: 600, fontSize: 13, marginBottom: 8 }}>What each role can do</div>
        <div style={{ display: "grid", gap: 6 }}>
          {roles.map((r) => (
            <div key={r.id} style={{ display: "flex", gap: 8, fontSize: 13 }}>
              <span className="role-pill" style={{ minWidth: 92, textAlign: "center" }}>{r.label}</span>
              <span style={{ color: "var(--text-muted)" }}>{r.desc}</span>
            </div>
          ))}
        </div>
      </div>

      {/* Company-domain auto-join rule */}
      <div className="section-card">
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 12 }}>
          <div>
            <div style={{ fontWeight: 600, fontSize: 14 }}>Company-domain access</div>
            <p className="settings-sub" style={{ margin: "2px 0 0" }}>
              Automatically add anyone who signs up with your company email domain, and give them a starting role.
            </p>
          </div>
          <label style={{ display: "inline-flex", alignItems: "center", gap: 8, fontSize: 13, whiteSpace: "nowrap" }}>
            <input
              type="checkbox"
              checked={drEnabled}
              disabled={!isAdmin || drBusy}
              onChange={(e) => setDrEnabled(e.target.checked)}
            />
            Enabled
          </label>
        </div>

        <div style={{ display: "flex", gap: 12, alignItems: "flex-end", marginTop: 14, flexWrap: "wrap", opacity: drEnabled ? 1 : 0.55 }}>
          <div style={{ display: "grid", gap: 4 }}>
            <label style={{ fontSize: 12, color: "var(--text-muted)" }}>Email domain</label>
            <div className="search" style={{ width: 220 }}>
              <span style={{ color: "var(--text-faint)" }}>@</span>
              <input
                placeholder="acme.com"
                value={drDomain}
                disabled={!isAdmin || !drEnabled || drBusy}
                onChange={(e) => setDrDomain(e.target.value)}
              />
            </div>
          </div>
          <div style={{ display: "grid", gap: 4 }}>
            <label style={{ fontSize: 12, color: "var(--text-muted)" }}>Default role</label>
            <RoleSelect
              value={drRole}
              disabled={!isAdmin || !drEnabled || drBusy}
              options={roleOptions}
              onChange={setDrRole}
            />
          </div>
          {isAdmin && (
            <button className="btn" disabled={drBusy} onClick={saveDomainRule}>
              {drBusy ? "Saving…" : drSaved ? "Saved ✓" : "Save rule"}
            </button>
          )}
        </div>
        {!isAdmin && (
          <p className="settings-sub" style={{ marginTop: 10 }}>Only admins can change workspace access.</p>
        )}
      </div>
    </>
  );
}

// New-field modal — pick a label, type and category for a custom field.
function NewFieldModal({ types, categories, onCreate, onClose }) {
  const [label, setLabel] = React.useState("");
  const [type, setType] = React.useState((types && types[0]) || "Text");
  const [category, setCategory] = React.useState("Custom");
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const inputRef = React.useRef(null);
  React.useEffect(() => { inputRef.current && inputRef.current.focus(); }, []);
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
  }, [onClose]);

  const submit = async () => {
    const l = label.trim();
    if (!l || busy) return;
    setBusy(true); setError(null);
    try { await onCreate({ label: l, type, category }); }
    catch (e) { setError(e.message || "Could not create field."); setBusy(false); }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal nf-modal" onClick={(e) => e.stopPropagation()}>
        <header className="nf-head">
          <div>
            <h2 className="nf-title">New field</h2>
            <p className="nf-sub">Add a custom metadata field for your assets.</p>
          </div>
          <button className="btn ghost sm" onClick={onClose} title="Close"><IcClose size={16} /></button>
        </header>

        <div className="nf-body">
          <div className="nf-block">
            <label className="nf-label" htmlFor="nf-name">Field name</label>
            <input
              id="nf-name"
              ref={inputRef}
              className="nf-input"
              placeholder="e.g. Campaign"
              value={label}
              onChange={(e) => setLabel(e.target.value)}
              onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); submit(); } }}
            />
          </div>

          <div className="nf-grid">
            <div className="nf-block">
              <label className="nf-label" htmlFor="nf-type">Type</label>
              <select id="nf-type" className="nf-select" value={type} onChange={(e) => setType(e.target.value)}>
                {(types || []).map((t) => <option key={t} value={t}>{t}</option>)}
              </select>
            </div>
            <div className="nf-block">
              <label className="nf-label" htmlFor="nf-cat">Category</label>
              <select id="nf-cat" className="nf-select" value={category} onChange={(e) => setCategory(e.target.value)}>
                {(categories || []).map((c) => <option key={c} value={c}>{c}</option>)}
              </select>
            </div>
          </div>

          <div className="nf-hint">
            <IcSparkles className="ic" size={14} />
            Custom fields show up on every asset and are fully searchable.
          </div>

          {error && <div style={{ fontSize: 12.5, color: "var(--danger, oklch(0.6 0.18 25))" }}>{error}</div>}
        </div>

        <footer className="nf-foot">
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn accent" onClick={submit} disabled={!label.trim() || busy}>
            <IcPlus size={14} /> {busy ? "Adding…" : "Add field"}
          </button>
        </footer>
      </div>
    </div>
  );
}

function FieldsSection() {
  const [fields, setFields] = React.useState(null);
  const [meta, setMeta] = React.useState({ types: [], categories: [] });
  const [err, setErr] = React.useState(null);
  const [busyKey, setBusyKey] = React.useState(null);
  const [showNew, setShowNew] = React.useState(false);

  const load = React.useCallback(() => {
    window.VandayAPI.listFields()
      .then((d) => { setFields(d.fields || []); setMeta({ types: d.types || [], categories: d.categories || [] }); })
      .catch((e) => setErr(e.message || "Failed to load"));
  }, []);
  React.useEffect(() => { load(); }, [load]);

  const toggleVisible = async (f) => {
    setBusyKey(f.key);
    const next = !f.visible;
    setFields((fs) => fs.map((x) => x.key === f.key ? { ...x, visible: next } : x));
    try { await window.VandayAPI.setFieldVisible(f.key, next); }
    catch (e) {
      setFields((fs) => fs.map((x) => x.key === f.key ? { ...x, visible: !next } : x));
      window.alert(`Couldn't update: ${e.message || "error"}`);
    } finally { setBusyKey(null); }
  };
  const removeField = async (f) => {
    if (!window.confirm(`Remove the "${f.label}" field?`)) return;
    setFields((fs) => fs.filter((x) => x.key !== f.key));
    try { await window.VandayAPI.deleteField(f.key); }
    catch (e) { window.alert(`Couldn't remove: ${e.message || "error"}`); load(); }
  };
  const createField = async ({ label, type, category }) => {
    const res = await window.VandayAPI.createField({ label, type, category });
    setFields((fs) => [...(fs || []), res.field]);
    setShowNew(false);
  };

  if (err) {
    return (<><h1 className="settings-h1">Fields</h1>
      <p className="settings-sub" style={{ color: "var(--danger, oklch(0.6 0.18 25))" }}>Couldn't load fields: {err}</p></>);
  }
  if (!fields) {
    return (<><h1 className="settings-h1">Fields</h1><p className="settings-sub">Loading…</p></>);
  }

  // Preserve the server order but group by category for display.
  const order = [];
  const grouped = {};
  for (const f of fields) {
    if (!grouped[f.category]) { grouped[f.category] = []; order.push(f.category); }
    grouped[f.category].push(f);
  }

  return (
    <>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 20, marginBottom: 28 }}>
        <div>
          <h1 className="settings-h1">Fields</h1>
          <p className="settings-sub" style={{ marginBottom: 0 }}>Define the metadata captured for every asset. AI fields auto-populate on upload.</p>
        </div>
        <button className="btn accent" onClick={() => setShowNew(true)}><IcPlus size={14} /> New field</button>
      </div>

      {order.map((cat) => (
        <div className="section-card" key={cat}>
          <h2 className="section-h" style={{ display: "flex", alignItems: "center", gap: 8 }}>
            {cat}
            {cat === "Auto-generated" && (
              <span className="tag ai">
                <IcSparkles size={9} style={{ verticalAlign: "middle", marginRight: 3 }} />
                AI
              </span>
            )}
          </h2>
          {grouped[cat].map((f) => (
            <div className="row" key={f.key}>
              <div>
                <div className="row-label">{f.label}</div>
                <div className="row-sub">{f.type}{f.isCustom ? " · Custom" : ""}</div>
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                {f.isCustom && (
                  <button className="btn ghost sm" title="Remove field" onClick={() => removeField(f)}><IcTrash size={14} /></button>
                )}
                <button
                  className={`toggle ${f.visible ? "on" : ""}`}
                  disabled={busyKey === f.key}
                  onClick={() => toggleVisible(f)}
                  title={f.visible ? "Visible — click to hide" : "Hidden — click to show"}
                />
              </div>
            </div>
          ))}
        </div>
      ))}

      {showNew && (
        <NewFieldModal
          types={meta.types}
          categories={meta.categories}
          onCreate={createField}
          onClose={() => setShowNew(false)}
        />
      )}
    </>
  );
}

// Admin → Workflow labels: manage the per-org list of asset statuses.
// Create / rename / recolor / reorder / delete-with-migration.
function WorkflowLabelsSection() {
  const COLORS = ["green", "yellow", "gray", "red", "blue", "purple"];
  const { labels, reload } = window.VandayServer.useWorkflowLabels();
  const [draftName, setDraftName] = React.useState("");
  const [draftColor, setDraftColor] = React.useState("green");
  const [editingId, setEditingId] = React.useState(null);
  const [editName, setEditName] = React.useState("");
  const [editColor, setEditColor] = React.useState("green");
  const [deletingId, setDeletingId] = React.useState(null);
  const [migrateTo, setMigrateTo] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);

  // Friendlier wording for the most common backend error codes. Anything
  // else falls through to the raw message.
  const friendlyError = (msg) => {
    if (!msg) return null;
    const s = String(msg);
    if (s.includes("duplicate") || s.includes("UNIQUE")) return "A label with that name already exists.";
    if (s.includes("invalid_color")) return "Pick one of the six allowed colors.";
    if (s.includes("empty_name") || s.includes("required")) return "Give the label a name.";
    if (s.includes("migrate_target_not_found")) return "The label to move assets to no longer exists.";
    return s;
  };

  const sorted = React.useMemo(() => {
    return [...(labels || [])].sort((a, b) => {
      const sa = a.sortOrder ?? a.sort_order ?? 0;
      const sb = b.sortOrder ?? b.sort_order ?? 0;
      if (sa !== sb) return sa - sb;
      return (a.name || "").localeCompare(b.name || "");
    });
  }, [labels]);

  const add = async () => {
    const name = draftName.trim();
    if (!name) return;
    setError(null); setBusy(true);
    try {
      await VandayAPI.createWorkflowLabel({ name, color: draftColor });
      setDraftName("");
      setDraftColor("green");
      await reload();
    } catch (e) { setError(e.message); }
    finally { setBusy(false); }
  };

  const beginEdit = (l) => {
    setEditingId(l.id);
    setEditName(l.name);
    setEditColor(l.color);
    setDeletingId(null);
    setError(null);
  };
  const saveEdit = async () => {
    if (!editingId) return;
    const name = editName.trim();
    if (!name) return;
    setError(null); setBusy(true);
    try {
      await VandayAPI.updateWorkflowLabel(editingId, { name, color: editColor });
      setEditingId(null);
      await reload();
    } catch (e) { setError(e.message); }
    finally { setBusy(false); }
  };

  const move = async (l, dir) => {
    const idx = sorted.findIndex((x) => x.id === l.id);
    const target = sorted[idx + dir];
    if (!target) return;
    setBusy(true); setError(null);
    try {
      const myOrder = l.sortOrder ?? l.sort_order ?? idx;
      const theirOrder = target.sortOrder ?? target.sort_order ?? (idx + dir);
      await Promise.all([
        VandayAPI.updateWorkflowLabel(l.id, { sortOrder: theirOrder }),
        VandayAPI.updateWorkflowLabel(target.id, { sortOrder: myOrder }),
      ]);
      await reload();
    } catch (e) { setError(e.message); }
    finally { setBusy(false); }
  };

  const beginDelete = (l) => {
    setDeletingId(l.id);
    setMigrateTo("");
    setEditingId(null);
    setError(null);
  };
  const confirmDelete = async () => {
    if (!deletingId) return;
    setBusy(true); setError(null);
    try {
      await VandayAPI.deleteWorkflowLabel(deletingId, migrateTo || null);
      setDeletingId(null);
      setMigrateTo("");
      await reload();
    } catch (e) { setError(e.message); }
    finally { setBusy(false); }
  };

  const ColorPalette = ({ value, onChange }) => (
    <div className="wf-swatch-row" role="radiogroup" aria-label="Color">
      {COLORS.map((c) => (
        <button
          key={c}
          type="button"
          role="radio"
          aria-checked={value === c}
          title={c}
          className={`wf-swatch wf-color-${c} ${value === c ? "is-active" : ""}`}
          onClick={() => onChange(c)}
        />
      ))}
    </div>
  );

  return (
    <>
      <h1 className="settings-h1">Workflow labels</h1>
      <p className="settings-sub" style={{ marginBottom: 20 }}>
        The statuses your team can apply to assets — e.g. <em>For review</em>, <em>Approved</em>, <em>Retired</em>.
        Anyone in the workspace can change an asset's status; only admins manage this list.
      </p>

      <div className="section-card">
        <h2 className="section-h">Current labels</h2>
        {sorted.length === 0 && (
          <p style={{ color: "var(--text-faint)", fontSize: 13, margin: 0 }}>
            No labels yet — add your first one below.
          </p>
        )}
        <div className="wf-label-list">
          {sorted.map((l, idx) => {
            if (editingId === l.id) {
              return (
                <div key={l.id} className="wf-label-row is-editing">
                  <ColorPalette value={editColor} onChange={setEditColor} />
                  <input
                    className="wf-label-input"
                    value={editName}
                    onChange={(e) => setEditName(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === "Enter") saveEdit();
                      if (e.key === "Escape") setEditingId(null);
                    }}
                    autoFocus
                  />
                  <button className="btn sm accent" onClick={saveEdit} disabled={busy || !editName.trim()}>Save</button>
                  <button className="btn ghost sm" onClick={() => setEditingId(null)} disabled={busy}>Cancel</button>
                </div>
              );
            }
            if (deletingId === l.id) {
              const others = sorted.filter((x) => x.id !== l.id);
              return (
                <div key={l.id} className="wf-label-row is-deleting">
                  <span className={`wf-pill wf-color-${l.color}`}>
                    <span className="wf-dot" />{l.name}
                  </span>
                  <span style={{ fontSize: 12.5, color: "var(--text-muted)", flex: "1 1 auto" }}>
                    Assets currently tagged with this should:
                  </span>
                  <select
                    value={migrateTo}
                    onChange={(e) => setMigrateTo(e.target.value)}
                    className="wf-label-select"
                  >
                    <option value="">Become uncategorized</option>
                    {others.map((x) => (
                      <option key={x.id} value={x.id}>Move to "{x.name}"</option>
                    ))}
                  </select>
                  <button className="btn sm" onClick={confirmDelete} disabled={busy}>Confirm delete</button>
                  <button className="btn ghost sm" onClick={() => setDeletingId(null)} disabled={busy}>Cancel</button>
                </div>
              );
            }
            return (
              <div key={l.id} className="wf-label-row">
                <span className={`wf-pill wf-color-${l.color}`}>
                  <span className="wf-dot" />{l.name}
                </span>
                <div style={{ flex: 1 }} />
                <button
                  className="btn ghost sm"
                  onClick={() => move(l, -1)}
                  disabled={idx === 0 || busy}
                  title="Move up"
                >↑</button>
                <button
                  className="btn ghost sm"
                  onClick={() => move(l, +1)}
                  disabled={idx === sorted.length - 1 || busy}
                  title="Move down"
                >↓</button>
                <button className="btn ghost sm" onClick={() => beginEdit(l)} disabled={busy}>Edit</button>
                <button className="btn ghost sm" onClick={() => beginDelete(l)} disabled={busy}>Delete</button>
              </div>
            );
          })}
        </div>
      </div>

      <div className="section-card">
        <h2 className="section-h">Add a label</h2>
        {error && (
          <div style={{
            background: "oklch(0.94 0.06 25)", color: "oklch(0.36 0.16 25)",
            padding: "8px 12px", borderRadius: 6, fontSize: 12.5, marginBottom: 12,
          }}>{friendlyError(error)}</div>
        )}
        <div style={{ display: "flex", gap: 12, alignItems: "center", flexWrap: "wrap" }}>
          <ColorPalette value={draftColor} onChange={setDraftColor} />
          <input
            className="wf-label-input"
            value={draftName}
            onChange={(e) => setDraftName(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") add(); }}
            placeholder="Label name (e.g. Needs revision)"
            style={{ flex: "1 1 200px" }}
          />
          <button className="btn accent" onClick={add} disabled={busy || !draftName.trim()}>
            <IcPlus size={12} /> Add
          </button>
        </div>
      </div>
    </>
  );
}

function BillingSection() {
  return (
    <>
      <h1 className="settings-h1">Billing</h1>
      <p className="settings-sub">Manage your plan, payment method and invoice history.</p>

      <div className="section-card" style={{ background: "linear-gradient(180deg, var(--accent-soft) 0%, var(--surface) 90%)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
          <div>
            <span className="role-pill" style={{ background: "white", borderColor: "transparent" }}>Current plan</span>
            <h2 style={{ fontSize: 28, fontWeight: 500, margin: "12px 0 4px", letterSpacing: "-0.02em" }}>Team</h2>
            <p style={{ fontSize: 13, color: "var(--text-muted)", margin: 0 }}>
              Billed monthly · Free trial ends May 24, 2026
            </p>
          </div>
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn">Cancel trial</button>
            <button className="btn primary">Manage plan</button>
          </div>
        </div>

        <div style={{ marginTop: 28, display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr", gap: 16, fontSize: 13 }}>
          <div style={{ color: "var(--text-muted)" }}>Description</div>
          <div style={{ color: "var(--text-muted)" }}>Qty</div>
          <div style={{ color: "var(--text-muted)" }}>Unit price</div>
          <div style={{ color: "var(--text-muted)", textAlign: "right" }}>Amount</div>

          <div>Team plan (1 member)</div>
          <div style={{ fontFamily: "var(--font-mono)" }}>1</div>
          <div style={{ fontFamily: "var(--font-mono)" }}>$25/mo</div>
          <div style={{ fontFamily: "var(--font-mono)", textAlign: "right" }}>$25/mo</div>

          <div>Subtotal</div>
          <div></div>
          <div></div>
          <div style={{ fontFamily: "var(--font-mono)", textAlign: "right" }}>$25/mo</div>

          <div>Sales tax (0%)</div>
          <div></div>
          <div></div>
          <div style={{ fontFamily: "var(--font-mono)", textAlign: "right" }}>$0/mo</div>

          <div style={{ fontWeight: 500 }}>After trial ends</div>
          <div></div>
          <div></div>
          <div style={{ fontFamily: "var(--font-mono)", textAlign: "right", fontWeight: 500 }}>$25/mo</div>
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 18 }}>
        <div className="section-card">
          <h2 className="section-h">Payment method</h2>
          <p style={{ fontSize: 13, color: "var(--text-muted)", margin: "0 0 16px" }}>
            By adding a card, your free trial converts to a paid subscription at the end of the trial.
          </p>
          <button className="btn"><IcPlus size={14} /> Add card</button>
        </div>
        <div className="section-card">
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
            <h2 className="section-h">Invoice information</h2>
            <button className="btn sm">Edit</button>
          </div>
          <div style={{ fontSize: 13 }}>
            <div className="row" style={{ borderTop: 0, paddingTop: 0 }}>
              <span style={{ color: "var(--text-muted)" }}>Company name</span>
              <span>Vanday Studio Ltd.</span>
            </div>
            <div className="row">
              <span style={{ color: "var(--text-muted)" }}>Tax ID</span>
              <span style={{ color: "var(--text-faint)" }}>Not set</span>
            </div>
            <div className="row">
              <span style={{ color: "var(--text-muted)" }}>Invoice email</span>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>billing@vanday.com</span>
            </div>
          </div>
        </div>
      </div>

      <div className="section-card">
        <h2 className="section-h">Invoice history</h2>
        <table className="table">
          <thead>
            <tr>
              <th>Date</th>
              <th>Description</th>
              <th>Amount</th>
              <th>Invoice ID</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {[
              { d: "May 10, 2026", a: "$0.00",  id: "INV-2026-0001", desc: "Free trial started" },
              { d: "Apr 10, 2026", a: "$25.00", id: "INV-2026-0000", desc: "Team plan (1 member)" },
              { d: "Mar 10, 2026", a: "$25.00", id: "INV-2025-0999", desc: "Team plan (1 member)" },
            ].map((row) => (
              <tr key={row.id}>
                <td>{row.d}</td>
                <td style={{ color: "var(--text-muted)" }}>{row.desc}</td>
                <td style={{ fontFamily: "var(--font-mono)" }}>{row.a}</td>
                <td style={{ fontFamily: "var(--font-mono)", color: "var(--text-muted)", fontSize: 12 }}>{row.id}</td>
                <td style={{ textAlign: "right" }}><button className="btn sm">View</button></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </>
  );
}

function UsageSection() {
  // Storage is real (per-account bytes against the beta cap); the others
  // remain plan-mock placeholders until wired up.
  const limits = (typeof window.useVandayLimits === "function") ? window.useVandayLimits() : null;
  const storageCapBytes = limits?.maxStorageBytes ?? (50 * 1024 * 1024 * 1024);
  const storageUsedBytes = limits?.storageBytesUsed ?? 0;
  const capGB = storageCapBytes / (1024 * 1024 * 1024);
  const fmtSize = (bytes) => {
    const gb = (bytes || 0) / (1024 * 1024 * 1024);
    if (gb < 0.1) return ((bytes || 0) / (1024 * 1024)).toFixed(1) + " MB";
    return gb.toFixed(2) + " GB";
  };
  const blocks = [
    { name: "Members", value: "6 of 15", sub: "5 active · 1 invited",  progress: 0.4, action: "Manage members" },
    { name: "Storage", value: `${fmtSize(storageUsedBytes)} of ${capGB} GB`, sub: "Includes versions and trash", progress: storageUsedBytes / storageCapBytes, action: null },
    { name: "Projects", value: "4 projects",  sub: "Unlimited on Team plan", progress: 0, action: "Manage projects" },
    { name: "Auto-tagging", value: "1,248 of 10,000", sub: "AI credits this month", progress: 0.125, action: null },
  ];
  return (
    <>
      <h1 className="settings-h1">Usage</h1>
      <p className="settings-sub">Monitor your account usage and plan limits.</p>
      {blocks.map((b) => (
        <div className="section-card" key={b.name}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
            <div>
              <h2 className="section-h" style={{ marginBottom: 4 }}>{b.name}</h2>
              <div style={{ fontSize: 13, color: "var(--text-muted)" }}>
                <span style={{ color: "var(--text)", fontWeight: 500 }}>{b.value}</span>
                {" · "}{b.sub}
              </div>
            </div>
            {b.action && <button className="btn sm">{b.action}</button>}
          </div>
          <div style={{ marginTop: 14, height: 6, background: "var(--surface-sunken)", borderRadius: 999, overflow: "hidden" }}>
            <div style={{
              width: `${Math.max(2, b.progress * 100)}%`, height: "100%",
              background: b.progress > 0.8 ? "oklch(0.62 0.18 28)" : "var(--accent)",
            }} />
          </div>
        </div>
      ))}
    </>
  );
}

// Full-size usage meter (DAM Refresh design). Bar shifts accent -> amber
// (>=75%) -> red (>=90%); foot copy changes tone with it. Pass an explicit
// `pct` when used/total aren't comparable numbers (e.g. "61.2 GB" / "3 TB").
function UsageMeter({ label, icon, used, total, unit, left, reset, pct, tone }) {
  const ratio = pct != null ? pct : Math.min(100, Math.round((used / total) * 100));
  const state = tone || (ratio >= 90 ? "danger" : ratio >= 75 ? "warning" : "ok");
  const color = state === "danger" ? "var(--status-danger)"
    : state === "warning" ? "var(--status-warning)"
    : "var(--accent)";
  return (
    <div style={{ border: "1px solid var(--border)", background: "var(--surface)", borderRadius: "var(--radius)", padding: "18px 20px" }}>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 12 }}>
        <span style={{ fontSize: 13.5, fontWeight: 600, display: "inline-flex", alignItems: "center", gap: 8 }}>{icon} {label}</span>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 14 }}>
          <b style={{ color: "var(--text)", fontWeight: 600 }}>{used}</b>{" "}
          <span style={{ color: "var(--text-faint)" }}>/ {total}{unit ? ` ${unit}` : ""}</span>
        </span>
      </div>
      <div style={{ height: 9, background: "var(--surface-sunken)", borderRadius: 999, overflow: "hidden" }}>
        <div style={{ width: ratio + "%", height: "100%", borderRadius: 999, background: color, transition: "width 500ms cubic-bezier(0.3,0.7,0.3,1)" }} />
      </div>
      <div style={{ marginTop: 11, fontSize: 12.5, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
        {state === "ok"
          ? <span style={{ color: "var(--text-muted)", display: "inline-flex", alignItems: "center", gap: 7 }}><IcCheck size={13} /> {left} left this cycle</span>
          : <span style={{ color: color, fontWeight: 500, display: "inline-flex", alignItems: "center", gap: 6 }}><IcInfo size={13} /> {left} left — {state === "danger" ? "at your limit" : "approaching your limit"}</span>}
        <span style={{ color: "var(--text-faint)", fontFamily: "var(--font-mono)", fontSize: 11.5 }}>{reset}</span>
      </div>
    </div>
  );
}

function PlanSection() {
  const gridStyle = { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 };

  // Real upload + seat limits from the server (single source of truth) so the
  // numbers here can never drift from what's actually enforced.
  const limits = (typeof window.useVandayLimits === "function") ? window.useVandayLimits() : null;
  const uploadCap = limits?.maxUploads ?? 100;
  const uploadsUsed = limits?.uploadsUsed ?? 0;
  const seatCap = limits?.maxSeats ?? 3;

  // Seat usage = current members + outstanding invites. Fetched lazily.
  const [seatsUsed, setSeatsUsed] = React.useState(null);
  React.useEffect(() => {
    let alive = true;
    (async () => {
      try {
        const a = await window.VandayAPI.getOrgAccess();
        if (!alive) return;
        const members = Array.isArray(a?.members) ? a.members.length : 1;
        const pending = Array.isArray(a?.invites) ? a.invites.filter((iv) => !iv.acceptedAt).length : 0;
        setSeatsUsed(members + pending);
      } catch { if (alive) setSeatsUsed(1); }
    })();
    return () => { alive = false; };
  }, []);

  const seats = seatsUsed == null ? 1 : seatsUsed;

  return (
    <>
      <h1 className="settings-h1">Plan &amp; usage</h1>
      <p className="settings-sub">Track what you've used this cycle. Free Beta includes {uploadCap} uploads and up to {seatCap} workspace members.</p>
      <div style={{ display: "flex", alignItems: "center", gap: 16, padding: "18px 20px", border: "1px solid var(--border)", borderRadius: "var(--radius)", background: "var(--surface)", marginBottom: 18 }}>
        <div style={{ width: 46, height: 46, borderRadius: 12, background: "var(--accent-soft)", color: "var(--accent)", display: "grid", placeItems: "center", flexShrink: 0 }}><IcSparkles size={22} /></div>
        <div>
          <div style={{ fontSize: 15, fontWeight: 600 }}>Free Beta</div>
          <div style={{ fontSize: 12.5, color: "var(--text-muted)", marginTop: 2 }}>You're on the free beta plan</div>
        </div>
        {/* No upgrade path during beta — paid plans aren't available yet. */}
        <span
          style={{
            marginLeft: "auto",
            display: "inline-flex", alignItems: "center", gap: 6,
            padding: "7px 14px", borderRadius: 999,
            background: "var(--surface-sunken)",
            border: "1px solid var(--border)",
            color: "var(--text-muted)",
            fontSize: 12.5, fontWeight: 600, whiteSpace: "nowrap",
          }}
        >
          <IcSparkles size={13} /> Paid plans coming soon
        </span>
      </div>
      <div style={gridStyle}>
        <UsageMeter label="Uploads" icon={<IcUpload size={15} />} used={uploadsUsed} total={uploadCap} left={Math.max(0, uploadCap - uploadsUsed)} reset="beta limit" />
        <UsageMeter label="Team seats" icon={<IcUsers size={15} />} used={seats} total={seatCap} left={Math.max(0, seatCap - seats)} reset="beta limit" />
      </div>
    </>
  );
}

function PlaceholderSection({ name }) {
  return (
    <>
      <h1 className="settings-h1">{name}</h1>
      <p className="settings-sub">This section is part of Vanday's full settings — content placeholder for the prototype.</p>
      <div className="section-card" style={{ padding: 48, textAlign: "center", color: "var(--text-muted)", fontSize: 13 }}>
        <div style={{
          width: 56, height: 56, borderRadius: 14, margin: "0 auto 16px",
          background: "var(--surface-sunken)", display: "grid", placeItems: "center",
          color: "var(--text-faint)",
        }}><IcSettings size={24} /></div>
        {name} settings would live here.
      </div>
    </>
  );
}

function SettingsPage({ onNav, onQuickUpload }) {
  // Honour a one-shot section hint (e.g. from the welcome modal's "Connect
  // accounts" button) so deep-linking into a specific section works.
  const initialSection = (() => {
    try {
      const hint = localStorage.getItem("vanday_settings_section");
      if (hint) {
        localStorage.removeItem("vanday_settings_section");
        return hint;
      }
    } catch {}
    return "users";
  })();
  const [section, setSection] = React.useState(initialSection);

  // Workspace, Plan, and the whole Admin group are admin-only. A non-admin who
  // somehow lands on one (e.g. the default "users" section, or a stale deep
  // link) is bounced to their Profile.
  const ADMIN_ONLY_SECTIONS = React.useMemo(() => new Set([
    "workspace", "plan",
    "users", "projects", "fields", "workflow",
    "integrations", "connections", "api", "audit", "security", "flags",
  ]), []);
  const features = (typeof window.useVandayFeatures === "function")
    ? window.useVandayFeatures()
    : null;
  const featuresLoaded = !!(features && features.loaded);
  const isWsAdmin = features ? features.isWorkspaceAdmin === true : true;
  React.useEffect(() => {
    if (featuresLoaded && !isWsAdmin && ADMIN_ONLY_SECTIONS.has(section)) {
      setSection("profile");
    }
  }, [featuresLoaded, isWsAdmin, section, ADMIN_ONLY_SECTIONS]);
  const restricted = featuresLoaded && !isWsAdmin && ADMIN_ONLY_SECTIONS.has(section);

  const sectionTitle = {
    profile: "Profile", notifs: "Notifications",
    usage: "Usage", plan: "Plan & usage", billing: "Billing", branding: "Branding",
    users: "Users", projects: "Projects", fields: "Fields",
    workflow: "Workflow labels",
    integrations: "Integrations", api: "API & webhooks",
    audit: "Audit log", security: "Content security",
  }[section];

  // Audit + Users + Integrations + API tables benefit from a wider content area.
  const wideSection = section === "audit" || section === "users" || section === "integrations" || section === "api" || section === "flags";

  return (
    <div className="app settings-shell">
      <Rail active="settings" onNav={onNav} onLogout={() => (window.__vandayLogout ? window.__vandayLogout() : onNav("login"))} onSearch={() => onNav("library")} onNotifs={() => onNav("library")} onHelp={() => onNav("library")} onQuickUpload={onQuickUpload} />
      <SettingsSidebar section={section} setSection={setSection} />
      <main className="main">
        <header className="topbar">
          <div className="crumbs">
            <span>Vanday studio</span>
            <span className="sep">/</span>
            <span>Settings</span>
            <span className="sep">/</span>
            <span className="here">{sectionTitle}</span>
          </div>
          <div className="topbar-right">
            <span className="trial-pill" title="Free beta plan"><span className="dot" /> Free Beta</span>
          </div>
        </header>
        <div className="settings-content" style={wideSection ? { maxWidth: 1200 } : undefined}>
          {restricted && (
            <div className="section-card" style={{ display: "flex", gap: 10, alignItems: "flex-start" }}>
              <IcShield size={16} />
              <div style={{ fontSize: 13, color: "var(--text-muted)" }}>
                This area is only available to workspace admins. Ask an admin if you need access.
              </div>
            </div>
          )}
          {!restricted && (
            <>
              {section === "profile"      && <ProfileSection />}
              {/* "connections" route legacy-redirects to integrations — they're merged. */}
              {section === "connections"  && <IntegrationsSection />}
              {section === "workspace"    && <WorkspaceSection />}
              {section === "users"    && <UsersSection />}
              {section === "fields"   && <FieldsSection />}
              {section === "workflow" && <WorkflowLabelsSection />}
              {section === "billing"  && <BillingSection />}
              {section === "usage"    && <UsageSection />}
              {section === "plan"     && <PlanSection />}
              {section === "audit"    && <AuditLogSection />}
              {section === "integrations" && <IntegrationsSection />}
              {section === "api"      && <ApiSection />}
              {section === "flags"    && <FeatureFlagsSection />}
              {(section === "notifs" || section === "branding" ||
                section === "projects" || section === "security") &&
                <PlaceholderSection name={sectionTitle} />}
            </>
          )}
        </div>
      </main>
    </div>
  );
}

window.SettingsPage = SettingsPage;
