(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);
})();