/* ============================================================
   Globinex Research — custom.js
   ============================================================ */
(function () {
  "use strict";

  /* ---------- 1. Navbar on scroll ---------- */
  var nav = document.getElementById("gxNav");
  var menu = document.getElementById("gxMenu");
  var mobileDropdowns = nav ? nav.querySelectorAll(".gx-dropdown") : [];

  function onScroll() {
    if (!nav) return;
    if (window.scrollY > 60) nav.classList.add("scrolled");
    else nav.classList.remove("scrolled");
  }

  function closeMobileMenu() {
    if (!menu || window.innerWidth >= 992) return;
    if (typeof bootstrap !== "undefined" && bootstrap.Collapse && bootstrap.Collapse.getOrCreateInstance) {
      var collapse = bootstrap.Collapse.getOrCreateInstance(menu);
      collapse.hide();
    }
    mobileDropdowns.forEach(function (dropdown) {
      dropdown.classList.remove("open");
    });
  }

  if (menu) {
    menu.querySelectorAll(".nav-link, .dropdown-item, .lang-item").forEach(function (link) {
      link.addEventListener("click", function (event) {
        if (window.innerWidth < 992 && !link.classList.contains("gx-drop-toggle")) {
          closeMobileMenu();
        }
      });
    });
  }

  mobileDropdowns.forEach(function (dropdown) {
    var toggle = dropdown.querySelector(".gx-drop-toggle");
    if (toggle) {
      toggle.addEventListener("click", function (event) {
        if (window.innerWidth < 992) {
          var target = event.target;
          var isChevron = target && (target.classList.contains("bi") || target.closest(".bi"));

          if (isChevron) {
            event.preventDefault();
            event.stopPropagation();
            dropdown.classList.toggle("open");
          } else {
            closeMobileMenu();
          }
        }
      });
    }
  });

  document.addEventListener("click", function (event) {
    if (!nav || window.innerWidth >= 992 || !menu) return;
    if (!nav.contains(event.target)) closeMobileMenu();
  });

  window.addEventListener("resize", function () {
    if (window.innerWidth >= 992) {
      if (menu) menu.classList.remove("show");
      mobileDropdowns.forEach(function (dropdown) {
        dropdown.classList.remove("open");
      });
    }
  });

  window.addEventListener("scroll", onScroll, { passive: true });
  onScroll();

  /* ---------- 2. Scroll reveal ---------- */
  var revealEls = document.querySelectorAll(".reveal");
  var revObserver = new IntersectionObserver(function (entries) {
    entries.forEach(function (e) {
      if (e.isIntersecting) {
        e.target.classList.add("in");
        revObserver.unobserve(e.target);
      }
    });
  }, { threshold: 0.15, rootMargin: "0px 0px -40px 0px" });
  revealEls.forEach(function (el) { revObserver.observe(el); });

  /* ---------- 3a. Pill marquee (Solutions services rows) ----------
     A continuous linear CSS animation (no JS-driven pauses). The set is
     cloned twice (3 copies total) so there's always real content filling
     the clip box, then we measure the exact width of one set — including
     its trailing gap — and drive the loop off that via a CSS variable. */
  document.querySelectorAll(".pill-slider").forEach(function (wrap) {
    var track = wrap.querySelector(".sol-row");
    if (!track) return;
    var originals = track.querySelectorAll(".sol-pill");
    if (originals.length < 2) return;

    function cloneSet() {
      var frag = document.createDocumentFragment();
      originals.forEach(function (item) {
        var clone = item.cloneNode(true);
        clone.setAttribute("aria-hidden", "true");
        frag.appendChild(clone);
      });
      track.appendChild(frag);
    }
    cloneSet();
    cloneSet();

    var firstOriginal = track.querySelector(".sol-pill");
    var firstOfNextSet = track.querySelectorAll(".sol-pill")[originals.length];
    var distance = firstOfNextSet.getBoundingClientRect().left - firstOriginal.getBoundingClientRect().left;
    if (!(distance > 0)) return;

    var pxPerSecond = 35; // slow, steady pace
    var duration = Math.max(18, distance / pxPerSecond);

    track.style.setProperty("--marquee-distance", distance + "px");
    track.style.setProperty("--marquee-duration", duration + "s");

    var io = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) track.classList.add("pill-anim");
      });
    }, { threshold: 0.3 });
    io.observe(wrap);
  });

  /* ---------- 3. Partners logo slider ---------- */
  (function () {
    var slider = document.querySelector(".partners-slider");
    if (!slider) return;

    var track = slider.querySelector(".partners-track");
    if (!track) return;

    var logos = track.querySelectorAll(".partner-logo");
    if (logos.length < 2) return;

    logos.forEach(function (logo) {
      var clone = logo.cloneNode(true);
      clone.setAttribute("aria-hidden", "true");
      track.appendChild(clone);
    });

    var timer = null;
    var isMoving = false;

    function slideNext() {
      if (isMoving) return;

      var firstLogo = track.querySelector(".partner-logo");
      var gap = parseFloat(getComputedStyle(track).gap) || 0;
      var distance = firstLogo.getBoundingClientRect().width + gap;

      isMoving = true;
      track.style.transform = "translate3d(-" + distance + "px, 0, 0)";

      track.addEventListener("transitionend", function onSlideEnd(e) {
        if (e.propertyName !== "transform") return;
        track.removeEventListener("transitionend", onSlideEnd);
        track.style.transition = "none";
        track.appendChild(firstLogo);
        track.style.transform = "translate3d(0, 0, 0)";
        void track.offsetWidth;
        track.style.transition = "transform 2.5s cubic-bezier(.22, .61, .36, 1)";
        isMoving = false;
      });
    }

    function start() {
      if (timer) return;
      timer = setInterval(slideNext, 3000);
    }

    var sliderObserver = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) start();
      });
    }, { threshold: 0.3 });

    sliderObserver.observe(slider);
  })();

  /* ---------- 4. Count-up numbers ---------- */
  function animateCount(el) {
    var target = parseFloat(el.getAttribute("data-count"));
    var suffix = el.getAttribute("data-suffix") || "";
    var comma = el.hasAttribute("data-comma");
    var dur = 1600, start = null;
    function format(n) { return comma ? Math.round(n).toLocaleString("en-US") : n; }
    function step(ts) {
      if (!start) start = ts;
      var p = Math.min((ts - start) / dur, 1);
      var eased = 1 - Math.pow(1 - p, 3);
      var val = target * eased;
      el.textContent = format(target % 1 === 0 ? Math.round(val) : val.toFixed(1)) + suffix;
      if (p < 1) requestAnimationFrame(step);
      else el.textContent = format(target) + suffix;
    }
    requestAnimationFrame(step);
  }
  var countObserver = new IntersectionObserver(function (entries) {
    entries.forEach(function (e) {
      if (e.isIntersecting) {
        animateCount(e.target);
        countObserver.unobserve(e.target);
      }
    });
  }, { threshold: 0.6 });
  document.querySelectorAll("[data-count]").forEach(function (el) { countObserver.observe(el); });

  /* ---------- 4. FAQ — left list drives right answer panel ---------- */
  var faqItems = document.querySelectorAll(".faq-item");
  var pNum = document.getElementById("faqPanelNum");
  var pTitle = document.getElementById("faqPanelTitle");
  var pA1 = document.getElementById("faqPanelA1");
  var pA2 = document.getElementById("faqPanelA2");
  var faqPanel = document.getElementById("faqPanel");

  function selectFaq(item) {
    faqItems.forEach(function (i) { i.classList.remove("active"); });
    item.classList.add("active");
    if (!pTitle) return;
    var num = item.querySelector(".num").textContent;
    if (pNum) pNum.textContent = num;
    pTitle.textContent = item.getAttribute("data-title");
    pA1.textContent = item.getAttribute("data-a1");
    pA2.textContent = item.getAttribute("data-a2");
    // tiny fade pulse
    faqPanel.classList.remove("swap");
    void faqPanel.offsetWidth;
    faqPanel.classList.add("swap");
  }

  faqItems.forEach(function (item) {
    item.querySelector(".faq-q").addEventListener("click", function () {
      selectFaq(item);
    });
  });

  /* ---------- 5. Card carousels (Case Studies / Blog) — slides one card at a time ---------- */
  function initCarousel(trackId, prevId, nextId) {
    var track = document.getElementById(trackId);
    if (!track) return;
    var viewport = track.parentElement;
    var prevBtn = document.getElementById(prevId);
    var nextBtn = document.getElementById(nextId);
    var slides = track.querySelectorAll(".blog-slide");
    var total = slides.length;
    var index = 0;
    var autoTimer = null;

    function perView() {
      var first = slides[0];
      if (!first) return 1;
      var gap = parseFloat(getComputedStyle(track).gap) || 0;
      var cardWidth = first.getBoundingClientRect().width;
      return Math.max(1, Math.round((viewport.clientWidth + gap) / (cardWidth + gap)));
    }
    function maxIndex() { return Math.max(0, total - perView()); }

    function step() {
      var first = slides[0];
      var gap = parseFloat(getComputedStyle(track).gap) || 20;
      return first.getBoundingClientRect().width + gap;
    }

    function render() {
      if (index > maxIndex()) index = maxIndex();
      track.style.transform = "translateX(" + (-index * step()) + "px)";
      if (prevBtn) prevBtn.disabled = index === 0;
      if (nextBtn) nextBtn.disabled = index === maxIndex();
    }

    function go(dir) {
      var mi = maxIndex();
      index += dir;
      if (index > mi) index = 0;        // loop to start
      if (index < 0) index = mi;        // loop to end
      render();
    }

    function restart() {
      clearInterval(autoTimer);
      autoTimer = setInterval(function () { go(1); }, 3500);
    }

    if (nextBtn) nextBtn.addEventListener("click", function () { go(1); restart(); });
    if (prevBtn) prevBtn.addEventListener("click", function () { go(-1); restart(); });

    var rt;
    window.addEventListener("resize", function () {
      clearTimeout(rt);
      rt = setTimeout(render, 150);
    });

    render();
    restart();
  }
  initCarousel("csTrack", "csPrev", "csNext");
  initCarousel("blogTrack", "blogPrev", "blogNext");

  /* ---------- 6. Hero network canvas ---------- */
  var canvas = document.getElementById("heroCanvas");
  if (!canvas) return;
  var ctx = canvas.getContext("2d");
  var nodes = [], W = 0, H = 0, DPR = Math.min(window.devicePixelRatio || 1, 2);

  function resize() {
    var 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);
    buildNodes();
  }

  function buildNodes() {
    nodes = [];
    // weight the cluster toward the right half of the hero
    var count = Math.max(26, Math.round(W / 36));
    for (var i = 0; i < count; i++) {
      var rightBias = Math.random() * Math.random(); // skews to the right
      var x = W * (0.42 + rightBias * 0.56);
      var y = H * (0.08 + Math.random() * 0.84);
      nodes.push({
        x: x, y: y,
        ox: x, oy: y,
        r: 2 + Math.random() * 2.6,
        phase: Math.random() * Math.PI * 2,
        speed: 0.4 + Math.random() * 0.7,
        amp: 8 + Math.random() * 18,
        person: Math.random() > 0.55
      });
    }
  }

  function drawPerson(n, alpha) {
    ctx.save();
    ctx.globalAlpha = alpha;
    ctx.fillStyle = "#00CC5E";
    // head
    ctx.beginPath();
    ctx.arc(n.x, n.y - n.r * 1.4, n.r * 0.95, 0, Math.PI * 2);
    ctx.fill();
    // body
    ctx.beginPath();
    ctx.moveTo(n.x - n.r * 1.3, n.y + n.r * 1.7);
    ctx.quadraticCurveTo(n.x, n.y - n.r * 0.2, n.x + n.r * 1.3, n.y + n.r * 1.7);
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  }

  var t = 0;
  function frame() {
    ctx.clearRect(0, 0, W, H);
    t += 0.012;

    // update positions (gentle float)
    for (var i = 0; i < nodes.length; i++) {
      var n = nodes[i];
      n.x = n.ox + Math.cos(t * n.speed + n.phase) * n.amp;
      n.y = n.oy + Math.sin(t * n.speed * 0.8 + n.phase) * n.amp * 0.6;
    }

    // connecting lines
    for (var a = 0; a < nodes.length; a++) {
      for (var b = a + 1; b < nodes.length; b++) {
        var dx = nodes[a].x - nodes[b].x;
        var dy = nodes[a].y - nodes[b].y;
        var dist = Math.sqrt(dx * dx + dy * dy);
        if (dist < 130) {
          var op = (1 - dist / 130) * 0.45;
          ctx.strokeStyle = "rgba(0, 171, 79," + op + ")";
          ctx.lineWidth = 1;
          ctx.beginPath();
          ctx.moveTo(nodes[a].x, nodes[a].y);
          ctx.lineTo(nodes[b].x, nodes[b].y);
          ctx.stroke();
        }
      }
    }

    // nodes
    for (var k = 0; k < nodes.length; k++) {
      var nd = nodes[k];
      var pulse = 0.55 + 0.45 * Math.sin(t * 1.5 + nd.phase);
      if (nd.person) {
        drawPerson(nd, 0.5 + pulse * 0.5);
      } else {
        ctx.beginPath();
        ctx.fillStyle = "rgba(0, 204, 94," + (0.4 + pulse * 0.5) + ")";
        ctx.arc(nd.x, nd.y, nd.r, 0, Math.PI * 2);
        ctx.fill();
        // glow
        ctx.beginPath();
        ctx.fillStyle = "rgba(0, 204, 94, 0.08)";
        ctx.arc(nd.x, nd.y, nd.r * 3.4, 0, Math.PI * 2);
        ctx.fill();
      }
    }

    requestAnimationFrame(frame);
  }

  window.addEventListener("resize", resize);
  resize();
  requestAnimationFrame(frame);
})();

