// HeroSwarm.jsx — the live "agent swarm" dashboard widget shown in the hero.
// Used by ConceptB (renders <PSA_SwarmHero />) and HeroMorph (uses
// window.PSA_Cycler for cycling thoughts).

const PSA_AGENTS_HERO = [
{ id: "a017", proj: "attn-kernel", thoughts: ["sweep head dim 64→128", "seed 2/5 running", "+0.4% val · sig", "ablating qk-norm", "scaling rope base", "memory check ok", "fused softmax try"], delta: "+0.4%", status: "ok" },
{ id: "a031", proj: "moe-router", thoughts: ["top-2 vs top-4", "baseline +1.9%", "proposing PR", "load-balance loss", "expert capacity 1.25", "router-z reg", "no expert collapse"], delta: "+1.9%", status: "ok" },
{ id: "a042", proj: "norm-init", thoughts: ["rms-norm eps", "no-sig vs baseline", "archiving", "init scale 0.02", "deepnorm test", "post-vs-pre norm", "p=0.81 inconclusive"], delta: "−0.02%", status: "bad" },
{ id: "a055", proj: "mlp-gating", thoughts: ["GeGLU vs SwiGLU", "4 seeds queued", "in verifier", "ReGLU baseline", "gated-mlp width", "fp8 forward", "act memory profile"], delta: "running", status: "run" },
{ id: "a061", proj: "optimizer", thoughts: ["muon β₂ sweep", "2/6 seeds done", "mid-run eval", "lion warmup", "adamw-vs-shampoo", "lr decay cosine", "wd=0.1 stable"], delta: "running", status: "run" },
{ id: "a078", proj: "flash-3", thoughts: ["splitkv=8", "+18% prefill", "proposing PR", "warp-spec on", "tile shape 128", "long-ctx pass", "fp8 attn matmul"], delta: "+18% pf", status: "ok" },
{ id: "a082", proj: "kv-cache", thoughts: ["paged attn blk 16", "throughput +22%", "in verifier", "block size 32 try", "memory −18%", "p99 latency check", "no acc regression"], delta: "+22% t/s", status: "ok" },
{ id: "a107", proj: "moe-gated-v4", thoughts: ["aux-free balancing", "converged", "\u2713 passed eval", "router entropy ok", "expert util 0.94", "PR drafted", "branch promoted"], delta: "+4.1%", status: "win" },
{ id: "a144", proj: "reward-shape", thoughts: ["length-norm pen.", "+0.8% on bench", "in verifier", "format reward 0.5", "kl ref clamp", "step penalty try", "dpo β tune"], delta: "+0.8%", status: "ok" }];


const STATUS_DOT = { ok: "ok", run: "", bad: "bad", win: "ok" };

