/* =========================================================
   NETRA AI — Website visualizations (hero iris, capability viz, pipeline, sitemap)
   ========================================================= */

/* ---------- HeroIris: the giant scanning eye ---------- */
const HeroIris = ({ size = 620 }) => {
  // pre-compute a bunch of "detection lock" markers that fade in/out around the iris
  const locks = React.useMemo(() => {
    return Array.from({ length: 7 }).map((_, i) => ({
      a: (i / 7) * Math.PI * 2 + 0.3,
      r: 200 + (i % 3) * 18,
      delay: i * 0.7,
    }));
  }, []);

  return (
    <svg
      viewBox="0 0 600 600"
      width={size}
      height={size}
      style={{ display: "block", overflow: "visible" }}
      className="hero-iris"
    >
      <defs>
        <radialGradient id="iris-fill" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="#0a1828" />
          <stop offset="55%" stopColor="#072036" />
          <stop offset="100%" stopColor="#04111a" />
        </radialGradient>
        <radialGradient id="pupil-fill" cx="40%" cy="40%" r="60%">
          <stop offset="0%" stopColor="#0a0f1a" />
          <stop offset="100%" stopColor="#000" />
        </radialGradient>
        <linearGradient id="ring-sweep" x1="0" y1="0" x2="1" y2="1">
          <stop offset="0%" stopColor="#4dd6ff" stopOpacity="0" />
          <stop offset="40%" stopColor="#4dd6ff" stopOpacity="0.8" />
          <stop offset="60%" stopColor="#f0a73a" stopOpacity="0.8" />
          <stop offset="100%" stopColor="#f0a73a" stopOpacity="0" />
        </linearGradient>
        <linearGradient id="scanbeam" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stopColor="#4dd6ff" stopOpacity="0" />
          <stop offset="50%" stopColor="#4dd6ff" stopOpacity="1" />
          <stop offset="100%" stopColor="#4dd6ff" stopOpacity="0" />
        </linearGradient>
        <radialGradient id="iris-glow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="#4dd6ff" stopOpacity="0.5" />
          <stop offset="60%" stopColor="#4dd6ff" stopOpacity="0.05" />
          <stop offset="100%" stopColor="#4dd6ff" stopOpacity="0" />
        </radialGradient>
        <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="3" result="b" />
          <feMerge>
            <feMergeNode in="b" />
            <feMergeNode in="SourceGraphic" />
          </feMerge>
        </filter>
      </defs>

      {/* outer soft glow */}
      <circle cx="300" cy="300" r="290" fill="url(#iris-glow)" />

      {/* very outermost telemetry ring with tick marks (counter-rotating) */}
      <g style={{ transformOrigin: "300px 300px", animation: "spin-r 80s linear infinite" }}>
        <circle cx="300" cy="300" r="285" fill="none" stroke="rgba(255,255,255,0.04)" strokeWidth="1" />
        {Array.from({ length: 120 }).map((_, i) => {
          const a = (i / 120) * Math.PI * 2;
          const isMaj = i % 10 === 0;
          const isMid = i % 5 === 0;
          const r1 = 285, r2 = isMaj ? 268 : isMid ? 275 : 280;
          const c = isMaj ? "#4dd6ff" : "rgba(255,255,255,0.18)";
          return (
            <line
              key={i}
              x1={300 + Math.cos(a) * r1}
              y1={300 + Math.sin(a) * r1}
              x2={300 + Math.cos(a) * r2}
              y2={300 + Math.sin(a) * r2}
              stroke={c}
              strokeWidth={isMaj ? 1.2 : 0.6}
            />
          );
        })}
        {/* corner markers — N E S W */}
        {["N", "E", "S", "W"].map((l, i) => {
          const a = (i / 4) * Math.PI * 2 - Math.PI / 2;
          return (
            <text
              key={l}
              x={300 + Math.cos(a) * 256}
              y={300 + Math.sin(a) * 256 + 3.5}
              fill="#4dd6ff"
              fontSize="10"
              fontFamily="Geist Mono, monospace"
              textAnchor="middle"
              opacity="0.7"
            >
              {l}
            </text>
          );
        })}
      </g>

      {/* main rotating analyzer ring (clockwise) */}
      <g style={{ transformOrigin: "300px 300px", animation: "spin 30s linear infinite" }}>
        <circle cx="300" cy="300" r="245" fill="none" stroke="rgba(77,214,255,0.15)" strokeWidth="1" />
        <circle
          cx="300"
          cy="300"
          r="245"
          fill="none"
          stroke="url(#ring-sweep)"
          strokeWidth="2"
          strokeDasharray="4 8"
          filter="url(#glow)"
        />
        {/* anchor brackets at 0/90/180/270 */}
        {[0, 90, 180, 270].map((d) => {
          const a = (d / 180) * Math.PI;
          const cx = 300 + Math.cos(a) * 245;
          const cy = 300 + Math.sin(a) * 245;
          return (
            <g key={d} transform={`translate(${cx} ${cy}) rotate(${d + 90})`}>
              <path d="M -8 -4 L -8 4 M -8 0 L 8 0 M 8 -4 L 8 4" stroke="#4dd6ff" strokeWidth="1.2" fill="none" opacity="0.9" />
            </g>
          );
        })}
      </g>

      {/* mid label ring — Devanagari + brand string */}
      <g style={{ transformOrigin: "300px 300px", animation: "spin-r 90s linear infinite" }}>
        <circle cx="300" cy="300" r="215" fill="none" stroke="rgba(240,167,58,0.18)" strokeWidth="1" />
        {Array.from({ length: 8 }).map((_, i) => {
          const a = (i / 8) * Math.PI * 2 + Math.PI / 8;
          return (
            <g key={i}>
              <line
                x1={300 + Math.cos(a) * 215}
                y1={300 + Math.sin(a) * 215}
                x2={300 + Math.cos(a) * 222}
                y2={300 + Math.sin(a) * 222}
                stroke="#f0a73a"
                strokeWidth="1"
                opacity="0.8"
              />
            </g>
          );
        })}
        <defs>
          <path
            id="mid-text-path"
            d="M 300 300 m -205 0 a 205 205 0 1 1 410 0 a 205 205 0 1 1 -410 0"
          />
        </defs>
        <text fill="#8a93a6" fontSize="9.5" fontFamily="Geist Mono, monospace" letterSpacing="6">
          <textPath href="#mid-text-path" startOffset="0">
            NETRA · नेत्र · VISION INTELLIGENCE · PERCEPTION ENGINE · 2026 · NETRA · नेत्र · VISION INTELLIGENCE · PERCEPTION ENGINE · 2026 ·
          </textPath>
        </text>
      </g>

      {/* concentric scan ring — dashed offset */}
      <g style={{ transformOrigin: "300px 300px", animation: "spin 22s linear infinite reverse" }}>
        <circle
          cx="300"
          cy="300"
          r="185"
          fill="none"
          stroke="#4dd6ff"
          strokeOpacity="0.5"
          strokeWidth="0.6"
          strokeDasharray="2 6"
        />
      </g>

      {/* IRIS body — outer almond shape giving "eye" feel */}
      <path
        d="M 60 300 Q 300 80 540 300 Q 300 520 60 300 Z"
        fill="none"
        stroke="rgba(77,214,255,0.18)"
        strokeWidth="1"
      />
      <path
        d="M 100 300 Q 300 130 500 300 Q 300 470 100 300 Z"
        fill="none"
        stroke="rgba(77,214,255,0.12)"
        strokeWidth="1"
      />

      {/* iris radial spokes (the "eye" feel) */}
      <g>
        {Array.from({ length: 72 }).map((_, i) => {
          const a = (i / 72) * Math.PI * 2;
          const x1 = 300 + Math.cos(a) * 95;
          const y1 = 300 + Math.sin(a) * 95;
          const x2 = 300 + Math.cos(a) * 165;
          const y2 = 300 + Math.sin(a) * 165;
          const opacity = 0.15 + ((i % 4) * 0.12);
          return (
            <line
              key={i}
              x1={x1}
              y1={y1}
              x2={x2}
              y2={y2}
              stroke="#4dd6ff"
              strokeOpacity={opacity}
              strokeWidth="0.8"
            />
          );
        })}
      </g>

      {/* secondary inner spokes — saffron accent */}
      <g style={{ transformOrigin: "300px 300px", animation: "spin 60s linear infinite" }}>
        {Array.from({ length: 36 }).map((_, i) => {
          const a = (i / 36) * Math.PI * 2;
          const x1 = 300 + Math.cos(a) * 100;
          const y1 = 300 + Math.sin(a) * 100;
          const x2 = 300 + Math.cos(a) * 130;
          const y2 = 300 + Math.sin(a) * 130;
          return (
            <line
              key={i}
              x1={x1}
              y1={y1}
              x2={x2}
              y2={y2}
              stroke="#f0a73a"
              strokeOpacity={i % 2 === 0 ? 0.25 : 0.08}
              strokeWidth="0.6"
            />
          );
        })}
      </g>

      {/* IRIS fill disc */}
      <circle cx="300" cy="300" r="160" fill="url(#iris-fill)" />
      <circle
        cx="300"
        cy="300"
        r="160"
        fill="none"
        stroke="#4dd6ff"
        strokeOpacity="0.45"
        strokeWidth="1"
      />
      <circle
        cx="300"
        cy="300"
        r="160"
        fill="none"
        stroke="url(#ring-sweep)"
        strokeOpacity="0.8"
        strokeWidth="2"
        filter="url(#glow)"
      />

      {/* fine inner ring */}
      <circle cx="300" cy="300" r="115" fill="none" stroke="rgba(77,214,255,0.3)" strokeWidth="0.8" />
      <circle
        cx="300"
        cy="300"
        r="115"
        fill="none"
        stroke="rgba(77,214,255,0.7)"
        strokeWidth="1.2"
        strokeDasharray="1 4"
        style={{ transformOrigin: "300px 300px", animation: "spin 12s linear infinite" }}
      />

      {/* PUPIL */}
      <circle cx="300" cy="300" r="68" fill="url(#pupil-fill)" />
      <circle cx="300" cy="300" r="68" fill="none" stroke="rgba(77,214,255,0.7)" strokeWidth="1.4" />
      <circle cx="300" cy="300" r="68" fill="none" stroke="rgba(77,214,255,0.3)" strokeWidth="0.6" strokeDasharray="2 3" />

      {/* pupil reticle */}
      <g stroke="#4dd6ff" strokeWidth="0.9" opacity="0.7" fill="none">
        <line x1="300" y1="240" x2="300" y2="260" />
        <line x1="300" y1="340" x2="300" y2="360" />
        <line x1="240" y1="300" x2="260" y2="300" />
        <line x1="340" y1="300" x2="360" y2="300" />
        <circle cx="300" cy="300" r="18" strokeDasharray="2 3" />
      </g>

      {/* pupil highlight */}
      <circle cx="285" cy="280" r="6" fill="#4dd6ff" opacity="0.85" />
      <circle cx="318" cy="318" r="2.5" fill="#f0a73a" opacity="0.7" />

      {/* "detection locks" — fading squares around iris */}
      <g>
        {locks.map((l, i) => {
          const x = 300 + Math.cos(l.a) * l.r;
          const y = 300 + Math.sin(l.a) * l.r;
          return (
            <g
              key={i}
              transform={`translate(${x - 9} ${y - 9})`}
              style={{ animation: `lockblink 4s ease-in-out infinite ${l.delay}s` }}
            >
              <path
                d="M 0 4 L 0 0 L 4 0 M 14 0 L 18 0 L 18 4 M 0 14 L 0 18 L 4 18 M 14 18 L 18 18 L 18 14"
                fill="none"
                stroke="#4dd6ff"
                strokeWidth="1.2"
              />
              <circle cx="9" cy="9" r="1" fill="#4dd6ff" />
            </g>
          );
        })}
      </g>

      {/* sweeping scan beam — a thin line rotating */}
      <g style={{ transformOrigin: "300px 300px", animation: "spin 6s linear infinite" }}>
        <line x1="300" y1="300" x2="300" y2="55" stroke="url(#scanbeam)" strokeWidth="2" opacity="0.7" />
        <line x1="300" y1="300" x2="300" y2="55" stroke="#4dd6ff" strokeWidth="0.6" opacity="0.5" />
      </g>

      {/* connecting lines to floating annotations (to give "data flow" sense) */}
      <g stroke="rgba(77,214,255,0.3)" strokeWidth="0.8" fill="none" strokeDasharray="2 4">
        <path d="M 480 120 L 540 70" />
        <path d="M 480 480 L 540 530" />
        <path d="M 120 480 L 60 540" />
        <path d="M 120 120 L 60 60" />
      </g>
    </svg>
  );
};

