/* global React */
// =========================================================================
// SkillPluginRail — left-edge slide-out rail of droppable skill-plugins.
// "Integrations" → "Skills" — everything here is just a skill with env_keys,
// treated as a plugin you drag into the catalog.
// Hover/drag a tile → skills that would wire to it light up (others dim).
// Data lineage (source / scope / reads / writes / last sync) disclosed inline.
// =========================================================================
const { useState: igUseState, useMemo: igUseMemo, useEffect: igUseEffect, useRef: igUseRef } = React;

// ---- relative-time formatter ----
function relTime(ms) {
  if (!ms) return "never";
  const d = Date.now() - ms;
  if (d < 60e3) return Math.max(1, Math.round(d/1e3)) + "s ago";
  if (d < 3600e3) return Math.round(d/60e3) + "m ago";
  if (d < 86400e3) return Math.round(d/3600e3) + "h ago";
  return Math.round(d/86400e3) + "d ago";
}

// ---- brand logos — inline SVG so they respect currentColor where useful ----
function BrandLogo({ id, size = 22 }) {
  const s = { width: size, height: size, display: "block" };
  switch (id) {
    case "gmail":
      return <svg style={s} viewBox="0 0 24 24"><path d="M22 6.98v10.04c0 .54-.44.98-.98.98H19V9.91l-7 5.25-7-5.25v8.09H2.98A.98.98 0 0 1 2 17.02V6.98c0-.54.44-.98.98-.98h.37L12 12.5 20.65 6h.37c.54 0 .98.44.98.98z" fill="#EA4335"/><path d="M5 9.91V18h14V9.91l-7 5.25-7-5.25z" fill="#fff" opacity=".9"/></svg>;
    case "google-calendar":
      return <svg style={s} viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="16" rx="2" fill="#fff" stroke="#4285F4" strokeWidth="1.5"/><rect x="3" y="5" width="18" height="4" fill="#4285F4"/><text x="12" y="18" fontSize="10" fontWeight="700" fill="#4285F4" textAnchor="middle" fontFamily="Arial, sans-serif">31</text><rect x="6" y="3" width="2" height="5" rx="1" fill="#1a1a1a"/><rect x="16" y="3" width="2" height="5" rx="1" fill="#1a1a1a"/></svg>;
    case "google-drive":
      return <svg style={s} viewBox="0 0 24 24"><path d="M7.71 3h8.58l5.71 9.9-4.29 7.1H6.29L2 12.9 7.71 3z" fill="none"/><path d="M7.71 3L2 12.9h5.71L13.43 3H7.71z" fill="#FBBC04"/><path d="M16.29 3h-2.86l5.71 9.9h2.86L16.29 3z" fill="#34A853"/><path d="M2 12.9l2.86 5 5.71-9.9H7.71L2 12.9z" fill="#4285F4"/><path d="M10.57 8H16.29L22 17.9h-5.71L10.57 8z" fill="#1A73E8"/><path d="M7.71 17.9H22l-2.86 2.1H10.57l-2.86-2.1z" fill="#EA4335"/></svg>;
    case "slack":
      return <svg style={s} viewBox="0 0 24 24"><path d="M5.5 15a1.75 1.75 0 1 1 0-3.5H7V13a1.75 1.75 0 0 1-1.5 2z" fill="#E01E5A"/><path d="M8.25 15a1.75 1.75 0 0 1 3.5 0v4.25a1.75 1.75 0 0 1-3.5 0V15z" fill="#E01E5A"/><path d="M9 5.5a1.75 1.75 0 1 1 3.5 0V7H9V5.5z" fill="#36C5F0"/><path d="M9 8.25a1.75 1.75 0 0 1 0 3.5H4.75a1.75 1.75 0 0 1 0-3.5H9z" fill="#36C5F0"/><path d="M18.5 9a1.75 1.75 0 1 1 0 3.5H17V11a1.75 1.75 0 0 1 1.5-2z" fill="#2EB67D"/><path d="M15.75 9a1.75 1.75 0 0 1-3.5 0V4.75a1.75 1.75 0 0 1 3.5 0V9z" fill="#2EB67D"/><path d="M15 18.5a1.75 1.75 0 1 1-3.5 0V17H15v1.5z" fill="#ECB22E"/><path d="M15 15.75a1.75 1.75 0 0 1 0-3.5h4.25a1.75 1.75 0 0 1 0 3.5H15z" fill="#ECB22E"/></svg>;
    case "notion":
      return <svg style={s} viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2" fill="#fff" stroke="#1a1a1a" strokeWidth="1.5"/><path d="M8 7v10M8 7l8 10M16 7v10" stroke="#1a1a1a" strokeWidth="1.8" fill="none" strokeLinecap="round"/></svg>;
    case "stripe":
      return <svg style={s} viewBox="0 0 24 24"><rect x="2" y="4" width="20" height="16" rx="3" fill="#635BFF"/><path d="M10.5 15.2c0-.4.3-.6 1-.6.9 0 2 .3 2.9.8v-2.7c-1-.4-2-.6-2.9-.6-2.3 0-3.9 1.2-3.9 3.2 0 3.1 4.3 2.6 4.3 3.9 0 .5-.4.7-1.1.7-1 0-2.3-.4-3.3-1v2.7c1.1.5 2.2.7 3.3.7 2.4 0 4-1.2 4-3.2 0-3.4-4.3-2.8-4.3-3.9z" fill="#fff" transform="translate(0,-4)"/></svg>;
    case "linear":
      return <svg style={s} viewBox="0 0 24 24"><defs><linearGradient id="lin" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#5E6AD2"/><stop offset="1" stopColor="#8A92D8"/></linearGradient></defs><rect x="3" y="3" width="18" height="18" rx="4" fill="url(#lin)"/><path d="M7 11l6 6M7 7l10 10M11 7l6 6" stroke="#fff" strokeWidth="1.4" strokeLinecap="round" opacity=".95"/></svg>;
    case "github":
      return <svg style={s} viewBox="0 0 24 24"><path fill="#24292F" d="M12 2C6.5 2 2 6.6 2 12.3c0 4.5 2.9 8.4 6.8 9.8.5.1.7-.2.7-.5v-2c-2.8.6-3.4-1.3-3.4-1.3-.5-1.2-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.5 1 1.5 1 .9 1.6 2.4 1.1 3 .9.1-.7.4-1.1.7-1.4-2.2-.3-4.6-1.1-4.6-5 0-1.1.4-2 1-2.7-.1-.3-.4-1.3.1-2.7 0 0 .8-.3 2.7 1 .8-.2 1.7-.3 2.5-.3s1.7.1 2.5.3c1.9-1.3 2.7-1 2.7-1 .5 1.4.2 2.4.1 2.7.6.7 1 1.6 1 2.7 0 3.9-2.3 4.7-4.6 5 .4.3.7.9.7 1.8v2.7c0 .3.2.6.7.5 4-1.4 6.8-5.3 6.8-9.8C22 6.6 17.5 2 12 2z"/></svg>;
    case "hubspot":
      return <svg style={s} viewBox="0 0 24 24"><path fill="#FF7A59" d="M18.2 8V5.3a1.6 1.6 0 1 0-1.6-.1v2.8c-1 .3-1.9.9-2.6 1.6L7.3 4.5c.1-.2.1-.4.1-.7a2.1 2.1 0 1 0-2.1 2.1c.3 0 .6-.1.9-.2l6.5 5-.3.4c-2.4 3.4-1.8 8 1.3 10.6 3.1 2.5 7.7 2.1 10.1-1s1.8-8-1.3-10.6c-.8-.6-1.7-1.1-2.6-1.3l-1.7-.8zm-1.1 10.6a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7z"/></svg>;
    case "airtable":
      return <svg style={s} viewBox="0 0 24 24"><path d="M2 7l10-4 10 4-10 4L2 7z" fill="#FCB400"/><path d="M12 11l10-4v4l-10 4V11z" fill="#FF6F61"/><path d="M12 11L2 7v4l10 4v-4z" fill="#18BFFF"/><path d="M12 15l10-4v6l-10 4v-6z" fill="#B2222F"/></svg>;
    case "supabase":
      return <svg style={s} viewBox="0 0 24 24"><path fill="#3ECF8E" d="M13.5 2L3 14h8l-1 8 10.5-12H12l1.5-8z"/></svg>;
    case "discord":
      return <svg style={s} viewBox="0 0 24 24"><path fill="#5865F2" d="M19.6 5.3a17.6 17.6 0 0 0-4.4-1.4l-.2.4c1.6.4 2.9 1 4.2 1.8-2.3-1.2-5-1.8-7.7-1.8-2.6 0-5.2.5-7.4 1.7C5.4 5.3 6.7 4.7 8.3 4.3l-.2-.4a17.6 17.6 0 0 0-4.4 1.4C.8 9.9.3 14.4.5 18.9a17.4 17.4 0 0 0 5.2 2.6l.7-1.1c-1-.4-2-.9-2.9-1.6.2-.2.4-.3.6-.5 3.5 1.7 7.3 2.2 10.9 1.1 1-.3 1.9-.7 2.8-1.1.2.2.4.3.6.5-.9.6-1.9 1.2-2.9 1.6l.7 1.1a17.4 17.4 0 0 0 5.2-2.6c.2-4.7-.5-9.2-2.9-13.6zM8 15.6c-1 0-1.9-1-1.9-2.1s.8-2.1 1.9-2.1 1.9 1 1.9 2.1-.9 2.1-1.9 2.1zm7.9 0c-1 0-1.9-1-1.9-2.1s.8-2.1 1.9-2.1 1.9 1 1.9 2.1-.9 2.1-1.9 2.1z"/></svg>;
    case "telegram":
      return <svg style={s} viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#24A1DE"/><path fill="#fff" d="M16.6 7.5l-1.8 8.8c-.1.6-.5.7-1 .5l-2.8-2.1-1.4 1.3c-.1.1-.3.3-.5.3l.2-2.8 5.1-4.6c.2-.2 0-.3-.3-.1l-6.3 4-2.7-.9c-.6-.2-.6-.6.1-.9L16 7c.5-.2.9.1.7.5z"/></svg>;
    case "twilio":
      return <svg style={s} viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#F22F46"/><circle cx="8.5" cy="8.5" r="1.7" fill="#fff"/><circle cx="15.5" cy="8.5" r="1.7" fill="#fff"/><circle cx="8.5" cy="15.5" r="1.7" fill="#fff"/><circle cx="15.5" cy="15.5" r="1.7" fill="#fff"/></svg>;
    case "openai":
      return <svg style={s} viewBox="0 0 24 24"><path fill="#10A37F" d="M22 9.4a5.4 5.4 0 0 0-.5-4.4 5.5 5.5 0 0 0-5.9-2.6 5.5 5.5 0 0 0-9.3 2 5.4 5.4 0 0 0-3.6 2.6 5.5 5.5 0 0 0 .7 6.4 5.4 5.4 0 0 0 .5 4.4 5.5 5.5 0 0 0 5.9 2.6 5.4 5.4 0 0 0 4.1 1.8 5.5 5.5 0 0 0 5.2-3.8 5.4 5.4 0 0 0 3.6-2.6 5.5 5.5 0 0 0-.7-6.4zM13 20.4a4.1 4.1 0 0 1-2.6-.9l.1-.1 4.3-2.5a.7.7 0 0 0 .4-.6V10l1.8 1.1v5a4.1 4.1 0 0 1-4 4.3zm-8.8-3.8a4.1 4.1 0 0 1-.5-2.8l.1.1 4.3 2.5a.7.7 0 0 0 .7 0l5.3-3v2l-4.4 2.6a4.1 4.1 0 0 1-5.5-1.4zm-1.1-9.4a4 4 0 0 1 2.2-1.8V11a.7.7 0 0 0 .4.6l5.2 3-1.8 1-4.4-2.5a4.1 4.1 0 0 1-1.6-5.8zm14.9 3.5L12.7 7.6v-2L17.1 8a4.1 4.1 0 0 1-.6 7.4v-4.9a.7.7 0 0 0-.4-.6zm1.8-2.8l-.1-.1-4.3-2.5a.7.7 0 0 0-.7 0l-5.3 3v-2l4.4-2.6a4.1 4.1 0 0 1 6 4.3zM8.5 12.5L6.7 11.4V6.3a4.1 4.1 0 0 1 6.7-3.1l-.1.1-4.3 2.4a.7.7 0 0 0-.4.6zm1 2.1l2.4-1.4 2.4 1.4v2.8l-2.4 1.4L9.5 17.4z"/></svg>;
    case "anthropic":
      return <svg style={s} viewBox="0 0 24 24"><path fill="#D97757" d="M14.1 4L8.5 20h3.2l1-3.1h5.8l1 3.1h3.2L17 4h-2.9zM13.4 14l2-6.3 2 6.3h-4z"/><path fill="#D97757" d="M4.8 4h3.1L2.3 20h3.1z"/></svg>;
    default:
      return <span style={{fontSize:13, fontWeight:600}}>◈</span>;
  }
}

