(function () {
  "use strict";

  var canvas = document.getElementById("techNodes");
  if (!canvas || !canvas.getContext) return;

  var ctx = canvas.getContext("2d");
  var nodes = [];
  var scrollProgress = 0;
  var pulsePhase = 0;
  var width = 0;
  var height = 0;
  var nodeCount = 0;
  var animId = null;
  var reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  var colors = {
    light: {
      node: "rgba(0, 212, 255, 0.85)",
      nodeCore: "rgba(61, 123, 255, 1)",
      line: "rgba(0, 212, 255, 0.12)",
      lineActive: "rgba(0, 255, 136, 0.35)",
      glow: "rgba(0, 212, 255, 0.15)",
    },
    dark: {
      node: "rgba(0, 240, 255, 1)",
      nodeCore: "rgba(57, 255, 20, 1)",
      line: "rgba(0, 240, 255, 0.08)",
      lineActive: "rgba(57, 255, 20, 0.45)",
      glow: "rgba(0, 240, 255, 0.25)",
    },
  };

  function getTheme() {
    return document.documentElement.getAttribute("data-theme") === "light" ? "light" : "dark";
  }

  function getPalette() {
    return colors[getTheme()];
  }

  function resize() {
    width = window.innerWidth;
    height = window.innerHeight;
    var dpr = Math.min(window.devicePixelRatio || 1, 2);
    canvas.width = width * dpr;
    canvas.height = height * dpr;
    canvas.style.width = width + "px";
    canvas.style.height = height + "px";
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    nodeCount = width < 768 ? 42 : width < 1200 ? 68 : 95;
    initNodes();
  }

  function initNodes() {
    nodes = [];
    for (var i = 0; i < nodeCount; i++) {
      nodes.push({
        x: Math.random() * width,
        y: Math.random() * height,
        vx: (Math.random() - 0.5) * 0.35,
        vy: (Math.random() - 0.5) * 0.35,
        r: Math.random() * 1.8 + 1.2,
        pulse: Math.random() * Math.PI * 2,
      });
    }
  }

  function updateScroll() {
    var docH = document.documentElement.scrollHeight - window.innerHeight;
    scrollProgress = docH > 0 ? window.scrollY / docH : 0;
  }

  function draw() {
    var pal = getPalette();
    ctx.clearRect(0, 0, width, height);

    var linkDist = width < 768 ? 110 : 150;
    var scrollBoost = 0.35 + scrollProgress * 0.65;
    pulsePhase += reducedMotion ? 0 : 0.018;

    for (var i = 0; i < nodes.length; i++) {
      var a = nodes[i];
      if (!reducedMotion) {
        a.x += a.vx;
        a.y += a.vy;
        if (a.x < 0 || a.x > width) a.vx *= -1;
        if (a.y < 0 || a.y > height) a.vy *= -1;
        a.pulse += 0.04;
      }

      for (var j = i + 1; j < nodes.length; j++) {
        var b = nodes[j];
        var dx = a.x - b.x;
        var dy = a.y - b.y;
        var dist = Math.sqrt(dx * dx + dy * dy);
        if (dist < linkDist) {
          var alpha = (1 - dist / linkDist) * scrollBoost;
          ctx.beginPath();
          ctx.strokeStyle = alpha > 0.2 ? pal.lineActive : pal.line;
          ctx.lineWidth = alpha > 0.25 ? 1.2 : 0.6;
          ctx.globalAlpha = Math.min(alpha, 0.9);
          ctx.moveTo(a.x, a.y);
          ctx.lineTo(b.x, b.y);
          ctx.stroke();
          ctx.globalAlpha = 1;
        }
      }
    }

    var viewCenter = window.scrollY + height * 0.45;

    for (var k = 0; k < nodes.length; k++) {
      var n = nodes[k];
      var docY = n.y + window.scrollY * 0.15;
      var nearView = 1 - Math.min(Math.abs(docY - viewCenter) / (height * 0.9), 1);
      var glow = 0.4 + Math.sin(n.pulse + pulsePhase) * 0.35 + nearView * 0.4;

      ctx.beginPath();
      ctx.arc(n.x, n.y, n.r * glow * 2.5, 0, Math.PI * 2);
      ctx.fillStyle = pal.glow;
      ctx.fill();

      ctx.beginPath();
      ctx.arc(n.x, n.y, n.r * (0.9 + nearView * 0.5), 0, Math.PI * 2);
      ctx.fillStyle = nearView > 0.5 ? pal.nodeCore : pal.node;
      ctx.fill();

      if (nearView > 0.55) {
        ctx.beginPath();
        ctx.arc(n.x, n.y, n.r * 0.4, 0, Math.PI * 2);
        ctx.fillStyle = "#fff";
        ctx.globalAlpha = 0.7;
        ctx.fill();
        ctx.globalAlpha = 1;
      }
    }

    animId = requestAnimationFrame(draw);
  }

  window.addEventListener("resize", resize);
  window.addEventListener("scroll", updateScroll, { passive: true });
  window.addEventListener("themechange", function () {
    /* palette refresh on next frame */
  });

  window.TechNodes = {
    pulseAt: function (y) {
      nodes.forEach(function (n) {
        var dist = Math.abs(n.y - y);
        if (dist < 120) n.pulse += 2;
      });
    },
  };

  resize();
  updateScroll();
  if (!reducedMotion) draw();
})();