/* ---------- Capability micro-visualizations ---------- */
const VizTailgate = () => (
  <svg viewBox="0 0 240 180" style={{ width: "100%", height: "100%" }}>
    <defs>
      <linearGradient id="cap-door" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stopColor="#1a2030" />
        <stop offset="100%" stopColor="#0a0f18" />
      </linearGradient>
    </defs>
    {/* floor perspective lines */}
    <line x1="0" y1="170" x2="240" y2="170" stroke="rgba(255,255,255,0.08)" />
    <line x1="40" y1="170" x2="100" y2="40" stroke="rgba(255,255,255,0.05)" />
    <line x1="200" y1="170" x2="140" y2="40" stroke="rgba(255,255,255,0.05)" />
    {/* door */}
    <rect x="98" y="38" width="44" height="100" fill="url(#cap-door)" stroke="rgba(77,214,255,0.4)" strokeWidth="1" />
    <rect x="98" y="38" width="44" height="100" fill="none" stroke="rgba(77,214,255,0.2)" strokeWidth="0.5" strokeDasharray="3 3" />
    {/* badge reader */}
    <rect x="146" y="78" width="6" height="14" fill="#4dd6ff" opacity="0.9" />
    {/* person A — green */}
    <g>
      <circle cx="80" cy="118" r="9" fill="#04111a" stroke="#5ce0a8" strokeWidth="1.6" />
      <rect x="69" y="128" width="22" height="28" rx="3" fill="#04111a" stroke="#5ce0a8" strokeWidth="1.6" />
      <text x="80" y="172" fill="#5ce0a8" fontSize="8" fontFamily="Geist Mono, monospace" textAnchor="middle">PERSON A · OK</text>
    </g>
    {/* person B — crit, animated */}
    <g style={{ animation: "tg-step 3.4s ease-in-out infinite" }}>
      <circle cx="44" cy="118" r="9" fill="#04111a" stroke="#ff3d6e" strokeWidth="1.6" />
      <rect x="33" y="128" width="22" height="28" rx="3" fill="#04111a" stroke="#ff3d6e" strokeWidth="1.6" />
      <text x="44" y="172" fill="#ff3d6e" fontSize="8" fontFamily="Geist Mono, monospace" textAnchor="middle">PERSON B · ?</text>
    </g>
    {/* alert burst at door */}
    <g style={{ animation: "tg-alert 3.4s ease-in-out infinite" }}>
      <circle cx="120" cy="88" r="22" fill="none" stroke="#ff3d6e" strokeWidth="1.4" opacity="0.6" />
      <text x="120" y="22" fill="#ff3d6e" fontSize="9" fontFamily="Geist Mono, monospace" textAnchor="middle" letterSpacing="1">TAILGATE</text>
    </g>
  </svg>
);

