/* VCP shared primitives. Exports to window at the bottom. */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ---------------- Icons (Lucide, 1.6 stroke) ---------------- */
const ICONS = {
  layers: '<path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.84Z"/><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"/><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/>',
  trendingUp: '<path d="M16 7h6v6"/><path d="m22 7-8.5 8.5-5-5L2 17"/>',
  columns: '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/><path d="M15 3v18"/>',
  users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
  sliders: '<line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/>',
  chevronR: '<path d="m9 18 6-6-6-6"/>',
  chevronD: '<path d="m6 9 6 6 6-6"/>',
  chevronL: '<path d="m15 18-6-6 6-6"/>',
  search: '<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',
  plus: '<path d="M5 12h14"/><path d="M12 5v14"/>',
  x: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
  pencil: '<path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"/>',
  download: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/>',
  check: '<path d="M20 6 9 17l-5-5"/>',
  alert: '<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/>',
  arrowUp: '<path d="m5 12 7-7 7 7"/><path d="M12 19V5"/>',
  arrowDown: '<path d="M12 5v14"/><path d="m19 12-7 7-7-7"/>',
  sun: '<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>',
  moon: '<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>',
  building: '<rect width="16" height="20" x="4" y="2" rx="2"/><path d="M9 22v-4h6v4"/><path d="M8 6h.01"/><path d="M16 6h.01"/><path d="M12 6h.01"/><path d="M12 10h.01"/><path d="M12 14h.01"/><path d="M16 10h.01"/><path d="M16 14h.01"/><path d="M8 10h.01"/><path d="M8 14h.01"/>',
  folder: '<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/>',
  shield: '<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1Z"/>',
  barChart: '<line x1="12" x2="12" y1="20" y2="10"/><line x1="18" x2="18" y1="20" y2="4"/><line x1="6" x2="6" y1="20" y2="16"/>',
  link: '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',
  mail: '<rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>',
  phone: '<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92Z"/>',
  filter: '<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>',
  arrowLeft: '<path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>',
  fileText: '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M16 13H8"/><path d="M16 17H8"/><path d="M10 9H8"/>',
  briefcase: '<rect width="20" height="14" x="2" y="7" rx="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>',
  clock: '<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>',
  list: '<line x1="8" x2="21" y1="6" y2="6"/><line x1="8" x2="21" y1="12" y2="12"/><line x1="8" x2="21" y1="18" y2="18"/><line x1="3" x2="3.01" y1="6" y2="6"/><line x1="3" x2="3.01" y1="12" y2="12"/><line x1="3" x2="3.01" y1="18" y2="18"/>',
  minus: '<path d="M5 12h14"/>',
  upload: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/>',
  externalLink: '<path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>',
  network: '<line x1="6" x2="6" y1="3" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>',
  maximize: '<path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/>',
  logout: '<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/>',
  grip: '<circle cx="9" cy="5" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="9" cy="19" r="1"/><circle cx="15" cy="5" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="19" r="1"/>',
  help: '<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/>',
  refresh: '<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M3 21v-5h5"/>',
  gauge: '<path d="m12 14 4-4"/><path d="M3.34 19a10 10 0 1 1 17.32 0"/>',
  trash: '<path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>',
  microsoft: '<rect x="3" y="3" width="8" height="8"/><rect x="13" y="3" width="8" height="8"/><rect x="3" y="13" width="8" height="8"/><rect x="13" y="13" width="8" height="8"/>',
  globe: '<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>',
  flag: '<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" x2="4" y1="22" y2="15"/>',
  book: '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>',
  target: '<circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/>',
  calendar: '<path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/>',
  euro: '<path d="M4 10h12"/><path d="M4 14h9"/><path d="M19 6a7.7 7.7 0 0 0-5.2-2A7.9 7.9 0 0 0 6 12c0 4.4 3.5 8 7.8 8 2 0 3.8-.8 5.2-2"/>',
  star: '<path d="M11.5 2.5 14 8l6 .9-4.3 4.2 1 6-5.2-2.8L6 19l1-6L2.7 8.9 8.7 8z"/>',
  trendingDown: '<path d="M16 17h6v-6"/><path d="m22 17-8.5-8.5-5 5L2 7"/>',
};
function Icon({ name, size = 16, color, style, strokeWidth = 1.6, className }) {
  return <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color || "currentColor"}
    strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round" className={className}
    style={Object.assign({ flexShrink: 0, display: "block" }, style)}
    dangerouslySetInnerHTML={{ __html: ICONS[name] || "" }} />;
}

