/* ========================================================================
   roles-users.jsx — Users and roles (Settings tab) + invite / details /
   change role / remove access / compare roles
   ======================================================================== */
const { useState: uU, useMemo: mU, useEffect: eU } = React;

/* =====================================================================
   Users and roles
   ===================================================================== */
function UsersRolesTab() {
  const ctx = useRoles();
  const { members, actor, role } = ctx;
  const [query, setQuery] = uU("");
  const [roleFilter, setRoleFilter] = uU("");
  const [statusFilter, setStatusFilter] = uU("");
  const [inviteOpen, setInviteOpen] = uU(false);
  const [compareOpen, setCompareOpen] = uU(false);
  const [detailId, setDetailId] = uU(null);

  const rows = mU(() => {
    let list = members.filter((m) => m.status !== "removed");
    if (query) {
      const q = query.toLowerCase();
      list = list.filter((m) => m.name.toLowerCase().includes(q) || m.email.toLowerCase().includes(q));
    }
    if (roleFilter) list = list.filter((m) => m.role === roleFilter);
    if (statusFilter) list = list.filter((m) => m.status === statusFilter);
    return list.slice().sort((a, b) => {
      if (a.role === "owner") return -1;
      if (b.role === "owner") return 1;
      const r = window.ROLES[b.role].rank - window.ROLES[a.role].rank;
      if (r) return r;
      return a.name.localeCompare(b.name);
    });
  }, [members, query, roleFilter, statusFilter]);

  const canInvite = ctx.can("users.invite");

  /* Scroll the activity card into view inside whichever ancestor actually scrolls */
  const jumpToLog = () => {
    const card = document.querySelector(".mp-audit-card");
    if (!card) return;
    let scroller = card.parentElement;
    while (scroller && scroller !== document.body && scroller.scrollHeight <= scroller.clientHeight + 4) scroller = scroller.parentElement;
    const top = scroller && scroller !== document.body
      ? card.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop - 16
      : card.getBoundingClientRect().top + window.scrollY - 16;
    (scroller && scroller !== document.body ? scroller : window).scrollTo({ top, behavior: "smooth" });
    card.classList.remove("is-flash");
    requestAnimationFrame(() => card.classList.add("is-flash"));
  };
  const detail = detailId != null ? members.find((m) => m.id === detailId) : null;

  return (
    <>
      <div className="mp-sec-head" style={{ justifyContent: "flex-end" }}>
        <div className="mp-sec-actions">
          <button type="button" className="mp-linkbtn" onClick={() => setCompareOpen(true)}>
            <Icon name="table-2" size={15} /><span>Compare Roles</span>
          </button>
          {canInvite ? <Button variant="primary" icon="user-plus" onClick={() => setInviteOpen(true)}>Invite Admin User</Button> : null}
        </div>
      </div>

      <Card>
        <div className="mp-mem-filters">
          <SearchInput value={query} onChange={setQuery} placeholder="Search name or email..." />
          <Select value={roleFilter} onChange={setRoleFilter} placeholder="All roles"
            options={window.ROLE_ORDER.map((r) => ({ value: r, label: window.ROLES[r].label }))} />
          <Select value={statusFilter} onChange={setStatusFilter} placeholder="All statuses"
            options={[{ value: "active", label: "Active" }, { value: "pending", label: "Invitation pending" }]} />
        </div>

        <TableScroll className="mp-mem-table-wrap" narrowCards>
          <table className="mp-table">
            <thead>
              <tr>
                <th>Admin Name</th><th>Email address</th><th>Role</th><th>Status</th><th>Last active</th><th></th>
              </tr>
            </thead>
            <tbody>
              {rows.map((m) => (
                <MemberRow key={m.id} m={m} onOpen={() => setDetailId(m.id)} />
              ))}
            </tbody>
          </table>
        </TableScroll>

        <div className="mp-mem-cards">
          {rows.map((m) => <MemberCard key={m.id} m={m} onOpen={() => setDetailId(m.id)} />)}
        </div>

        {!rows.length ? <Empty icon="users-round" title="No one matches those filters" message="Try a different search term, role or status." /> : null}
      </Card>

      {inviteOpen ? <InviteModal onClose={() => setInviteOpen(false)} onOpenMember={(id) => setDetailId(id)} /> : null}
      {compareOpen ? <CompareRolesDrawer onClose={() => setCompareOpen(false)} /> : null}
      {detail ? <MemberDrawer m={detail} onClose={() => setDetailId(null)} /> : null}
    </>
  );
}