const VizLoiter = () => (
  <svg viewBox="0 0 240 180" style={{ width: "100%", height: "100%" }}>
    {/* zone */}
    <rect x="20" y="20" width="200" height="140" fill="none" stroke="rgba(240,167,58,0.4)" strokeWidth="1" strokeDasharray="4 4" />
    <text x="28" y="36" fill="#f0a73a" fontSize="9" fontFamily="Geist Mono, monospace" letterSpacing="1">PERIMETER · LOITER 4M</text>
    {/* dwell trail (path the person took, sitting around) */}
    <path
      d="M 60 130 Q 80 110 100 120 T 140 100 Q 150 90 130 80 Q 110 70 100 90"
      fill="none"
      stroke="#f0a73a"
      strokeOpacity="0.6"
      strokeWidth="1.4"
      strokeDasharray="3 3"
    />
    {[
      [60, 130], [80, 118], [100, 120], [120, 110], [140, 100], [130, 80], [110, 75], [100, 90],
    ].map((p, i) => (
      <circle key={i} cx={p[0]} cy={p[1]} r="2" fill="#f0a73a" opacity={0.4 + i * 0.07} />
    ))}
    {/* person */}
    <g style={{ animation: "loiter-breath 3s ease-in-out infinite" }}>
      <circle cx="100" cy="90" r="9" fill="#04111a" stroke="#f0a73a" strokeWidth="1.6" />
      <rect x="89" y="100" width="22" height="28" rx="3" fill="#04111a" stroke="#f0a73a" strokeWidth="1.6" />
    </g>
    {/* timer */}
    <g transform="translate(176 130)">
      <circle cx="0" cy="0" r="18" fill="none" stroke="rgba(240,167,58,0.2)" strokeWidth="2" />
      <circle cx="0" cy="0" r="18" fill="none" stroke="#f0a73a" strokeWidth="2"
        strokeDasharray="113" strokeDashoffset="35"
        transform="rotate(-90)" strokeLinecap="round" />
      <text x="0" y="3" fill="#f0a73a" fontSize="10" fontFamily="Geist Mono, monospace" textAnchor="middle">6m</text>
    </g>
  </svg>
);

