// Shell — sidebar, topbar, command palette, scope filters.

const D = window.VAULT_DATA;
const F = window.VAULT_FIRM;
const { useState, useEffect, useMemo, useRef, useCallback } = React;

// ---------- Helpers ----------
function fmtUSD(m, dp = 0) {
  if (m == null) return "—";
  const sign = m < 0 ? "–" : "";
  const v = Math.abs(m);
  if (v >= 1000) return `${sign}$${(v/1000).toFixed(2)}B`;
  return `${sign}$${v.toFixed(dp)}M`;
}
function fmtNum(n) { if (n == null) return "—"; return n.toLocaleString("en-US"); }
function fmtPct(p, dp = 0) { if (p == null) return "—"; return `${(p*100).toFixed(dp)}%`; }
function relativeTime(iso) {
  const d = new Date(iso);
  const now = new Date("2026-05-08T10:00:00");
  const mins = Math.round((now - d) / 60000);
  if (mins < 60) return `${mins}m ago`;
  if (mins < 60*24) return `${Math.round(mins/60)}h ago`;
  const days = Math.round(mins / (60*24));
  if (days < 7) return `${days}d ago`;
  return d.toLocaleDateString("en-US", { month:"short", day:"numeric" });
}
function personById(id) { return F.PEOPLE_BY_ID[id]; }
function subteamById(id) { return F.SUBTEAMS.find(s => s.id === id); }
function moduleById(id)  { return F.MODULES.find(m => m.id === id); }
function projectById(id) { return F.PROJECTS.find(p => p.id === id); }

window.VaultUtils = { fmtUSD, fmtNum, fmtPct, relativeTime, personById, subteamById, moduleById, projectById };

// ---------- Avatar ----------
function Avatar({ id, size = "md", showName = false, showSynth = false }) {
  const p = personById(id);
  if (!p) return null;
  const cls = "avatar" + (size === "lg" ? " lg" : size === "xl" ? " xl" : "");
  return (
    <span style={{ display:"inline-flex", alignItems:"center", gap: 8 }}>
      <span className={cls} data-tone={p.tone} title={`${p.name} — ${p.role}${p.synth ? " · SYNTH" : ""}`}>{p.initials}</span>
      {showName && <span style={{ fontSize: 12.5 }}>{p.name}{p.synth && showSynth && <SynthTag/>}</span>}
    </span>
  );
}
function AvatarStack({ ids, max = 3 }) {
  const shown = ids.slice(0, max);
  const extra = Math.max(0, ids.length - max);
  return (
    <span className="stack">
      {shown.map(id => <Avatar key={id} id={id}/>)}
      {extra > 0 && <span className="avatar" style={{ background: "var(--surface-2)", color: "var(--muted)", border: "1px solid var(--line)" }}>+{extra}</span>}
    </span>
  );
}
function SynthTag() {
  return (
    <span style={{
      marginLeft: 6, fontSize: 9, fontWeight: 700, letterSpacing: ".08em",
      padding: "1px 4px", borderRadius: 3,
      background: "color-mix(in oklab, var(--warn) 12%, transparent)",
      color: "var(--warn)", border: "1px solid color-mix(in oklab, var(--warn) 30%, transparent)",
      verticalAlign: "1px",
    }}>SYNTH</span>
  );
}
window.Avatar = Avatar; window.AvatarStack = AvatarStack; window.SynthTag = SynthTag;

