// MCP Hero — shared UI primitives
const { useState, useEffect, useRef, useContext, createContext } = React;

// ---------- Icons ----------
const MH_ICON_PATHS = {
  search: 'M11 19a8 8 0 1 1 5.29-2.04L21 21.7 19.7 23l-4.74-4.74A7.96 7.96 0 0 1 11 19Zm0-2a6 6 0 1 0 0-12 6 6 0 0 0 0 12Z',
  building: 'M4 21V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v4h2a2 2 0 0 1 2 2v10h-7v-4h-2v4H4Zm3-12h2V7H7v2Zm4 0h2V7h-2v2Zm-4 4h2v-2H7v2Zm4 0h2v-2h-2v2Zm5 0h2v-2h-2v2Zm0 6h2v-4h-2v4Z',
  scale: 'M12 3a1.5 1.5 0 0 1 1.5 1.5h4.5v2h-1.6l2.6 6a3.5 3.5 0 1 1-6.6.1l2.5-6.1H13.5V19h4v2h-10v-2h4V6.5H10l2.6 6a3.5 3.5 0 1 1-6.6.1l2.5-6.1H6v-2h4.5A1.5 1.5 0 0 1 12 3ZM7.7 9.3 6.2 13h3L7.7 9.3Zm8.6 0L14.8 13h3l-1.5-3.7Z',
  receipt: 'M6 2h12a1 1 0 0 1 1 1v19l-3-2-3 2-3-2-3 2V3a1 1 0 0 1 1-1Zm2 5v2h8V7H8Zm0 4v2h8v-2H8Zm0 4v2h5v-2H8Z',
  calculator: 'M5 3h14a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Zm2 2v4h10V5H7Zm0 6v2h2v-2H7Zm4 0v2h2v-2h-2Zm4 0v2h2v-2h-2Zm-8 4v2h2v-2H7Zm4 0v2h2v-2h-2Zm4 0v2h2v-2h-2Z',
  eye: 'M12 5c5 0 9.3 3 11 7-1.7 4-6 7-11 7S2.7 16 1 12c1.7-4 6-7 11-7Zm0 2C8.2 7 4.8 9 3.2 12 4.8 15 8.2 17 12 17s7.2-2 8.8-5C19.2 9 15.8 7 12 7Zm0 2a3 3 0 1 1 0 6 3 3 0 0 1 0-6Z',
  document: 'M6 2h8l4 4v15a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Zm7 1.5V7h3.5L13 3.5ZM8 11v2h8v-2H8Zm0 4v2h8v-2H8Z',
  language: 'M12.9 15.4 11.5 12l3-7h2l3 7h-1.9l-.6-1.6h-3l-.6 1.6ZM4 5h6V3h2v2h3v2h-2.1a13 13 0 0 1-2.6 5.1A12 12 0 0 0 13 14l-.8 1.8a14 14 0 0 1-3.2-2.2 14 14 0 0 1-4.3 2.8L4 14.6a12 12 0 0 0 3.7-2.3A13 13 0 0 1 5.6 9h2.1a11 11 0 0 0 1.4 2.1A11 11 0 0 0 10.8 7H4V5Zm10.7 3.6-.9 2.4h1.9l-1-2.4ZM7 16h2l4 8h-2l-.9-2H7.9L7 24H5l2-4.9V16Zm1.5 2.5L8 20h1.5l-1-1.5Z',
  home: 'M12 3l9 8h-3v9h-5v-6h-2v6H6v-9H3l9-8Z',
  plug: 'M9 2h2v5h2V2h2v5h2a1 1 0 0 1 1 1v3a6 6 0 0 1-5 5.92V22h-2v-5.08A6 6 0 0 1 6 11V8a1 1 0 0 1 1-1h2V2Z',
  zap: 'M13 2 4 14h6l-1 8 9-12h-6l1-8Z',
  coin: 'M12 2C6.5 2 2 4 2 6.5v11C2 20 6.5 22 12 22s10-2 10-4.5v-11C22 4 17.5 2 12 2Zm0 2c4.7 0 8 1.6 8 2.5S16.7 9 12 9 4 7.4 4 6.5 7.3 4 12 4Zm8 13.5c0 .9-3.3 2.5-8 2.5s-8-1.6-8-2.5v-2.4C5.8 14.3 8.7 15 12 15s6.2-.7 8-1.9v2.4Zm0-5.5c0 .9-3.3 2.5-8 2.5S4 12.9 4 12V9.6C5.8 10.8 8.7 11.5 12 11.5s6.2-.7 8-1.9V12Z',
  key: 'M14.5 2a7.5 7.5 0 0 1 0 15c-.8 0-1.5-.1-2.2-.3L11 18h-2v2H7v2H2v-4.5l7.3-7.3A7.5 7.5 0 0 1 14.5 2Zm1.5 5a2 2 0 1 0 0 4 2 2 0 0 0 0-4Z',
  users: 'M8 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8Zm0 2c3.3 0 8 1.7 8 5v3H0v-3c0-3.3 4.7-5 8-5Zm8.5-2.3A4 4 0 0 0 18 3.5a4 4 0 0 1-1.5 7.2ZM17 13c2.8.5 7 2 7 5v3h-4v-3c0-2-1.2-3.9-3-5Z',
  chart: 'M4 20V10h3v10H4Zm6.5 0V4h3v16h-3ZM17 20v-7h3v7h-3Z',
  grid: 'M4 4h7v7H4V4Zm9 0h7v7h-7V4ZM4 13h7v7H4v-7Zm9 0h7v7h-7v-7Z',
  list: 'M4 6h2v2H4V6Zm4 0h12v2H8V6ZM4 11h2v2H4v-2Zm4 0h12v2H8v-2ZM4 16h2v2H4v-2Zm4 0h12v2H8v-2Z',
  copy: 'M8 4h11a1 1 0 0 1 1 1v12h-2V6H8V4ZM5 8h10a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Zm1 2v9h8v-9H6Z',
  check: 'M9.5 16.2 5.3 12l-1.4 1.4 5.6 5.6 12-12L20.1 5.6 9.5 16.2Z',
  chevronDown: 'M12 15.4 6.3 9.7l1.4-1.4L12 12.6l4.3-4.3 1.4 1.4L12 15.4Z',
  chevronRight: 'M9.7 17.7l-1.4-1.4L12.6 12 8.3 7.7l1.4-1.4L15.4 12l-5.7 5.7Z',
  arrowLeft: 'M11 4 4.6 10.4a2.3 2.3 0 0 0 0 3.2L11 20l1.4-1.4-4.6-4.6H20v-2H7.8l4.6-4.6L11 4Z',
  arrowRight: 'M13 4l6.4 6.4a2.3 2.3 0 0 1 0 3.2L13 20l-1.4-1.4 4.6-4.6H4v-2h12.2l-4.6-4.6L13 4Z',
  sun: 'M12 17a5 5 0 1 1 0-10 5 5 0 0 1 0 10Zm0-15h0l1 3h-2l1-3Zm0 20 -1-3h2l-1 3ZM2 12l3-1v2l-3-1Zm20 0-3 1v-2l3 1ZM4.2 4.2l2.8 1.4-1.4 1.4-1.4-2.8Zm15.6 15.6-2.8-1.4 1.4-1.4 1.4 2.8ZM19.8 4.2l-1.4 2.8-1.4-1.4 2.8-1.4ZM4.2 19.8l1.4-2.8 1.4 1.4-2.8 1.4Z',
  moon: 'M12.3 2a9.9 9.9 0 0 0 9.5 13.1A10 10 0 1 1 12.3 2Z',
  plus: 'M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2h6Z',
  refresh: 'M12 4a8 8 0 0 1 7.4 5H22l-3.5 4.5L15 9h2.3A6 6 0 1 0 18 14h2.2A8 8 0 1 1 12 4Z',
  trash: 'M9 3h6l1 2h4v2H4V5h4l1-2ZM6 9h12l-1 13H7L6 9Zm4 2v9h1.5v-9H10Zm3 0v9h1.5v-9H13Z',
  alert: 'M12 2 1 21h22L12 2Zm-1 13v-5h2v5h-2Zm0 4v-2h2v2h-2Z',
  external: 'M14 3h7v7h-2V6.4l-8.3 8.3-1.4-1.4L17.6 5H14V3ZM5 5h6v2H7v10h10v-4h2v6H5V5Z',
  clock: 'M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20Zm0 2a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm1 3v5.4l4 2.4-1 1.7L11 13V7h2Z',
  shield: 'M12 2l8 3v6c0 5.5-3.8 9.7-8 11-4.2-1.3-8-5.5-8-11V5l8-3Z',
  box: 'M12 2 3 7v10l9 5 9-5V7l-9-5Zm0 2.3L18.5 8 12 11.6 5.5 8 12 4.3ZM5 9.7l6 3.4v6.6l-6-3.4V9.7Zm14 0v6.6l-6 3.4v-6.6l6-3.4Z',
  settings: 'M12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8Zm8.9 5.4-.1-2.8 2-1.8-2-3.5-2.6.8a8 8 0 0 0-2.4-1.4L15.2 2h-4l-.6 2.7a8 8 0 0 0-2.4 1.4l-2.6-.8-2 3.5 2 1.8a8 8 0 0 0 0 2.8l-2 1.8 2 3.5 2.6-.8a8 8 0 0 0 2.4 1.4l.6 2.7h4l.6-2.7a8 8 0 0 0 2.4-1.4l2.6.8 2-3.5-2-1.8Z',
  mail: 'M3 5h18a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Zm9 7.5L4.5 7v10h15V7L12 12.5ZM5.8 7h12.4L12 11.2 5.8 7Z',
  logout: 'M5 3h8v2H7v14h6v2H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Zm11.6 4.6L20 11H11v2h9l-3.4 3.4 1.4 1.4 5-5a1.3 1.3 0 0 0 0-1.6l-5-5-1.4 1.4Z',
  filter: 'M3 5h18l-7 8.5V19l-4 2v-7.5L3 5Z',
  download: 'M11 3h2v9.2l3.1-3.1 1.4 1.4L12 16 6.5 10.5l1.4-1.4L11 12.2V3ZM4 19h16v2H4v-2Z',
  dots: 'M6 10.5a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm6 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Zm6 0a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3Z',
  sparkle: 'M12 2l2 6 6 2-6 2-2 6-2-6-6-2 6-2 2-6Zm7 12 1 3 3 1-3 1-1 3-1-3-3-1 3-1 1-3Z',
  close: 'M12 10.6 6.6 5.2 5.2 6.6 10.6 12l-5.4 5.4 1.4 1.4L12 13.4l5.4 5.4 1.4-1.4L13.4 12l5.4-5.4-1.4-1.4L12 10.6Z',
  wallet: 'M3 5h16v3h2a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5Zm17 5h-5a2.5 2.5 0 0 0 0 5h5v-5Zm-5 1.5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z',
  pause: 'M7 4h4v16H7V4Zm6 0h4v16h-4V4Z',
  play: 'M7 4l13 8-13 8V4Z',
};

