/* Rinus features grid — v3 diagrams.
   Six operators (agents), each a distinct micro-animation.
   ALL pulsing leads/signals show as SIGNAL orange. */

const { useEffect, useRef, useState } = React;

const FEAT_TOKENS = {
  PITCH:        "var(--pitch-700)",
  PITCH_400:    "var(--pitch-400)",
  LINE_STRONG:  "var(--line-strong)",
  LINE:         "var(--line)",
  INK_SUBTLE:   "var(--ink-subtle)",
  INK:          "var(--ink)",
  INK_MUTED:    "var(--ink-muted)",
  PAPER_50:     "var(--paper-50)",
  PAPER_100:    "var(--paper-100)",
  PAPER_200:    "var(--paper-200)",
  PAPER_300:    "var(--paper-300)",
  PAPER_400:    "var(--paper-400)",
  PAPER_500:    "var(--paper-500)",
  PATINA:       "var(--patina)",
  SIGNAL:       "var(--signal)",
  SIGNAL_INK:   "var(--signal-ink)",
  MONO:         "var(--font-mono)",
  DISPLAY:      "var(--font-display)",
};

const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
const easeOut = (t) => 1 - Math.pow(1 - t, 3);
const easeInOut = (t) => t < 0.5 ? 2*t*t : 1 - Math.pow(-2*t + 2, 2) / 2;