const VizObject = () => (
  <svg viewBox="0 0 240 180" style={{ width: "100%", height: "100%" }}>
    <line x1="0" y1="150" x2="240" y2="150" stroke="rgba(255,255,255,0.1)" />
    {/* chair */}
    <g stroke="#5c6577" strokeWidth="1.4" fill="none">
      <line x1="80" y1="120" x2="80" y2="150" />
      <line x1="130" y1="120" x2="130" y2="150" />
      <line x1="80" y1="120" x2="130" y2="120" />
      <line x1="80" y1="120" x2="80" y2="90" />
    </g>
    {/* bag */}
    <g style={{ animation: "obj-pulse 2.2s ease-in-out infinite" }}>
      <path d="M 92 110 L 92 100 Q 92 95 97 95 L 113 95 Q 118 95 118 100 L 118 110 Z" fill="none" stroke="#f0a73a" strokeWidth="1.6" />
      <rect x="86" y="110" width="38" height="22" rx="2" fill="#1a2030" stroke="#f0a73a" strokeWidth="1.6" />
    </g>
    {/* AI bbox */}
    <g style={{ animation: "obj-detect 2.2s ease-in-out infinite" }}>
      <rect x="78" y="86" width="54" height="50" fill="none" stroke="#ff3d6e" strokeWidth="1.4" />
      <rect x="78" y="86" width="14" height="2" fill="#ff3d6e" />
      <rect x="78" y="86" width="2" height="14" fill="#ff3d6e" />
      <rect x="118" y="86" width="14" height="2" fill="#ff3d6e" />
      <rect x="130" y="86" width="2" height="14" fill="#ff3d6e" />
      <rect x="78" y="122" width="14" height="2" fill="#ff3d6e" />
      <rect x="78" y="134" width="2" height="2" fill="#ff3d6e" />
      <text x="76" y="80" fill="#ff3d6e" fontSize="9" fontFamily="Geist Mono, monospace">UNATTENDED · 9m</text>
    </g>
    {/* ghost person walking away */}
    <g opacity="0.3">
      <circle cx="180" cy="105" r="7" fill="none" stroke="#8a93a6" strokeWidth="1.2" />
      <rect x="172" y="112" width="16" height="22" rx="2" fill="none" stroke="#8a93a6" strokeWidth="1.2" />
    </g>
    <path d="M 130 130 Q 160 130 175 115" fill="none" stroke="#5c6577" strokeWidth="1" strokeDasharray="2 3" />
  </svg>
);

