/* ============ Icons ============ */
const Icon = ({ n, s=14, w=1.7, c="" }) => {
  const p = {
    home:<><path d="m3 11 9-8 9 8v10a1 1 0 0 1-1 1h-5v-7h-6v7H4a1 1 0 0 1-1-1z"/></>,
    building:<><path d="M3 21h18"/><path d="M5 21V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16"/><path d="M9 9h1M9 13h1M9 17h1M14 9h1M14 13h1M14 17h1"/></>,
    template:<><rect x="3" y="3" width="18" height="5" rx="1"/><rect x="3" y="11" width="9" height="10" rx="1"/><rect x="15" y="11" width="6" height="10" rx="1"/></>,
    bell:<><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></>,
    user:<><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></>,
    users:<><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></>,
    plus:<><path d="M12 5v14"/><path d="M5 12h14"/></>,
    search:<><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></>,
    check:<path d="M20 6 9 17l-5-5"/>,
    "check-circle":<><circle cx="12" cy="12" r="9"/><path d="m8 12 3 3 5-6"/></>,
    x:<><path d="M18 6 6 18"/><path d="m6 6 12 12"/></>,
    "x-circle":<><circle cx="12" cy="12" r="9"/><path d="m9 9 6 6M15 9l-6 6"/></>,
    clock:<><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>,
    edit:<><path d="M17 3a2.83 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5z"/></>,
    "edit-3":<><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 1 1 3 3L7 19l-4 1 1-4z"/></>,
    chev:<path d="m9 6 6 6-6 6"/>,
    "chev-d":<path d="m6 9 6 6 6-6"/>,
    "chev-r":<path d="m9 6 6 6-6 6"/>,
    folder:<><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></>,
    file:<><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/></>,
    "file-text":<><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M9 13h6M9 17h4"/></>,
    archive:<><path d="M3 6h18v4H3z"/><path d="M5 10v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V10"/><path d="M10 14h4"/></>,
    send:<><path d="m22 2-7 20-4-9-9-4z"/><path d="M22 2 11 13"/></>,
    inbox:<><path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></>,
    lock:<><rect x="4" y="11" width="16" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></>,
    info:<><circle cx="12" cy="12" r="9"/><path d="M12 16v-4M12 8h.01"/></>,
    alert:<><path d="m10.3 3.9-8.2 14a2 2 0 0 0 1.7 3.1h16.4a2 2 0 0 0 1.7-3.1l-8.2-14a2 2 0 0 0-3.4 0z"/><path d="M12 9v4M12 17h.01"/></>,
    history:<><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l3 2"/></>,
    eye:<><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></>,
    "eye-off":<><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><path d="M6.61 6.61A18.45 18.45 0 0 0 1 12s4 8 11 8a9.12 9.12 0 0 0 5.39-1.61"/><path d="M1 1l22 22"/></>,
    settings:<><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></>,
    "arrow-l":<><path d="m15 18-6-6 6-6"/></>,
    "arrow-r":<><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></>,
    sparkle:<><path d="M12 3l1.6 4.4L18 9l-4.4 1.6L12 15l-1.6-4.4L6 9l4.4-1.6z"/></>,
    "thumbs-up":<><path d="M7 10v12"/><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88z"/></>,
    flag:<><path d="M4 22V4"/><path d="M4 4h13l-2 5 2 5H4"/></>,
    layers:<><path d="m12 2 9 5-9 5-9-5z"/><path d="m3 12 9 5 9-5"/><path d="m3 17 9 5 9-5"/></>,
    database:<><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/></>,
    more:<><circle cx="12" cy="5" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="12" cy="19" r="1.5"/></>,
    "log-out":<><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="m16 17 5-5-5-5"/><path d="M21 12H9"/></>,
    copy:<><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></>,
    refresh:<><path d="M23 4v6h-6"/><path d="M1 20v-6h6"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></>,
    trash:<><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M6 6v14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V6"/><path d="M10 11v6M14 11v6"/></>,
    upload:<><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8l-5-5-5 5"/><path d="M12 3v12"/></>,
    download:<><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/></>,
    pencil:<path d="M17 3a2.83 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5z"/>,
    shield:<path d="M12 2 4 6v6c0 5 3.5 9 8 10 4.5-1 8-5 8-10V6l-8-4z"/>,
    "folder-open":<><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2"/><path d="m3 9 2 10h14l2-8H5"/></>,
    grid:<><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></>,
    "alert-triangle":<><path d="m10.3 3.9-8.2 14a2 2 0 0 0 1.7 3.1h16.4a2 2 0 0 0 1.7-3.1l-8.2-14a2 2 0 0 0-3.4 0z"/><path d="M12 9v4M12 17h.01"/></>,
    "external":<><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></>,
    filter:<path d="M22 3H2l8 9v7l4 2v-9l8-9z"/>,
    kanban:<><rect x="3" y="3" width="5" height="18"/><rect x="10" y="3" width="5" height="12"/><rect x="17" y="3" width="5" height="8"/></>,
    progress:<><path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20z"/><path d="M12 6v6l4 2"/></>,
    pin:<><path d="M12 17v5"/><path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z"/></>,
    "pin-off":<><path d="M12 17v5"/><path d="M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89"/><path d="m2 2 20 20"/><path d="M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11"/></>,
  };
  return <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={w} strokeLinecap="round" strokeLinejoin="round" className={c}>{p[n]||p.file}</svg>;
};

