// Nexora Cores — Website UI Kit · Animated constellation / network mesh
// Replicates the brand banner: glowing nodes + connecting lines on navy,
// concentrated toward the bottom-left, drifting slowly. Cyan/electric accent.
(function () {
  const { useRef, useEffect } = React;

  function NetworkCanvas({ style = {} }) {
    const ref = useRef(null);
    useEffect(() => {
      const canvas = ref.current;
      if (!canvas) return;
      const ctx = canvas.getContext('2d');
      const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
      let w, h, dpr, nodes = [], raf, running = true;

      function resize() {
        dpr = Math.min(window.devicePixelRatio || 1, 2);
        const r = canvas.getBoundingClientRect();
        w = r.width; h = r.height;
        canvas.width = w * dpr; canvas.height = h * dpr;
        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
        // Density scales with area; clamp for perf.
        const count = Math.max(34, Math.min(90, Math.round((w * h) / 16000)));
        nodes = new Array(count).fill(0).map(() => {
          // Bias spawn toward bottom-left (matches banner energy).
          const bx = Math.pow(Math.random(), 1.7);       // 0..1, skewed low
          const by = 1 - Math.pow(Math.random(), 1.7);   // skewed high
          return {
            x: bx * w, y: by * h,
            vx: (Math.random() - 0.5) * 0.25,
            vy: (Math.random() - 0.5) * 0.25,
            r: Math.random() * 1.6 + 0.8,
          };
        });
      }

      function intensity(x, y) {
        // 1 near bottom-left → ~0.12 near top-right.
        const d = Math.hypot(x / w, (h - y) / h) / 1.414;
        return Math.max(0.12, 1 - d);
      }

      function frame() {
        ctx.clearRect(0, 0, w, h);
        const LINK = 132;
        for (let i = 0; i < nodes.length; i++) {
          const a = nodes[i];
          for (let j = i + 1; j < nodes.length; j++) {
            const b = nodes[j];
            const dx = a.x - b.x, dy = a.y - b.y;
            const dist = Math.hypot(dx, dy);
            if (dist < LINK) {
              const inten = intensity((a.x + b.x) / 2, (a.y + b.y) / 2);
              const o = (1 - dist / LINK) * 0.55 * inten;
              ctx.strokeStyle = `rgba(56,189,248,${o})`;
              ctx.lineWidth = 1;
              ctx.beginPath();
              ctx.moveTo(a.x, a.y);
              ctx.lineTo(b.x, b.y);
              ctx.stroke();
            }
          }
        }
        for (const n of nodes) {
          const inten = intensity(n.x, n.y);
          ctx.beginPath();
          ctx.arc(n.x, n.y, n.r, 0, Math.PI * 2);
          ctx.fillStyle = `rgba(125,224,255,${0.5 + inten * 0.5})`;
          ctx.shadowColor = 'rgba(56,189,248,0.9)';
          ctx.shadowBlur = 8 + inten * 12;
          ctx.fill();
          ctx.shadowBlur = 0;
          n.x += n.vx; n.y += n.vy;
          if (n.x < -20) n.x = w + 20; if (n.x > w + 20) n.x = -20;
          if (n.y < -20) n.y = h + 20; if (n.y > h + 20) n.y = -20;
        }
        if (running) raf = requestAnimationFrame(frame);
      }

      resize();
      if (reduce) { frame(); } // single static frame
      else raf = requestAnimationFrame(frame);
      const onResize = () => resize();
      window.addEventListener('resize', onResize);
      const onVis = () => {
        if (document.hidden) { running = false; cancelAnimationFrame(raf); }
        else if (!reduce) { running = true; raf = requestAnimationFrame(frame); }
      };
      document.addEventListener('visibilitychange', onVis);
      return () => {
        running = false; cancelAnimationFrame(raf);
        window.removeEventListener('resize', onResize);
        document.removeEventListener('visibilitychange', onVis);
      };
    }, []);

    return React.createElement('canvas', {
      ref,
      'aria-hidden': 'true',
      style: { position: 'absolute', inset: 0, width: '100%', height: '100%', display: 'block', ...style },
    });
  }

  window.NetworkCanvas = NetworkCanvas;
})();