function useFrameTime() {
  const [t, setT] = useState(0);
  useEffect(() => {
    let raf = 0;
    let start = null;
    const step = (ts) => {
      if (start == null) start = ts;
      setT((ts - start) / 1000);
      raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, []);
  return t;
}

/* ── 1. Signals: pulsing radar takes in input dots, emits typed cards ── */
function SignalsDiag() {
  const t = useFrameTime();
  const SIGNAL_TYPES = [
    { type: "FINANCIAM.",  detail: "Serie B · $48M",         time: "2m",  color: FEAT_TOKENS.SIGNAL },
    { type: "NUEVO ROL",  detail: "Nuevo VP Ingeniería",      time: "5m",  color: FEAT_TOKENS.PITCH },
    { type: "PRECIOS",    detail: "3 visitas a precios",      time: "12m", color: FEAT_TOKENS.PITCH_400 },
    { type: "COMPETIDOR", detail: "Comparó con Helix",        time: "1h",  color: FEAT_TOKENS.SIGNAL_INK },
    { type: "CONTRATAC.", detail: "12 roles SDR publicados",  time: "2h",  color: FEAT_TOKENS.PITCH },
    { type: "MENCIÓN",    detail: "Nota en TechCrunch",       time: "3h",  color: FEAT_TOKENS.PITCH_400 },
    { type: "TECH STACK", detail: "Migró a Snowflake",        time: "5h",  color: FEAT_TOKENS.PAPER_500 },
  ];
  const SPAWN = 2.2;
  const LIFE = 6.0;
  const ANCHOR_X = 30;
  const PATH_END_X = 280;
  // Y rows — clamped to stay within viewBox (max 69 so card bottom ≤ 112).
  const Y_ROWS = [18, 36, 54, 65, 28, 46];

  const lastSpawn = Math.floor(t / SPAWN);
  const inFlight = [];
  for (let k = Math.max(0, lastSpawn - 4); k <= lastSpawn; k++) {
    const age = t - k * SPAWN;
    if (age < 0 || age > LIFE) continue;
    const sig = SIGNAL_TYPES[k % SIGNAL_TYPES.length];
    const y = Y_ROWS[k % Y_ROWS.length];
    inFlight.push({ k, age, sig, y });
  }

  // Tiny grey input dots streaming into the radar from off-canvas left.
  const INPUT_DOTS = 5;
  const INPUT_LIFE = 2.4;
  const inputs = [];
  for (let k = 0; k < INPUT_DOTS; k++) {
    const phase = ((t + k * 0.5) % INPUT_LIFE) / INPUT_LIFE;
    const e = easeOut(phase);
    const startY = [18, 52, 90, 36, 76][k];
    const x = -8 + e * (ANCHOR_X + 8);
    const y = startY + (56 - startY) * e;
    const op = phase < 0.08 ? phase * 12 : (phase > 0.92 ? (1 - phase) * 12 : 0.85);
    inputs.push({ x, y, op });
  }

  const localPulse = (t % SPAWN) / SPAWN;

  return (
    <svg width="100%" height="112" viewBox="0 0 280 112" aria-hidden="true">
      <defs>
        <linearGradient id="sig-fade-v4" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0" stopColor="white" stopOpacity="0" />
          <stop offset="0.16" stopColor="white" stopOpacity="1" />
          <stop offset="0.92" stopColor="white" stopOpacity="1" />
          <stop offset="1" stopColor="white" stopOpacity="0" />
        </linearGradient>
        <mask id="sig-mask-v4">
          <rect width="280" height="112" fill="url(#sig-fade-v4)" />
        </mask>
      </defs>

      {/* Grey input dots heading into the radar */}
      {inputs.map((d, i) => (
        <circle key={`in-${i}`} cx={d.x} cy={d.y} r="1.4"
          fill={FEAT_TOKENS.PAPER_500} opacity={d.op * 0.85} />
      ))}

      {/* Drifting signal chips (varied y, per-type color) */}
      <g mask="url(#sig-mask-v4)">
        {inFlight.map(({ k, age, sig, y: rowY }) => {
          const p = age / LIFE;
          const x = ANCHOR_X + 14 + p * (PATH_END_X - ANCHOR_X - 30);
          const op = p < 0.06 ? p / 0.06 : (p > 0.88 ? Math.max(0, (1 - p) / 0.12) : 1);
          const W = 122, H = 30;
          const y = rowY - H / 2 + 28; // center around 56 with offsets
          return (
            <g key={k} transform={`translate(${x}, ${y})`} opacity={op}>
              <rect x="0" y="0" width={W} height={H} rx="4"
                fill={FEAT_TOKENS.PAPER_50}
                stroke={FEAT_TOKENS.LINE_STRONG} strokeWidth="1" />
              <rect x="0" y="0" width="2" height={H} fill={sig.color} />
              <text x="9" y="12" fontFamily={FEAT_TOKENS.MONO} fontSize="7"
                letterSpacing="0.14em" fontWeight="700" fill={sig.color}>
                {sig.type}
              </text>
              <text x={W - 8} y="12" fontFamily={FEAT_TOKENS.MONO} fontSize="7"
                fill={FEAT_TOKENS.INK_SUBTLE} textAnchor="end" letterSpacing="0.08em">
                {sig.time}
              </text>
              <text x="9" y="24" fontFamily={FEAT_TOKENS.DISPLAY} fontSize="11"
                fontWeight="500" fill={FEAT_TOKENS.INK}>
                {sig.detail}
              </text>
            </g>
          );
        })}
      </g>

      {/* Pulsing orange radar — emits a ring out every spawn */}
      {[0, 1].map((i) => {
        const phase = (localPulse + i * 0.5) % 1;
        const r = 9 + phase * 24;
        const op = (1 - phase) * 0.4;
        return (
          <circle key={i} cx={ANCHOR_X} cy="56" r={r}
            fill="none" stroke={FEAT_TOKENS.SIGNAL} strokeWidth="1.5" opacity={op} />
        );
      })}
      <circle cx={ANCHOR_X} cy="56" r="9" fill={FEAT_TOKENS.SIGNAL} />
      <circle cx={ANCHOR_X} cy="56" r="3.5" fill={FEAT_TOKENS.PAPER_50} />
    </svg>
  );
}

/* ── 2. Draft: editorial email UI — typed → sending (3-dot loader) → sent ── */
function DraftDiag() {
  const t = useFrameTime();
  const CYCLE = 7.98;
  const p = (t % CYCLE) / CYCLE;
  // 0.00–0.08 reveal
  // 0.08–0.70 typing
  // 0.70–0.78 idle, send button "armed"
  // 0.78–0.92 sending (button pressed, 3-dot loader)
  // 0.92–1.00 SENT label, slow fade
  const body = "Clara, felicitaciones por el nuevo rol en TechBA. Vi que pasaste años en observabilidad y me encantaría comparar notas. ¿15 min la semana que viene?";
  const typeStart = 0.08;
  const typeEnd = 0.70;
  const typeP = clamp((p - typeStart) / (typeEnd - typeStart), 0, 1);
  const chars = Math.floor(body.length * typeP);
  const typed = body.slice(0, chars);
  const cursorOn = typeP > 0 && typeP < 1 && Math.floor(t * 2) % 2 === 0;
  const sending = p >= 0.78 && p < 0.92;
  const sent = p >= 0.92;

  // Auto-scroll the body area to the bottom as new text arrives.
  const bodyRef = useRef(null);
  useEffect(() => {
    if (bodyRef.current) bodyRef.current.scrollTop = bodyRef.current.scrollHeight;
  });

  return (
    <svg width="100%" height="120" viewBox="0 0 280 120" aria-hidden="true">
      {/* Email card */}
      <rect x="14" y="6" width="252" height="108" rx="4"
        fill={FEAT_TOKENS.PAPER_50} stroke={FEAT_TOKENS.LINE_STRONG} strokeWidth="1" />
      {/* Window chrome dots */}
      <g>
        <circle cx="24" cy="14" r="2" fill={FEAT_TOKENS.LINE_STRONG} />
        <circle cx="32" cy="14" r="2" fill={FEAT_TOKENS.LINE_STRONG} />
        <circle cx="40" cy="14" r="2" fill={FEAT_TOKENS.LINE_STRONG} />
      </g>
      <text x="142" y="17" textAnchor="middle"
        fontFamily={FEAT_TOKENS.MONO} fontSize="7" letterSpacing="0.14em"
        fill={FEAT_TOKENS.INK_SUBTLE} fontWeight="500">NUEVO MENSAJE</text>
      <line x1="14" y1="22" x2="266" y2="22" stroke={FEAT_TOKENS.LINE} strokeWidth="1" />

      {/* To: field */}
      <text x="22" y="32" fontFamily={FEAT_TOKENS.MONO} fontSize="7"
        letterSpacing="0.12em" fontWeight="500" fill={FEAT_TOKENS.INK_SUBTLE}>TO</text>
      <text x="40" y="32" fontFamily={FEAT_TOKENS.DISPLAY} fontSize="10"
        fontWeight="500" fill={FEAT_TOKENS.INK}>clara@techbalabs.com</text>
      <line x1="22" y1="36" x2="258" y2="36" stroke={FEAT_TOKENS.LINE} strokeWidth="1" />

      {/* Subject: field */}
      <text x="22" y="46" fontFamily={FEAT_TOKENS.MONO} fontSize="7"
        letterSpacing="0.12em" fontWeight="500" fill={FEAT_TOKENS.INK_SUBTLE}>SUBJ</text>
      <text x="46" y="46" fontFamily={FEAT_TOKENS.DISPLAY} fontSize="10"
        fontWeight="500" fill={FEAT_TOKENS.INK}>Nuevo rol + intro rápida</text>
      <line x1="22" y1="50" x2="258" y2="50" stroke={FEAT_TOKENS.LINE} strokeWidth="1" />

      {/* Body — three-line viewport, auto-scrolls as text grows */}
      <foreignObject x="22" y="54" width="236" height="40">
        <div xmlns="http://www.w3.org/1999/xhtml" ref={bodyRef} style={{
          height: 34, overflowY: "hidden",
          fontFamily: "var(--font-sans)", fontSize: 9.5, lineHeight: 1.45,
          color: "var(--ink)", letterSpacing: "-0.005em",
        }}>
          {typed}
          {cursorOn && <span style={{ color: "var(--signal)" }}>▍</span>}
        </div>
      </foreignObject>

      {/* Footer with status + send button */}
      <line x1="14" y1="96" x2="266" y2="96" stroke={FEAT_TOKENS.LINE} strokeWidth="1" />
      <g>
        {!sent && !sending && (
          <g>
            <circle cx="26" cy="105" r="2.5" fill={FEAT_TOKENS.SIGNAL} />
            <text x="32" y="108" fontFamily={FEAT_TOKENS.MONO} fontSize="7"
              letterSpacing="0.12em" fontWeight="600" fill={FEAT_TOKENS.INK_SUBTLE}>BORRADOR</text>
          </g>
        )}
        {sending && (
          <g>
            <circle cx="26" cy="105" r="2.5" fill={FEAT_TOKENS.SIGNAL}>
              <animate attributeName="opacity" values="1;0.2;1" dur="0.5s" repeatCount="indefinite" />
            </circle>
            <text x="32" y="108" fontFamily={FEAT_TOKENS.MONO} fontSize="7"
              letterSpacing="0.12em" fontWeight="600" fill={FEAT_TOKENS.SIGNAL}>ENVIANDO</text>
          </g>
        )}
        {sent && (
          <g>
            <path d="M 22 105 L 26 109 L 32 101" stroke={FEAT_TOKENS.PITCH_400}
              strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round" />
            <text x="38" y="108" fontFamily={FEAT_TOKENS.MONO} fontSize="7"
              letterSpacing="0.12em" fontWeight="600" fill={FEAT_TOKENS.PITCH_400}>ENVIADO</text>
          </g>
        )}
      </g>
      {/* Send button — pressed (translateY 1, darker) during sending */}
      <g transform={`translate(192, ${sending ? 99 : 98})`}>
        <rect width="62" height="16" rx="3"
          fill={sent ? FEAT_TOKENS.PITCH_400
              : sending ? FEAT_TOKENS.SIGNAL_INK
              : FEAT_TOKENS.SIGNAL} />
        {sending ? (
          <g>
            {[0, 1, 2].map((i) => (
              <circle key={i} cx={22 + i * 6} cy="8" r="1.6" fill={FEAT_TOKENS.PAPER_50}>
                <animate attributeName="opacity"
                  values="0.25;1;0.25" dur="0.9s"
                  begin={`${i * 0.3}s`} repeatCount="indefinite" />
              </circle>
            ))}
          </g>
        ) : (
          <text x="31" y="11" textAnchor="middle"
            fontFamily={FEAT_TOKENS.MONO} fontSize="7" letterSpacing="0.14em"
            fontWeight="700" fill={FEAT_TOKENS.PAPER_50}>
            {sent ? "ENVIADO" : "ENVIAR →"}
          </text>
        )}
      </g>
    </svg>
  );
}

/* ── 3. Qualify: Rinus logo emits dots → HOT/WARM/DROP, with arrival pulses ── */
function QualifyDiag() {
  const t = useFrameTime();
  const DUR = 2.8;
  // Source on left, 3 destinations on right, curved bezier paths.
  const SX = 36, SY = 56;
  const lanes = [
    { name: "INTERESADO",    color: FEAT_TOKENS.SIGNAL,    ex: 182, ey: 18,  cx: 108, cy: 0   },
    { name: "CALIFICADO",    color: "#166534",              ex: 182, ey: 56,  cx: 108, cy: 56  },
    { name: "ARCHIVAR",      color: FEAT_TOKENS.PAPER_400, ex: 182, ey: 94,  cx: 108, cy: 112 },
  ];

  // Central pulse — fires when any lane emits a dot (p≈0)
  let centralPulse = 0;
  for (let i = 0; i < 3; i++) {
    const ph = i / 3;
    const lp = ((t / DUR + ph) % 1);
    const ep = lp < 0.15 ? 1 - lp / 0.15 : 0;
    centralPulse = Math.max(centralPulse, ep);
  }

  function bezAt(lane, p) {
    const u = 1 - p;
    const x = u * u * SX + 2 * u * p * lane.cx + p * p * lane.ex;
    const y = u * u * SY + 2 * u * p * lane.cy + p * p * lane.ey;
    return { x, y };
  }

  // Per-lane state: dot position + post-arrival pulse + drop animation
  const laneData = lanes.map((lane, i) => {
    const phase = i / 3;
    const p = ((t / DUR + phase) % 1);
    const point = bezAt(lane, p);
    const op = p < 0.08 ? p / 0.08 : (p > 0.93 ? (1 - p) / 0.07 : 1);
    const sinceArrival = p * DUR; // p=0 ≡ instant after destination
    const PULSE_T = 0.75;
    const pulse = sinceArrival < PULSE_T ? 1 - sinceArrival / PULSE_T : 0;
    return { lane, x: point.x, y: point.y, op, pulse, sinceArrival };
  });

  return (
    <svg width="100%" height="112" viewBox="0 0 280 112" aria-hidden="true">
      {/* Bezier paths */}
      <g stroke={FEAT_TOKENS.LINE_STRONG} strokeWidth="1" fill="none" strokeDasharray="3 4">
        {lanes.map((lane, i) => (
          <path key={i} d={`M ${SX + 8} ${SY} Q ${lane.cx} ${lane.cy} ${lane.ex - 8} ${lane.ey}`} />
        ))}
      </g>

      {/* Pulse ring behind logo */}
      {centralPulse > 0 && (
        <circle cx={SX} cy={SY} r={8 + centralPulse * 10}
          fill="none" stroke={FEAT_TOKENS.SIGNAL}
          strokeWidth="1.5" opacity={centralPulse * 0.55} />
      )}

      {/* Orange signal dot — pulsing center */}
      <circle cx={SX} cy={SY} r="6" fill={FEAT_TOKENS.SIGNAL} />

      {/* Flowing dots along curves — colored per lane */}
      {laneData.map((d, i) => (
        <circle key={`dot-${i}`} cx={d.x} cy={d.y} r="3.2"
          fill={d.lane.color} opacity={d.op} />
      ))}

      {/* Destinations — base disc + arrival pulse + (DROP) leak */}
      {laneData.map((d, i) => {
        const lane = d.lane;
        const isDrop = lane.name === "DROP";
        return (
          <g key={`dest-${i}`}>
            {d.pulse > 0 && (
              <circle cx={lane.ex} cy={lane.ey}
                r={6 + d.pulse * 9}
                fill="none" stroke={lane.color}
                strokeWidth="1.5" opacity={d.pulse * 0.7} />
            )}
            <circle cx={lane.ex} cy={lane.ey}
              r={6 + d.pulse * 1.4}
              fill={lane.color}
              opacity={isDrop ? 0.7 : 1} />
            <text x={lane.ex + 12} y={lane.ey + 3}
              fontFamily={FEAT_TOKENS.MONO} fontSize="9" fontWeight="600"
              letterSpacing="0.1em" fill={FEAT_TOKENS.INK}>
              {lane.name}
            </text>
            {/* DROP — a grey dot leaks out vertically and fades */}
            {isDrop && d.sinceArrival < 1.4 && (
              <circle
                cx={lane.ex}
                cy={lane.ey + 4 + (d.sinceArrival / 1.4) * 12}
                r="2.2"
                fill={FEAT_TOKENS.PAPER_400}
                opacity={Math.max(0, 1 - d.sinceArrival / 1.4)} />
            )}
          </g>
        );
      })}
    </svg>
  );
}

/* ── 4. Calendar: weekly grid, persistent bookings, reset per cycle ─ */
function CalendarDiag() {
  const t = useFrameTime();
  const CYCLE = 8.4;
  const DAYS = ["DOM", "LUN", "MAR", "MIÉ", "JUE", "VIE", "SÁB"];
  const TIMES = ["9", "11", "14", "16"]; // 4 rows
  // Pre-defined bookings that "drop" one by one across the cycle.
  const BOOKINGS = [
    { day: 2, row: 0, time: "09:30", appearAt: 0.06 }, // Tue 09:30
    { day: 1, row: 1, time: "11:15", appearAt: 0.16 }, // Mon 11:15
    { day: 3, row: 2, time: "14:00", appearAt: 0.27 }, // Wed 14:00
    { day: 4, row: 0, time: "10:00", appearAt: 0.38 }, // Thu 10:00
    { day: 4, row: 3, time: "16:00", appearAt: 0.48 }, // Thu 16:00
    { day: 5, row: 0, time: "09:00", appearAt: 0.59 }, // Fri 09:00
    { day: 2, row: 2, time: "14:30", appearAt: 0.70 }, // Tue 14:30
    { day: 5, row: 2, time: "13:45", appearAt: 0.82 }, // Fri 13:45
  ];

  const localT = (t % CYCLE) / CYCLE;

  const GRID_X = 16, GRID_Y = 18;
  const COL_W = 36, ROW_H = 18;
  const HEAD_H = 12;

  return (
    <svg width="100%" height="112" viewBox="0 0 280 112" aria-hidden="true">
      {/* Outer frame */}
      <rect x={GRID_X} y={GRID_Y - 2} width={COL_W * 7} height={HEAD_H + ROW_H * 4 + 2}
        rx="3" fill="none" stroke={FEAT_TOKENS.LINE_STRONG} strokeWidth="1" />

      {/* Weekend wash on cols 0 (SUN) and 6 (SAT) */}
      {[0, 6].map((i) => (
        <rect key={i} x={GRID_X + i * COL_W} y={GRID_Y + HEAD_H}
          width={COL_W} height={ROW_H * 4} fill={FEAT_TOKENS.PAPER_100} />
      ))}

      {/* Vertical dividers */}
      {[1, 2, 3, 4, 5, 6].map((i) => (
        <line key={i} x1={GRID_X + i * COL_W} y1={GRID_Y - 2}
          x2={GRID_X + i * COL_W} y2={GRID_Y + HEAD_H + ROW_H * 4}
          stroke={FEAT_TOKENS.LINE} strokeWidth="1" />
      ))}

      {/* Horizontal dividers */}
      <line x1={GRID_X} y1={GRID_Y + HEAD_H} x2={GRID_X + COL_W * 7} y2={GRID_Y + HEAD_H}
        stroke={FEAT_TOKENS.LINE_STRONG} strokeWidth="1" />
      {[1, 2, 3].map((i) => (
        <line key={i} x1={GRID_X} y1={GRID_Y + HEAD_H + i * ROW_H}
          x2={GRID_X + COL_W * 7} y2={GRID_Y + HEAD_H + i * ROW_H}
          stroke={FEAT_TOKENS.LINE} strokeWidth="1" strokeDasharray="2 3" opacity="0.5" />
      ))}

      {/* Day labels */}
      {DAYS.map((d, i) => (
        <text key={d}
          x={GRID_X + i * COL_W + COL_W / 2}
          y={GRID_Y + 8}
          textAnchor="middle"
          fontFamily={FEAT_TOKENS.MONO} fontSize="7" letterSpacing="0.12em" fontWeight="600"
          fill={(i === 0 || i === 6) ? FEAT_TOKENS.PAPER_400 : FEAT_TOKENS.INK_SUBTLE}>
          {d}
        </text>
      ))}

      {/* Time row labels (left margin would be too cramped — fold into cells) */}

      {/* Pre-booking pulse — orange dot appears just before each slot is booked */}
      {BOOKINGS.map((b, i) => {
        const preStart = b.appearAt - 0.055;
        if (localT < preStart || localT >= b.appearAt) return null;
        const bx = GRID_X + b.day * COL_W + 3;
        const by = GRID_Y + HEAD_H + b.row * ROW_H + 2;
        const dotX = bx + (COL_W - 6) - 4;
        const dotY = by + 3.5;
        const pulseP = (t % 0.32) / 0.32;
        return (
          <g key={`pre-${i}`}>
            <circle cx={dotX} cy={dotY} r={2 + pulseP * 7} fill="none"
              stroke={FEAT_TOKENS.SIGNAL} strokeWidth="1" opacity={(1 - pulseP) * 0.65} />
            <circle cx={dotX} cy={dotY} r="2.5" fill={FEAT_TOKENS.SIGNAL} />
          </g>
        );
      })}

      {/* Bookings — persistent across the cycle, all clear on reset */}
      {BOOKINGS.map((b, i) => {
        if (localT < b.appearAt) return null;
        // Fade in over 0.05 of cycle
        const age = localT - b.appearAt;
        const opIn = clamp(age / 0.04, 0, 1);
        // Fade out only at very end
        const op = localT > 0.96 ? Math.max(0, 1 - (localT - 0.96) / 0.04) : opIn;
        const x = GRID_X + b.day * COL_W + 3;
        const y = GRID_Y + HEAD_H + b.row * ROW_H + 2;
        return (
          <g key={i} opacity={op}>
            <rect x={x} y={y} width={COL_W - 6} height={ROW_H - 4}
              rx="2" fill={FEAT_TOKENS.SIGNAL} />
            <text x={x + (COL_W - 6) / 2} y={y + (ROW_H - 4) / 2 + 2.5}
              textAnchor="middle" fontFamily={FEAT_TOKENS.MONO} fontSize="7"
              fontWeight="600" fill={FEAT_TOKENS.PAPER_50} letterSpacing="0.06em">
              {b.time}
            </text>
          </g>
        );
      })}
    </svg>
  );
}

/* ── 5. Pipeline: kanban — varied travelers, GANADO fills to 5 then resets ── */
function PipelineDiag() {
  const t = useFrameTime();

  const COLS = ["NUEVO", "CALIF.", "DEMO", "GANADO"];
  const COL_W = 66;
  const COL_X = [6, 74, 142, 210];
  const TOP = 14, HEAD_H = 11;
  const CARD_H = 13, SLOT = 15;
  const CARD_W = COL_W - 4;
  const SIT = 2.2, TRANSIT = 0.85;
  const STEP = SIT + TRANSIT;

  // 9 company cards: 3 in each of col0, col1, col2 initially. GANADO starts empty.
  const CARDS = [
    { id: 0, co: "Vercel",      lc: "#fff", bg: "#111111" },
    { id: 1, co: "Stripe",      lc: "#fff", bg: "#635BFF" },
    { id: 2, co: "Notion",      lc: "#fff", bg: "#373530" },
    { id: 3, co: "Linear",      lc: "#fff", bg: "#5E6AD2" },
    { id: 4, co: "Figma",       lc: "#fff", bg: "#F24E1E" },
    { id: 5, co: "Loom",        lc: "#fff", bg: "#625DF5" },
    { id: 6, co: "HubSpot",     lc: "#fff", bg: "#FF7A59" },
    { id: 7, co: "Salesforce",  lc: "#fff", bg: "#00A1E0" },
    { id: 8, co: "Atlassian",   lc: "#fff", bg: "#0052CC" },
  ];
  const INIT_COL = [0, 0, 0, 1, 1, 1, 2, 2, 2];

  // Sequence of single moves — only ONE card moves at a time.
  // Result: GANADO ends with {6,7,8}, others redistributed.
  const SEQ = [
    { c: 6, to: 3 }, // HubSpot  col2→GANADO
    { c: 3, to: 2 }, // Linear   col1→col2
    { c: 7, to: 3 }, // Salesforce col2→GANADO
    { c: 0, to: 1 }, // Vercel   col0→col1
    { c: 4, to: 2 }, // Figma    col1→col2
    { c: 8, to: 3 }, // Atlassian col2→GANADO
  ];

  const TOTAL = SEQ.length * STEP + SIT;
  const tc = t % TOTAL;

  // Fade-out in last 0.8s of cycle, fade-in in first 0.5s
  const globalOp = tc < 0.5 ? tc / 0.5 : tc > TOTAL - 0.8 ? (TOTAL - tc) / 0.8 : 1;

  function getMoveStart(mi) { return mi * STEP + SIT; }

  // Returns current column for card (toCol if mid-transit — card ranks in dest immediately)
  function getCardCol(cardId) {
    let col = INIT_COL[cardId];
    for (let mi = 0; mi < SEQ.length; mi++) {
      if (SEQ[mi].c !== cardId) continue;
      if (tc >= getMoveStart(mi)) col = SEQ[mi].to;
    }
    return col;
  }

  // Returns transit info for card if currently moving
  function getCardTransit(cardId) {
    let prevCol = INIT_COL[cardId];
    for (let mi = 0; mi < SEQ.length; mi++) {
      if (SEQ[mi].c !== cardId) continue;
      const ms = getMoveStart(mi);
      const me = ms + TRANSIT;
      if (tc < ms) break;
      if (tc < me) {
        return { isMoving: true, fromCol: prevCol, progress: easeInOut((tc - ms) / TRANSIT) };
      }
      prevCol = SEQ[mi].to;
    }
    return { isMoving: false };
  }

  // Rank = # of cards with lower id in same column (packs from top, no gaps)
  function getCardRank(cardId) {
    const col = getCardCol(cardId);
    let rank = 0;
    for (let j = 0; j < cardId; j++) {
      if (getCardCol(j) === col) rank++;
    }
    return rank;
  }

  function colY(rank) { return TOP + HEAD_H + rank * SLOT + 2; }

  const BODY_H = 3 * SLOT + 6;

  // Pulsing dot in GANADO once first card arrives
  const firstGandoTime = getMoveStart(0) + TRANSIT;
  const showPulse = tc > firstGandoTime;
  const pulseR = showPulse ? 1.5 + ((t * 1.4) % 1) * 4 : 0;
  const pulseOp = showPulse ? (1 - (t * 1.4) % 1) * 0.5 : 0;

  return (
    <svg width="100%" height="112" viewBox="0 0 280 112" aria-hidden="true">
      <g opacity={globalOp}>
      {/* Column headers + bodies */}
      {COLS.map((c, i) => (
        <g key={c}>
          <rect x={COL_X[i]} y={TOP} width={COL_W} height={HEAD_H}
            fill={FEAT_TOKENS.PAPER_100} stroke={FEAT_TOKENS.LINE_STRONG} strokeWidth="1" />
          <text x={COL_X[i] + COL_W / 2} y={TOP + 8}
            textAnchor="middle" fontFamily={FEAT_TOKENS.MONO} fontSize="6.5"
            letterSpacing="0.12em" fontWeight="600" fill={FEAT_TOKENS.INK}>{c}</text>
          <rect x={COL_X[i]} y={TOP + HEAD_H} width={COL_W} height={BODY_H}
            fill="none" stroke={FEAT_TOKENS.LINE} strokeWidth="1" strokeDasharray="2 3" />
        </g>
      ))}

      {/* Pulsing activity dot in GANADO */}
      {showPulse && (
        <g>
          <circle cx={COL_X[3] + COL_W - 8} cy={TOP + 6} r={pulseR}
            fill="none" stroke={FEAT_TOKENS.SIGNAL} strokeWidth="0.8" opacity={pulseOp} />
          <circle cx={COL_X[3] + COL_W - 8} cy={TOP + 6} r="1.8" fill={FEAT_TOKENS.SIGNAL} />
        </g>
      )}

      {/* Cards — dynamic rank packing ensures no empty rows */}
      {CARDS.map((card) => {
        const transit = getCardTransit(card.id);
        const col = getCardCol(card.id);
        const rank = getCardRank(card.id);
        const y = colY(rank);
        const x = transit.isMoving
          ? COL_X[transit.fromCol] + (COL_X[col] - COL_X[transit.fromCol]) * transit.progress
          : COL_X[col];
        const cx = x + 2;
        const accent = transit.isMoving ? FEAT_TOKENS.SIGNAL : FEAT_TOKENS.PITCH_400;
        const stroke = transit.isMoving ? FEAT_TOKENS.SIGNAL : FEAT_TOKENS.LINE_STRONG;

        return (
          <g key={card.id}>
            {/* Card body */}
            <rect x={cx} y={y} width={CARD_W} height={CARD_H} rx="2"
              fill={FEAT_TOKENS.PAPER_50} stroke={stroke} strokeWidth={transit.isMoving ? 1.2 : 1} />
            {/* Left accent bar */}
            <rect x={cx} y={y} width="2" height={CARD_H} rx="1" fill={accent} />
            {/* Company icon box */}
            <rect x={cx + 4} y={y + 3} width="7" height="7" rx="1" fill={card.bg} />
            <text x={cx + 7.5} y={y + 9.5}
              textAnchor="middle" fontFamily={FEAT_TOKENS.MONO} fontSize="4.5" fontWeight="700"
              fill={card.lc}>{card.co[0]}</text>
            {/* Company name */}
            <text x={cx + 15} y={y + 9.5}
              fontFamily={FEAT_TOKENS.DISPLAY} fontSize="7" fontWeight="600"
              fill={FEAT_TOKENS.INK} letterSpacing="-0.01em">{card.co}</text>
            {/* Moving indicator dot */}
            {transit.isMoving && (
              <circle cx={cx + CARD_W - 5} cy={y + CARD_H / 2} r="1.8" fill={FEAT_TOKENS.SIGNAL} />
            )}
          </g>
        );
      })}
      </g>
    </svg>
  );
}

/* ── 6. Connect: central Rinus, icons orbit counter-clockwise, pulse dots ── */
function ConnectDiag() {
  const t = useFrameTime();
  const CX = 140, CY = 56;
  // 6 icons in a ring around the center — angles are BASE angles before spin.
  const ICONS = [
    { name: "linkedin", angle: -Math.PI / 2 },
    { name: "gmail",    angle: -Math.PI / 2 + Math.PI/3 },
    { name: "calendar", angle: -Math.PI / 2 + 2*Math.PI/3 },
    { name: "whatsapp", angle:  Math.PI / 2 },
    { name: "messenger",angle:  Math.PI / 2 + Math.PI/3 },
    { name: "phone",    angle:  Math.PI / 2 + 2*Math.PI/3 },
  ];
  const RX = 92, RY = 36;

  // Counter-clockwise spin — very slow (one full revolution every 60s).
  const SPIN_DUR = 42;
  const spin = -(t / SPIN_DUR) * Math.PI * 2;

  // Pulse dots: each icon emits a dot in or out along its CURRENT (rotated) radius.
  const PULSE_DUR = 1.64;
  const pulses = ICONS.map((icon, i) => {
    const phase = (t / PULSE_DUR + i / ICONS.length) % 1;
    const inbound = Math.floor((t / PULSE_DUR + i / ICONS.length)) % 2 === 0;
    const liveAngle = icon.angle + spin;
    const iconX = CX + RX * Math.cos(liveAngle);
    const iconY = CY + RY * Math.sin(liveAngle);
    const p = phase;
    const start = inbound ? { x: iconX, y: iconY } : { x: CX, y: CY };
    const end   = inbound ? { x: CX, y: CY }       : { x: iconX, y: iconY };
    const x = start.x + (end.x - start.x) * easeOut(p);
    const y = start.y + (end.y - start.y) * easeOut(p);
    const eased_p = easeOut(p);
    const op = p < 0.12 ? p / 0.12 : (eased_p > 0.75 ? Math.max(0, (1 - eased_p) / 0.25) : 1);
    return { x, y, op };
  });

  return (
    <svg width="100%" height="112" viewBox="0 0 280 112" aria-hidden="true">
      {/* Faint orbit ellipse */}
      <ellipse cx={CX} cy={CY} rx={RX} ry={RY}
        fill="none" stroke={FEAT_TOKENS.LINE_STRONG} strokeDasharray="2 5" opacity="0.55" />

      {/* Pulse dots traveling between center and icons (follow current angle) */}
      {pulses.map((p, i) => (
        <circle key={i} cx={p.x} cy={p.y} r="2.5" fill={FEAT_TOKENS.SIGNAL} opacity={p.op} />
      ))}

      {/* Orbiting icons — rotate slowly counter-clockwise */}
      {ICONS.map((icon, i) => {
        const liveAngle = icon.angle + spin;
        const x = CX + RX * Math.cos(liveAngle) - 9;
        const y = CY + RY * Math.sin(liveAngle) - 9;
        return <ChannelIcon key={icon.name} name={icon.name} x={x} y={y} />;
      })}

      {/* Center: pulsing orange dot only */}
      <circle cx={CX} cy={CY} r="6" fill={FEAT_TOKENS.SIGNAL}>
        <animate attributeName="r" values="6;9;6" dur="1.8s" repeatCount="indefinite" />
        <animate attributeName="opacity" values="1;0.55;1" dur="1.8s" repeatCount="indefinite" />
      </circle>
    </svg>
  );
}

function ChannelIcon({ name, x, y }) {
  const fill = FEAT_TOKENS.PITCH;
  if (name === "linkedin") return (
    <svg width="18" height="18" viewBox="0 0 24 24" fill={fill} x={x} y={y}>
      <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
    </svg>
  );
  if (name === "gmail") return (
    <svg width="18" height="18" viewBox="0 0 24 24" fill={fill} x={x} y={y}>
      <path d="M24 5.457v13.909c0 .904-.732 1.636-1.636 1.636h-3.819V11.73L12 16.64l-6.545-4.91v9.273H1.636A1.636 1.636 0 0 1 0 19.366V5.457c0-2.023 2.309-3.178 3.927-1.964L5.455 4.64 12 9.548l6.545-4.91 1.528-1.145C21.69 2.28 24 3.434 24 5.457z" />
    </svg>
  );
  if (name === "calendar") return (
    <svg width="18" height="18" viewBox="0 0 24 24" x={x} y={y}>
      {/* Page binding (top tabs) */}
      <rect x="6.5" y="2.5" width="2.4" height="4" rx="0.6" fill={fill} />
      <rect x="15.1" y="2.5" width="2.4" height="4" rx="0.6" fill={fill} />
      {/* Card body */}
      <rect x="2.5" y="4.5" width="19" height="17" rx="2" fill={FEAT_TOKENS.PAPER_50}
        stroke={fill} strokeWidth="1.4" />
      {/* Header bar */}
      <rect x="2.5" y="4.5" width="19" height="3.2" fill={fill} />
      {/* Date number */}
      <text x="12" y="17.6" textAnchor="middle"
        fontFamily="var(--font-display)" fontSize="9" fontWeight="700" fill={fill}>14</text>
    </svg>
  );
  if (name === "whatsapp") return (
    <svg width="18" height="18" viewBox="0 0 24 24" fill={fill} x={x} y={y}>
      <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413Z" />
    </svg>
  );
  if (name === "messenger") return (
    <svg width="18" height="18" viewBox="0 0 24 24" fill={fill} x={x} y={y}>
      <path d="M12 2C6.36 2 2 6.13 2 11.7c0 2.91 1.19 5.44 3.14 7.17.16.15.26.35.27.57l.05 1.78c.02.57.6.94 1.12.71l1.98-.87c.17-.08.36-.09.54-.04.91.25 1.88.39 2.9.39 5.64 0 10-4.13 10-9.71S17.64 2 12 2zm6 7.46l-2.94 4.66c-.47.74-1.47.93-2.17.4l-2.34-1.75a.6.6 0 0 0-.72 0l-3.16 2.4c-.42.32-.98-.18-.7-.63l2.94-4.66c.47-.74 1.47-.93 2.17-.4l2.34 1.75c.21.16.51.16.72 0l3.16-2.4c.42-.32.98.18.7.63z" />
    </svg>
  );
  if (name === "phone") return (
    <svg width="18" height="18" viewBox="0 0 24 24" fill={fill} x={x} y={y}>
      <path d="M6.62 10.79a15.05 15.05 0 0 0 6.59 6.59l2.2-2.2a1 1 0 0 1 1.02-.24c1.12.37 2.33.57 3.57.57a1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.49a1 1 0 0 1 1 1c0 1.25.2 2.45.57 3.57a1 1 0 0 1-.25 1.02l-2.19 2.2z" />
    </svg>
  );
  return null;
}

/* ── Icon for kind label (unchanged) ─────────────────────────────── */
function FeatIcon({ name, size = 12 }) {
  const s = { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" };
  if (name === "spark") return <svg width={size} height={size} viewBox="0 0 24 24"><path d="M12 3v6m0 6v6M3 12h6m6 0h6M6 6l4 4m4 4l4 4M18 6l-4 4m-4 4l-4 4" {...s}></path></svg>;
  if (name === "chat") return <svg width={size} height={size} viewBox="0 0 24 24"><path d="M4 5h16v11H9l-4 4v-4H4z" {...s}></path></svg>;
  if (name === "branch") return <svg width={size} height={size} viewBox="0 0 24 24"><path d="M6 3v18M6 9c4 0 6 2 6 6v6M6 15c4 0 6-2 6-6V3" {...s}></path><circle cx="6" cy="3" r="1.5" {...s}></circle><circle cx="18" cy="3" r="1.5" {...s}></circle><circle cx="18" cy="21" r="1.5" {...s}></circle></svg>;
  if (name === "calendar") return <svg width={size} height={size} viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="16" rx="1" {...s}></rect><path d="M8 3v4M16 3v4M3 10h18" {...s}></path></svg>;
  if (name === "pipeline") return <svg width={size} height={size} viewBox="0 0 24 24"><circle cx="4" cy="12" r="2" {...s}></circle><circle cx="12" cy="12" r="2" {...s}></circle><circle cx="20" cy="12" r="2" {...s}></circle><path d="M6 12h4M14 12h4" {...s}></path></svg>;
  if (name === "node") return <svg width={size} height={size} viewBox="0 0 24 24"><circle cx="6" cy="6" r="2.5" {...s}></circle><circle cx="18" cy="6" r="2.5" {...s}></circle><circle cx="6" cy="18" r="2.5" {...s}></circle><circle cx="18" cy="18" r="2.5" {...s}></circle><path d="M8 7l8 10M16 7l-8 10M8 6h8M8 18h8" {...s}></path></svg>;
  if (name === "arrow") return <svg width={14} height={14} viewBox="0 0 24 24"><path d="M4 12h16M14 6l6 6-6 6" {...s}></path></svg>;
  return null;
}

const FEATURES = [
  { kind: "Señales",   title: "Llegá primero.",          body: "Los agentes monitorean rondas de financiamiento, cambios de rol, visitas a precios y comparaciones con competidores. Disparan el proceso indicado para cada señal.", icon: "spark",    Diag: SignalsDiag  },
  { kind: "Mensajes",  title: "Contacta a tus leads.",   body: "Enviáles mensajes apenas se genere la oportunidad, o con el trigger que vos quieras. El agente puede enviarte un borrador para que apruebes o contactar de forma directa.", icon: "chat",     Diag: DraftDiag    },
  { kind: "Calificar", title: "Filtrá el ruido.",        body: "Procesá a tus prospectos con las reglas que quieras. Tus agentes diseñan y ejecutan los procesos que necesités, dependiendo de ICP, tiempos, o las variables que elijas.", icon: "branch",   Diag: QualifyDiag  },
  { kind: "Agenda",    title: "Agendá la reunión.",      body: "Tus agentes pueden verificar disponibilidad, pasar horarios y agendar reuniones. Manejan la conversación de agendado por su cuenta y te notifican cuando está hecho.", icon: "calendar", Diag: CalendarDiag },
  { kind: "Pipeline",  title: "Avanzá tus deals.",       body: "Cada interacción se registra sola. Tus agentes mantienen monitoreado y actualizado tu CRM para entender tu pipeline en tiempo real.", icon: "pipeline", Diag: PipelineDiag },
  { kind: "Conectar",  title: "Integrá todo.",           body: "Email, LinkedIn, calendario, WhatsApp, Messenger, teléfono y el CRM que ya usás. Rinus corre sobre tu stack como la capa de operaciones.", icon: "node",     Diag: ConnectDiag  },
];

function FeatureGrid() {
  return (
    <section className="features" id="product">
      <div className="wrap">
        <div className="section-head">
          <div className="section-head-label eyebrow">El sistema</div>
          <h2 className="section-head-title">Nosotros te <em className="pitch">cubrimos.</em></h2>
          <p className="section-head-lede">Usá Rinus para manejar agentes que busquen y procesen leads desde las fuentes que necesites. Explicales las tareas a automatizar y ellos las ejecutan.</p>
        </div>
        <div className="feat-grid">
          {FEATURES.map((f) => (
            <article key={f.kind} className="feat">
              <div className="feat-head">
                <span className="feat-kind"><FeatIcon name={f.icon} size={12} />{f.kind}</span>
              </div>
              <div className="feat-diag"><f.Diag /></div>
              <h3>{f.title}</h3>
              <p>{f.body}</p>
              <span className="feat-corner" aria-hidden="true"><FeatIcon name="arrow" size={14} /></span>
            </article>
          ))}
        </div>
      </div>
    </section>
  );
}

window.FeatureGrid = FeatureGrid;
