// ============================================
// Reliq — Team page
// Step 9: full state-aware rewrite
// ============================================

// ── localStorage keys (resolved from RELIQ_KEYS, with fallbacks) ─────────────
const TEAM_MBR_KEY = window.RELIQ_KEYS?.TEAM_MEMBERS || "reliq_team_members";
const TEAM_LOG_KEY = window.RELIQ_KEYS?.AUDIT_LOG    || "reliq_audit_log";
const TEAM_SSO_KEY = window.RELIQ_KEYS?.SSO_SETTINGS || "reliq_sso_settings";

// ── Role display maps ─────────────────────────────────────────────────────────
const ROLE_LABELS = {
  owner: "Owner", admin: "Admin", developer: "Developer",
  viewer: "Viewer", billing: "Billing",
};
const ROLE_COLORS = {
  owner:     "var(--teal)",
  admin:     "var(--blue)",
  developer: "var(--fg-1)",
  viewer:    "var(--fg-2)",
  billing:   "var(--amber)",
};

// 14 canonical permission keys (same order as RELIQ_PERMISSIONS)
const ALL_PERM_KEYS = [
  "manage_workspace","manage_billing","manage_team","manage_roles",
  "manage_api_keys","manage_webhooks","run_scans","view_scans",
  "view_reports","export_reports","share_reports","view_audit_logs",
  "manage_sso","delete_workspace",
];

const PERM_LABELS = {
  manage_workspace: "Workspace settings",
  manage_billing:   "Billing & plans",
  manage_team:      "Manage team",
  manage_roles:     "Manage roles",
  manage_api_keys:  "API keys",
  manage_webhooks:  "Webhooks",
  run_scans:        "Run scans",
  view_scans:       "View scans",
  view_reports:     "View reports",
  export_reports:   "Export PDFs",
  share_reports:    "Share reports",
  view_audit_logs:  "Audit logs",
  manage_sso:       "SSO",
  delete_workspace: "Delete workspace",
};

// ── Audit event helpers ───────────────────────────────────────────────────────
const auditEventText = (ev) => {
  const map = {
    member_invited:     `invited ${ev.target}`,
    member_removed:     `removed ${ev.target} from workspace`,
    role_changed:       `changed role of ${ev.target}${ev.metadata?.from ? ` (${ev.metadata.from} → ${ev.metadata.to})` : ""}`,
    invite_resent:      `resent invite to ${ev.target}`,
    invite_cancelled:   `cancelled invite for ${ev.target}`,
    api_key_rotated:    `rotated API key`,
    scan_run:           `ran scan — ${ev.target}`,
    webhook_enabled:    `enabled webhook`,
    pdf_exported:       `exported PDF — ${ev.target}`,
    sso_settings_saved: `updated SSO settings`,
    sso_enabled:        `enabled SSO`,
    sso_disabled:       `disabled SSO`,
    workspace_updated:  `updated workspace settings`,
  };
  return map[ev.event] || ev.event;
};

const auditEventIcon = (event) => ({
  member_invited:     "users",
  member_removed:     "users",
  role_changed:       "shield",
  invite_resent:      "send",
  invite_cancelled:   "x",
  api_key_rotated:    "key",
  scan_run:           "scan",
  webhook_enabled:    "webhook",
  pdf_exported:       "download",
  sso_settings_saved: "lock",
  sso_enabled:        "lock",
  sso_disabled:       "lock",
  workspace_updated:  "settings",
}[event] || "activity");

// ── Timestamp helpers ─────────────────────────────────────────────────────────
const relTs = (ts) => {
  if (!ts) return "—";
  if (typeof ts === "string" && !ts.includes("T")) return ts; // already formatted
  try {
    const d = new Date(ts);
    const now = new Date();
    const diffMin = Math.round((now - d) / 60000);
    if (diffMin < 2)   return "just now";
    if (diffMin < 60)  return `${diffMin} min ago`;
    const diffH = Math.floor(diffMin / 60);
    if (diffH < 24)    return `${diffH}h ago`;
    const diffD = Math.floor(diffH / 24);
    if (diffD === 1)   return "Yesterday";
    if (diffD < 7)     return `${diffD} days ago`;
    return d.toLocaleDateString("en-US", { month:"short", day:"numeric", year:"numeric" });
  } catch (_) { return String(ts); }
};

const joinedFmt = (ts) => {
  if (!ts) return "—";
  if (typeof ts === "string" && !ts.includes("T") && !ts.match(/^\d{4}-/)) return ts;
  try {
    return new Date(ts).toLocaleDateString("en-US", { day:"numeric", month:"short", year:"numeric" });
  } catch (_) { return ts; }
};

// ── localStorage helpers ──────────────────────────────────────────────────────
const teamLoad = (key, initial) => {
  try {
    const raw = localStorage.getItem(key);
    if (raw) { const p = JSON.parse(raw); if (p !== null && p !== undefined) return p; }
  } catch (_) {}
  return typeof initial === "function" ? initial() : initial;
};
const teamSave = (key, val) => {
  try { localStorage.setItem(key, JSON.stringify(val)); } catch (_) {}
};

// ── Initial data getters ──────────────────────────────────────────────────────
const getInitialMembers = () =>
  window.INITIAL_TEAM_MEMBERS || [
    { id:"mbr_owner",  name:"Zola Lena",      email:"zola@holt.africa",  role:"owner",     status:"active",  avatar:"ZL", grad:"linear-gradient(135deg,#A78BFA,#5B9DFF)", joinedAt:"2025-08-14", lastActiveAt:"just now",    isCurrentUser:true,  isMock:true },
    { id:"mbr_admin",  name:"Sasha Pillai",   email:"sasha@roamly.app",  role:"admin",     status:"active",  avatar:"SP", grad:"linear-gradient(135deg,#00D4AA,#5B9DFF)", joinedAt:"2025-08-16", lastActiveAt:"12 min ago",  isCurrentUser:false, isMock:true },
    { id:"mbr_dev1",   name:"Marcus Botha",   email:"marcus@roamly.app", role:"developer", status:"active",  avatar:"MB", grad:"linear-gradient(135deg,#F59E0B,#EF4444)", joinedAt:"2025-08-22", lastActiveAt:"2 hours ago", isCurrentUser:false, isMock:true },
    { id:"mbr_dev2",   name:"Aisha Ndlovu",   email:"aisha@roamly.app",  role:"developer", status:"active",  avatar:"AN", grad:"linear-gradient(135deg,#5B9DFF,#00D4AA)", joinedAt:"2025-09-01", lastActiveAt:"Yesterday",   isCurrentUser:false, isMock:true },
    { id:"mbr_viewer", name:"Theo Pretorius", email:"theo@roamly.app",   role:"viewer",    status:"invited", avatar:"TP", grad:"linear-gradient(135deg,#7C828D,#565B65)", joinedAt:null,         lastActiveAt:null,          isCurrentUser:false, isMock:true },
  ];