function Icon({ name, size = 18, style = {}, className }) {
  const d = MH_ICON_PATHS[name] || MH_ICON_PATHS.box;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" style={{ flexShrink: 0, ...style }} className={className} aria-hidden="true">
      <path d={d}></path>
    </svg>
  );
}

// ---------- Buttons ----------
function Btn({ children, variant = 'primary', size = 'md', icon, onClick, style = {}, disabled, title }) {
  const [hover, setHover] = useState(false);
  const pad = size === 'sm' ? '6px 12px' : size === 'lg' ? '12px 22px' : '9px 16px';
  const fs = size === 'sm' ? 13 : size === 'lg' ? 15.5 : 14;
  const variants = {
    primary: { background: hover ? 'var(--accent-strong)' : 'var(--accent)', color: 'var(--accent-contrast)', border: '1px solid transparent' },
    secondary: { background: hover ? 'var(--bg-sunken)' : 'var(--bg-raised)', color: 'var(--text)', border: '1px solid var(--border-strong)' },
    ghost: { background: hover ? 'var(--bg-sunken)' : 'transparent', color: 'var(--text-2)', border: '1px solid transparent' },
    danger: { background: hover ? 'var(--danger)' : 'transparent', color: hover ? '#fff' : 'var(--danger)', border: '1px solid var(--danger)' },
    inverse: { background: hover ? '#33323c' : 'var(--bg-inverse)', color: 'var(--bg)', border: '1px solid transparent' },
  };
  return (
    <button
      onClick={onClick} disabled={disabled} title={title}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: 7, padding: pad, fontSize: fs,
        fontWeight: 600, borderRadius: 9, cursor: disabled ? 'default' : 'pointer',
        opacity: disabled ? 0.5 : 1, transition: 'all .15s ease', whiteSpace: 'nowrap',
        ...variants[variant], ...style,
      }}
    >
      {icon ? <Icon name={icon} size={fs + 1}></Icon> : null}
      {children}
    </button>
  );
}