const VizMask = () => (
  <svg viewBox="0 0 240 180" style={{ width: "100%", height: "100%" }}>
    {/* face */}
    <g transform="translate(120 90)">
      <circle cx="0" cy="0" r="42" fill="#04111a" stroke="rgba(255,255,255,0.2)" strokeWidth="1" />
      {/* obscured face — fine grid noise */}
      <g clipPath="url(#face-clip)">
        <pattern id="noise" width="6" height="6" patternUnits="userSpaceOnUse">
          <rect width="6" height="6" fill="#0a0f18" />
          <rect x="0" y="0" width="3" height="3" fill="#1a2030" />
          <rect x="3" y="3" width="3" height="3" fill="#1a2030" />
        </pattern>
        <circle cx="0" cy="0" r="42" fill="url(#noise)" />
      </g>
      <defs>
        <clipPath id="face-clip">
          <circle cx="0" cy="0" r="42" />
        </clipPath>
      </defs>
      {/* failed face landmarks — red Xs */}
      <g stroke="#ff3d6e" strokeWidth="1.4" opacity="0.9">
        <line x1="-14" y1="-10" x2="-8" y2="-4" />
        <line x1="-14" y1="-4" x2="-8" y2="-10" />
        <line x1="14" y1="-10" x2="8" y2="-4" />
        <line x1="14" y1="-4" x2="8" y2="-10" />
        <line x1="-8" y1="14" x2="8" y2="14" />
      </g>
      {/* scan ring around face */}
      <circle cx="0" cy="0" r="48" fill="none" stroke="#ff3d6e" strokeWidth="1.4"
        strokeDasharray="3 4"
        style={{ animation: "spin 8s linear infinite", transformOrigin: "0 0" }} />
    </g>
    <text x="120" y="160" fill="#ff3d6e" fontSize="10" fontFamily="Geist Mono, monospace" textAnchor="middle" letterSpacing="2">FACE NOT ENROLLED</text>
    <text x="120" y="32" fill="#8a93a6" fontSize="9" fontFamily="Geist Mono, monospace" textAnchor="middle">CONFIDENCE 0.92 · OBSCURED 32s</text>
  </svg>
);