/* =========================
   Request Proposal Modal JS
   ========================= */
(function () {
  'use strict';
  var modal = document.getElementById('gxModal');
  if (!modal) return;
  var overlay = modal.querySelector('.gx-modal-overlay');
  var closeEls = modal.querySelectorAll('[data-close]');
  var form = document.getElementById('gxProposalForm');
  var feedback = document.getElementById('gxModalFeedback');
  var firstInput = form ? form.querySelector('input[name="name"]') : null;

  function openModal() {
    modal.classList.add('open');
    modal.setAttribute('aria-hidden', 'false');
    document.body.style.overflow = 'hidden';
    if (firstInput) firstInput.focus();
  }
  function closeModal() {
    modal.classList.remove('open');
    modal.setAttribute('aria-hidden', 'true');
    document.body.style.overflow = '';
    if (feedback) feedback.textContent = '';
  }

  closeEls.forEach(function (el) { el.addEventListener('click', function (e) { e.preventDefault(); closeModal(); }); });
  if (overlay) overlay.addEventListener('click', closeModal);
  document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && modal.classList.contains('open')) closeModal(); });

  // Attach to any visible "Request Proposal" button/link with .btn-gx
  document.querySelectorAll('a.btn-gx, button.btn-gx').forEach(function (btn) {
    var txt = (btn.textContent || '').trim();
    if (/request proposal/i.test(txt)) {
      btn.addEventListener('click', function (e) { e.preventDefault(); openModal(); });
    }
  });

  if (form) {
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      var name = (form.elements['name'] || {}).value || '';
      var email = (form.elements['email'] || {}).value || '';
      name = name.trim(); email = email.trim();
      if (!name) { if (feedback) feedback.textContent = 'Please enter your full name.'; form.elements['name'].focus(); return; }
      if (!email || !/^\S+@\S+\.\S+$/.test(email)) { if (feedback) feedback.textContent = 'Please enter a valid email address.'; form.elements['email'].focus(); return; }
      if (typeof grecaptcha !== 'undefined' && grecaptcha.getResponse() === '') {
        if (feedback) feedback.textContent = 'Please complete the reCAPTCHA.';
        return;
      }

      var sendBtn = document.getElementById('gxSendBtn');
      if (sendBtn) { sendBtn.disabled = true; sendBtn.innerHTML = 'Sending...'; }

      fetch('proposal-handler.php', { method: 'POST', body: new FormData(form) })
        .then(function (r) { return r.json(); })
        .then(function (data) {
          if (feedback) {
            feedback.textContent = data.message;
            feedback.style.color = data.success ? '#00cc5e' : '#ff6b6b';
          }
          if (data.success) {
            if (form) form.reset();
            if (typeof grecaptcha !== 'undefined') grecaptcha.reset();
            setTimeout(function () { closeModal(); }, 1400);
          }
        })
        .catch(function () {
          if (feedback) { feedback.textContent = 'Something went wrong. Please try again later.'; feedback.style.color = '#ff6b6b'; }
        })
        .finally(function () {
          if (sendBtn) { sendBtn.disabled = false; sendBtn.innerHTML = 'Send <i class="bi bi-arrow-right"></i>'; }
        });
    });
  }
})();