// ---------- Badges & tags ----------
function Badge({ children, tone = 'neutral', style = {} }) {
  const tones = {
    neutral: { background: 'var(--bg-sunken)', color: 'var(--text-2)' },
    ok: { background: 'var(--ok-bg)', color: 'var(--ok)' },
    warn: { background: 'var(--warn-bg)', color: 'var(--warn)' },
    danger: { background: 'var(--danger-bg)', color: 'var(--danger)' },
    accent: { background: 'color-mix(in oklch, var(--accent) 14%, transparent)', color: 'var(--accent)' },
  };
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 9px', fontSize: 12,
      fontWeight: 600, borderRadius: 999, letterSpacing: '.01em', whiteSpace: 'nowrap',
      ...tones[tone], ...style,
    }}>{children}</span>
  );
}

function CategoryTag({ cat, size = 12 }) {
  const hue = mhCatHue(cat);
  return (
    <span data-cat={cat} style={{
      display: 'inline-flex', alignItems: 'center', padding: '3px 9px', fontSize: size, fontWeight: 600,
      borderRadius: 999, whiteSpace: 'nowrap',
      background: `oklch(0.93 0.05 ${hue} / 1)`, color: `oklch(0.45 0.13 ${hue})`,
    }}>{mhCatLabel(cat)}</span>
  );
}