const VizAfter = () => (
  <svg viewBox="0 0 240 180" style={{ width: "100%", height: "100%" }}>
    {/* clock dial */}
    <g transform="translate(120 90)">
      <circle cx="0" cy="0" r="58" fill="none" stroke="rgba(255,255,255,0.08)" strokeWidth="1" />
      {/* night arc */}
      <path d="M 0 -58 A 58 58 0 1 1 -41 41" fill="none" stroke="#7aa2ff" strokeWidth="3" opacity="0.4" />
      {/* hour ticks */}
      {Array.from({ length: 12 }).map((_, i) => {
        const a = (i / 12) * Math.PI * 2 - Math.PI / 2;
        const r1 = 58, r2 = i % 3 === 0 ? 48 : 52;
        return (
          <line key={i} x1={Math.cos(a) * r1} y1={Math.sin(a) * r1} x2={Math.cos(a) * r2} y2={Math.sin(a) * r2}
            stroke={i % 3 === 0 ? "#c8cfdc" : "rgba(255,255,255,0.2)"} strokeWidth={i % 3 === 0 ? 1.4 : 0.8} />
        );
      })}
      {/* numbers */}
      {[12, 3, 6, 9].map((n, i) => {
        const a = (i / 4) * Math.PI * 2 - Math.PI / 2;
        return (
          <text key={n} x={Math.cos(a) * 40} y={Math.sin(a) * 40 + 4} fill="#8a93a6"
            fontSize="10" fontFamily="Geist Mono, monospace" textAnchor="middle">{n}</text>
        );
      })}
      {/* hands at 22:14 — hour ~ -50deg from top */}
      <line x1="0" y1="0" x2="0" y2="-22" stroke="#c8cfdc" strokeWidth="2.4" strokeLinecap="round"
        transform="rotate(305)" />
      <line x1="0" y1="0" x2="0" y2="-34" stroke="#7aa2ff" strokeWidth="1.8" strokeLinecap="round"
        transform="rotate(84)" />
      <circle cx="0" cy="0" r="2.5" fill="#7aa2ff" />
      {/* badge ping */}
      <g style={{ animation: "pulse 2s ease-in-out infinite" }}>
        <circle cx="32" cy="-32" r="4" fill="#7aa2ff" />
        <circle cx="32" cy="-32" r="8" fill="none" stroke="#7aa2ff" strokeWidth="1" opacity="0.4" />
      </g>
    </g>
    <text x="120" y="170" fill="#7aa2ff" fontSize="9" fontFamily="Geist Mono, monospace" textAnchor="middle" letterSpacing="2">22:14 · BADGE AB-2117 · SERVER ROOM</text>
  </svg>
);