const getInitialAuditLog = () =>
  window.INITIAL_AUDIT_LOG || [
    { id:"aud_001", event:"api_key_rotated",  actor:"Sasha Pillai", target:"sk_live_••••N9pA", timestamp:"2026-05-26T13:48:00Z", metadata:{},                              isMock:true },
    { id:"aud_002", event:"scan_run",         actor:"Zola Lena",    target:"Roamly v1.4.0",     timestamp:"2026-05-26T12:00:00Z", metadata:{},                              isMock:true },
    { id:"aud_003", event:"member_invited",   actor:"Marcus Botha", target:"theo@roamly.app",   timestamp:"2026-05-26T10:00:00Z", metadata:{ role:"viewer" },               isMock:true },
    { id:"aud_004", event:"role_changed",     actor:"Sasha Pillai", target:"Aisha Ndlovu",      timestamp:"2026-05-25T16:00:00Z", metadata:{ from:"viewer", to:"developer" }, isMock:true },
    { id:"aud_005", event:"webhook_enabled",  actor:"Zola Lena",    target:"Linear webhook",     timestamp:"2026-05-24T10:00:00Z", metadata:{},                              isMock:true },
    { id:"aud_006", event:"pdf_exported",     actor:"Marcus Botha", target:"QuickInvoice scan",  timestamp:"2026-05-23T09:00:00Z", metadata:{},                              isMock:true },
  ];

const getInitialSso = () => ({
  enabled: false, provider: "okta", domain: "roamly.app",
  ssoUrl: "", entityId: "", certificateStatus: "none",
  lastTestedAt: null, isMock: true,
});

// ── Restricted-access banner ──────────────────────────────────────────────────
const TeamRestrictedBanner = ({ message }) => (
  <div style={{
    display:"flex", alignItems:"center", gap:10,
    padding:"11px 14px", marginBottom:16,
    background:"rgba(239,68,68,0.07)", border:"1px solid rgba(239,68,68,0.3)", borderRadius:8,
    fontSize:12.5, color:"var(--fg-1)",
  }}>
    <Icon name="alert" size={13} style={{ color:"var(--red)", flexShrink:0 }} />
    {message}
  </div>
);

// ── Mock badge ────────────────────────────────────────────────────────────────
const TeamMockBadge = () => (
  <span style={{
    display:"inline-flex", alignItems:"center",
    padding:"2px 7px", borderRadius:4,
    background:"rgba(245,158,11,0.1)", border:"1px solid var(--amber, #f59e0b)",
    fontSize:10.5, fontWeight:600, color:"var(--amber, #f59e0b)",
    letterSpacing:"0.04em", textTransform:"uppercase", marginLeft:6, verticalAlign:"middle",
  }}>mock</span>
);