/* ============================================================
   About section — subtle animated network background
   ============================================================ */
(function () {
  "use strict";
  var canvas = document.getElementById("aboutCanvas");
  if (!canvas) return;
  var ctx = canvas.getContext("2d");
  var pts = [], W = 0, H = 0, running = false, raf = null;
  var DPR = Math.min(window.devicePixelRatio || 1, 2);

  function resize() {
    var r = canvas.getBoundingClientRect();
    W = r.width; H = r.height;
    if (!W || !H) return;
    canvas.width = W * DPR; canvas.height = H * DPR;
    ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
    build();
  }

  function build() {
    pts = [];
    var count = Math.max(28, Math.round((W * H) / 26000));
    for (var i = 0; i < count; i++) {
      pts.push({
        x: Math.random() * W,
        y: Math.random() * H,
        vx: (Math.random() - 0.5) * 0.35,
        vy: (Math.random() - 0.5) * 0.35,
        r: 1.4 + Math.random() * 2.2
      });
    }
  }

  function frame() {
    ctx.clearRect(0, 0, W, H);
    for (var i = 0; i < pts.length; i++) {
      var p = pts[i];
      p.x += p.vx; p.y += p.vy;
      if (p.x < 0 || p.x > W) p.vx *= -1;
      if (p.y < 0 || p.y > H) p.vy *= -1;
    }
    // links
    for (var a = 0; a < pts.length; a++) {
      for (var b = a + 1; b < pts.length; b++) {
        var dx = pts[a].x - pts[b].x, dy = pts[a].y - pts[b].y;
        var d = Math.sqrt(dx * dx + dy * dy);
        if (d < 150) {
          ctx.strokeStyle = "rgba(0,135,62," + (1 - d / 150) * 0.16 + ")";
          ctx.lineWidth = 1;
          ctx.beginPath();
          ctx.moveTo(pts[a].x, pts[a].y);
          ctx.lineTo(pts[b].x, pts[b].y);
          ctx.stroke();
        }
      }
    }
    // dots
    for (var k = 0; k < pts.length; k++) {
      ctx.beginPath();
      ctx.fillStyle = "rgba(0,135,62,0.30)";
      ctx.arc(pts[k].x, pts[k].y, pts[k].r, 0, Math.PI * 2);
      ctx.fill();
    }
    raf = requestAnimationFrame(frame);
  }

  // Only animate while the section is on screen (saves CPU)
  var io = new IntersectionObserver(function (entries) {
    entries.forEach(function (e) {
      if (e.isIntersecting && !running) {
        running = true; raf = requestAnimationFrame(frame);
      } else if (!e.isIntersecting && running) {
        running = false; cancelAnimationFrame(raf);
      }
    });
  }, { threshold: 0 });

  window.addEventListener("resize", resize);
  resize();
  io.observe(canvas);
})();