/* ---------------- Buttons ---------------- */
function Btn({ children, variant = "primary", icon, size = "md", onClick, disabled, style, title }) {
  const base = {
    display: "inline-flex", alignItems: "center", gap: 7, borderRadius: 8,
    fontWeight: 600, fontSize: size === "sm" ? 12 : 13, letterSpacing: "0.005em",
    padding: size === "sm" ? "5px 10px" : "8px 14px", border: "1px solid transparent",
    transition: "all 150ms ease", whiteSpace: "nowrap",
    opacity: disabled ? 0.45 : 1, pointerEvents: disabled ? "none" : "auto",
  };
  const variants = {
    primary: { background: "var(--accent)", color: "var(--accent-ink)", borderColor: "var(--accent)" },
    ghost: { background: "var(--surface-card)", color: "var(--ink)", borderColor: "var(--line)" },
    subtle: { background: "transparent", color: "var(--ink-muted)", borderColor: "transparent" },
    danger: { background: "var(--danger-soft)", color: "var(--danger)", borderColor: "transparent" },
  };
  return <button title={title} onClick={onClick} disabled={disabled}
    style={Object.assign(base, variants[variant], style)}>
    {icon && <Icon name={icon} size={size === "sm" ? 13 : 15} />}
    {children}
  </button>;
}
function IconBtn({ name, onClick, title, active, size = 16, style }) {
  return <button title={title} onClick={onClick} style={Object.assign({
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    width: 32, height: 32, borderRadius: 8, border: "1px solid transparent",
    background: active ? "var(--accent-soft)" : "transparent",
    color: active ? "var(--accent)" : "var(--ink-soft)", transition: "all 150ms ease",
  }, style)}>
    <Icon name={name} size={size} />
  </button>;
}

/* ---------------- Badges & scores ---------------- */
const BAND_BG = { green: "var(--band-green-soft)", teal: "var(--band-teal-soft)", yellow: "var(--band-yellow-soft)", red: "var(--band-red-soft)" };
const BAND_FG = { green: "var(--band-green)", teal: "var(--band-teal)", yellow: "var(--band-yellow)", red: "var(--band-red)" };

function ScoreBadge({ score, size = "md" }) {
  if (score == null) return <span style={{ color: "var(--ink-faint)" }}>—</span>;
  const band = VCP.scoreBand(score);
  return <span className="tabular" style={{
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    minWidth: size === "sm" ? 34 : 40, padding: size === "sm" ? "2px 6px" : "3px 8px",
    borderRadius: 6, fontWeight: 700, fontSize: size === "sm" ? 12 : 13,
    background: BAND_BG[band], color: BAND_FG[band],
  }}>{score.toFixed(1)}</span>;
}

function Badge({ children, variant = "neutral", style }) {
  const variants = {
    neutral: { background: "var(--surface-deep)", color: "var(--ink-muted)" },
    accent: { background: "var(--accent-soft)", color: "var(--accent)" },
    positive: { background: "var(--positive-soft)", color: "var(--positive)" },
    warn: { background: "var(--warn-soft)", color: "var(--warn)" },
    danger: { background: "var(--danger-soft)", color: "var(--danger)" },
  };
  return <span style={Object.assign({
    display: "inline-flex", alignItems: "center", gap: 4, padding: "2px 8px",
    borderRadius: 100, fontSize: 11, fontWeight: 600, letterSpacing: "0.01em", whiteSpace: "nowrap",
  }, variants[variant], style)}>{children}</span>;
}