/* ---------- One table row ---------- */
function MemberRow({ m, onOpen }) {
  const ctx = useRoles();
  const isOwner = m.role === "owner";
  const isYou = m.id === ctx.actor.id;
  const manageable = window.canManageMember(ctx.role, m, ctx.actor.id);
  const [action, setAction] = uU(null);

  const exp = window.inviteExpiry(m);
  const items = [{ label: "View Details", onClick: onOpen }];
  if (manageable) {
    if (m.status === "pending") {
      items.push({ label: exp && exp.expired ? "Resend Invitation" : "Resend Invitation", onClick: () => ctx.resendInvite(m) });
      items.push({ label: "Cancel Invitation", onClick: () => setAction("cancel") });
    } else {
      items.push({ label: "Change Role", onClick: () => setAction("role") });
      items.push({ label: "Remove Access", onClick: () => setAction("remove") });
    }
  }

  return (
    <>
      <tr className={isOwner ? "is-owner" : m.status === "pending" ? "is-pending" : ""}>
        <td>
          <button type="button" className="mp-rowlink" onClick={onOpen}>
            <div className="mp-mem-cell">
              <Avatar initials={m.initials} size={26} tone={"role-" + m.role} />
              <div style={{ minWidth: 0 }}>
                <div className="mp-mem-name">
                  <span>{m.name}</span>
                  {isYou ? <span className="mp-you">You</span> : null}
                  {isOwner ? <Icon name="lock" size={13} /> : null}
                </div>
              </div>
            </div>
          </button>
        </td>
        <td><span className="mp-mem-email">{m.email}</span></td>
        <td><RoleBadge role={m.role} /></td>
        <td><MemberStatusBadge status={m.status} expired={exp && exp.expired} /></td>
        <td style={{ color: "var(--fg-3)" }}>
          {m.status === "pending"
            ? <span className={"mp-expiry" + (exp && exp.expired ? " is-expired" : "")}>
                <Icon name={exp && exp.expired ? "clock-alert" : "clock"} size={13} />
                <span>{exp ? exp.label : "—"}</span>
              </span>
            : window.fmtLastActive(m.last_active)}
        </td>
        <td style={{ textAlign: "right" }}>
          <ActionsMenu items={items} />
        </td>
      </tr>
      {action === "role" ? <ChangeRoleModal m={m} onClose={() => setAction(null)} /> : null}
      {action === "remove" ? <RemoveAccessModal m={m} onClose={() => setAction(null)} /> : null}
      {action === "cancel" ? <CancelInviteModal m={m} onClose={() => setAction(null)} /> : null}
    </>
  );
}

/* ---------- Narrow-layout card ---------- */
function MemberCard({ m, onOpen }) {
  const ctx = useRoles();
  const isOwner = m.role === "owner";
  const isYou = m.id === ctx.actor.id;
  const exp = window.inviteExpiry(m);
  const manageable = window.canManageMember(ctx.role, m, ctx.actor.id);
  return (
    <div className={"mp-mem-card" + (isOwner ? " is-owner" : m.status === "pending" ? " is-pending" : "")}>
      <div className="mp-mem-card-top">
        <Avatar initials={m.initials} size={34} tone={"role-" + m.role} />
        <div style={{ minWidth: 0, flex: 1 }}>
          <div className="mp-mem-name"><span>{m.name}</span>{isYou ? <span className="mp-you">You</span> : null}{isOwner ? <Icon name="lock" size={13} /> : null}</div>
          <div className="mp-mem-sub" style={{ overflowWrap: "anywhere" }}>{m.email}</div>
        </div>
      </div>
      <div className="mp-mem-card-meta">
        <RoleBadge role={m.role} />
        <MemberStatusBadge status={m.status} expired={exp && exp.expired} />
      </div>
      <div className="mp-mem-card-foot">
        <span style={{ fontSize: 13, color: "var(--fg-3)" }}>{m.status === "pending" ? (exp ? exp.label : "—") : window.fmtLastActive(m.last_active)}</span>
      </div>
    </div>
  );
}