const VizCrowd = () => (
  <svg viewBox="0 0 240 180" style={{ width: "100%", height: "100%" }}>
    {/* heatmap grid */}
    <defs>
      <radialGradient id="heat" cx="50%" cy="50%" r="50%">
        <stop offset="0%" stopColor="#ff3d6e" stopOpacity="0.6" />
        <stop offset="50%" stopColor="#f0a73a" stopOpacity="0.3" />
        <stop offset="100%" stopColor="#4dd6ff" stopOpacity="0" />
      </radialGradient>
    </defs>
    <rect x="20" y="20" width="200" height="140" fill="none" stroke="rgba(255,255,255,0.06)" />
    {/* faint grid */}
    {Array.from({ length: 8 }).map((_, i) => (
      <line key={"v" + i} x1={20 + i * 25} y1="20" x2={20 + i * 25} y2="160" stroke="rgba(255,255,255,0.04)" />
    ))}
    {Array.from({ length: 6 }).map((_, i) => (
      <line key={"h" + i} x1="20" y1={20 + i * 23.3} x2="220" y2={20 + i * 23.3} stroke="rgba(255,255,255,0.04)" />
    ))}
    {/* density blobs */}
    <ellipse cx="105" cy="90" rx="62" ry="42" fill="url(#heat)" />
    <ellipse cx="155" cy="115" rx="36" ry="26" fill="url(#heat)" opacity="0.6" />
    {/* dots */}
    {[
      [80, 70], [95, 88], [110, 78], [125, 95], [100, 110], [85, 100], [120, 70],
      [140, 105], [155, 115], [165, 125], [150, 100], [60, 130], [70, 145],
    ].map((p, i) => (
      <circle key={i} cx={p[0]} cy={p[1]} r="3" fill="#fff" opacity="0.85"
        style={{ animation: `crowdshift 2.6s ease-in-out infinite ${i * 0.12}s` }} />
    ))}
    <text x="200" y="36" fill="#ff3d6e" fontSize="9" fontFamily="Geist Mono, monospace" textAnchor="end" letterSpacing="1">11 PERSONS · 6m²</text>
    <text x="200" y="48" fill="#8a93a6" fontSize="9" fontFamily="Geist Mono, monospace" textAnchor="end">CAP 8</text>
  </svg>
);

/* ---------- Pipeline diagram ---------- */
const Pipeline = () => {
  return (
    <svg viewBox="0 0 1200 280" style={{ width: "100%", height: "auto" }}>
      <defs>
        <linearGradient id="pipe-line" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stopColor="#4dd6ff" stopOpacity="0.2" />
          <stop offset="100%" stopColor="#4dd6ff" stopOpacity="0.6" />
        </linearGradient>
        <marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
          <path d="M 0 0 L 10 5 L 0 10 Z" fill="#4dd6ff" />
        </marker>
      </defs>

      {/* nodes */}
      {[
        { x: 90, lbl: "SENSE", title: "Cameras · Badges · Sensors", lines: ["12,847 streams", "Edge ingest 4K@30"] },
        { x: 390, lbl: "PERCEIVE", title: "Perception models", lines: ["YOLO-v9 · pose", "ReID · face · OCR"] },
        { x: 690, lbl: "REASON", title: "Correlation + LLM", lines: ["Multi-modal fusion", "Rule engine + Netra-LM"] },
        { x: 990, lbl: "ACT", title: "Response & evidence", lines: ["Page on-call · lock door", "Clip + chain of custody"] },
      ].map((n, i) => (
        <g key={i} transform={`translate(${n.x} 60)`}>
          {/* card */}
          <rect x="0" y="0" width="180" height="160" rx="12" fill="#0b0f17" stroke="rgba(255,255,255,0.1)" />
          <rect x="0" y="0" width="180" height="160" rx="12" fill="none" stroke="#4dd6ff" strokeOpacity="0.18" />
          {/* glow at corner */}
          <circle cx="12" cy="12" r="3" fill="#4dd6ff" />
          {/* number */}
          <text x="160" y="22" fill="#5c6577" fontSize="11" fontFamily="Geist Mono, monospace" textAnchor="end">0{i + 1}</text>
          {/* label */}
          <text x="20" y="36" fill="#4dd6ff" fontSize="10" fontFamily="Geist Mono, monospace" letterSpacing="3">{n.lbl}</text>
          {/* title */}
          <text x="20" y="64" fill="#f4f6fb" fontSize="14" fontFamily="Geist, sans-serif" fontWeight="500">{n.title}</text>
          {/* lines */}
          {n.lines.map((l, j) => (
            <text key={j} x="20" y={92 + j * 16} fill="#8a93a6" fontSize="11" fontFamily="Geist Mono, monospace">› {l}</text>
          ))}
          {/* mini glyph */}
          <PipeGlyph kind={n.lbl} />
        </g>
      ))}

      {/* connecting lines + arrows */}
      {[270, 570, 870].map((x, i) => (
        <g key={i}>
          <line x1={x} y1="140" x2={x + 120} y2="140" stroke="url(#pipe-line)" strokeWidth="1.6" markerEnd="url(#arr)" />
          {/* flowing dots */}
          <circle cx={x + 60} cy="140" r="2.5" fill="#4dd6ff">
            <animate attributeName="cx" from={x} to={x + 120} dur="2s" repeatCount="indefinite" begin={`${i * 0.5}s`} />
            <animate attributeName="opacity" values="0;1;1;0" dur="2s" repeatCount="indefinite" begin={`${i * 0.5}s`} />
          </circle>
          <circle cx={x + 60} cy="140" r="2" fill="#f0a73a">
            <animate attributeName="cx" from={x} to={x + 120} dur="2s" repeatCount="indefinite" begin={`${i * 0.5 + 0.9}s`} />
            <animate attributeName="opacity" values="0;1;1;0" dur="2s" repeatCount="indefinite" begin={`${i * 0.5 + 0.9}s`} />
          </circle>
        </g>
      ))}

      {/* under-labels */}
      {[
        { x: 180, t: "p99 < 80ms" },
        { x: 480, t: "47 model heads" },
        { x: 780, t: "context: 24h estate" },
      ].map((u, i) => (
        <text key={i} x={u.x} y="245" fill="#5c6577" fontSize="10" fontFamily="Geist Mono, monospace" textAnchor="middle" letterSpacing="1.4">— {u.t} —</text>
      ))}
    </svg>
  );
};