function CreditPill({ mcp, size = 12.5 }) {
  if (mcp.free) {
    return <span style={{ fontSize: size, fontWeight: 700, color: 'var(--ok)' }}>Free</span>;
  }
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: size, fontWeight: 600, color: 'var(--text-2)' }}>
      <Icon name="coin" size={size + 1} style={{ color: 'var(--warn)' }}></Icon>
      From {mcp.fromCredits} cr/call
    </span>
  );
}

// ---------- MCP icon tile ----------
function McpIcon({ mcp, size = 44 }) {
  const hue = mcp.iconHue;
  return (
    <div style={{
      width: size, height: size, borderRadius: size * 0.27, display: 'flex', alignItems: 'center',
      justifyContent: 'center', flexShrink: 0,
      background: `linear-gradient(135deg, oklch(0.92 0.06 ${hue}), oklch(0.85 0.09 ${hue + 30}))`,
      color: `oklch(0.42 0.14 ${hue})`,
      border: `1px solid oklch(0.85 0.07 ${hue})`,
    }}>
      <Icon name={mcp.icon} size={size * 0.5}></Icon>
    </div>
  );
}

function Avatar({ initials, size = 34, hue = 280 }) {
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center',
      background: `oklch(0.88 0.06 ${hue})`, color: `oklch(0.4 0.12 ${hue})`,
      fontSize: size * 0.38, fontWeight: 700, flexShrink: 0, letterSpacing: '.02em',
    }}>{initials}</div>
  );
}