function TrendTag({ trend, delta, showLabel }) {
  const map = {
    up: { icon: "arrowUp", color: "var(--positive)" },
    down: { icon: "arrowDown", color: "var(--danger)" },
    stable: { icon: "minus", color: "var(--ink-faint)" },
  };
  const m = map[trend] || map.stable;
  return <span className="tabular" style={{ display: "inline-flex", alignItems: "center", gap: 3, color: m.color, fontWeight: 600, fontSize: 12 }}>
    <Icon name={m.icon} size={13} />
    {delta != null && <span>{(delta >= 0 ? "+" : "") + delta.toFixed(1)}</span>}
    {showLabel && <span style={{ textTransform: "capitalize" }}>{trend}</span>}
  </span>;
}

const PRIORITY_VARIANT = { critical: "danger", high: "warn", medium: "accent", low: "neutral" };
const PROGRESS_VARIANT = { "completed": "positive", "started": "accent", "planning": "warn", "not-started": "neutral" };

/* ---------------- Avatar ---------------- */
function Avatar({ name, size = 28, color }) {
  const initials = (name || "?").split(" ").map(w => w[0]).slice(0, 2).join("").toUpperCase();
  return <span style={{
    width: size, height: size, borderRadius: "50%", flexShrink: 0,
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    background: color || "var(--surface-deep)", color: color ? "#fff" : "var(--ink-muted)",
    fontSize: size * 0.38, fontWeight: 700, letterSpacing: "0.01em",
  }}>{initials}</span>;
}
function CompanyMark({ company, size = 26 }) {
  return <span style={{
    width: size, height: size, borderRadius: 7, flexShrink: 0,
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    background: company.color, color: "#fff", fontSize: size * 0.36, fontWeight: 700,
  }}>{company.short}</span>;
}

/* ---------------- Section header ---------------- */
function SectionHeader({ eyebrow, title, right, sub }) {
  return <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", marginBottom: 14, gap: 16 }}>
    <div>
      {eyebrow && <div className="micro" style={{ marginBottom: 5 }}>{eyebrow}</div>}
      <h2 style={{ margin: 0, fontSize: 18, fontWeight: 700, letterSpacing: "-0.01em" }}>{title}</h2>
      {sub && <p style={{ margin: "5px 0 0", color: "var(--ink-muted)", fontSize: 13, maxWidth: 620 }}>{sub}</p>}
    </div>
    {right && <div style={{ display: "flex", gap: 8, alignItems: "center", flexShrink: 0 }}>{right}</div>}
  </div>;
}

/* ---------------- Card ---------------- */
function Card({ children, style, pad = 18, onClick, hover }) {
  const [h, setH] = useState(false);
  return <div onClick={onClick}
    onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
    style={Object.assign({
      background: "var(--surface-card)", border: "1px solid var(--line)", borderRadius: "var(--radius)",
      padding: pad, boxShadow: "var(--shadow-card)", transition: "all 150ms ease",
      cursor: onClick ? "pointer" : "default",
      borderColor: hover && h ? "var(--accent)" : "var(--line)",
    }, style)}>{children}</div>;
}

/* ---------------- KPI strip ---------------- */
function KPIStrip({ items, columns }) {
  return <div style={{
    display: "grid", gridTemplateColumns: `repeat(${columns || items.length}, 1fr)`,
    background: "var(--surface-card)", border: "1px solid var(--line)", borderRadius: "var(--radius)",
    overflow: "hidden", boxShadow: "var(--shadow-card)",
  }}>
    {items.map((it, i) => <div key={i} style={{
      padding: "14px 18px", borderRight: i < items.length - 1 ? "1px solid var(--line-soft)" : "none",
    }}>
      <div className="micro" style={{ display: "flex", alignItems: "center", gap: 6 }}>
        {it.icon && <Icon name={it.icon} size={12} />}{it.label}
      </div>
      <div className="tabular" style={{ fontSize: 24, fontWeight: 700, marginTop: 8, letterSpacing: "-0.02em", color: it.color || "var(--ink)" }}>{it.value}</div>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 4, minHeight: 16 }}>
        {it.sub && <span style={{ fontSize: 11, color: "var(--ink-soft)" }}>{it.sub}</span>}
        {it.delta && <span className="tabular" style={{ fontSize: 11, fontWeight: 600, color: it.deltaColor || "var(--positive)" }}>{it.delta}</span>}
      </div>
    </div>)}
  </div>;
}

