Skip to content
(function () {
  "use strict";

  document.documentElement.classList.add("has-motion");

  var motionMedia;
  var sectionTriggers = [];
  var sectionScrollFrame;
  var themeMedia = window.matchMedia("(prefers-color-scheme: dark)");

  function getStoredTheme() {
    try {
      var theme = localStorage.getItem("theme");
      return theme === "light" || theme === "dark" ? theme : null;
    } catch (_error) {
      return null;
    }
  }

  function applyTheme(theme) {
    var dark = theme === "dark";
    document.documentElement.dataset.theme = theme;
    document.documentElement.style.colorScheme = theme;

    document.querySelectorAll(".theme-toggle").forEach(function (button) {
      var action = dark ? "Switch to light mode" : "Switch to dark mode";
      button.setAttribute("aria-label", action);
      button.setAttribute("aria-pressed", String(dark));
      button.setAttribute("title", action);

      var label = button.querySelector("[data-theme-label]");
      if (label) {
        label.textContent = dark ? "Light mode" : "Dark mode";
      }
    });
  }

  function initTheme() {
    applyTheme(getStoredTheme() || (themeMedia.matches ? "dark" : "light"));
  }

  window.toggleTheme = function () {
    var theme =
      document.documentElement.dataset.theme === "dark" ? "light" : "dark";

    try {
      localStorage.setItem("theme", theme);
    } catch (_error) {
      // The selected theme still applies for the current page.
    }

    applyTheme(theme);
  };

  themeMedia.addEventListener("change", function (event) {
    if (!getStoredTheme()) {
      applyTheme(event.matches ? "dark" : "light");
    }
  });

  function prefersReducedMotion() {
    return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  }

  function setMobileMenuState(open) {
    var menu = document.getElementById("mobile-menu");
    var button = document.querySelector(".menu-toggle");

    if (!menu || !button) {
      return;
    }

    button.setAttribute("aria-expanded", String(open));

    if (open) {
      menu.classList.remove("dn");
      if (window.gsap && !prefersReducedMotion()) {
        gsap.fromTo(
          menu.querySelectorAll("a"),
          { autoAlpha: 0, y: 12 },
          {
            autoAlpha: 1,
            y: 0,
            duration: 0.55,
            ease: "power3.out",
            stagger: 0.06,
            overwrite: true,
          },
        );
      }
      return;
    }

    if (
      !window.gsap ||
      prefersReducedMotion() ||
      menu.classList.contains("dn")
    ) {
      menu.classList.add("dn");
      return;
    }

    gsap.to(menu.querySelectorAll("a"), {
      autoAlpha: 0,
      y: -8,
      duration: 0.2,
      ease: "power2.in",
      stagger: 0.025,
      overwrite: true,
      onComplete: function () {
        menu.classList.add("dn");
        gsap.set(menu.querySelectorAll("a"), {
          clearProps: "opacity,transform,visibility",
        });
      },
    });
  }

  window.toggleMobileMenu = function () {
    var menu = document.getElementById("mobile-menu");
    if (menu) {
      setMobileMenuState(menu.classList.contains("dn"));
    }
  };

  window.closeMobileMenu = function () {
    setMobileMenuState(false);
  };

  function setActiveSection(sectionId) {
    document.querySelectorAll("[data-section-link]").forEach(function (link) {
      var active = link.dataset.sectionLink === sectionId;
      link.classList.toggle("is-active", active);

      if (active) {
        link.setAttribute("aria-current", "location");
      } else {
        link.removeAttribute("aria-current");
      }
    });
  }

  function getHashTarget(hash) {
    if (!hash || hash === "#") {
      return null;
    }

    try {
      return document.getElementById(decodeURIComponent(hash.slice(1)));
    } catch (_error) {
      return null;
    }
  }

  function scrollToHash(hash, behavior) {
    var target = getHashTarget(hash);
    if (!target) {
      return;
    }

    if (sectionScrollFrame) {
      cancelAnimationFrame(sectionScrollFrame);
    }

    sectionScrollFrame = requestAnimationFrame(function () {
      target.scrollIntoView({ behavior: behavior, block: "start" });
      setActiveSection(target.id);
      sectionScrollFrame = null;
    });
  }

  function handleSectionLinkClick(event) {
    var link = event.target.closest("a[data-section-link]");
    if (!link) {
      return;
    }

    var url = new URL(link.href, window.location.href);
    if (
      url.origin !== window.location.origin ||
      url.pathname !== window.location.pathname ||
      !getHashTarget(url.hash)
    ) {
      return;
    }

    event.preventDefault();
    if (window.location.hash !== url.hash) {
      history.pushState(null, "", url.hash);
    }
    scrollToHash(url.hash, "smooth");
  }

  function initSectionNavigation() {
    sectionTriggers.forEach(function (trigger) {
      trigger.kill();
    });
    sectionTriggers = [];

    if (!window.ScrollTrigger) {
      return;
    }

    gsap.utils.toArray("[data-scroll-section]").forEach(function (section) {
      sectionTriggers.push(
        ScrollTrigger.create({
          trigger: section,
          start: "top center",
          end: "bottom center",
          onToggle: function (self) {
            if (self.isActive) {
              setActiveSection(section.id);
            }
          },
        }),
      );
    });
  }

  function directMotionItems(group) {
    return gsap.utils
      .toArray("[data-motion-item]", group)
      .filter(function (item) {
        return item.closest("[data-motion-group]") === group;
      });
  }

  function initAnimations() {
    if (!window.gsap) {
      document.documentElement.classList.remove("has-motion");
      return;
    }

    if (motionMedia) {
      motionMedia.revert();
    }

    if (window.ScrollTrigger) {
      gsap.registerPlugin(ScrollTrigger);
    }

    initSectionNavigation();
    motionMedia = gsap.matchMedia();
    motionMedia.add(
      {
        animate: "(prefers-reduced-motion: no-preference)",
      },
      function (context) {
        var groups = gsap.utils.toArray("[data-motion-group]");

        if (!context.conditions.animate) {
          gsap.set("[data-motion-item]", {
            autoAlpha: 1,
            clearProps: "transform",
          });
          gsap.set(".editorial-rule", { scaleX: 1 });
          return;
        }

        groups.forEach(function (group) {
          var items = directMotionItems(group);
          var rules = gsap.utils.toArray(".editorial-rule", group);
          if (!items.length) {
            return;
          }

          var timeline = gsap.timeline({
            defaults: { ease: "power3.out" },
            scrollTrigger: window.ScrollTrigger
              ? {
                  trigger: group,
                  start: "top 88%",
                  once: true,
                }
              : undefined,
          });

          timeline.fromTo(
            items,
            { autoAlpha: 0, y: 20 },
            {
              autoAlpha: 1,
              y: 0,
              duration: 0.8,
              stagger: 0.08,
              clearProps: "transform,visibility",
            },
          );

          if (rules.length) {
            timeline.fromTo(
              rules,
              { scaleX: 0 },
              {
                scaleX: 1,
                duration: 0.75,
                stagger: 0.08,
                clearProps: "transform",
              },
              0.08,
            );
          }
        });

        if (window.ScrollTrigger) {
          gsap.to(".scroll-progress", {
            scaleX: 1,
            ease: "none",
            scrollTrigger: {
              start: 0,
              end: "max",
              scrub: 0.25,
            },
          });
        }
      },
    );

    if (window.ScrollTrigger) {
      ScrollTrigger.refresh();
    }
  }

  function initPage() {
    initTheme();
    initAnimations();
    scrollToHash(window.location.hash, "instant");
  }

  document.addEventListener("click", handleSectionLinkClick);
  window.addEventListener("hashchange", function () {
    scrollToHash(window.location.hash, "smooth");
  });
  document.addEventListener("DOMContentLoaded", initPage);
  document.addEventListener("htmx:afterSettle", initPage);
})();