const PipeGlyph = ({ kind }) => {
  // tiny diagram in the lower-right of each pipeline card
  const tx = 130, ty = 110;
  if (kind === "SENSE") {
    return (
      <g transform={`translate(${tx} ${ty})`} stroke="#4dd6ff" fill="none" strokeWidth="1.2">
        <rect x="0" y="6" width="22" height="14" rx="2" />
        <path d="M 22 10 L 32 6 L 32 20 L 22 16 Z" fill="#4dd6ff" fillOpacity="0.2" />
        <circle cx="5" cy="10" r="0.8" fill="#4dd6ff" stroke="none" />
      </g>
    );
  }
  if (kind === "PERCEIVE") {
    return (
      <g transform={`translate(${tx} ${ty})`}>
        <rect x="0" y="0" width="32" height="22" rx="2" fill="none" stroke="#4dd6ff" strokeWidth="1.2" />
        <rect x="4" y="4" width="10" height="6" fill="none" stroke="#ff3d6e" strokeWidth="1" />
        <rect x="18" y="10" width="10" height="8" fill="none" stroke="#f0a73a" strokeWidth="1" />
        <circle cx="8" cy="14" r="1.2" fill="#5ce0a8" />
      </g>
    );
  }
  if (kind === "REASON") {
    return (
      <g transform={`translate(${tx} ${ty})`} stroke="#4dd6ff" fill="none" strokeWidth="1.2">
        <circle cx="6" cy="6" r="3" />
        <circle cx="26" cy="6" r="3" />
        <circle cx="6" cy="18" r="3" />
        <circle cx="26" cy="18" r="3" />
        <circle cx="16" cy="12" r="4" fill="#f0a73a" fillOpacity="0.3" />
        <line x1="9" y1="6" x2="13" y2="11" />
        <line x1="23" y1="6" x2="19" y2="11" />
        <line x1="9" y1="18" x2="13" y2="13" />
        <line x1="23" y1="18" x2="19" y2="13" />
      </g>
    );
  }
  if (kind === "ACT") {
    return (
      <g transform={`translate(${tx} ${ty})`} stroke="#4dd6ff" fill="none" strokeWidth="1.2">
        <rect x="0" y="2" width="30" height="18" rx="2" />
        <path d="M 4 10 L 8 14 L 16 6" stroke="#5ce0a8" />
        <line x1="20" y1="10" x2="26" y2="10" />
        <line x1="20" y1="14" x2="24" y2="14" />
      </g>
    );
  }
  return null;
};

Object.assign(window, { HeroIris, VizTailgate, VizLoiter, VizObject, VizMask, VizAfter, VizCrowd, Pipeline });