/* ---------------- Sortable table ---------------- */
function useSort(initialKey, initialDir) {
  const [sort, setSort] = useState(initialKey ? { key: initialKey, dir: initialDir || "desc" } : null);
  const toggle = (key) => setSort(s => {
    if (!s || s.key !== key) return { key, dir: "asc" };
    if (s.dir === "asc") return { key, dir: "desc" };
    return null; // three-state: off
  });
  const apply = (rows, accessors) => {
    if (!sort) return rows;
    const acc = (accessors && accessors[sort.key]) || (r => r[sort.key]);
    const out = [...rows].sort((a, b) => {
      const va = acc(a), vb = acc(b);
      if (va == null) return 1; if (vb == null) return -1;
      if (typeof va === "number" && typeof vb === "number") return va - vb;
      return String(va).localeCompare(String(vb));
    });
    return sort.dir === "desc" ? out.reverse() : out;
  };
  return { sort, toggle, apply };
}

function Table({ columns, rows, sortCtl, onRowClick, rowKey, rowStyle, dense, footRow }) {
  return <div style={{ background: "var(--surface-card)", border: "1px solid var(--line)", borderRadius: "var(--radius)", overflow: "hidden", boxShadow: "var(--shadow-card)" }}>
    <div style={{ overflowX: "auto" }}>
      <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
        <thead>
          <tr style={{ background: "var(--surface-deep)" }}>
            {columns.map(c => {
              const active = sortCtl && sortCtl.sort && sortCtl.sort.key === c.key;
              return <th key={c.key} onClick={() => c.sortable !== false && sortCtl && sortCtl.toggle(c.key)}
                style={{
                  textAlign: c.align || "left", padding: dense ? "8px 12px" : "10px 14px",
                  position: "sticky", top: 0, background: "var(--surface-deep)", zIndex: 1,
                  fontSize: 11, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.04em",
                  color: active ? "var(--accent)" : "var(--ink-soft)", whiteSpace: "nowrap",
                  cursor: c.sortable !== false && sortCtl ? "pointer" : "default", userSelect: "none",
                  borderBottom: "1px solid var(--line)", width: c.width,
                }}>
                <span style={{ display: "inline-flex", alignItems: "center", gap: 4, justifyContent: c.align === "right" ? "flex-end" : "flex-start" }}>
                  {c.label}
                  {active && <Icon name={sortCtl.sort.dir === "asc" ? "arrowUp" : "arrowDown"} size={12} />}
                </span>
              </th>;
            })}
          </tr>
        </thead>
        <tbody>
          {rows.map((r, i) => <Row key={rowKey ? rowKey(r) : i} r={r} columns={columns} onRowClick={onRowClick} rowStyle={rowStyle} dense={dense} />)}
          {footRow}
          {rows.length === 0 && <tr><td colSpan={columns.length} style={{ padding: 28, textAlign: "center", color: "var(--ink-faint)" }}>No rows match the current filters.</td></tr>}
        </tbody>
      </table>
    </div>
  </div>;
}
function Row({ r, columns, onRowClick, rowStyle, dense }) {
  const [h, setH] = useState(false);
  return <tr onClick={onRowClick ? () => onRowClick(r) : undefined}
    onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
    style={Object.assign({ cursor: onRowClick ? "pointer" : "default", background: h && onRowClick ? "var(--surface)" : "transparent", transition: "background 120ms ease" }, rowStyle ? rowStyle(r) : null)}>
    {columns.map(c => <td key={c.key} style={{
      textAlign: c.align || "left", padding: dense ? "8px 12px" : "11px 14px",
      borderBottom: "1px solid var(--line-soft)", whiteSpace: c.wrap ? "normal" : "nowrap",
      color: "var(--ink)", verticalAlign: "middle",
    }}>{c.render ? c.render(r) : r[c.key]}</td>)}
  </tr>;
}