// ---------- Icons ----------
const Icon = {
  overview:    (p) => (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...p}><path d="M2 2h5v5H2zM9 2h5v3H9zM9 7h5v7H9zM2 9h5v5H2z" stroke="currentColor" strokeWidth="1.3"/></svg>),
  team:        (p) => (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...p}><circle cx="6" cy="6" r="2.2" stroke="currentColor" strokeWidth="1.3"/><circle cx="11.5" cy="7" r="1.6" stroke="currentColor" strokeWidth="1.3"/><path d="M2 13c0-2 1.7-3 4-3s4 1 4 3M9 13c0-1.5 1.2-2.4 2.8-2.4S14.5 11.5 14.5 13" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/></svg>),
  leaderboard: (p) => (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...p}><path d="M3 13h3V8H3zM6.5 13h3V4h-3zM10 13h3V9h-3z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round"/></svg>),
  projects:    (p) => (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...p}><rect x="2" y="3" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.3"/><rect x="9" y="3" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.3"/><rect x="2" y="10" width="5" height="3" rx="1" stroke="currentColor" strokeWidth="1.3"/><rect x="9" y="10" width="5" height="3" rx="1" stroke="currentColor" strokeWidth="1.3"/></svg>),
  pipeline:    (p) => (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...p}><path d="M2 4h12M3.5 4v3.5l3 3v3M12.5 4v3.5l-3 3v3" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  closed:      (p) => (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...p}><circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="1.3"/><path d="M5 8.2l2 2 4-4.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  newclient:   (p) => (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...p}><circle cx="6.5" cy="6" r="2.2" stroke="currentColor" strokeWidth="1.3"/><path d="M2 13c0-2 1.7-3 4.5-3s4.5 1 4.5 3" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/><path d="M12 4v4M14 6h-4" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>),
  search:      (p) => (<svg width="14" height="14" viewBox="0 0 16 16" fill="none" {...p}><circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.5"/><path d="M10.5 10.5L13.5 13.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>),
  plus:        (p) => (<svg width="14" height="14" viewBox="0 0 16 16" fill="none" {...p}><path d="M8 3v10M3 8h10" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>),
  bell:        (p) => (<svg width="14" height="14" viewBox="0 0 16 16" fill="none" {...p}><path d="M3.5 11h9l-1-1.5V7a3.5 3.5 0 0 0-7 0v2.5zM6.5 13h3" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  caret:       (p) => (<svg width="10" height="10" viewBox="0 0 10 10" fill="none" {...p}><path d="M3 4l2 2 2-2" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  orgchart:    (p) => (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...p}><rect x="5.5" y="1.5" width="5" height="3.5" rx="1" stroke="currentColor" strokeWidth="1.3"/><rect x="1.5" y="10.5" width="4" height="3.5" rx="1" stroke="currentColor" strokeWidth="1.3"/><rect x="6" y="10.5" width="4" height="3.5" rx="1" stroke="currentColor" strokeWidth="1.3"/><rect x="10.5" y="10.5" width="4" height="3.5" rx="1" stroke="currentColor" strokeWidth="1.3"/><path d="M8 5v3M3.5 10V8h9v2" stroke="currentColor" strokeWidth="1.3"/></svg>),
  refresh:     (p) => (<svg width="12" height="12" viewBox="0 0 16 16" fill="none" {...p}><path d="M13 8a5 5 0 1 1-1.5-3.5L13 3v3.5h-3.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  cloud:       (p) => (<svg width="14" height="14" viewBox="0 0 16 16" fill="none" {...p}><path d="M4.5 12h7a2.5 2.5 0 0 0 .5-4.95A4 4 0 0 0 4.6 7.05 2.5 2.5 0 0 0 4.5 12z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round"/></svg>),
  chevron:     (p) => (<svg width="10" height="10" viewBox="0 0 10 10" fill="none" {...p}><path d="M3.5 2L6.5 5L3.5 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  fire:        (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M8 14c-3 0-5-2-5-4.5 0-2 2-3 2-5 0 0 1 1 1 2.5 0 0 1.5-1 1.5-3 2 1 4 3.5 4 6.2C11.5 12 10 14 8 14z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round"/></svg>),
  trophy:      (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M5 3h6v3a3 3 0 0 1-6 0zM3 4h2v1a1.5 1.5 0 0 1-1.5 1.5H3zM13 4h-2v1a1.5 1.5 0 0 0 1.5 1.5H13zM6 11h4v2H6zM5 13h6" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round"/></svg>),
  phone:       (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M3 3.5c0 5 4.5 9.5 9.5 9.5l1-2.5-3-1-1 1.5C7.5 9.5 6.5 8.5 5.5 6.5L7 5.5l-1-3z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round"/></svg>),
  visit:       (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M8 14s-4.5-3.5-4.5-7.5a4.5 4.5 0 0 1 9 0C12.5 10.5 8 14 8 14z" stroke="currentColor" strokeWidth="1.3"/><circle cx="8" cy="6.5" r="1.6" stroke="currentColor" strokeWidth="1.3"/></svg>),
  rain:        (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M4 7a3 3 0 0 1 6-1 2.5 2.5 0 0 1 2.5 4.5h-8A2.5 2.5 0 0 1 4 7zM5 12l-.5 1.5M8 12l-.5 1.5M11 12l-.5 1.5" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  loi:         (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M3.5 2.5h6L13 6v7.5h-9.5z" stroke="currentColor" strokeWidth="1.3"/><path d="M9.5 2.5V6H13M5.5 9h5M5.5 11h3" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/></svg>),
  lead:        (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="1.3"/><circle cx="8" cy="8" r="3" stroke="currentColor" strokeWidth="1.3"/><circle cx="8" cy="8" r="0.8" fill="currentColor"/></svg>),
};
window.Icon = Icon;

// ---------- Sidebar ----------
function Sidebar({ view, setView, user, onLogout }) {
  const isAdmin = user?.access === "admin";
  const [tabPanelOpen, setTabPanelOpen] = useState(false);
  // Subscribe to hidden-tab changes so the sidebar re-renders when admin toggles
  const [, force] = React.useReducer(x => x + 1, 0);
  useEffect(() => {
    const h = () => force();
    window.addEventListener("vault:hidden-tabs-changed", h);
    return () => window.removeEventListener("vault:hidden-tabs-changed", h);
  }, []);

  const allUserTabs = [
    { id: "overview",     label: "Overview",            icon: "overview"    },
    { id: "team",         label: "Team",                icon: "team"        },
    { id: "leaderboards", label: "Leaderboards",        icon: "leaderboard" },
    { id: "projects",     label: "Projects",            icon: "projects"    },
    { id: "pipeline",     label: "Deal Pipeline",       icon: "pipeline"    },
    { id: "closed",       label: "Closed Deals",        icon: "closed"      },
    { id: "newclients",   label: "New Client Tracker",  icon: "newclient"   },
    { id: "badges",       label: "Badges",              icon: "trophy"      },
  ];
  const adminTabs = [
    { id: "accounts",  label: "Accounts",  icon: "team"       },
    { id: "datasets",  label: "Data Sets", icon: "cloud"      },
    { id: "org",       label: "Org Chart", icon: "orgchart"   },
    { id: "goals",     label: "Goals",     icon: "trophy"     },
    { id: "approvals", label: "Approvals", icon: "leaderboard" },
  ];

  const hidden = (window.VAULT_ADMIN_STORE && window.VAULT_ADMIN_STORE.hiddenTabs) || new Set();
  // For non-admins, drop hidden tabs entirely. Admins see all (with a "hidden" indicator).
  const userTabs = isAdmin ? allUserTabs : allUserTabs.filter(t => !hidden.has(t.id));
  return (
    <aside style={{
      background: "var(--canvas)",
      borderRight: "1px solid var(--line)",
      position: "sticky", top: 0, height: "100vh",
      display: "flex", flexDirection: "column",
    }}>
      <div style={{ padding: "20px 22px 14px" }}>
        <VaultLogo size={26}/>
      </div>

      <div style={{ padding: "4px 12px 8px" }}>
        <div className="row" style={{
          background: "var(--surface)",
          border: "1px solid var(--line)",
          borderRadius: 8,
          padding: "6px 10px",
          fontSize: 12, color: "var(--muted)",
          cursor: "pointer",
        }} onClick={() => window.dispatchEvent(new CustomEvent("vault:cmdk"))}>
          <Icon.search style={{ color: "var(--muted)" }}/>
          <span className="stretch">Search…</span>
          <span className="mono" style={{
            fontSize: 10.5, color: "var(--muted)",
            background: "var(--surface-2)", padding: "1px 5px", borderRadius: 4,
            border: "1px solid var(--line)",
          }}>⌘K</span>
        </div>
      </div>

      <nav style={{ padding: "8px 10px", flex: 1, overflowY: "auto", position: "relative" }}>
        <div className="micro" style={{ padding: "10px 12px 6px" }}>Workspace</div>
        {userTabs.map(n => {
          const I = Icon[n.icon];
          const active = view === n.id;
          const isHidden = isAdmin && hidden.has(n.id);
          return (
            <button key={n.id}
              onClick={() => setView(n.id)}
              style={{
                display: "flex", alignItems: "center", gap: 10,
                width: "100%", textAlign: "left",
                padding: "8px 12px",
                background: active ? "var(--surface)" : "transparent",
                border: active ? "1px solid var(--line)" : "1px solid transparent",
                color: active ? "var(--ink)" : (isHidden ? "var(--muted-2)" : "var(--ink-2)"),
                borderRadius: 7,
                fontSize: 13, fontWeight: active ? 600 : 500,
                marginBottom: 1,
                boxShadow: active ? "var(--shadow)" : "none",
                opacity: isHidden ? 0.6 : 1,
              }}>
              <span style={{ color: active ? "var(--accent)" : "var(--muted)", display: "inline-flex" }}><I/></span>
              <span className="stretch">{n.label}</span>
              {isHidden && <span className="tag" style={{ fontSize: 9, padding: "1px 4px", background: "var(--warn-soft)", color: "var(--warn)", borderColor: "transparent" }}>Hidden</span>}
            </button>
          );
        })}

        {isAdmin && (
          <>
            <div className="row" style={{ padding: "16px 12px 6px" }}>
              <span className="micro" style={{ flex: 1 }}>Admin</span>
              <button className="btn ghost sm" style={{ padding: 3, fontSize: 10 }}
                onClick={() => setTabPanelOpen(v => !v)} title="Manage tab visibility">
                <svg width="11" height="11" viewBox="0 0 16 16" fill="none">
                  <circle cx="8" cy="8" r="1.6" fill="currentColor"/>
                  <path d="M8 1v2.5M8 12.5V15M3.5 3.5l1.8 1.8M10.7 10.7l1.8 1.8M1 8h2.5M12.5 8H15M3.5 12.5l1.8-1.8M10.7 5.3l1.8-1.8" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/>
                </svg>
              </button>
            </div>
            {adminTabs.map(n => {
              const I = Icon[n.icon];
              const active = view === n.id;
              const pendingBadge = n.id === "approvals" ? (window.VAULT_ADMIN_STORE?.pendingEdits?.length || 0)
                                : n.id === "accounts" ? (window.VAULT_ADMIN_STORE?.pendingAccounts?.length || 0)
                                : 0;
              return (
                <button key={n.id}
                  onClick={() => setView(n.id)}
                  style={{
                    display: "flex", alignItems: "center", gap: 10,
                    width: "100%", textAlign: "left",
                    padding: "8px 12px",
                    background: active ? "var(--surface)" : "transparent",
                    border: active ? "1px solid var(--line)" : "1px solid transparent",
                    color: active ? "var(--ink)" : "var(--ink-2)",
                    borderRadius: 7,
                    fontSize: 13, fontWeight: active ? 600 : 500,
                    marginBottom: 1,
                    boxShadow: active ? "var(--shadow)" : "none",
                  }}>
                  <span style={{ color: active ? "var(--accent)" : "var(--muted)", display: "inline-flex" }}><I/></span>
                  <span className="stretch">{n.label}</span>
                  {pendingBadge > 0 && (
                    <span className="tag" style={{
                      fontSize: 10, padding: "1px 5px",
                      background: "var(--warn)", color: "#fff", borderColor: "transparent",
                      borderRadius: 999, minWidth: 16, justifyContent: "center",
                    }}>{pendingBadge}</span>
                  )}
                </button>
              );
            })}
          </>
        )}

        {tabPanelOpen && window.TabVisibilityPanel && <window.TabVisibilityPanel onClose={() => setTabPanelOpen(false)}/>}
      </nav>

      <SyncBlock/>

      <div style={{ padding: "12px", borderTop: "1px solid var(--line)" }}>
        <div className="row" style={{ padding: "8px 10px", borderRadius: 7, gap: 10 }}>
          <span className="avatar lg" data-tone="a">{(user?.name || "David Harvey").split(" ").map(s=>s[0]).join("").slice(0,2)}</span>
          <div className="stretch" style={{ minWidth: 0 }}>
            <div style={{ fontSize: 12.5, fontWeight: 600 }}>{user?.name || "David Harvey"}</div>
            <div className="muted" style={{ fontSize: 11 }}>{user?.role || "President"}</div>
          </div>
          <button className="btn ghost sm" onClick={onLogout} title="Sign out" style={{ padding: 4 }}>
            <svg width="13" height="13" viewBox="0 0 16 16" fill="none"><path d="M9 3H4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h5M7 8h6m0 0l-2-2m2 2l-2 2" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </button>
        </div>
      </div>
    </aside>
  );
}
window.Sidebar = Sidebar;

// ---------- Topbar ----------
function Topbar({ title, subtitle, right }) {
  return (
    <header style={{
      display:"flex", alignItems:"center", gap: 16,
      padding: "0 28px",
      height: "var(--topbar-h)",
      borderBottom: "1px solid var(--line)",
      background: "color-mix(in oklab, var(--bg) 75%, transparent)",
      backdropFilter: "blur(8px)",
      position: "sticky", top: 0, zIndex: 5,
    }}>
      <div className="stretch" style={{ minWidth: 0 }}>
        <h1 style={{
          margin: 0,
          fontFamily: "var(--f-display)",
          fontSize: 22, fontWeight: 400,
          letterSpacing: "-.01em",
        }}>{title}</h1>
        {subtitle && <div className="muted small" style={{ marginTop: 1 }}>{subtitle}</div>}
      </div>
      {right}
    </header>
  );
}
window.Topbar = Topbar;

// ---------- Scope filters (Module → Sub-Team → Individual w/ multi-select) ----------
function ScopeFilters({ scope, setScope, allowMulti = true }) {
  const allSubteams = scope.module ? F.SUBTEAMS.filter(s => s.moduleId === scope.module) : F.SUBTEAMS;
  // Filter to deal-team modules only in dropdown (hide Operations + President)
  const subteams = allSubteams.filter(s => s.moduleId === "deals");
  const subSubteams = scope.subteam ? (F.SUBSUBTEAMS || []).filter(s => s.parentSubteam === scope.subteam) : [];
  const individuals = window.VaultPeriod.applyScope(F.PEOPLE, { module: scope.module, subteam: scope.subteam, subSubteam: scope.subSubteam, individuals: [] });
  const indDropdownRef = useRef(null);
  const [indOpen, setIndOpen] = useState(false);
  useEffect(() => {
    const onClick = (e) => {
      if (indDropdownRef.current && !indDropdownRef.current.contains(e.target)) setIndOpen(false);
    };
    document.addEventListener("mousedown", onClick);
    return () => document.removeEventListener("mousedown", onClick);
  }, []);

  const SelectStyle = {
    border: "1px solid var(--line)", background: "var(--surface)",
    borderRadius: 8, padding: "5px 9px", fontSize: 12.5, color: "var(--ink)", minWidth: 0,
  };

  const indSummary = scope.individuals.length === 0
    ? "All individuals"
    : scope.individuals.length === 1
      ? personById(scope.individuals[0]).name
      : `${scope.individuals.length} selected`;

  return (
    <div className="row" style={{ gap: 8, flexWrap: "wrap" }}>
      <select value={scope.subteam || ""} onChange={e => setScope({ ...scope, subteam: e.target.value || null, subSubteam: null, individuals: [] })} style={SelectStyle}>
        <option value="">All modules</option>
        {[...subteams].sort((a, b) => a.label.localeCompare(b.label)).map(s => <option key={s.id} value={s.id}>{s.label.replace(/^.*— /, "")}{s.synth ? " · SYNTH" : ""}</option>)}
      </select>

      {subSubteams.length > 0 && (
        <select value={scope.subSubteam || ""} onChange={e => setScope({ ...scope, subSubteam: e.target.value || null, individuals: [] })} style={SelectStyle}>
          <option value="">All sub-teams</option>
          {[...subSubteams].sort((a, b) => a.label.localeCompare(b.label)).map(s => <option key={s.id} value={s.id}>{s.label}</option>)}
        </select>
      )}

      {allowMulti ? (
        <div ref={indDropdownRef} style={{ position: "relative" }}>
          <button onClick={() => setIndOpen(v => !v)} style={{ ...SelectStyle, cursor: "pointer", display: "flex", alignItems: "center", gap: 6 }}>
            <span>{indSummary}</span>
            <Icon.caret style={{ color: "var(--muted)" }}/>
          </button>
          {indOpen && (
            <div style={{
              position: "absolute", top: "calc(100% + 4px)", right: 0,
              width: 280, maxHeight: 360, overflowY: "auto",
              background: "var(--surface)", border: "1px solid var(--line)",
              borderRadius: 10, boxShadow: "var(--shadow-md)", zIndex: 10,
              padding: "6px 4px",
            }}>
              <div className="row" style={{ padding: "6px 10px", justifyContent: "space-between" }}>
                <span className="micro">Individuals · ⌘-click to add</span>
                {scope.individuals.length > 0 && (
                  <button className="btn ghost sm" onClick={() => setScope({ ...scope, individuals: [] })} style={{ fontSize: 10.5 }}>Clear</button>
                )}
              </div>
              {individuals.map(p => {
                const checked = scope.individuals.includes(p.id);
                return (
                  <label key={p.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 10px", cursor: "pointer", borderRadius: 6, fontSize: 12.5 }}
                    onMouseEnter={e => e.currentTarget.style.background = "var(--surface-2)"}
                    onMouseLeave={e => e.currentTarget.style.background = "transparent"}
                    onClick={(e) => {
                      // Cmd/Ctrl-click toggles add; bare click sets to single
                      if (e.metaKey || e.ctrlKey) {
                        e.preventDefault();
                        const next = checked
                          ? scope.individuals.filter(id => id !== p.id)
                          : [...scope.individuals, p.id];
                        setScope({ ...scope, individuals: next });
                      } else {
                        e.preventDefault();
                        setScope({ ...scope, individuals: checked ? [] : [p.id] });
                      }
                    }}>
                    <span style={{
                      width: 14, height: 14, borderRadius: 3,
                      border: "1.5px solid " + (checked ? "var(--accent)" : "var(--line)"),
                      background: checked ? "var(--accent)" : "transparent",
                      display: "inline-flex", alignItems: "center", justifyContent: "center",
                      flexShrink: 0,
                    }}>
                      {checked && <svg width="9" height="9" viewBox="0 0 9 9"><path d="M2 5l1.6 1.6L7 2.5" stroke="var(--accent-ink)" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>}
                    </span>
                    <Avatar id={p.id}/>
                    <span className="stretch">{p.name}</span>
                    <span className="muted small">{p.role}</span>
                    {p.synth && <SynthTag/>}
                  </label>
                );
              })}
            </div>
          )}
        </div>
      ) : (
        <select value={scope.individuals[0] || ""} onChange={e => setScope({ ...scope, individuals: e.target.value ? [e.target.value] : [] })} style={SelectStyle}>
          <option value="">All individuals</option>
          {individuals.map(p => <option key={p.id} value={p.id}>{p.name}{p.synth ? " · SYNTH" : ""}</option>)}
        </select>
      )}

      {(scope.module || scope.subteam || scope.subSubteam || scope.individuals.length > 0) && (
        <button className="btn ghost sm" onClick={() => setScope({ module: null, subteam: null, subSubteam: null, individuals: [] })}>Clear scope</button>
      )}
    </div>
  );
}
window.ScopeFilters = ScopeFilters;

// ---------- Command Palette ----------
function CommandPalette({ open, onClose, onCommand }) {
  const [q, setQ] = useState("");
  const [idx, setIdx] = useState(0);
  const inputRef = useRef(null);
  useEffect(() => {
    if (open) { setQ(""); setIdx(0); setTimeout(() => inputRef.current?.focus(), 30); }
  }, [open]);

  const items = useMemo(() => {
    const base = [
      { id: "v:overview",     kind: "View", label: "Go to Overview",         sub: "Firm dashboard",      action: { type: "view", id: "overview" } },
      { id: "v:team",         kind: "View", label: "Go to Team",             sub: "Activity drill-down", action: { type: "view", id: "team" } },
      { id: "v:leaderboards", kind: "View", label: "Go to Leaderboards",     sub: "Top performers",      action: { type: "view", id: "leaderboards" } },
      { id: "v:projects",     kind: "View", label: "Go to Projects",         sub: "Engagement grid",     action: { type: "view", id: "projects" } },
      { id: "v:pipeline",     kind: "View", label: "Go to Deal Pipeline",    sub: "Active targets",      action: { type: "view", id: "pipeline" } },
      { id: "v:closed",       kind: "View", label: "Go to Closed Deals",     sub: "Realized fees",       action: { type: "view", id: "closed" } },
      { id: "v:newclients",   kind: "View", label: "Go to New Client Tracker", sub: "Pre-engagement",    action: { type: "view", id: "newclients" } },
      ...F.PROJECTS.map(p => ({ id: `pj:${p.id}`, kind: "Project", label: p.name, sub: `${p.client} · ${p.type}`, action: { type: "view", id: "projects" } })),
      ...F.PIPELINE.map(t => {
        const st = F.STATUS_BY_CODE[Number(t.status).toFixed(2)];
        return { id: `pl:${t.id}`, kind: "Target", label: t.target || t.client || "Target", sub: `${st ? st.label : "Status " + t.status} · ${t.nextAction || ""}`, action: { type: "view", id: "pipeline" } };
      }),
    ];
    if (!q.trim()) return base.slice(0, 9);
    const needle = q.toLowerCase();
    return base.filter(i => (i.label + " " + i.sub).toLowerCase().includes(needle)).slice(0, 14);
  }, [q]);

  useEffect(() => {
    if (!open) return;
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      else if (e.key === "ArrowDown") { e.preventDefault(); setIdx(i => Math.min(i+1, items.length-1)); }
      else if (e.key === "ArrowUp")   { e.preventDefault(); setIdx(i => Math.max(i-1, 0)); }
      else if (e.key === "Enter")     { if (items[idx]) { onCommand(items[idx].action); onClose(); } }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, items, idx, onClose, onCommand]);

  if (!open) return null;
  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, zIndex: 50,
      background: "rgba(20,19,15,.35)",
      display: "flex", alignItems: "flex-start", justifyContent: "center",
      paddingTop: "16vh",
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: 580, maxWidth: "92vw",
        background: "var(--surface)",
        border: "1px solid var(--line)",
        borderRadius: 14, boxShadow: "var(--shadow-md)", overflow: "hidden",
      }}>
        <div style={{ display:"flex", alignItems:"center", gap: 10, padding: "14px 16px", borderBottom: "1px solid var(--line-2)" }}>
          <Icon.search style={{ color: "var(--muted)" }}/>
          <input ref={inputRef} value={q} onChange={e => { setQ(e.target.value); setIdx(0); }}
            placeholder="Search views, projects, targets…"
            style={{
              flex: 1, border: 0, outline: "none", background: "transparent",
              fontSize: 15, color: "var(--ink)",
            }}/>
          <span className="mono small muted">esc</span>
        </div>
        <div style={{ maxHeight: 380, overflowY: "auto", padding: 6 }}>
          {items.map((it, i) => (
            <button key={it.id}
              onClick={() => { onCommand(it.action); onClose(); }}
              onMouseEnter={() => setIdx(i)}
              style={{
                display: "flex", alignItems: "center", gap: 12,
                width: "100%", textAlign: "left",
                padding: "9px 12px",
                background: i === idx ? "var(--accent-soft)" : "transparent",
                border: 0, borderRadius: 8, color: "var(--ink)",
              }}>
              <span className="micro" style={{ width: 60, color: i === idx ? "var(--accent)" : "var(--muted)" }}>{it.kind}</span>
              <span className="stretch" style={{ minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 500 }}>{it.label}</div>
                <div className="muted small">{it.sub}</div>
              </span>
              {i === idx && <Icon.chevron style={{ color: "var(--accent)" }}/>}
            </button>
          ))}
          {items.length === 0 && <div className="muted" style={{ padding: 18, textAlign: "center", fontSize: 12 }}>No matches</div>}
        </div>
      </div>
    </div>
  );
}
window.CommandPalette = CommandPalette;