/* =====================================================================
   Member details drawer
   ===================================================================== */
function MemberDrawer({ m, onClose }) {
  const ctx = useRoles();
  const isOwner = m.role === "owner";
  const isYou = m.id === ctx.actor.id;
  const exp = window.inviteExpiry(m);
  const manageable = window.canManageMember(ctx.role, m, ctx.actor.id);
  const note = window.restrictionNote(ctx.role, m, ctx.actor.id);
  const [action, setAction] = uU(null);
  const r = window.ROLES[m.role];

  return (
    <>
      <div className="mp-drawer-scrim" onClick={onClose} />
      <aside className="mp-drawer mp-drawer--wide" role="dialog" aria-label="User details">
        <header className="mp-drawer-head">
          <div>
            <h3>User Details</h3>
          </div>
          <button className="mp-drawer-x" onClick={onClose} aria-label="Close"><Icon name="x" size={16} /></button>
        </header>

        <div className="mp-drawer-body">
          <div className="mp-drawer-person">
            <Avatar initials={m.initials} size={52} tone={"role-" + m.role} />
            <div style={{ minWidth: 0 }}>
              <div className="mp-drawer-person-name">
                {m.name}
                {isYou ? <span className="mp-you" style={{ marginLeft: 8, verticalAlign: "middle" }}>You</span> : null}
                {isOwner ? <span className="mp-lock" style={{ marginLeft: 8 }}><Icon name="lock" size={13} />Protected</span> : null}
              </div>
              <div className="mp-drawer-person-email">{m.email}</div>
            </div>
          </div>

          <div className="mp-dl">
            <div className="mp-dl-row"><span className="mp-dl-k">Role</span><span className="mp-dl-v"><RoleBadge role={m.role} /></span></div>
            <div className="mp-dl-row"><span className="mp-dl-k">Status</span><span className="mp-dl-v"><MemberStatusBadge status={m.status} expired={exp && exp.expired} /></span></div>
            <div className="mp-dl-row">
              <span className="mp-dl-k">{m.status === "pending" ? "Invited" : "Joined"}</span>
              <span className="mp-dl-v">{m.status === "pending" ? window.fmtDate(m.invited) + (m.invited_by ? " by " + m.invited_by : "") : window.fmtDate(m.joined)}</span>
            </div>
            {m.status === "pending" ? (
              <div className="mp-dl-row">
                <span className="mp-dl-k">Invitation</span>
                <span className="mp-dl-v">
                  <span className={"mp-expiry" + (exp && exp.expired ? " is-expired" : "")}>
                    <Icon name={exp && exp.expired ? "clock-alert" : "clock"} size={13} />
                    <span>{exp ? exp.label : "—"}</span>
                  </span>
                </span>
              </div>
            ) : (
              <div className="mp-dl-row"><span className="mp-dl-k">Last active</span><span className="mp-dl-v">{window.fmtLastActive(m.last_active)}</span></div>
            )}
          </div>

          <div className="mp-drawer-block">
            <div className="mp-drawer-block-title">What this role permits</div>
            <div className={"mp-only-role mp-only-role--" + m.role}>
              <Icon name={r.icon} size={17} style={{ marginTop: 1 }} />
              <div>
                <div className="mp-role-opt-name">{r.label}</div>
                <div className="mp-role-opt-desc">{r.long}</div>
              </div>
            </div>
          </div>

          {note ? <div className="mp-drawer-block"><ReadOnlyNote>{note}</ReadOnlyNote></div> : null}

          {manageable ? (
            <div className="mp-drawer-block">
              <div className="mp-drawer-block-title">Manage access</div>
              <div className="mp-drawer-stack">
                {m.status === "pending" ? (
                  <>
                    {exp && exp.expired ? (
                      <ReadOnlyNote icon="clock-alert">
                        This invitation expired {window.fmtUtc(exp.expires.toISOString())} and its link no longer works. Resending sends a fresh link with a new 48-hour window.
                      </ReadOnlyNote>
                    ) : null}
                    <Button variant={exp && exp.expired ? "primary" : "secondary"} icon="send" onClick={() => ctx.resendInvite(m)}>Resend Invitation</Button>
                    <Button variant="danger" icon="x" onClick={() => setAction("cancel")}>Cancel Invitation</Button>
                  </>
                ) : (
                  <>
                    <Button variant="secondary" icon="user-cog" onClick={() => setAction("role")}>Change Role</Button>
                    <Button variant="danger" icon="user-x" onClick={() => setAction("remove")}>Remove Access</Button>
                  </>
                )}
              </div>
            </div>
          ) : null}
        </div>

        <footer className="mp-drawer-foot">
          <Button variant="secondary" onClick={onClose}>Close</Button>
        </footer>
      </aside>
      {action === "role" ? <ChangeRoleModal m={m} onClose={() => setAction(null)} /> : null}
      {action === "remove" ? <RemoveAccessModal m={m} onClose={() => { setAction(null); onClose(); }} /> : null}
      {action === "cancel" ? <CancelInviteModal m={m} onClose={() => { setAction(null); onClose(); }} /> : null}
    </>
  );
}