// Resolve all skill ids that relate to an integration (via env_keys + hints + installed)
function relatedSkillIds(integration, S) {
  const out = new Set(integration.skillHints || []);
  (integration.env_keys || []).forEach(k => {
    const users = S.usersOfKey(k);
    users.forEach(id => out.add(id));
  });
  S.installedSkills.forEach(sk => {
    if (sk.fromIntegration === integration.id) out.add(sk.id);
  });
  return out;
}

function SkillPluginRail() {
  const S = window.useSnappyState();
  const [open, setOpen] = igUseState(false);
  const [query, setQuery] = igUseState("");
  const [hoverId, setHoverId] = igUseState(null);
  const [dragId, setDragId] = igUseState(null);
  const [expandedId, setExpandedId] = igUseState(null);
  const [dropHotCard, setDropHotCard] = igUseState(null); // id of skill card currently hovered during drag

  const activeId = dragId || hoverId;

  const installedIds = igUseMemo(
    () => new Set(S.installedSkills.map(s => s.id)),
    [S.installedSkills]
  );

  const filtered = igUseMemo(() => {
    const q = query.trim().toLowerCase();
    if (!q) return S.INTEGRATIONS;
    return S.INTEGRATIONS.filter(i =>
      i.name.toLowerCase().includes(q) ||
      i.id.toLowerCase().includes(q) ||
      i.blurb.toLowerCase().includes(q)
    );
  }, [query, S.INTEGRATIONS]);

  // Broadcast "active integration" → catalog cards light/dim
  igUseEffect(() => {
    if (!activeId) {
      document.documentElement.removeAttribute("data-lit-integration");
      document.querySelectorAll(".skill-card.lit, .skill-card.dim, .skill-card.drop-hot").forEach(el => {
        el.classList.remove("lit", "dim", "drop-hot");
      });
      return;
    }
    const intg = S.INTEGRATIONS.find(i => i.id === activeId);
    if (!intg) return;
    const related = relatedSkillIds(intg, S);
    document.documentElement.setAttribute("data-lit-integration", activeId);
    document.querySelectorAll(".skill-card").forEach(el => {
      const sid = el.getAttribute("data-skill-id");
      if (!sid) return;
      if (related.has(sid)) { el.classList.add("lit"); el.classList.remove("dim"); }
      else { el.classList.add("dim"); el.classList.remove("lit"); }
    });
  }, [activeId, S.INTEGRATIONS, S.installedSkills]);

  // Global drag-over tracker — finds which skill card the cursor is over
  igUseEffect(() => {
    if (!dragId) { setDropHotCard(null); return; }
    const onMove = (e) => {
      const el = document.elementFromPoint(e.clientX, e.clientY);
      const card = el?.closest(".skill-card");
      const sid = card?.getAttribute("data-skill-id");
      setDropHotCard(sid || null);
    };
    window.addEventListener("dragover", onMove);
    return () => window.removeEventListener("dragover", onMove);
  }, [dragId]);

  // Apply drop-hot class whenever dropHotCard changes
  igUseEffect(() => {
    document.querySelectorAll(".skill-card.drop-hot").forEach(el => el.classList.remove("drop-hot"));
    if (dropHotCard) {
      const el = document.querySelector(`.skill-card[data-skill-id="${dropHotCard}"]`);
      if (el) el.classList.add("drop-hot");
    }
  }, [dropHotCard]);

  igUseEffect(() => { if (dragId) setOpen(true); }, [dragId]);

  const install = (intId) => {
    const r = S.installIntegration(intId);
    if (r.ok) {
      const intg = S.INTEGRATIONS.find(i => i.id === intId);
      const related = relatedSkillIds(intg, S);
      related.add(intId);
      requestAnimationFrame(() => {
        document.querySelectorAll(".skill-card").forEach(el => {
          const sid = el.getAttribute("data-skill-id");
          if (sid && related.has(sid)) {
            el.classList.add("just-wired");
            setTimeout(() => el.classList.remove("just-wired"), 1800);
          }
        });
      });
    }
  };

  const activeIntg = activeId ? S.INTEGRATIONS.find(i => i.id === activeId) : null;
  const activeRelated = activeIntg ? [...relatedSkillIds(activeIntg, S)] : [];
  const connectedCount = S.INTEGRATIONS.filter(i => installedIds.has(i.id)).length;

  // Unified rail: one list, widens on open. Items hold y-position; text
  // content and chips fade in as horizontal space opens up. Search is
  // only wired when the rail is open — collapsed state renders all 16.
  const q = query.trim().toLowerCase();
  const matches = (i) => !open || !q
    || i.name.toLowerCase().includes(q)
    || i.id.toLowerCase().includes(q)
    || (i.blurb || "").toLowerCase().includes(q);

  return (
    <aside className={"irail" + (open ? " open" : "") + (activeId ? " has-active" : "") + (dragId ? " is-dragging" : "")}
           onMouseLeave={() => setHoverId(null)}>
      <button className="irail-toggle"
              onClick={() => setOpen(o => !o)}
              title={open ? "Collapse skill plugins" : "Expand skill plugins"}>
        <span className="irail-toggle-mark mono">{open ? "◄" : "◈"}</span>
        {open
          ? <span className="irail-toggle-lbl mono">{connectedCount}/{S.INTEGRATIONS.length}</span>
          : <span className="irail-toggle-lbl mono">{connectedCount}/{S.INTEGRATIONS.length}</span>}
      </button>

      {open && (
        <div className="irail-head">
          <div>
            <div className="irail-eyebrow mono">SKILLS · PLUG-IN CATALOG</div>
            <div className="irail-title">
              {connectedCount}<span className="irail-title-sep">/</span>{S.INTEGRATIONS.length}
              <span className="irail-title-sub"> connected</span>
            </div>
            <div className="irail-title-hint">
              All of these are just skills — drag one onto any card to wire it in.
            </div>
          </div>
          <button className="irail-close" onClick={() => setOpen(false)} title="Collapse">×</button>
        </div>
      )}

      {open && (
        <div className="irail-search-row">
          <span className="irail-search-icon mono">⌕</span>
          <input className="irail-search" placeholder="Search plug-in skills…"
                 value={query} onChange={e=>setQuery(e.target.value)}/>
          {query && <button className="irail-search-clear" onClick={()=>setQuery("")}>×</button>}
        </div>
      )}

      <div className="irail-list">
        {S.INTEGRATIONS.map(i => {
          const installed = installedIds.has(i.id);
          const missing = i.env_keys.filter(k => !S.env[k]?.value).length;
          const isExpanded = open && expandedId === i.id;
          const isActive = activeId === i.id;
          const related = relatedSkillIds(i, S);
          const visible = matches(i);
        return (
                <div key={i.id}
                     className={"irail-tile"
                       + (installed?" installed":"")
                       + (isExpanded?" expanded":"")
                       + (isActive?" active":"")
                       + (dragId===i.id?" dragging":"")
                       + (!visible?" hidden":"")}
                     style={{"--tile-accent": i.accent}}
                     onMouseEnter={() => setHoverId(i.id)}
                     onMouseLeave={() => { if (hoverId===i.id) setHoverId(null); }}>
                  <div className="irail-tile-main"
                       draggable
                       onDragStart={(e) => {
                         setDragId(i.id);
                         try {
                           e.dataTransfer.setData("application/snappy-integration", i.id);
                           e.dataTransfer.setData("text/plain", `integration:${i.id}`);
                         } catch(_){}
                         e.dataTransfer.effectAllowed = "copy";
                       }}
                       onDragEnd={() => setDragId(null)}
                       onClick={() => {
                         if (!open) { setOpen(true); setExpandedId(i.id); return; }
                         setExpandedId(isExpanded ? null : i.id);
                       }}
                       title={!open ? "Drag " + i.name + " onto a skill card" : undefined}>
                    <span className="irail-tile-mark" style={{background:"#fff", borderColor:i.accent}}>
                      <BrandLogo id={i.id} size={22}/>
                    </span>
                    <div className="irail-tile-body">
                      <div className="irail-tile-name-row">
                        <span className="irail-tile-name">{i.name}</span>
                        {installed
                          ? <span className="irail-chip irail-chip-installed">● connected</span>
                          : <span className="irail-chip irail-chip-add mono">drag</span>}
                      </div>
                      <div className="irail-tile-lineage mono">
                        <span className="irail-tile-lineage-src">{i.source}</span>
                        <span className="irail-tile-lineage-sep">·</span>
                        <span className={"irail-tile-lineage-sync " + (i.lastSync ? "has" : "never")}>
                          {i.lastSync ? "synced " + relTime(i.lastSync) : "never synced"}
                        </span>
                      </div>
                    </div>
                    <span className="irail-tile-related mono"
                          title={`${related.size} skill${related.size!==1?"s":""} wire to this`}>
                      <span className="irail-related-num">{related.size}</span>
                      <span className="irail-related-arrow">↔</span>
                    </span>
                  </div>

                  {isExpanded && (
                    <div className="irail-tile-details">
                      <div className="irail-tile-blurb">{i.blurb}</div>

                      <div className="irail-lineage-grid">
                        <div className="irail-lineage-row">
                          <div className="irail-lineage-lbl mono">READS</div>
                          <div className="irail-lineage-val">{i.reads || "—"}</div>
                        </div>
                        <div className="irail-lineage-row">
                          <div className="irail-lineage-lbl mono">WRITES</div>
                          <div className="irail-lineage-val">{i.writes || "—"}</div>
                        </div>
                        <div className="irail-lineage-row">
                          <div className="irail-lineage-lbl mono">SCOPE</div>
                          <div className="irail-lineage-val mono-val">{i.scope || "—"}</div>
                        </div>
                        <div className="irail-lineage-row">
                          <div className="irail-lineage-lbl mono">LAST SYNC</div>
                          <div className="irail-lineage-val">
                            {i.lastSync
                              ? <span className="irail-sync-fresh">{relTime(i.lastSync)}</span>
                              : <span className="irail-sync-never">never — populates on first run</span>}
                          </div>
                        </div>
                      </div>

                      <div className="irail-keys-section">
                        <div className="irail-lineage-lbl mono">ENV KEYS</div>
                        <div className="irail-keys-list">
                          {i.env_keys.map(k => {
                            const set = !!S.env[k]?.value;
                            const st = S.env[k]?.state;
                            return (
                              <span key={k} className={"irail-keychip " + (set?"set ":"") + (st||"")}
                                    title={set?`set · ${st||"unknown"}`:"not set"}>
                                <span className="irail-keychip-dot"/>
                                {k}
                              </span>
                            );
                          })}
                        </div>
                        {!installed && missing > 0 && (
                          <div className="irail-warn mono">↳ connecting adds {missing} key{missing>1?"s":""} to Settings</div>
                        )}
                      </div>

                      {related.size > 0 && (
                        <div className="irail-relations">
                          <div className="irail-lineage-lbl mono">WIRES INTO · {related.size} SKILL{related.size>1?"S":""}</div>
                          <div className="irail-relations-list">
                            {[...related].slice(0,8).map(sid => (
                              <a key={sid} className="irail-rel-chip mono" href={"#/skill/"+sid}>
                                <span className="irail-rel-arrow">→</span>{sid}
                              </a>
                            ))}
                            {related.size > 8 && <span className="irail-rel-more mono">+{related.size-8}</span>}
                          </div>
                        </div>
                      )}

                      <div className="irail-tile-actions">
                        {installed
                          ? <span className="irail-tile-installed-note">Wired in. Edit credentials in Settings.</span>
                          : <button className="irail-install-btn"
                                    style={{background: i.accent}}
                                    onClick={()=>install(i.id)}>
                              Connect {i.name}
                            </button>}
                        <a className="irail-tile-settings" href="#/settings">Settings →</a>
                      </div>
                    </div>
                  )}
                </div>
          );
        })}
      </div>

      {open && (
        <div className="irail-foot mono">
          <span>or drop any <code>.md</code> anywhere on the page</span>
        </div>
      )}

      {activeIntg && (
        <div className="irail-beacon">
          <div className="irail-beacon-head">
            <span className="irail-beacon-dot" style={{background: activeIntg.accent}}/>
            <span className="irail-beacon-name">{activeIntg.name}</span>
            <span className="irail-beacon-arrow mono">→</span>
            <span className="irail-beacon-count mono">{activeRelated.length} skill{activeRelated.length!==1?"s":""} lit</span>
          </div>
          <div className="irail-beacon-hint mono">
            {dragId
              ? (dropHotCard
                  ? <>drop to wire <b style={{color:"var(--primary)"}}>{dropHotCard}</b></>
                  : "drop anywhere in the catalog to connect")
              : "drag this tile anywhere on the page"}
          </div>
        </div>
      )}
    </aside>
  );
}

window.IntegrationRail = SkillPluginRail;
window.IntegrationGallery = function() { return null; };