/* ============ Status Badge ============
   Per user clarification (rev. MTG3) — only 3 states: Draft / Active / Archived.
   All drafts (Admin's or Creator's) route to Approval Center; there's no
   sub-state distinction. */
const STATUS_META = {
  draft:    { cls:"draft",    icon:"edit-3",       label:"Draft" },
  active:   { cls:"active",   icon:"check-circle", label:"Active" },
  archived: { cls:"archived", icon:"archive",      label:"Archived" },
};
const StatusBadge = ({ status, project, size }) => {
  let key = project ? project.status : status;
  // legacy: callers passing status="pending" → draft (since pending was removed)
  if (key === "pending") key = "draft";
  const m = STATUS_META[key] || STATUS_META.draft;
  return (
    <span className={`sbadge ${m.cls} ${size==='lg'?'lg':''}`}>
      <Icon n={m.icon} s={size==='lg'?13:11.5}/>
      {m.label}
    </span>
  );
};

/* ============ Risk-level badge — just the level word, color-coded ============ */
const RiskBadge = ({ level, size }) => {
  if (!level) return <span className="muted" style={{fontSize:11}}>—</span>;
  const info = (typeof RISK_INFO !== "undefined" && RISK_INFO[level]) || { label: level, tone: "" };
  const toneCls = info.tone === "danger" ? "danger" : info.tone === "warn" ? "warn" : info.tone === "ok" ? "ok" : "";
  return (
    <span className={`sbadge ${toneCls} ${size==='lg'?'lg':''}`} title={info.desc}>
      {info.label}
    </span>
  );
};

/* ============ Tooltip (info icon w/ hover popover) ============ */
/* `bare` — no ⓘ trigger; hovering the wrapped child itself opens the tip */
const Tooltip = ({ text, children, side="right", size=12, bare=false }) => {
  const [open, setOpen] = React.useState(false);
  return (
    <span style={{position:"relative",display:"inline-flex",alignItems:"center",gap:4}}
      {...(bare ? { onMouseEnter:()=>setOpen(true), onMouseLeave:()=>setOpen(false) } : {})}>
      {children}
      {!bare && <span
        onMouseEnter={()=>setOpen(true)}
        onMouseLeave={()=>setOpen(false)}
        onFocus={()=>setOpen(true)}
        onBlur={()=>setOpen(false)}
        tabIndex={0}
        style={{
          display:"inline-grid",placeItems:"center",
          width:16,height:16,borderRadius:"50%",
          background:"var(--panel-2)",color:"var(--muted)",
          cursor:"help",border:"1px solid var(--line)",
        }}
        aria-label="More info"
      >
        <Icon n="info" s={size-2}/>
      </span>}
      {open && (
        <span style={{
          position:"absolute",
          [side==="right"?"left":"right"]: "calc(100% + 8px)",
          top:"50%",transform:"translateY(-50%)",
          minWidth:200,maxWidth:280,
          background:"var(--ink)",color:"#fff",
          padding:"7px 10px",borderRadius:"var(--radius)",
          fontSize:11.5,lineHeight:1.4,
          zIndex:1000,
          boxShadow:"0 4px 12px rgba(0,0,0,.18)",
          fontWeight:400,
          whiteSpace:"normal",
        }}>{text}</span>
      )}
    </span>
  );
};