/* =====================================================================
   Invite user
   ===================================================================== */
function InviteModal({ onClose, onOpenMember }) {
  const ctx = useRoles();
  const opts = window.assignableRoles(ctx.role);
  const single = opts.length === 1;
  const [email, setEmail] = uU("");
  const [name, setName] = uU("");
  const [nameErr, setNameErr] = uU(null);
  const [pick, setPick] = uU(single ? opts[0] : "");
  const [err, setErr] = uU(null);
  const [formErr, setFormErr] = uU(null);
  const [busy, setBusy] = uU(false);

  const submit = () => {
    setFormErr(null);
    setNameErr(null);
    const clean = email.trim().toLowerCase();
    if (!clean) return setErr("Enter an email address.");
    if (!window.EMAIL_RE.test(clean)) return setErr("Enter a valid email address, for example name@company.co.uk.");
    if (clean === ctx.actor.email.toLowerCase()) return setErr("That's your own email address. You already have access to this organisation.");
    const clash = ctx.members.find((m) => m.email.toLowerCase() === clean && m.status !== "removed");
    if (clash) return setErr(clash.status === "pending"
      ? "An invitation is already pending for this email address. You can resend or cancel it from the user list."
      : clash.name + " already has access as a " + window.ROLES[clash.role].label + ".");
    setErr(null);
    if (!name.trim()) { setNameErr("Enter their full name."); return; }
    if (!pick) { setFormErr("Choose a role for this person."); return; }
    setBusy(true);
    setTimeout(() => {
      setBusy(false);
      if (ctx.failMode === "invite") {
        setFormErr("We couldn't send that invitation. Nothing has been changed — check the address and try again.");
        return;
      }
      const id = Math.max(...ctx.members.map((m) => m.id)) + 1;
      const initials = name.trim().split(/\s+/).map((p) => p[0]).slice(0, 2).join("").toUpperCase();
      ctx.setMembers((list) => [...list, {
        id, name: name.trim(), email: clean, initials, role: pick,
        status: "pending", invited: new Date().toISOString().slice(0, 10), invited_by: ctx.actor.name
      }]);
      ctx.toast({ kind: "ok", title: "Invitation sent", body: "Invitation sent to " + clean + ". They will receive access as a " + window.ROLES[pick].label + " when they sign in." });
      onClose();
    }, 450);
  };

  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal mp-modal--form" onClick={(e) => e.stopPropagation()}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="user-plus" size={20} /></div>
        <h3 className="mp-modal-title">Invite someone to {window.MILO_DATA.COMPANY}</h3>
        <p className="mp-modal-sub">They'll get an email invitation. Their role decides what they can see and change in the platform.</p>

        <div className="mp-field">
          <label className="mp-field-label">Email address</label>
          <input className={"mp-field-input" + (err ? " has-err" : "")} type="email" autoFocus value={email}
            placeholder="name@company.co.uk"
            onChange={(e) => { setEmail(e.target.value); setErr(null); }} />
          {err ? <div className="mp-inline-err"><Icon name="triangle-alert" size={13} /><span>{err}</span></div> : null}
        </div>

        <div className="mp-field">
          <label className="mp-field-label">Full Name</label>
          <input className={"mp-field-input" + (nameErr ? " has-err" : "")} value={name} placeholder="Sam Fielding"
            onChange={(e) => { setName(e.target.value); setNameErr(null); }} />
          {nameErr ? <div className="mp-inline-err"><Icon name="triangle-alert" size={13} /><span>{nameErr}</span></div> : null}
        </div>

        <div className="mp-field">
          <label className="mp-field-label">Role</label>
          {single ? (
            <div className={"mp-only-role mp-only-role--" + opts[0]}>
              <Icon name={window.ROLES[opts[0]].icon} size={17} style={{ marginTop: 1 }} />
              <div>
                <div className="mp-role-opt-name">{window.ROLES[opts[0]].label}</div>
                <div className="mp-role-opt-desc">{window.ROLES[opts[0]].long}</div>
                <div className="mp-role-opt-desc" style={{ color: "var(--mp-pine)", fontWeight: 600, marginTop: 6 }}>As an Admin, this is the only role you can invite.</div>
              </div>
            </div>
          ) : (
            <div className="mp-role-opts">
              {opts.map((k) => (
                <button key={k} type="button" className={"mp-role-opt mp-role-opt--" + k + (pick === k ? " is-sel" : "")} onClick={() => { setPick(k); setFormErr(null); }}>
                  <span className="mp-role-radio" />
                  <span className="mp-role-opt-ic"><Icon name={window.ROLES[k].icon} size={16} /></span>
                  <span>
                    <span className="mp-role-opt-name">{window.ROLES[k].label}</span>
                    <span className="mp-role-opt-desc">{window.ROLES[k].long}</span>
                  </span>
                </button>
              ))}
            </div>
          )}
        </div>

        {formErr ? <div className="mp-modal-note mp-modal-note--danger"><Icon name="triangle-alert" size={15} /><span>{formErr}</span></div> : null}

        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon="send" className={busy ? "is-disabled" : ""} onClick={busy ? undefined : submit}>
            {busy ? "Sending..." : "Send Invitation"}
          </Button>
        </div>
      </div>
    </div>
  );
}