/* ---------------- Tabs ---------------- */
function Tabs({ tabs, active, onChange, style }) {
  return <div style={Object.assign({ display: "flex", gap: 2, borderBottom: "1px solid var(--line)", marginBottom: 18 }, style)}>
    {tabs.map(t => {
      const on = active === t.key;
      return <button key={t.key} onClick={() => onChange(t.key)} style={{
        display: "inline-flex", alignItems: "center", gap: 7, padding: "9px 14px",
        background: "transparent", border: "none", borderBottom: "2px solid " + (on ? "var(--accent)" : "transparent"),
        color: on ? "var(--ink)" : "var(--ink-soft)", fontWeight: on ? 600 : 500, fontSize: 13,
        marginBottom: -1, transition: "color 150ms ease",
      }}>
        {t.icon && <Icon name={t.icon} size={15} />}{t.label}
        {t.badge != null && <span style={{ fontSize: 10, fontWeight: 700, background: on ? "var(--accent)" : "var(--surface-deep)", color: on ? "#fff" : "var(--ink-soft)", borderRadius: 100, padding: "1px 6px", minWidth: 16, textAlign: "center" }}>{t.badge}</span>}
      </button>;
    })}
  </div>;
}

/* ---------------- Inputs ---------------- */
function SearchInput({ value, onChange, placeholder, width }) {
  return <div style={{ display: "flex", alignItems: "center", gap: 7, background: "var(--surface-card)", border: "1px solid var(--line)", borderRadius: 8, padding: "6px 10px", width: width || 220 }}>
    <Icon name="search" size={14} color="var(--ink-faint)" />
    <input value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder || "Search"}
      style={{ border: "none", outline: "none", background: "transparent", width: "100%", fontSize: 13 }} />
    {value && <button onClick={() => onChange("")} style={{ border: "none", background: "none", padding: 0, color: "var(--ink-faint)", display: "flex" }}><Icon name="x" size={13} /></button>}
  </div>;
}
function Select({ value, onChange, options, width, placeholder }) {
  return <select value={value} onChange={e => onChange(e.target.value)} style={{
    background: "var(--surface-card)", border: "1px solid var(--line)", borderRadius: 8,
    padding: "7px 28px 7px 10px", fontSize: 13, color: "var(--ink)", width, cursor: "pointer",
    appearance: "none", backgroundImage: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236e7479' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\")",
    backgroundRepeat: "no-repeat", backgroundPosition: "right 8px center",
  }}>
    {placeholder && <option value="">{placeholder}</option>}
    {options.map(o => typeof o === "string" ? <option key={o} value={o}>{o}</option> : <option key={o.value} value={o.value}>{o.label}</option>)}
  </select>;
}
function Field({ label, children }) {
  return <label style={{ display: "block" }}>
    <div className="micro" style={{ marginBottom: 5 }}>{label}</div>
    {children}
  </label>;
}
function TextInput(props) {
  return <input {...props} style={Object.assign({ width: "100%", border: "1px solid var(--line)", borderRadius: 8, padding: "7px 10px", background: "var(--surface-card)", outline: "none" }, props.style)} />;
}