// ═══════════════════════════════════════════════════════════════════════════════
// ── Main component ────────────────────────────────────────────────────────────
// ═══════════════════════════════════════════════════════════════════════════════
const Team = ({ go }) => {

  // ── Tab / filter state ───────────────────────────────────────────────────────
  const [tab, setTab] = React.useState(() => {
    const focus = window.__reliq_pending_focus;
    if (focus && focus.type === "team-tab" && focus.tab) {
      window.__reliq_pending_focus = null;
      return focus.tab;
    }
    return "members";
  });
  const [memberSearch, setMemberSearch] = React.useState("");
  const [filterRole,   setFilterRole]   = React.useState("all");

  // ── Members from localStorage ────────────────────────────────────────────────
  const [members, setMembers] = React.useState(() => teamLoad(TEAM_MBR_KEY, getInitialMembers));

  const persistMembers = (updated) => {
    setMembers(updated);
    teamSave(TEAM_MBR_KEY, updated);
  };

  // ── Audit log from localStorage ──────────────────────────────────────────────
  const [auditLog, setAuditLog] = React.useState(() => teamLoad(TEAM_LOG_KEY, getInitialAuditLog));

  const appendAudit = React.useCallback((event, actor, target, metadata = {}) => {
    setAuditLog(prev => {
      const entry = {
        id: `aud_${Date.now().toString(36)}`,
        event, actor, target,
        timestamp: new Date().toISOString(),
        metadata,
        isMock: true,
      };
      const updated = [entry, ...prev].slice(0, 200);
      teamSave(TEAM_LOG_KEY, updated);
      return updated;
    });
  }, []);

  // ── SSO settings from localStorage ──────────────────────────────────────────
  const [ssoSettings, setSsoSettings] = React.useState(() => teamLoad(TEAM_SSO_KEY, getInitialSso));
  const [ssoProvider,  setSsoProvider] = React.useState(() => teamLoad(TEAM_SSO_KEY, getInitialSso).provider || "okta");
  const [ssoUrl,       setSsoUrl]      = React.useState(() => teamLoad(TEAM_SSO_KEY, getInitialSso).ssoUrl    || "");
  const [ssoDomain,    setSsoDomain]   = React.useState(() => teamLoad(TEAM_SSO_KEY, getInitialSso).domain    || "roamly.app");
  const [ssoEntityId,  setSsoEntityId] = React.useState(() => teamLoad(TEAM_SSO_KEY, getInitialSso).entityId  || "");
  const [ssoSaving,    setSsoSaving]   = React.useState(false);

  const persistSso = (updates) => {
    const updated = { ...ssoSettings, ...updates };
    setSsoSettings(updated);
    teamSave(TEAM_SSO_KEY, updated);
    return updated;
  };

  // ── Invite modal state ───────────────────────────────────────────────────────
  const [inviteOpen,    setInviteOpen]    = React.useState(false);
  const [inviteEmail,   setInviteEmail]   = React.useState("");
  const [inviteRole,    setInviteRole]    = React.useState("developer");
  const [inviteErrors,  setInviteErrors]  = React.useState({});
  const [inviteSending, setInviteSending] = React.useState(false);
  const trapRef   = (window.useFocusTrap || (() => React.useRef(null)))(inviteOpen);
  const emailRef  = React.useRef(null);

  // ── Role change modal state ──────────────────────────────────────────────────
  const [roleChangeOpen,    setRoleChangeOpen]    = React.useState(false);
  const [roleChangeMember,  setRoleChangeMember]  = React.useState(null);
  const [roleChangeNewRole, setRoleChangeNewRole] = React.useState("");
  const roleTrapRef = (window.useFocusTrap || (() => React.useRef(null)))(roleChangeOpen);

  // ── Access enforcement ───────────────────────────────────────────────────────
  const productState      = window.reliqSubscription?.getProductState?.() || "";
  const canModify         = productState === "authenticated_trialing" || productState === "authenticated_active";
  const isPastDueOrCanceled = productState === "authenticated_past_due" || productState === "authenticated_canceled";
  const canUseTeam        = window.reliqPlans?.canUseFeature?.(window.FEATURE_KEYS?.TEAM_MEMBERS) ?? false;
  const canUseSso         = window.reliqPlans?.canUseFeature?.(window.FEATURE_KEYS?.SSO)          ?? false;
  const canUseAuditLogs   = window.reliqPlans?.canUseFeature?.(window.FEATURE_KEYS?.AUDIT_LOGS)   ?? false;

  // ── Current user and role ────────────────────────────────────────────────────
  const currentUser     = members.find(m => m.isCurrentUser);
  const currentUserRole = currentUser?.role || "viewer";
  const rolePerms       = window.RELIQ_ROLES?.[currentUserRole]?.permissions || [];
  const canManageTeamR  = rolePerms.includes("manage_team");
  const canManageRolesR = rolePerms.includes("manage_roles");

  // ── Seat calculation ─────────────────────────────────────────────────────────
  const planData       = window.reliqPlans?.getCurrentPlan?.() || { seats: 1, name: "Free Preview" };
  const planName       = window.reliqPlans?.getCurrentPlanKey?.() || "preview";
  const seatLimit      = planData.seats ?? 1;
  const activeCount    = members.filter(m => m.status === "active").length;
  const invitedCount   = members.filter(m => m.status === "invited").length;
  const occupiedSeats  = activeCount + invitedCount;
  const seatsAvailable = Math.max(0, seatLimit - occupiedSeats);
  const overLimit      = occupiedSeats > seatLimit;

  // ── Workspace info ───────────────────────────────────────────────────────────
  const workspace  = window.reliqWorkspace?.getWorkspace?.() || window.DEFAULT_WORKSPACE || {};
  const wsName     = workspace.name || "Workspace";
  const planLabel  = window.PLAN_META?.[planName]?.name || "Pro";

  // ── Escape closes modals ─────────────────────────────────────────────────────
  React.useEffect(() => {
    if (!inviteOpen && !roleChangeOpen) return;
    const h = (e) => {
      if (e.key === "Escape") {
        if (inviteOpen)    { setInviteOpen(false); }
        if (roleChangeOpen){ setRoleChangeOpen(false); setRoleChangeMember(null); }
      }
    };
    window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, [inviteOpen, roleChangeOpen]);

  // Lock body scroll while any modal is open
  React.useEffect(() => {
    document.body.style.overflow = (inviteOpen || roleChangeOpen) ? "hidden" : "";
    return () => { document.body.style.overflow = ""; };
  }, [inviteOpen, roleChangeOpen]);

  // ── Invite handlers ──────────────────────────────────────────────────────────
  const openInvite = () => {
    if (!canModify) {
      if (isPastDueOrCanceled) {
        window.reliqToast?.warning("Reactivate your plan to invite team members.");
      } else {
        window.reliqToast?.warning("Activate your plan to invite team members.");
      }
      return;
    }
    if (!canUseTeam) {
      window.reliqGatePrompt?.show({
        title:"Team features require Team plan",
        description:"Upgrade to Team to invite members, manage roles, and configure SSO.",
        planRequired:"team", go,
      });
      return;
    }
    if (seatsAvailable <= 0) {
      window.reliqGatePrompt?.show({
        title:"No seats available",
        description:`Your ${planLabel} plan includes ${seatLimit} seat${seatLimit !== 1 ? "s" : ""}. Upgrade to add more.`,
        planRequired:"team", go,
      });
      return;
    }
    setInviteEmail(""); setInviteRole("developer");
    setInviteErrors({}); setInviteSending(false);
    setInviteOpen(true);
  };

  const closeInvite = () => setInviteOpen(false);

  const handleInvite = async () => {
    const emailErr = (window.reliqValidate?.email(inviteEmail)) || null;
    const errs = {};
    if (emailErr) {
      errs.email = emailErr;
    } else if (members.some(m => m.email.toLowerCase() === inviteEmail.trim().toLowerCase())) {
      errs.email = "This person is already a member or has a pending invite.";
    }
    setInviteErrors(errs);
    if (Object.keys(errs).length > 0) return;

    setInviteSending(true);
    await new Promise(r => setTimeout(r, 600));

    const email   = inviteEmail.trim();
    const namePart = email.split("@")[0];
    const initials = namePart.slice(0, 2).toUpperCase();
    const newMember = {
      id:           `mbr_${Date.now().toString(36)}`,
      name:         email,
      email,
      role:         inviteRole,
      status:       "invited",
      avatar:       initials,
      grad:         "linear-gradient(135deg,#7C828D,#565B65)",
      joinedAt:     null,
      lastActiveAt: null,
      invitedAt:    new Date().toISOString(),
      isCurrentUser:false,
      isMock:       true,
    };

    const updated = [...members, newMember];
    persistMembers(updated);
    appendAudit("member_invited", currentUser?.name || "You", email, { role: inviteRole });

    setInviteSending(false);
    closeInvite();
    window.reliqToast?.success(`Invite sent to ${email}`);
  };

  // ── Resend invite ────────────────────────────────────────────────────────────
  const handleResendInvite = (member) => {
    const updated = members.map(m =>
      m.id === member.id ? { ...m, invitedAt: new Date().toISOString() } : m
    );
    persistMembers(updated);
    appendAudit("invite_resent", currentUser?.name || "You", member.email, {});
    window.reliqToast?.success(`Invite resent to ${member.email}`);
  };

  // ── Cancel invite ────────────────────────────────────────────────────────────
  const handleCancelInvite = (member) => {
    window.reliqConfirm?.show({
      title: "Cancel this invite?",
      message: `The invite to ${member.email} will be cancelled. They won't be able to join this workspace using this invite.`,
      danger: true,
      confirmLabel: "Cancel invite",
      onConfirm: () => {
        persistMembers(members.filter(m => m.id !== member.id));
        appendAudit("invite_cancelled", currentUser?.name || "You", member.email, {});
        window.reliqToast?.success(`Invite to ${member.email} cancelled`);
      },
    });
  };

  // ── Open role change modal ───────────────────────────────────────────────────
  const openRoleChange = (member) => {
    if (!canModify) {
      window.reliqToast?.warning("Reactivate your plan to manage roles.");
      return;
    }
    if (!canManageRolesR) {
      window.reliqToast?.warning("You don't have permission to change roles.");
      return;
    }
    if (member.role === "owner" && member.isCurrentUser) {
      window.reliqToast?.info("To transfer workspace ownership, contact Reliq support.");
      return;
    }
    if (member.role === "owner") {
      window.reliqToast?.info("Owner role cannot be changed. Transfer ownership to reassign.");
      return;
    }
    setRoleChangeMember(member);
    setRoleChangeNewRole(member.role);
    setRoleChangeOpen(true);
  };

  const closeRoleChange = () => {
    setRoleChangeOpen(false);
    setRoleChangeMember(null);
  };

  const handleRoleChange = () => {
    if (!roleChangeMember) return;
    if (!roleChangeNewRole || roleChangeNewRole === roleChangeMember.role) {
      closeRoleChange();
      return;
    }
    const oldRole = roleChangeMember.role;
    const newRole = roleChangeNewRole;
    persistMembers(members.map(m =>
      m.id === roleChangeMember.id ? { ...m, role: newRole } : m
    ));
    appendAudit("role_changed", currentUser?.name || "You", roleChangeMember.name, { from: oldRole, to: newRole });
    window.reliqToast?.success(`${roleChangeMember.name}'s role changed to ${ROLE_LABELS[newRole] || newRole}`);
    closeRoleChange();
  };

  // ── Remove member ────────────────────────────────────────────────────────────
  const handleRemove = (member) => {
    if (!canModify) {
      window.reliqToast?.warning("Reactivate your plan to manage members.");
      return;
    }
    if (!canManageTeamR) {
      window.reliqToast?.warning("You don't have permission to remove members.");
      return;
    }
    if (member.isCurrentUser) {
      window.reliqToast?.error("You cannot remove yourself from the workspace.");
      return;
    }
    window.reliqConfirm?.show({
      title: `Remove ${member.name}?`,
      message: `${member.name} (${member.email}) will lose access to this workspace immediately. This cannot be undone.`,
      danger: true,
      confirmLabel: "Remove member",
      onConfirm: () => {
        persistMembers(members.filter(m => m.id !== member.id));
        appendAudit("member_removed", currentUser?.name || "You", member.name, { email: member.email });
        window.reliqToast?.success(`${member.name} removed from workspace`);
      },
    });
  };

  // ── SSO handlers ─────────────────────────────────────────────────────────────
  const handleSsoToggle = () => {
    if (!canModify || !canUseSso) return;
    const enabled = !ssoSettings.enabled;
    persistSso({ enabled });
    appendAudit(enabled ? "sso_enabled" : "sso_disabled", currentUser?.name || "You", ssoProvider, {});
    window.reliqToast?.success(enabled ? "SSO enabled" : "SSO disabled");
  };

  const handleSsoSave = async () => {
    if (!ssoUrl.trim()) {
      window.reliqToast?.error("SAML SSO URL is required.");
      return;
    }
    setSsoSaving(true);
    await new Promise(r => setTimeout(r, 500));
    persistSso({ provider: ssoProvider, ssoUrl: ssoUrl.trim(), domain: ssoDomain.trim(), entityId: ssoEntityId.trim() });
    appendAudit("sso_settings_saved", currentUser?.name || "You", ssoProvider, {});
    setSsoSaving(false);
    window.reliqToast?.success("SSO settings saved");
  };

  // ── Filtered members for display ─────────────────────────────────────────────
  const filteredMembers = React.useMemo(() => {
    const q = memberSearch.toLowerCase();
    return members.filter(m => {
      if (q && !m.name.toLowerCase().includes(q) && !m.email.toLowerCase().includes(q)) return false;
      if (filterRole !== "all" && m.role !== filterRole) return false;
      return true;
    });
  }, [members, memberSearch, filterRole]);

  // ── Role counts for roles tab ────────────────────────────────────────────────
  const roleCounts = React.useMemo(() => {
    const c = {};
    members.forEach(m => { c[m.role] = (c[m.role] || 0) + 1; });
    return c;
  }, [members]);

  // ── All roles from RELIQ_ROLES (with fallback) ───────────────────────────────
  const allRoles = React.useMemo(() => {
    if (window.RELIQ_ROLES) return Object.values(window.RELIQ_ROLES);
    return [
      { key:"owner",     label:"Owner",     description:"Full access.",    permissions:ALL_PERM_KEYS },
      { key:"admin",     label:"Admin",     description:"No delete.",       permissions:ALL_PERM_KEYS.filter(p => p !== "delete_workspace") },
      { key:"developer", label:"Developer", description:"Scans & API.",    permissions:["manage_api_keys","manage_webhooks","run_scans","view_scans","view_reports","export_reports","share_reports"] },
      { key:"viewer",    label:"Viewer",    description:"Read-only.",        permissions:["view_scans","view_reports"] },
      { key:"billing",   label:"Billing",   description:"Billing only.",    permissions:["manage_billing","view_reports","view_audit_logs"] },
    ];
  }, []);

  // ═══════════════════════════════════════════════════════════════════════════
  // ── RENDER ─────────────────────────────────────────────────────────────────
  // ═══════════════════════════════════════════════════════════════════════════
  return (
    <AuthLayout
      route="team"
      go={go}
      crumbs={["Workspace", "Team"]}
      maxWidth={1180}
      actions={
        <button className="btn btn-primary btn-sm" onClick={openInvite}>
          <Icon name="plus" size={13} /> Invite member
        </button>
      }
    >
      {/* ── Page head ──────────────────────────────────────────────────────── */}
      <div className="page-head">
        <div>
          <h1 className="page-title">Team</h1>
          <p className="page-sub">
            {wsName} workspace · {activeCount} active{invitedCount > 0 ? ` · ${invitedCount} pending invite${invitedCount !== 1 ? "s" : ""}` : ""}
          </p>
        </div>
        <div className="text-mono" style={{ fontSize:12, color:"var(--fg-2)" }}>
          {planLabel} plan · seats reset on billing renewal
        </div>
      </div>

      {/* ── Seat usage strip ───────────────────────────────────────────────── */}
      <div className="card" style={{ marginBottom:20 }}>
        <div className="card-body" style={{ display:"flex", alignItems:"center", gap:24 }}>
          <div>
            <div className="mono" style={{ fontSize:10.5, letterSpacing:"0.12em", textTransform:"uppercase", color:"var(--fg-3)", marginBottom:6 }}>Seat usage</div>
            <div style={{ display:"flex", alignItems:"baseline", gap:6 }}>
              <span style={{ fontFamily:"var(--font-display)", fontSize:30, fontWeight:600, letterSpacing:"-0.015em", lineHeight:1 }}>
                {occupiedSeats}
              </span>
              <span style={{ fontSize:14, color:"var(--fg-2)" }}>/ {seatLimit} seats</span>
            </div>
          </div>
          <div style={{ flex:1 }}>
            <div style={{ display:"flex", gap:4, marginBottom:8 }}>
              {Array.from({ length: seatLimit }, (_, i) => {
                const filled = i < Math.min(occupiedSeats, seatLimit);
                const overLimitFill = overLimit && i < seatLimit;
                return (
                  <div key={i} style={{
                    flex:1, height:10, borderRadius:3,
                    background: overLimitFill
                      ? "linear-gradient(90deg, var(--red), rgba(239,68,68,0.7))"
                      : filled
                        ? "linear-gradient(90deg, var(--teal-d), var(--teal))"
                        : "var(--bg-3)",
                    boxShadow: filled ? "0 0 8px rgba(0,212,170,0.3)" : "none",
                    border: !filled ? "1px dashed var(--line-3)" : "0",
                  }} />
                );
              })}
            </div>
            <div className="mono" style={{ fontSize:12, color: overLimit ? "var(--red)" : "var(--fg-2)" }}>
              {overLimit
                ? `${occupiedSeats - seatLimit} seat${occupiedSeats - seatLimit !== 1 ? "s" : ""} over limit · upgrade to add more`
                : seatsAvailable > 0
                  ? `${seatsAvailable} seat${seatsAvailable !== 1 ? "s" : ""} available${invitedCount > 0 ? ` · ${invitedCount} pending invite${invitedCount !== 1 ? "s" : ""}` : ""}`
                  : `No seats available · upgrade for more`
              }
            </div>
          </div>
          {(!canUseTeam || seatsAvailable <= 0 || overLimit) && (
            <button className="btn" onClick={() => go("billing")}>
              <Icon name="bolt" size={13} /> Upgrade plan
            </button>
          )}
        </div>
      </div>

      {/* ── Access warning banners ──────────────────────────────────────────── */}
      {isPastDueOrCanceled && (
        <TeamRestrictedBanner message="Your subscription is inactive. Team management is read-only — reactivate your plan to invite or manage members." />
      )}
      {productState === "authenticated_pending_payment" && (
        <TeamRestrictedBanner message="Payment required. Add a payment method to manage your team." />
      )}

      {/* ── Tabs ───────────────────────────────────────────────────────────── */}
      <div className="tabs">
        {[
          { id:"members", label:"Members",           ic:"users",    ct: String(members.length) },
          { id:"roles",   label:"Roles & permissions", ic:"shield" },
          { id:"audit",   label:"Audit log",         ic:"activity" },
          { id:"sso",     label:"SSO",               ic:"lock" },
        ].map(t => (
          <div key={t.id} className={`tab ${tab === t.id ? "active" : ""}`} onClick={() => setTab(t.id)}>
            <Icon name={t.ic} size={14} />{t.label}
            {t.ct && <span className="ct">{t.ct}</span>}
          </div>
        ))}
      </div>

      {/* ══ MEMBERS TAB ═══════════════════════════════════════════════════════ */}
      {tab === "members" && (
        <div className="card">
          <div className="card-head">
            <div className="card-title">Workspace members</div>
            <div style={{ marginLeft:"auto", display:"flex", gap:8, alignItems:"center" }}>
              <div style={{ position:"relative" }}>
                <Icon name="search" size={13} style={{ position:"absolute", left:9, top:"50%", transform:"translateY(-50%)", color:"var(--fg-3)", pointerEvents:"none" }} />
                <input
                  value={memberSearch}
                  onChange={e => setMemberSearch(e.target.value)}
                  placeholder="Filter by name or email"
                  style={{ height:32, width:220, boxSizing:"border-box",
                    background:"var(--bg-2)", border:"1px solid var(--line-2)", borderRadius:"var(--r-sm)",
                    padding:"0 10px 0 30px", fontSize:12.5, color:"var(--fg-0)", outline:"none" }}
                />
              </div>
              <select value={filterRole} onChange={e => setFilterRole(e.target.value)} style={{
                background:"var(--bg-2)", border:"1px solid var(--line-2)", borderRadius:"var(--r-sm)",
                padding:"0 10px", height:32, fontSize:12.5, color:"var(--fg-0)", outline:"none", cursor:"pointer",
              }}>
                <option value="all">All roles</option>
                <option value="owner">Owner</option>
                <option value="admin">Admin</option>
                <option value="developer">Developer</option>
                <option value="viewer">Viewer</option>
                <option value="billing">Billing</option>
              </select>
              {(memberSearch || filterRole !== "all") && (
                <button className="btn btn-sm btn-ghost" onClick={() => { setMemberSearch(""); setFilterRole("all"); }}>
                  <Icon name="x" size={11} />
                </button>
              )}
            </div>
          </div>
          <table className="tbl">
            <thead>
              <tr>
                <th>Member</th>
                <th>Role</th>
                <th>Status</th>
                <th style={{ textAlign:"right" }}>Scans</th>
                <th>Joined</th>
                <th>Last active</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {filteredMembers.length === 0 && (
                <tr><td colSpan={7} style={{ textAlign:"center", padding:"40px 20px", color:"var(--fg-3)" }}>
                  No members match your search.
                </td></tr>
              )}
              {filteredMembers.map(m => (
                <tr key={m.id || m.email}>
                  <td>
                    <div style={{ display:"flex", alignItems:"center", gap:12 }}>
                      <div className="avatar" style={{ background: m.grad }}>{m.avatar}</div>
                      <div>
                        <div style={{ fontWeight:500, fontSize:13.5 }}>
                          {m.name}{m.isCurrentUser && <span className="mono" style={{ fontSize:11, color:"var(--fg-3)", marginLeft:6 }}>(you)</span>}
                        </div>
                        <div className="mono" style={{ fontSize:11.5, color:"var(--fg-3)" }}>{m.email}</div>
                      </div>
                    </div>
                  </td>
                  <td>
                    <span className="mono" style={{
                      fontSize:11, fontWeight:600, letterSpacing:"0.08em",
                      textTransform:"uppercase", color: ROLE_COLORS[m.role] || "var(--fg-1)",
                    }}>
                      {ROLE_LABELS[m.role] || m.role}
                    </span>
                  </td>
                  <td>
                    {m.status === "active" ? (
                      <span style={{ display:"inline-flex", alignItems:"center", gap:6, fontSize:12.5, color:"var(--fg-1)" }}>
                        <span className="live-dot" style={{ width:5, height:5 }}></span> Active
                      </span>
                    ) : (
                      <span className="chip" style={{ color:"var(--amber)", borderColor:"rgba(245,158,11,0.3)", background:"var(--amber-bg)" }}>
                        <Icon name="clock" size={10} /> Invited
                      </span>
                    )}
                  </td>
                  <td style={{ textAlign:"right", fontFamily:"var(--font-mono)", fontSize:13, color:"var(--fg-1)" }}>
                    {m.scans || "—"}
                  </td>
                  <td className="mono" style={{ fontSize:12, color:"var(--fg-2)" }}>
                    {m.status === "invited" ? "—" : joinedFmt(m.joinedAt)}
                  </td>
                  <td className="mono" style={{ fontSize:12, color:"var(--fg-2)" }}>
                    {m.status === "invited" ? (
                      <span style={{ color:"var(--fg-3)" }}>Invite sent</span>
                    ) : relTs(m.lastActiveAt)}
                  </td>
                  <td>
                    <div style={{ display:"flex", gap:4, justifyContent:"flex-end" }}>
                      {m.status === "invited" ? (
                        <>
                          <button
                            className="btn btn-sm btn-ghost"
                            title="Resend invite"
                            disabled={!canModify}
                            onClick={() => handleResendInvite(m)}
                          >
                            <Icon name="send" size={12} /> Resend
                          </button>
                          <button
                            className="btn btn-sm btn-ghost"
                            title="Cancel invite"
                            disabled={!canModify}
                            style={{ color:"var(--red)" }}
                            onClick={() => handleCancelInvite(m)}
                          >
                            <Icon name="x" size={12} />
                          </button>
                        </>
                      ) : (
                        <>
                          <button
                            className="btn btn-sm btn-ghost btn-icon"
                            title={m.role === "owner" ? "Owner role cannot be changed here" : `Change ${m.name}'s role`}
                            onClick={() => openRoleChange(m)}
                            disabled={!canModify || !canManageRolesR}
                          >
                            <Icon name="settings" size={13} />
                          </button>
                          {m.role !== "owner" && (
                            <button
                              className="btn btn-sm btn-ghost btn-icon"
                              style={{ color:"var(--red)" }}
                              aria-label={`Remove ${m.name}`}
                              title={`Remove ${m.name}`}
                              disabled={!canModify || !canManageTeamR}
                              onClick={() => handleRemove(m)}
                            >
                              <Icon name="trash" size={13} />
                            </button>
                          )}
                        </>
                      )}
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* ══ ROLES & PERMISSIONS TAB ═══════════════════════════════════════════ */}
      {tab === "roles" && (
        <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:14 }}>
          {allRoles.map(r => {
            const count = roleCounts[r.key] || 0;
            const perms  = r.permissions || [];
            return (
              <div className="card" key={r.key}>
                <div className="card-body">
                  <div style={{ display:"flex", alignItems:"center", gap:10, marginBottom:10 }}>
                    <span style={{
                      fontFamily:"var(--font-mono)", fontSize:11, fontWeight:600,
                      letterSpacing:"0.1em", textTransform:"uppercase",
                      color: ROLE_COLORS[r.key] || "var(--fg-1)",
                    }}>
                      {r.label}
                    </span>
                    <span className="mono" style={{ fontSize:11, color:"var(--fg-3)", marginLeft:"auto" }}>
                      {count === 0 ? "No members" : `${count} ${count === 1 ? "user" : "users"}`}
                      {r.key === "viewer" && invitedCount > 0 && count === invitedCount
                        ? ` · ${invitedCount} invite${invitedCount !== 1 ? "s" : ""}` : ""}
                    </span>
                  </div>
                  <div style={{ fontSize:13.5, color:"var(--fg-1)", marginBottom:14, lineHeight:1.5 }}>
                    {r.description}
                  </div>
                  <div style={{ display:"flex", flexWrap:"wrap", gap:6 }}>
                    {ALL_PERM_KEYS.map(p => {
                      const has = perms.includes(p);
                      return (
                        <span key={p} className="chip mono" style={{
                          fontSize:10.5,
                          color:       has ? "var(--teal)" : "var(--fg-3)",
                          background:  has ? "var(--teal-bg)" : "var(--bg-2)",
                          borderColor: has ? "rgba(0,212,170,0.25)" : "var(--line-1)",
                          opacity:     has ? 1 : 0.55,
                        }}>
                          {has ? <Icon name="check" size={10} /> : <Icon name="x" size={10} />}
                          {PERM_LABELS[p] || p}
                        </span>
                      );
                    })}
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      )}

      {/* ══ AUDIT LOG TAB ═════════════════════════════════════════════════════ */}
      {tab === "audit" && (
        <>
          {!canUseAuditLogs ? (
            <div className="card">
              <div className="card-body">
                <div style={{
                  padding:"14px 16px", borderRadius:10,
                  background:"radial-gradient(120% 80% at 0% 0%, rgba(91,157,255,0.10), transparent 60%), var(--bg-2)",
                  border:"1px solid rgba(91,157,255,0.25)",
                  display:"flex", alignItems:"center", gap:14,
                }}>
                  <Icon name="info" size={16} />
                  <div style={{ fontSize:13, color:"var(--fg-1)" }}>
                    Audit logs are available on the Team plan. Upgrade to view all workspace activity.
                  </div>
                  <button className="btn btn-sm btn-primary" style={{ marginLeft:"auto" }} onClick={() => go("billing")}>
                    Upgrade
                  </button>
                </div>
              </div>
            </div>
          ) : (
            <div className="card">
              <div className="card-head">
                <div className="card-title">Audit log</div>
                <span className="card-sub">Last 200 events <TeamMockBadge /></span>
              </div>
              <div>
                {auditLog.length === 0 && (
                  <div style={{ padding:"40px 20px", textAlign:"center", color:"var(--fg-3)", fontSize:13 }}>
                    No audit events yet. Member invites, role changes, and SSO actions will appear here.
                  </div>
                )}
                {auditLog.map((ev, i) => (
                  <div key={ev.id || i} style={{
                    display:"flex", alignItems:"center", gap:14,
                    padding:"14px 18px",
                    borderTop: "1px solid var(--line-1)",
                  }}>
                    <div style={{
                      width:32, height:32, borderRadius:8,
                      background:"var(--bg-2)", border:"1px solid var(--line-2)",
                      display:"grid", placeItems:"center", color:"var(--fg-1)", flexShrink:0,
                    }}>
                      <Icon name={auditEventIcon(ev.event)} size={14} />
                    </div>
                    <div style={{ fontSize:13, flex:1 }}>
                      <span style={{ fontWeight:500 }}>{ev.actor}</span>
                      <span style={{ color:"var(--fg-2)" }}> {auditEventText(ev)}</span>
                    </div>
                    <div className="mono" style={{ fontSize:11.5, color:"var(--fg-3)", flexShrink:0 }}>
                      {relTs(ev.timestamp)}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          )}
        </>
      )}

      {/* ══ SSO TAB ═══════════════════════════════════════════════════════════ */}
      {tab === "sso" && (
        <div className="card">
          <div className="card-head">
            <div className="card-title">Single Sign-On (SAML)</div>
            <span className="card-sub">Team plan only</span>
            {canUseSso && canModify && (
              <button
                className="btn btn-sm"
                style={{ marginLeft:"auto", color: ssoSettings.enabled ? "var(--red)" : "var(--teal)" }}
                onClick={handleSsoToggle}
              >
                <Icon name={ssoSettings.enabled ? "toggle-right" : "toggle-left"} size={13} />
                {ssoSettings.enabled ? " Disable SSO" : " Enable SSO"}
              </button>
            )}
          </div>
          <div className="card-body">
            {!canUseSso && (
              <div style={{
                padding:"14px 16px", borderRadius:10,
                background:"radial-gradient(120% 80% at 0% 0%, rgba(91,157,255,0.10), transparent 60%), var(--bg-2)",
                border:"1px solid rgba(91,157,255,0.25)",
                display:"flex", alignItems:"center", gap:14, marginBottom:20,
              }}>
                <Icon name="info" size={16} />
                <div style={{ fontSize:13, color:"var(--fg-1)" }}>
                  SSO is available on the Team plan. Upgrade to provision via Okta, Azure AD, or Google Workspace.
                </div>
                <button className="btn btn-sm btn-primary" style={{ marginLeft:"auto" }} onClick={() => go("billing")}>
                  Upgrade
                </button>
              </div>
            )}

            {canUseSso && ssoSettings.enabled && (
              <div style={{
                display:"flex", alignItems:"center", gap:8,
                padding:"10px 14px", borderRadius:8, marginBottom:20,
                background:"rgba(0,212,170,0.07)", border:"1px solid rgba(0,212,170,0.3)",
                fontSize:12.5, color:"var(--teal)",
              }}>
                <span className="live-dot" style={{ width:6, height:6 }}></span>
                <span style={{ fontWeight:600 }}>SSO active</span>
                <span style={{ color:"var(--fg-2)" }}> — members with a {ssoDomain} email must sign in via SSO</span>
                <TeamMockBadge />
              </div>
            )}

            <div className="field">
              <label>Identity provider</label>
              <select
                value={ssoProvider}
                onChange={e => setSsoProvider(e.target.value)}
                disabled={!canUseSso || !canModify}
              >
                <option value="okta">Okta</option>
                <option value="azure_ad">Azure AD</option>
                <option value="google">Google Workspace</option>
                <option value="onelogin">OneLogin</option>
              </select>
            </div>
            <div className="field">
              <label>SAML SSO URL</label>
              <input
                value={ssoUrl}
                onChange={e => setSsoUrl(e.target.value)}
                placeholder="https://idp.example.com/sso/saml"
                disabled={!canUseSso || !canModify}
              />
              <div className="hint">The SAML 2.0 endpoint URL from your identity provider.</div>
            </div>
            <div className="field">
              <label>Enforce SSO for domain</label>
              <input
                value={ssoDomain}
                onChange={e => setSsoDomain(e.target.value)}
                placeholder="example.com"
                disabled={!canUseSso || !canModify}
              />
              <div className="hint">Users with this email domain will be required to sign in via SSO.</div>
            </div>
            <div className="field">
              <label>Entity ID / Issuer <span style={{ color:"var(--fg-3)", fontWeight:400 }}>(optional)</span></label>
              <input
                value={ssoEntityId}
                onChange={e => setSsoEntityId(e.target.value)}
                placeholder="https://your-app.example.com"
                disabled={!canUseSso || !canModify}
              />
            </div>

            {canUseSso && canModify && (
              <div style={{ display:"flex", gap:8, marginTop:8 }}>
                <button
                  className="btn btn-sm btn-primary"
                  onClick={handleSsoSave}
                  disabled={ssoSaving}
                  style={ssoSaving ? { opacity:0.7 } : undefined}
                >
                  {ssoSaving
                    ? <><svg width="12" height="12" viewBox="0 0 24 24" style={{ animation:"spin 1s linear infinite" }}><circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" fill="none" strokeDasharray="40 60" strokeLinecap="round"/></svg> Saving…</>
                    : <><Icon name="check" size={12} /> Save SSO settings</>
                  }
                </button>
              </div>
            )}

            {!canUseSso && (
              <div className="field" style={{ marginTop:4 }}>
                <label>Entity ID / Issuer <span style={{ color:"var(--fg-3)", fontWeight:400 }}>(optional)</span></label>
                <input placeholder="https://your-app.example.com" disabled />
              </div>
            )}
          </div>
        </div>
      )}

      {/* ══ INVITE MEMBER MODAL ═══════════════════════════════════════════════ */}
      {inviteOpen && (
        <div
          role="dialog"
          aria-modal="true"
          aria-labelledby="invite-modal-title"
          onClick={e => { if (e.target === e.currentTarget) closeInvite(); }}
          style={{
            position:"fixed", inset:0, zIndex:1000,
            background:"rgba(0,0,0,0.55)", backdropFilter:"blur(4px)",
            display:"flex", alignItems:"center", justifyContent:"center",
            padding:24,
          }}
        >
          <div
            ref={trapRef}
            style={{
              background:"var(--bg-1)", border:"1px solid var(--line-2)",
              borderRadius:"var(--r-lg)", boxShadow:"0 16px 48px rgba(0,0,0,0.32)",
              width:"100%", maxWidth:460, padding:28,
            }}
          >
            <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:20 }}>
              <h2 id="invite-modal-title" style={{ margin:0, fontFamily:"var(--font-display)", fontSize:17, fontWeight:600, letterSpacing:"-0.01em" }}>
                Invite team member <TeamMockBadge />
              </h2>
              <button className="btn btn-sm btn-ghost btn-icon" onClick={closeInvite} aria-label="Close">
                <Icon name="x" size={15} />
              </button>
            </div>

            <div style={{ fontSize:12.5, color:"var(--fg-3)", marginBottom:18 }}>
              {seatsAvailable} seat{seatsAvailable !== 1 ? "s" : ""} available of {seatLimit} total.
              No real email is sent — invite is local only.
            </div>

            <div className="field" style={{ marginBottom:16 }}>
              <label htmlFor="invite-email">Email address</label>
              <input
                id="invite-email"
                ref={emailRef}
                type="email"
                value={inviteEmail}
                onChange={e => { setInviteEmail(e.target.value); if (inviteErrors.email) setInviteErrors(p => ({...p, email:null})); }}
                onBlur={e => {
                  const err = window.reliqValidate?.email(e.target.value) || null;
                  setInviteErrors(p => ({...p, email: err}));
                }}
                placeholder="colleague@company.com"
                aria-invalid={!!inviteErrors.email}
                aria-describedby={inviteErrors.email ? "invite-email-err" : undefined}
                style={inviteErrors.email ? { borderColor:"var(--red)" } : undefined}
              />
              {inviteErrors.email && (
                <span id="invite-email-err" role="alert" style={{ display:"block", marginTop:5, fontSize:12, color:"var(--red)" }}>
                  <Icon name="alert" size={11} /> {inviteErrors.email}
                </span>
              )}
            </div>

            <div className="field" style={{ marginBottom:24 }}>
              <label htmlFor="invite-role">Role</label>
              <select
                id="invite-role"
                value={inviteRole}
                onChange={e => setInviteRole(e.target.value)}
              >
                <option value="admin">Admin — manage members, scans, and integrations</option>
                <option value="developer">Developer — run scans, view reports, manage API keys</option>
                <option value="viewer">Viewer — read-only access to scans and reports</option>
                <option value="billing">Billing — manage billing and plans only</option>
              </select>
              <div className="hint">Owners can be transferred after the invite is accepted.</div>
            </div>

            <div style={{ display:"flex", gap:10, justifyContent:"flex-end" }}>
              <button className="btn btn-sm" onClick={closeInvite} disabled={inviteSending}>
                Cancel
              </button>
              <button
                className="btn btn-sm btn-primary"
                onClick={handleInvite}
                disabled={inviteSending}
                style={inviteSending ? { opacity:0.7 } : undefined}
              >
                {inviteSending
                  ? <><svg width="12" height="12" viewBox="0 0 24 24" style={{ animation:"spin 1s linear infinite" }}><circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" fill="none" strokeDasharray="40 60" strokeLinecap="round"/></svg> Sending…</>
                  : <><Icon name="send" size={12} /> Send invite</>
                }
              </button>
            </div>
          </div>
        </div>
      )}

      {/* ══ ROLE CHANGE MODAL ════════════════════════════════════════════════ */}
      {roleChangeOpen && roleChangeMember && (
        <div
          role="dialog"
          aria-modal="true"
          aria-labelledby="role-modal-title"
          onClick={e => { if (e.target === e.currentTarget) closeRoleChange(); }}
          style={{
            position:"fixed", inset:0, zIndex:1000,
            background:"rgba(0,0,0,0.55)", backdropFilter:"blur(4px)",
            display:"flex", alignItems:"center", justifyContent:"center",
            padding:24,
          }}
        >
          <div
            ref={roleTrapRef}
            style={{
              background:"var(--bg-1)", border:"1px solid var(--line-2)",
              borderRadius:"var(--r-lg)", boxShadow:"0 16px 48px rgba(0,0,0,0.32)",
              width:"100%", maxWidth:400, padding:28,
            }}
          >
            <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:20 }}>
              <h2 id="role-modal-title" style={{ margin:0, fontFamily:"var(--font-display)", fontSize:17, fontWeight:600, letterSpacing:"-0.01em" }}>
                Change role
              </h2>
              <button className="btn btn-sm btn-ghost btn-icon" onClick={closeRoleChange} aria-label="Close">
                <Icon name="x" size={15} />
              </button>
            </div>

            <div style={{ display:"flex", alignItems:"center", gap:12, marginBottom:20, padding:"12px 14px", background:"var(--bg-2)", borderRadius:8 }}>
              <div className="avatar" style={{ background: roleChangeMember.grad }}>
                {roleChangeMember.avatar}
              </div>
              <div>
                <div style={{ fontWeight:500, fontSize:13.5 }}>{roleChangeMember.name}</div>
                <div className="mono" style={{ fontSize:11.5, color:"var(--fg-3)" }}>{roleChangeMember.email}</div>
              </div>
            </div>

            <div className="field" style={{ marginBottom:24 }}>
              <label htmlFor="role-select">New role</label>
              <select
                id="role-select"
                value={roleChangeNewRole}
                onChange={e => setRoleChangeNewRole(e.target.value)}
                autoFocus
              >
                <option value="admin">Admin — manage members, scans, and integrations</option>
                <option value="developer">Developer — run scans, view reports, manage API keys</option>
                <option value="viewer">Viewer — read-only access to scans and reports</option>
                <option value="billing">Billing — manage billing and plans only</option>
              </select>
            </div>

            <div style={{ display:"flex", gap:10, justifyContent:"flex-end" }}>
              <button className="btn btn-sm" onClick={closeRoleChange}>Cancel</button>
              <button
                className="btn btn-sm btn-primary"
                onClick={handleRoleChange}
                disabled={roleChangeNewRole === roleChangeMember.role}
              >
                <Icon name="check" size={12} /> Change role
              </button>
            </div>
          </div>
        </div>
      )}
    </AuthLayout>
  );
};

Object.assign(window, { Team });