/* =====================================================================
   Change role
   ===================================================================== */
function ChangeRoleModal({ m, onClose }) {
  const ctx = useRoles();
  const opts = window.assignableRoles(ctx.role);
  const [pick, setPick] = uU(m.role);
  const [busy, setBusy] = uU(false);
  const [formErr, setFormErr] = uU(null);

  const save = () => {
    if (!pick) return setFormErr("Select a role.");
    if (pick === m.role) return setFormErr(m.name + " already has the " + window.ROLES[m.role].label + " role. Select a different role to change it.");
    setFormErr(null);
    setBusy(true);
    setTimeout(() => {
      setBusy(false);
      if (ctx.failMode === "role") {
        setFormErr("We couldn't save that role change. " + m.name + " keeps the " + window.ROLES[m.role].label + " role — try again.");
        return;
      }
      const from = window.ROLES[m.role].label, to = window.ROLES[pick].label;
      ctx.setMembers((list) => list.map((x) => x.id === m.id ? { ...x, role: pick } : x));
      ctx.toast({ kind: "ok", title: "Role updated", body: m.name + " is now a " + to + ". Their access updates on their next page load or action." });
      onClose();
    }, 420);
  };

  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal mp-modal--form" onClick={(e) => e.stopPropagation()}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="user-cog" size={20} /></div>
        <h3 className="mp-modal-title">Change role for {m.name}</h3>
        <p className="mp-modal-sub">{m.email} · Current role is {window.ROLES[m.role].label}</p>

        <div className="mp-field">
          <label className="mp-field-label">Select a Role</label>
          <div className="mp-role-opts">
            {opts.map((k) => (
              <button key={k} type="button" className={"mp-role-opt mp-role-opt--" + k + (pick === k ? " is-sel" : "")} onClick={() => { setPick(k); setFormErr(null); }}>
                <span className="mp-role-radio" />
                <span className="mp-role-opt-ic"><Icon name={window.ROLES[k].icon} size={16} /></span>
                <span>
                  <span className="mp-role-opt-name">
                    {window.ROLES[k].label}
                    {k === m.role ? <span className="mp-role-current">Current role</span> : null}
                  </span>
                  <span className="mp-role-opt-desc">{window.ROLES[k].long}</span>
                </span>
              </button>
            ))}
          </div>
        </div>

        <div className="mp-modal-note mp-modal-note--warn">
          <Icon name="info" size={15} />
          <span>
            {pick && pick !== m.role
              ? <>Change <strong>{m.name}</strong> from <strong>{window.ROLES[m.role].label}</strong> to <strong>{window.ROLES[pick].label}</strong>? Their access will update on their next page load or action.</>
              : <>The updated permissions apply on <strong>{m.name}</strong>'s next page load or action.</>}
          </span>
        </div>

        {formErr ? <div className="mp-modal-note mp-modal-note--danger"><Icon name="triangle-alert" size={15} /><span>{formErr}</span></div> : null}

        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon="check" className={busy ? "is-disabled" : ""} onClick={busy ? undefined : save}>{busy ? "Saving..." : "Save Role"}</Button>
        </div>
      </div>
    </div>
  );
}