/* ---------------- Drawer ---------------- */
function Drawer({ open, onClose, title, eyebrow, children, width = 460, footer }) {
  useEffect(() => {
    const h = e => e.key === "Escape" && onClose();
    if (open) window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, [open, onClose]);
  if (!open) return null;
  return <div style={{ position: "fixed", inset: 0, zIndex: 80 }}>
    <div onClick={onClose} style={{ position: "absolute", inset: 0, background: "rgba(26,28,30,0.32)", animation: "vcpScrim 150ms ease" }} />
    <div style={{
      position: "absolute", top: 0, right: 0, height: "100%", width, maxWidth: "92vw",
      background: "var(--surface-card)", boxShadow: "var(--shadow-drawer)", display: "flex", flexDirection: "column",
      animation: "vcpDrawerIn 180ms ease",
    }}>
      <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", padding: "16px 20px", borderBottom: "1px solid var(--line)" }}>
        <div>
          {eyebrow && <div className="micro" style={{ marginBottom: 4 }}>{eyebrow}</div>}
          <div style={{ fontSize: 16, fontWeight: 700, letterSpacing: "-0.01em" }}>{title}</div>
        </div>
        <IconBtn name="x" onClick={onClose} title="Close" />
      </div>
      <div className="scroll-y" style={{ flex: 1, padding: 20 }}>{children}</div>
      {footer && <div style={{ padding: "14px 20px", borderTop: "1px solid var(--line)", display: "flex", gap: 8, justifyContent: "flex-end" }}>{footer}</div>}
    </div>
  </div>;
}

/* ---------------- Save indicator ---------------- */
function SaveIndicator({ state }) {
  if (!state) return null;
  return <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12, color: state === "saving" ? "var(--ink-soft)" : "var(--positive)" }}>
    {state === "saving" ? <Icon name="refresh" size={13} /> : <Icon name="check" size={13} />}
    {state === "saving" ? "Saving" : "Saved"}
  </span>;
}
function useSaveFlash() {
  const [state, setState] = useState(null);
  const flash = useCallback(() => {
    setState("saving");
    setTimeout(() => setState("saved"), 350);
    setTimeout(() => setState(null), 1600);
  }, []);
  return [state, flash];
}

/* ---------------- Empty state ---------------- */
function EmptyState({ icon, title, sub, action }) {
  return <div style={{ textAlign: "center", padding: "56px 20px", color: "var(--ink-soft)" }}>
    {icon && <div style={{ display: "inline-flex", padding: 14, borderRadius: 14, background: "var(--surface-deep)", marginBottom: 14 }}><Icon name={icon} size={22} color="var(--ink-faint)" /></div>}
    <div style={{ fontSize: 15, fontWeight: 600, color: "var(--ink)" }}>{title}</div>
    {sub && <div style={{ fontSize: 13, marginTop: 5, maxWidth: 380, marginLeft: "auto", marginRight: "auto" }}>{sub}</div>}
    {action && <div style={{ marginTop: 16, display: "flex", justifyContent: "center" }}>{action}</div>}
  </div>;
}

/* ---------------- Dropdown (generic popover) ---------------- */
function Dropdown({ trigger, children, align = "left", width = 260 }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    const h = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);
  return <div ref={ref} style={{ position: "relative" }}>
    <div onClick={() => setOpen(o => !o)}>{trigger(open)}</div>
    {open && <div style={{
      position: "absolute", top: "calc(100% + 6px)", [align]: 0, width, zIndex: 70,
      background: "var(--surface-card)", border: "1px solid var(--line)", borderRadius: 10,
      boxShadow: "var(--shadow-pop)", overflow: "hidden", padding: 6,
    }}>{typeof children === "function" ? children(() => setOpen(false)) : children}</div>}
  </div>;
}

Object.assign(window, {
  Icon, Btn, IconBtn, ScoreBadge, Badge, TrendTag, Avatar, CompanyMark,
  SectionHeader, Card, KPIStrip, useSort, Table, Tabs, SearchInput, Select, Field, TextInput,
  Drawer, SaveIndicator, useSaveFlash, EmptyState, Dropdown,
  BAND_BG, BAND_FG, PRIORITY_VARIANT, PROGRESS_VARIANT,
  useState, useEffect, useRef, useMemo, useCallback,
});