const PSA_HERO_CSS = `
.psaH{position:relative;background:#1F1B2A;border-radius:14px;
  padding:18px;overflow:hidden;box-shadow:0 22px 60px -20px rgba(0,0,0,0.6);
  border:1px solid rgba(255,255,255,0.1);width:100%;}
.psaH__head{display:flex;justify-content:space-between;align-items:center;gap:12px;
  margin-bottom:14px;font-family:var(--font-mono);font-size:10.5px;letter-spacing:0.04em;
  color:rgba(247,247,237,0.55);}
.psaH__head .lbl{display:flex;align-items:center;gap:8px;color:rgba(247,247,237,0.78);
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.psaH__head .lbl .dot{width:6px;height:6px;border-radius:50%;background:var(--lime-500);
  box-shadow:0 0 6px var(--lime-500);animation:psaPulse 1.6s ease-in-out infinite;}
.psaH__head .run{color:rgba(247,247,237,0.45);letter-spacing:0.08em;text-transform:uppercase;
  white-space:nowrap;}
@keyframes psaPulse{0%,100%{opacity:0.55}50%{opacity:1}}

.psaH__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;}
.psaH__cell{background:#2A2538;border:1px solid rgba(238,238,226,0.08);
  border-radius:8px;padding:12px 12px;min-height:90px;
  display:flex;flex-direction:column;gap:10px;
  position:relative;overflow:hidden;font-family:var(--font-mono);}
.psaH__cellhead{display:flex;justify-content:space-between;align-items:center;gap:8px;
  font-size:10px;letter-spacing:-0.02em;min-width:0;}
.psaH__cellhead .id{display:inline-flex;align-items:center;gap:7px;
  color:rgba(255,255,255,0.75);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  min-width:0;flex:1;font-weight:500;}
.psaH__cellhead .id .dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;
  background:var(--lime-500);box-shadow:0 0 6px rgba(193,250,29,0.55);}
.psaH__cellhead .id .dot.run{background:var(--violet-400);box-shadow:0 0 5px rgba(178,162,255,0.55);
  animation:psaPulse 1.6s ease-in-out infinite;}
.psaH__cellhead .id .dot.bad{background:rgba(247,247,237,0.28);box-shadow:none;}
.psaH__cellhead .proj{color:rgba(247,247,237,0.38);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;min-width:0;flex-shrink:1;}

.psaH__cellrow{position:relative;height:15px;flex:0 0 15px;overflow:hidden;min-width:0;}
.psaH__cellstack{position:absolute;inset:0;will-change:transform;}
.psaH__cellline{position:absolute;left:0;right:0;height:15px;display:block;
  font-size:11px;letter-spacing:-0.01em;line-height:15px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;font-weight:500;}
.psaH__cellline span{color:rgba(247,247,237,0.55);font-weight:500;position:relative;display:inline-block;}
.psaH__cellline:not(.dim) span::after{
  content:attr(data-text);position:absolute;inset:0;pointer-events:none;
  background-image:linear-gradient(90deg,
    rgba(255,255,255,0) 0%, rgba(255,255,255,0) 42%,
    rgba(255,255,255,1) 50%, rgba(255,255,255,0) 58%, rgba(255,255,255,0) 100%);
  background-size:220% 100%;background-repeat:no-repeat;
  background-position:var(--psa-shim, 140% center);
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;will-change:background-position;}
.psaH__cellline.dim span{color:rgba(247,247,237,0.6);}

.psaH__celldelta{font-size:10px;letter-spacing:0.02em;font-weight:500;
  color:rgba(247,247,237,0.4);text-align:right;}
.psaH__celldelta.up{color:var(--lime-500);}
.psaH__celldelta.down{color:#ff9b85;}

.psaH__cell.is-winner{background:#2A2538;
  border-color:rgba(193,250,29,0.5);
  box-shadow:inset 0 0 0 1px rgba(193,250,29,0.15);}
.psaH__cell.is-winner .psaH__cellhead .id{color:var(--lime-500);}

.psaH__foot{margin-top:12px;display:flex;justify-content:space-between;align-items:center;gap:12px;
  padding-top:12px;border-top:1px solid rgba(255,255,255,0.08);
  font-family:var(--font-mono);font-size:10.5px;color:rgba(247,247,237,0.6);
  letter-spacing:-0.01em;flex-wrap:wrap;}
.psaH__foot > span:first-child{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.psaH__foot strong{color:var(--cream-50);font-weight:500;}
.psaH__pr{display:inline-flex;align-items:center;gap:6px;padding:4px 9px;border-radius:999px;
  background:rgba(193,250,29,0.12);border:1px solid rgba(193,250,29,0.35);color:var(--lime-500);
  font-size:10px;letter-spacing:0.06em;text-transform:uppercase;font-weight:500;white-space:nowrap;}
.psaH__pr::before{content:"→";opacity:0.7;}
@media(max-width:640px){
  .psaH{padding:14px;border-radius:12px;}
  .psaH__head{align-items:flex-start;flex-direction:column;gap:4px;margin-bottom:12px;}
  .psaH__grid{grid-template-columns:repeat(2,1fr);}
  .psaH__cell{min-height:82px;padding:10px;}
  .psaH__cell:nth-child(n+7){display:none;}
  .psaH__foot{font-size:10px;}
}
`;

// Single rAF driver shared by all PSA_Cycler instances.
const PSA_RAF = {
  entries: [], started: false,
  register(entry) {
    this.entries.push(entry);
    if (!this.started) {
      this.started = true;
      const start = performance.now();
      const loop = (now) => {
        const t = (now - start) / 1000;
        for (const e of this.entries) e.tick(t);
        requestAnimationFrame(loop);
      };
      requestAnimationFrame(loop);
    }
    return () => {
      const i = this.entries.indexOf(entry);
      if (i >= 0) this.entries.splice(i, 1);
    };
  }
};