/* =====================================================================
   Remove access
   ===================================================================== */
function RemoveAccessModal({ m, onClose }) {
  const ctx = useRoles();
  const sensitive = m.role === "admin";
  const [typed, setTyped] = uU("");
  const [busy, setBusy] = uU(false);
  const [formErr, setFormErr] = uU(null);
  const ready = !sensitive || typed.trim().toLowerCase() === m.email.toLowerCase();

  const remove = () => {
    setBusy(true);
    setFormErr(null);
    setTimeout(() => {
      setBusy(false);
      if (ctx.failMode === "remove") {
        setFormErr("We couldn't confirm that " + m.name + "'s access was revoked, so nothing has changed. They still have access — try again.");
        return;
      }
      ctx.setMembers((list) => list.map((x) => x.id === m.id ? { ...x, status: "removed" } : x));
      ctx.toast({ kind: "ok", title: "Access removed", body: m.name + " has been signed out of the platform and can no longer access " + window.MILO_DATA.COMPANY + "." });
      onClose();
    }, 480);
  };

  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal mp-modal--form" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 480 }}>
        <div className="mp-modal-ic mp-modal-ic--danger"><Icon name="user-x" size={20} /></div>
        <h3 className="mp-modal-title">Remove access for {m.name}?</h3>
        <p className="mp-modal-text">
          This person will immediately lose access to the platform and all of their active sessions will be ended.
          They will need to be invited again to regain access.
        </p>
        <p className="mp-modal-text">Their historic actions and audit records stay available to you.</p>
        {sensitive ? (
          <div className="mp-field">
            <label className="mp-field-label">Type <strong>{m.email}</strong> to confirm</label>
            <input className="mp-field-input" value={typed} autoFocus placeholder={m.email} onChange={(e) => setTyped(e.target.value)} />
          </div>
        ) : null}
        {formErr ? <div className="mp-modal-note mp-modal-note--danger"><Icon name="triangle-alert" size={15} /><span>{formErr}</span></div> : null}
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          <Button variant="danger-solid" icon="user-x" className={ready && !busy ? "" : "is-disabled"} onClick={ready && !busy ? remove : undefined}>
            {busy ? "Removing..." : "Remove Access"}
          </Button>
        </div>
      </div>
    </div>
  );
}

/* =====================================================================
   Cancel invitation
   ===================================================================== */