// ---------- Cards & layout ----------
function Card({ children, style = {}, onClick, hoverable }) {
  const [hover, setHover] = useState(false);
  return (
    <div
      onClick={onClick}
      onMouseEnter={() => hoverable && setHover(true)}
      onMouseLeave={() => hoverable && setHover(false)}
      style={{
        background: 'var(--surface)', border: `1px solid ${hover ? 'var(--border-strong)' : 'var(--border)'}`,
        borderRadius: 'var(--radius-lg)', boxShadow: hover ? 'var(--shadow-md)' : 'var(--shadow-sm)',
        transition: 'all .18s ease', cursor: onClick ? 'pointer' : 'default',
        transform: hover ? 'translateY(-2px)' : 'none',
        ...style,
      }}
    >{children}</div>
  );
}

function StatCard({ label, value, sub, icon, tone }) {
  return (
    <Card style={{ padding: '18px 20px', display: 'flex', flexDirection: 'column', gap: 4, flex: 1, minWidth: 160 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 7, color: 'var(--text-3)', fontSize: 12.5, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '.05em' }}>
        {icon ? <Icon name={icon} size={14}></Icon> : null}{label}
      </div>
      <div style={{ fontSize: 27, fontWeight: 700, fontFamily: 'var(--font-display)', color: tone === 'accent' ? 'var(--accent)' : 'var(--text)', lineHeight: 1.15 }}>{value}</div>
      {sub ? <div style={{ fontSize: 12.5, color: 'var(--text-3)' }}>{sub}</div> : null}
    </Card>
  );
}

// ---------- Forms ----------
function Field({ label, hint, children, style = {} }) {
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 6, ...style }}>
      <span style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--text)' }}>{label}</span>
      {children}
      {hint ? <span style={{ fontSize: 12.5, color: 'var(--text-3)' }}>{hint}</span> : null}
    </label>
  );
}

function TextInput({ value, onChange, placeholder, type = 'text', disabled, mono, style = {} }) {
  const [focus, setFocus] = useState(false);
  return (
    <input
      type={type} value={value} placeholder={placeholder} disabled={disabled}
      onChange={(e) => onChange && onChange(e.target.value)}
      onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
      style={{
        padding: '10px 13px', fontSize: 14.5, borderRadius: 9, outline: 'none', width: '100%',
        border: `1.5px solid ${focus ? 'var(--accent)' : 'var(--border-strong)'}`,
        background: disabled ? 'var(--bg-sunken)' : 'var(--bg-raised)', color: disabled ? 'var(--text-3)' : 'var(--text)',
        boxShadow: focus ? '0 0 0 3px color-mix(in oklch, var(--accent) 18%, transparent)' : 'none',
        transition: 'all .15s ease', fontFamily: mono ? 'var(--font-mono)' : 'inherit',
        ...style,
      }}
    ></input>
  );
}

function Select({ value, onChange, options, style = {} }) {
  return (
    <select
      value={value} onChange={(e) => onChange && onChange(e.target.value)}
      style={{
        padding: '10px 13px', fontSize: 14.5, borderRadius: 9, border: '1.5px solid var(--border-strong)',
        background: 'var(--bg-raised)', color: 'var(--text)', outline: 'none', cursor: 'pointer', ...style,
      }}
    >
      {options.map((o) => <option key={o.value != null ? o.value : o} value={o.value != null ? o.value : o}>{o.label != null ? o.label : o}</option>)}
    </select>
  );
}