/* ============ Avatar w/ color hash ============ */
const Avatar = ({ id, name, size="md" }) => {
  const initials = name ? name.split(/\s+/).slice(0,2).map(s=>s[0]).join("").toUpperCase() : (id||"?");
  const h = (id||name||"X").charCodeAt(0) % 7;
  return <div className={`avatar a${h} ${size}`}>{initials}</div>;
};

/* ============ Empty state ============ */
const EmptyState = ({ icon="sparkle", title, sub, cta }) => (
  <div className="empty">
    <div className="em-illu"><Icon n={icon} s={24} w={1.5}/></div>
    <div className="em-title">{title}</div>
    {sub && <div className="em-sub">{sub}</div>}
    {cta}
  </div>
);

/* ============ Time helper — dd/mm/yyyy hh:mm:ss ============ */
const fmtTs = (d) => {
  if (!d) return "—";
  const dt = (d instanceof Date) ? d : new Date(d);
  const pad = (n)=>String(n).padStart(2,'0');
  return `${pad(dt.getDate())}/${pad(dt.getMonth()+1)}/${dt.getFullYear()} ${pad(dt.getHours())}:${pad(dt.getMinutes())}:${pad(dt.getSeconds())}`;
};
const fmtTsShort = (d) => {
  if (!d) return "—";
  const dt = (d instanceof Date) ? d : new Date(d);
  if (isNaN(dt)) return String(d);
  const pad = (n) => n < 10 ? "0"+n : ""+n;
  return `${pad(dt.getDate())}/${pad(dt.getMonth()+1)}/${dt.getFullYear()} ${pad(dt.getHours())}:${pad(dt.getMinutes())}:${pad(dt.getSeconds())}`;
};
/* ---- Sortable table headers ----
   <SortTh label k sort setSort/> — click toggles asc/desc; the active column
   shows a solid arrow. Pair with sortRows(rows, sort, getters) where getters
   maps column key → value extractor (string or number). */
const SortTh = ({ label, k, sort, setSort, style }) => {
  const active = sort.k === k;
  return (
    <th
      style={{ ...style, cursor: "pointer", userSelect: "none", whiteSpace: "nowrap" }}
      title={`Sort by ${label}`}
      onClick={() => setSort(s => s.k === k ? { k, dir: s.dir === "asc" ? "desc" : "asc" } : { k, dir: "asc" })}>
      {label}{" "}
      <span style={{ opacity: active ? 1 : .28, fontSize: 8.5 }}>
        {active ? (sort.dir === "asc" ? "▲" : "▼") : "▲▼"}
      </span>
    </th>
  );
};
const sortRows = (rows, sort, getters) => {
  if (!sort || !sort.k || !getters[sort.k]) return rows;
  const g = getters[sort.k];
  const sorted = [...rows].sort((a, b) => {
    const va = g(a), vb = g(b);
    const cmp = (typeof va === "number" && typeof vb === "number")
      ? va - vb
      : String(va ?? "").localeCompare(String(vb ?? ""));
    return sort.dir === "asc" ? cmp : -cmp;
  });
  return sorted;
};

Object.assign(window, { Icon, StatusBadge, RiskBadge, Tooltip, Avatar, EmptyState, STATUS_META, fmtTs, fmtTsShort, SortTh, sortRows });