const PSA_Cycler = ({ thoughts, dwell = 2.2, offset = 0, dim = false, prefix = "psaH" }) => {
  const stackRef = React.useRef(null);
  const curSpanRef = React.useRef(null);
  const nxtSpanRef = React.useRef(null);
  const lineH = prefix === "psaH" ? 15 : 16;
  const thoughtsRef = React.useRef(thoughts);
  thoughtsRef.current = thoughts;
  const lastIdxRef = React.useRef(-1);

  React.useEffect(() => {
    const entry = {
      tick: (t) => {
        const eff = Math.max(0, t + offset);
        const rawIdx = eff / dwell;
        const idxFloor = Math.floor(rawIdx);
        const frac = rawIdx - idxFloor;
        const transFrac = 0.18;
        const transT = frac < 1 - transFrac ? 0 : Math.min(1, (frac - (1 - transFrac)) / transFrac);
        const ease = transT < 0.5 ? 4 * transT * transT * transT : 1 - Math.pow(-2 * transT + 2, 3) / 2;
        const yShift = -ease * lineH;

        const th = thoughtsRef.current;
        if (idxFloor !== lastIdxRef.current) {
          lastIdxRef.current = idxFloor;
          const cur = th[(idxFloor % th.length + th.length) % th.length];
          const nxt = th[((idxFloor + 1) % th.length + th.length) % th.length];
          if (curSpanRef.current) {curSpanRef.current.textContent = cur;curSpanRef.current.setAttribute('data-text', cur);}
          if (nxtSpanRef.current) {nxtSpanRef.current.textContent = nxt;nxtSpanRef.current.setAttribute('data-text', nxt);}
        }
        if (stackRef.current) stackRef.current.style.transform = `translateY(${yShift}px)`;
        if (curSpanRef.current) {
          const bgPos = 140 - frac * 180;
          curSpanRef.current.style.setProperty('--psa-shim', `${bgPos}% center`);
        }
      }
    };
    return PSA_RAF.register(entry);
  }, [offset, dwell]);

  const initCur = thoughts[0];
  const initNxt = thoughts[1 % thoughts.length];
  return (
    <div className={`${prefix}__cellrow`}>
      <div className={`${prefix}__cellstack`} ref={stackRef} style={{ transform: 'translateY(0px)' }}>
        <div className={`${prefix}__cellline` + (dim ? " dim" : "")} style={{ top: 0 }}>
          <span ref={curSpanRef} data-text={initCur}>{initCur}</span>
        </div>
        <div className={`${prefix}__cellline` + (dim ? " dim" : "")} style={{ top: lineH }}>
          <span ref={nxtSpanRef} data-text={initNxt}>{initNxt}</span>
        </div>
      </div>
    </div>);

};

const PSA_SwarmHero = () =>
<React.Fragment>
    <style dangerouslySetInnerHTML={{ __html: PSA_HERO_CSS }} />
    <div className="psaH">
    <div className="psaH__head">
      <span className="lbl"><span className="dot" />mira · your-repo/frontier-model</span>
      <span className="run">524 agents · live</span>
    </div>
    <div className="psaH__grid">
      {PSA_AGENTS_HERO.map((a, i) => {
      const isWinner = a.status === "win";
      const dotClass = STATUS_DOT[a.status];
      const deltaClass = a.delta.startsWith("+") ? "up" : a.delta.startsWith("−") ? "down" : "";
      return (
        <div key={a.id} className={"psaH__cell" + (isWinner ? " is-winner" : "")}>
            <div className="psaH__cellhead">
              <span className="id"><span className={"dot " + dotClass} />agent-{a.id}</span>
              <span className="proj">{a.proj}</span>
            </div>
            <PSA_Cycler thoughts={a.thoughts} offset={i * 0.35} dim={false} prefix="psaH" />
            <div className={"psaH__celldelta " + deltaClass}>
              {a.delta === "running" ? "running" : a.delta}
            </div>
          </div>);

    })}
    </div>
    <div className="psaH__foot">
      <span><strong>110</strong> experiments this week</span>
      <span className="psaH__pr">PR #247 · +4.1%</span>
    </div>
  </div>
  </React.Fragment>;


Object.assign(window, { PSA_SwarmHero, PSA_Cycler });