function Segmented({ value, onChange, options, size = 'md', style = {} }) {
  return (
    <div style={{ display: 'inline-flex', gap: 3, padding: 3, background: 'var(--bg-sunken)', borderRadius: 10, border: '1px solid var(--border)', ...style }}>
      {options.map((o) => {
        const v = o.value != null ? o.value : o;
        const l = o.label != null ? o.label : o;
        const active = v === value;
        return (
          <button key={v} onClick={() => onChange(v)} style={{
            padding: size === 'sm' ? '4px 10px' : '6px 14px', fontSize: size === 'sm' ? 12.5 : 13.5, fontWeight: 600,
            borderRadius: 8, border: 'none', cursor: 'pointer', transition: 'all .15s ease',
            background: active ? 'var(--bg-raised)' : 'transparent',
            color: active ? 'var(--text)' : 'var(--text-3)',
            boxShadow: active ? 'var(--shadow-sm)' : 'none',
          }}>{l}</button>
        );
      })}
    </div>
  );
}

// ---------- Copy block ----------
function CopyBlock({ code, label }) {
  const [copied, setCopied] = useState(false);
  const copy = () => {
    try { navigator.clipboard.writeText(code); } catch (e) { /* noop */ }
    setCopied(true);
    setTimeout(() => setCopied(false), 1800);
  };
  return (
    <div style={{ position: 'relative', borderRadius: 12, overflow: 'hidden', border: '1px solid var(--border)' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 14px', background: 'var(--bg-sunken)', borderBottom: '1px solid var(--border)' }}>
        <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-3)', fontFamily: 'var(--font-mono)' }}>{label || 'claude_desktop_config.json'}</span>
        <button onClick={copy} style={{
          display: 'inline-flex', alignItems: 'center', gap: 5, padding: '4px 10px', fontSize: 12, fontWeight: 600,
          borderRadius: 7, border: '1px solid var(--border-strong)', cursor: 'pointer',
          background: copied ? 'var(--ok-bg)' : 'var(--bg-raised)', color: copied ? 'var(--ok)' : 'var(--text-2)',
          transition: 'all .15s ease',
        }}>
          <Icon name={copied ? 'check' : 'copy'} size={13}></Icon>{copied ? 'Copied!' : 'Copy'}
        </button>
      </div>
      <pre style={{
        margin: 0, padding: '14px 16px', fontSize: 12.5, lineHeight: 1.6, overflowX: 'auto',
        fontFamily: 'var(--font-mono)', background: 'var(--bg-inverse)', color: 'var(--bg)',
      }}>{code}</pre>
    </div>
  );
}

// ---------- Modal ----------
function Modal({ open, onClose, title, children, width = 480 }) {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(15,14,20,.45)', zIndex: 200,
      display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24,
      animation: 'mh-fade .15s ease both', backdropFilter: 'blur(3px)',
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        background: 'var(--bg-raised)', borderRadius: 18, width: '100%', maxWidth: width,
        boxShadow: 'var(--shadow-lg)', border: '1px solid var(--border)',
        animation: 'mh-pop .18s ease both', maxHeight: '85vh', overflowY: 'auto',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '18px 22px 0' }}>
          <h3 style={{ margin: 0, fontSize: 18, fontFamily: 'var(--font-display)', fontWeight: 700 }}>{title}</h3>
          <button onClick={onClose} style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--text-3)', padding: 4 }}>
            <Icon name="close" size={18}></Icon>
          </button>
        </div>
        <div style={{ padding: '14px 22px 22px' }}>{children}</div>
      </div>
    </div>
  );
}