function CancelInviteModal({ m, onClose }) {
  const ctx = useRoles();
  const cancel = () => {
    ctx.setMembers((list) => list.filter((x) => x.id !== m.id));
    ctx.toast({ kind: "ok", title: "Invitation cancelled", body: "The invitation link sent to " + m.email + " no longer works." });
    onClose();
  };
  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 440 }}>
        <div className="mp-modal-ic mp-modal-ic--warn"><Icon name="mail-x" size={20} /></div>
        <h3 className="mp-modal-title">Cancel this invitation?</h3>
        <p className="mp-modal-text">The invitation link sent to {m.email} will stop working and they'll be removed from your user list. You can invite them again at any time.</p>
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Keep Invitation</Button>
          <Button variant="primary" icon="mail-x" onClick={cancel}>Cancel Invitation</Button>
        </div>
      </div>
    </div>
  );
}

/* =====================================================================
   Compare roles drawer
   ===================================================================== */
function CompareRolesDrawer({ onClose }) {
  const cell = (v) => {
    if (v === true) return <Icon name="check" size={16} className="mp-cmp-yes" />;
    if (v === false) return <Icon name="x" size={16} className="mp-cmp-no" />;
    if (v.yes) return (
      <span className="mp-cmp-qual">
        <Icon name="check" size={16} className="mp-cmp-yes" />
        <span className="mp-cmp-note">{v.yes}</span>
      </span>
    );
    /* A "no" with a note (e.g. "View only") shows only the note, not the ✕ —
       the note replaces the icon, it does not sit beside it. */
    return (
      <span className="mp-cmp-qual">
        <span className="mp-cmp-note">{v.no}</span>
      </span>
    );
  };
  return (
    <>
      <div className="mp-drawer-scrim" onClick={onClose} />
      <aside className="mp-drawer mp-drawer--wide mp-drawer--cmp" role="dialog" aria-label="Compare roles">
        <header className="mp-drawer-head">
          <div>
            <h3>Compare Roles</h3>
            <div className="mp-drawer-sub">What each role can do in the platform.</div>
          </div>
          <button className="mp-drawer-x" onClick={onClose} aria-label="Close"><Icon name="x" size={16} /></button>
        </header>
        <div className="mp-drawer-body">
          <div className="mp-drawer-stack" style={{ gap: 12, marginBottom: 20 }}>
            {window.ROLE_ORDER.map((k) => (
              <div key={k} className={"mp-only-role mp-only-role--plainbg mp-only-role--" + k}>
                <span className={"mp-role-opt-ic mp-role-opt-ic--" + k}><Icon name={window.ROLES[k].icon} size={16} /></span>
                <div>
                  <div className="mp-role-opt-name">{window.ROLES[k].label}</div>
                  <div className="mp-role-opt-desc">{window.ROLES[k].long}</div>
                </div>
              </div>
            ))}
          </div>
          <div className="mp-cmp-wrap">
          <table className="mp-cmp">
            <thead>
              <tr>
                <th>Permission</th>
                <th className="mp-cmp-th--owner">Account<br />Owner</th>
                <th className="mp-cmp-th--admin">Admin</th>
                <th className="mp-cmp-th--analyst">Financial<br />Analyst</th>
              </tr>
            </thead>
            <tbody>
              {window.PERMISSION_GROUPS.map((g) => (
                <React.Fragment key={g.title}>
                  <tr className="mp-cmp-grp-row"><td className="mp-cmp-grp" colSpan={4}>
                    <span className="mp-cmp-grp-inner">
                      <span>{g.title}</span>
                      {g.later ? <span className="mp-cmp-later">Later</span> : null}
                    </span>
                  </td></tr>
                  {g.rows.map((row) => (
                    <tr key={row.label}>
                      <td>{row.label}</td>
                      <td>{cell(row.owner)}</td><td>{cell(row.admin)}</td><td>{cell(row.analyst)}</td>
                    </tr>
                  ))}
                </React.Fragment>
              ))}
            </tbody>
          </table>
          </div>

        </div>
        <footer className="mp-drawer-foot">
          <Button variant="secondary" onClick={onClose}>Close</Button>
        </footer>
      </aside>
    </>
  );
}

Object.assign(window, {
  UsersRolesTab, MemberRow, MemberCard, MemberDrawer, InviteModal,
  ChangeRoleModal, RemoveAccessModal, CancelInviteModal, CompareRolesDrawer
});