/* ============================================================
   Services section — flowing aurora gradient background
   ============================================================ */
(function () {
  "use strict";
  var canvas = document.getElementById("servicesCanvas");
  if (!canvas) return;
  var ctx = canvas.getContext("2d");
  var pts = [], W = 0, H = 0, running = false, raf = null;
  var DPR = Math.min(window.devicePixelRatio || 1, 2);

  function resize() {
    var r = canvas.getBoundingClientRect();
    W = r.width; H = r.height;
    if (!W || !H) return;
    canvas.width = W * DPR; canvas.height = H * DPR;
    ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
    build();
  }

  function build() {
    pts = [];
    var count = Math.max(28, Math.round((W * H) / 26000));
    for (var i = 0; i < count; i++) {
      pts.push({
        x: Math.random() * W,
        y: Math.random() * H,
        vx: (Math.random() - 0.5) * 0.35,
        vy: (Math.random() - 0.5) * 0.35,
        r: 1.4 + Math.random() * 2.2
      });
    }
  }

  function frame() {
    ctx.clearRect(0, 0, W, H);
    for (var i = 0; i < pts.length; i++) {
      var p = pts[i];
      p.x += p.vx; p.y += p.vy;
      if (p.x < 0 || p.x > W) p.vx *= -1;
      if (p.y < 0 || p.y > H) p.vy *= -1;
    }
    // links
    for (var a = 0; a < pts.length; a++) {
      for (var b = a + 1; b < pts.length; b++) {
        var dx = pts[a].x - pts[b].x, dy = pts[a].y - pts[b].y;
        var d = Math.sqrt(dx * dx + dy * dy);
        if (d < 150) {
          ctx.strokeStyle = "rgba(0,135,62," + (1 - d / 150) * 0.16 + ")";
          ctx.lineWidth = 1;
          ctx.beginPath();
          ctx.moveTo(pts[a].x, pts[a].y);
          ctx.lineTo(pts[b].x, pts[b].y);
          ctx.stroke();
        }
      }
    }
    // dots
    for (var k = 0; k < pts.length; k++) {
      ctx.beginPath();
      ctx.fillStyle = "rgba(0,135,62,0.30)";
      ctx.arc(pts[k].x, pts[k].y, pts[k].r, 0, Math.PI * 2);
      ctx.fill();
    }
    raf = requestAnimationFrame(frame);
  }

  // Only animate while the section is on screen (saves CPU)
  var io = new IntersectionObserver(function (entries) {
    entries.forEach(function (e) {
      if (e.isIntersecting && !running) {
        running = true; raf = requestAnimationFrame(frame);
      } else if (!e.isIntersecting && running) {
        running = false; cancelAnimationFrame(raf);
      }
    });
  }, { threshold: 0 });

  window.addEventListener("resize", resize);
  resize();
  io.observe(canvas);
})();