// ---------- Toast ----------
const ToastContext = createContext(null);
function ToastProvider({ children }) {
  const [toasts, setToasts] = useState([]);
  const push = (msg, tone = 'ok') => {
    const id = Date.now() + Math.random();
    setToasts((t) => [...t, { id, msg, tone }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3200);
  };
  return (
    <ToastContext.Provider value={push}>
      {children}
      <div style={{ position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)', zIndex: 400, display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'center' }}>
        {toasts.map((t) => (
          <div key={t.id} style={{
            display: 'flex', alignItems: 'center', gap: 8, padding: '10px 18px', borderRadius: 12,
            background: 'var(--bg-inverse)', color: 'var(--bg)', fontSize: 13.5, fontWeight: 600,
            boxShadow: 'var(--shadow-lg)', animation: 'mh-pop .2s ease both',
          }}>
            <Icon name={t.tone === 'danger' ? 'alert' : 'check'} size={15} style={{ color: t.tone === 'danger' ? 'var(--danger)' : '#7BD8A5' }}></Icon>
            {t.msg}
          </div>
        ))}
      </div>
    </ToastContext.Provider>
  );
}
function useToast() { return useContext(ToastContext) || (() => {}); }

// ---------- Table ----------
function Table({ cols, children, style = {} }) {
  return (
    <div style={{ overflowX: 'auto', borderRadius: 14, border: '1px solid var(--border)', background: 'var(--surface)', ...style }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13.5 }}>
        <thead>
          <tr>
            {cols.map((c, i) => (
              <th key={i} style={{
                textAlign: c.align || 'left', padding: '11px 16px', fontSize: 11.5, fontWeight: 700,
                textTransform: 'uppercase', letterSpacing: '.06em', color: 'var(--text-3)',
                borderBottom: '1px solid var(--border)', background: 'var(--bg-sunken)', whiteSpace: 'nowrap',
              }}>{c.label != null ? c.label : c}</th>
            ))}
          </tr>
        </thead>
        <tbody>{children}</tbody>
      </table>
    </div>
  );
}
function Tr({ children, onClick }) {
  const [hover, setHover] = useState(false);
  return (
    <tr onClick={onClick} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{ background: hover && onClick ? 'var(--bg-sunken)' : 'transparent', cursor: onClick ? 'pointer' : 'default', transition: 'background .12s ease' }}>
      {children}
    </tr>
  );
}
function Td({ children, align, style = {} }) {
  return <td style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', textAlign: align || 'left', color: 'var(--text-2)', ...style }}>{children}</td>;
}

// ---------- Empty state ----------
function EmptyState({ icon = 'box', title, sub, action }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10, padding: '56px 24px', textAlign: 'center' }}>
      <div style={{ width: 56, height: 56, borderRadius: 16, background: 'var(--bg-sunken)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-3)' }}>
        <Icon name={icon} size={26}></Icon>
      </div>
      <div style={{ fontWeight: 700, fontSize: 16, fontFamily: 'var(--font-display)' }}>{title}</div>
      {sub ? <div style={{ fontSize: 13.5, color: 'var(--text-3)', maxWidth: 360 }}>{sub}</div> : null}
      {action}
    </div>
  );
}

// ---------- Logo ----------
function Logo({ size = 28, withWord = true, inverse }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
      <div style={{
        width: size, height: size, borderRadius: size * 0.3, position: 'relative', flexShrink: 0,
        background: 'linear-gradient(135deg, var(--accent), color-mix(in oklch, var(--accent) 60%, #E8604C))',
        display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff',
        boxShadow: '0 2px 6px color-mix(in oklch, var(--accent) 40%, transparent)',
      }}>
        <Icon name="plug" size={size * 0.62}></Icon>
      </div>
      {withWord ? (
        <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: size * 0.68, letterSpacing: '-.01em', color: inverse ? '#fff' : 'var(--text)' }}>
          MCP&nbsp;Hero
        </span>
      ) : null}
    </div>
  );
}

// ---------- Section heading ----------
function SectionHead({ title, sub, right }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 16, marginBottom: 18, flexWrap: 'wrap' }}>
      <div>
        <h2 style={{ margin: 0, fontSize: 21, fontFamily: 'var(--font-display)', fontWeight: 700, letterSpacing: '-.01em' }}>{title}</h2>
        {sub ? <p style={{ margin: '4px 0 0', fontSize: 13.5, color: 'var(--text-3)' }}>{sub}</p> : null}
      </div>
      {right}
    </div>
  );
}

Object.assign(window, {
  Icon, Btn, Badge, CategoryTag, CreditPill, McpIcon, Avatar, Card, StatCard,
  Field, TextInput, Select, Segmented, CopyBlock, Modal, ToastProvider, useToast,
  Table, Tr, Td, EmptyState, Logo, SectionHead,
});
