(() => {
const PRESETS = {
aurora: {
base: "#0b1020",
colors: ["#0b1020", "#1c3c68", "#3dd6d0"],
gradient: "linear-gradient(135deg, #0b1020 0%, #1c3c68 45%, #3dd6d0 100%)",
mesh: "radial-gradient(circle at 15% 20%, rgba(61, 214, 208, 0.65) 0%, rgba(61, 214, 208, 0) 55%), radial-gradient(circle at 80% 25%, rgba(88, 120, 255, 0.6) 0%, rgba(88, 120, 255, 0) 55%), radial-gradient(circle at 45% 85%, rgba(8, 14, 30, 0.9) 0%, rgba(8, 14, 30, 0) 60%)",
},
sunset: {
base: "#1d0c08",
colors: ["#2c0f09", "#ff7a59", "#ffd082"],
gradient: "linear-gradient(120deg, #2c0f09 0%, #ff7a59 45%, #ffd082 100%)",
mesh: "radial-gradient(circle at 20% 25%, rgba(255, 122, 89, 0.65) 0%, rgba(255, 122, 89, 0) 60%), radial-gradient(circle at 80% 30%, rgba(255, 208, 130, 0.6) 0%, rgba(255, 208, 130, 0) 60%), radial-gradient(circle at 50% 80%, rgba(55, 15, 8, 0.85) 0%, rgba(55, 15, 8, 0) 60%)",
},
ocean: {
base: "#061a2e",
colors: ["#061a2e", "#0d5c7f", "#39d2c0"],
gradient: "linear-gradient(140deg, #061a2e 0%, #0d5c7f 45%, #39d2c0 100%)",
mesh: "radial-gradient(circle at 18% 30%, rgba(57, 210, 192, 0.6) 0%, rgba(57, 210, 192, 0) 60%), radial-gradient(circle at 80% 20%, rgba(13, 92, 127, 0.7) 0%, rgba(13, 92, 127, 0) 60%), radial-gradient(circle at 50% 85%, rgba(5, 16, 34, 0.9) 0%, rgba(5, 16, 34, 0) 60%)",
},
"violet-mist": {
base: "#190c2d",
colors: ["#1c0d33", "#7a3bff", "#f4b9ff"],
gradient: "linear-gradient(135deg, #1c0d33 0%, #7a3bff 45%, #f4b9ff 100%)",
mesh: "radial-gradient(circle at 20% 25%, rgba(244, 185, 255, 0.6) 0%, rgba(244, 185, 255, 0) 60%), radial-gradient(circle at 80% 30%, rgba(122, 59, 255, 0.6) 0%, rgba(122, 59, 255, 0) 60%), radial-gradient(circle at 45% 80%, rgba(20, 8, 40, 0.9) 0%, rgba(20, 8, 40, 0) 60%)",
},
"lime-neon": {
base: "#0a1506",
colors: ["#0a1506", "#59ff6f", "#d7ff5c"],
gradient: "linear-gradient(135deg, #0a1506 0%, #59ff6f 45%, #d7ff5c 100%)",
mesh: "radial-gradient(circle at 25% 25%, rgba(89, 255, 111, 0.6) 0%, rgba(89, 255, 111, 0) 60%), radial-gradient(circle at 75% 30%, rgba(215, 255, 92, 0.6) 0%, rgba(215, 255, 92, 0) 60%), radial-gradient(circle at 50% 85%, rgba(10, 21, 6, 0.85) 0%, rgba(10, 21, 6, 0) 60%)",
},
"mono-glass": {
base: "#0f1115",
colors: ["#0f1115", "#3d3f44", "#a8aab0"],
gradient: "linear-gradient(135deg, #0f1115 0%, #3d3f44 45%, #a8aab0 100%)",
mesh: "radial-gradient(circle at 20% 30%, rgba(168, 170, 176, 0.55) 0%, rgba(168, 170, 176, 0) 60%), radial-gradient(circle at 80% 25%, rgba(61, 63, 68, 0.6) 0%, rgba(61, 63, 68, 0) 60%), radial-gradient(circle at 50% 80%, rgba(15, 17, 22, 0.9) 0%, rgba(15, 17, 22, 0) 60%)",
},
"forest-dew": {
base: "#0a1a12",
colors: ["#0a1a12", "#1e5a3a", "#7ee8a5"],
gradient: "linear-gradient(135deg, #0a1a12 0%, #1e5a3a 45%, #7ee8a5 100%)",
mesh: "radial-gradient(circle at 20% 25%, rgba(126, 232, 165, 0.6) 0%, rgba(126, 232, 165, 0) 60%), radial-gradient(circle at 75% 35%, rgba(30, 90, 58, 0.7) 0%, rgba(30, 90, 58, 0) 60%), radial-gradient(circle at 50% 80%, rgba(10, 26, 18, 0.9) 0%, rgba(10, 26, 18, 0) 60%)",
},
"candy-pop": {
base: "#2d0a2a",
colors: ["#2d0a2a", "#ff6b9d", "#ffc857"],
gradient: "linear-gradient(135deg, #2d0a2a 0%, #ff6b9d 45%, #ffc857 100%)",
mesh: "radial-gradient(circle at 25% 20%, rgba(255, 107, 157, 0.65) 0%, rgba(255, 107, 157, 0) 60%), radial-gradient(circle at 80% 30%, rgba(255, 200, 87, 0.6) 0%, rgba(255, 200, 87, 0) 60%), radial-gradient(circle at 50% 85%, rgba(45, 10, 42, 0.9) 0%, rgba(45, 10, 42, 0) 60%)",
},
"midnight-blue": {
base: "#050a1a",
colors: ["#050a1a", "#0a2463", "#247ba0"],
gradient: "linear-gradient(135deg, #050a1a 0%, #0a2463 45%, #247ba0 100%)",
mesh: "radial-gradient(circle at 20% 30%, rgba(36, 123, 160, 0.6) 0%, rgba(36, 123, 160, 0) 60%), radial-gradient(circle at 80% 20%, rgba(10, 36, 99, 0.7) 0%, rgba(10, 36, 99, 0) 60%), radial-gradient(circle at 50% 85%, rgba(5, 10, 26, 0.9) 0%, rgba(5, 10, 26, 0) 60%)",
},
"rose-gold": {
base: "#1a0f0f",
colors: ["#1a0f0f", "#b76e79", "#f7d1ba"],
gradient: "linear-gradient(135deg, #1a0f0f 0%, #b76e79 45%, #f7d1ba 100%)",
mesh: "radial-gradient(circle at 25% 25%, rgba(247, 209, 186, 0.6) 0%, rgba(247, 209, 186, 0) 60%), radial-gradient(circle at 75% 30%, rgba(183, 110, 121, 0.65) 0%, rgba(183, 110, 121, 0) 60%), radial-gradient(circle at 50% 80%, rgba(26, 15, 15, 0.9) 0%, rgba(26, 15, 15, 0) 60%)",
},
};
const DIRECTION_MAP = {
"left-right": { from: [0, 50], to: [100, 50] },
"right-left": { from: [100, 50], to: [0, 50] },
"top-bottom": { from: [50, 0], to: [50, 100] },
"bottom-top": { from: [50, 100], to: [50, 0] },
"diag-lr": { from: [0, 0], to: [100, 100] },
"diag-rl": { from: [100, 0], to: [0, 100] },
};
const supportsCssVars = () =>
window.CSS && CSS.supports && CSS.supports("--kng-agm-test: 0");
const supportsGradients = () =>
window.CSS && CSS.supports && CSS.supports("background-image", "linear-gradient(#000, #fff)");
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
const parsePayload = (element) => {
const raw = element.getAttribute("data-kng-agm");
if (!raw) {
return null;
}
try {
return JSON.parse(raw);
} catch (error) {
return null;
}
};
const isEditor = () =>
Boolean(window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode());
const getPreset = (key) => PRESETS[key] || PRESETS.aurora;
const parseColor = (value) => {
if (!value || typeof value !== "string") {
return null;
}
const hex = value.trim();
if (hex.startsWith("#")) {
const clean = hex.replace("#", "");
if (clean.length === 3) {
const r = parseInt(clean[0] + clean[0], 16);
const g = parseInt(clean[1] + clean[1], 16);
const b = parseInt(clean[2] + clean[2], 16);
return { r, g, b };
}
if (clean.length === 6) {
const r = parseInt(clean.slice(0, 2), 16);
const g = parseInt(clean.slice(2, 4), 16);
const b = parseInt(clean.slice(4, 6), 16);
return { r, g, b };
}
}
const rgbMatch = value.match(/rgba?\(([^)]+)\)/i);
if (rgbMatch) {
const parts = rgbMatch[1].split(",").map((part) => parseFloat(part.trim()));
if (parts.length >= 3) {
return { r: parts[0], g: parts[1], b: parts[2] };
}
}
return null;
};
const toRgba = (value, alpha) => {
const parsed = parseColor(value);
if (!parsed) {
return value;
}
return `rgba(${parsed.r}, ${parsed.g}, ${parsed.b}, ${alpha})`;
};
const buildGradient = (colors) =>
`linear-gradient(135deg, ${colors[0]} 0%, ${colors[1]} 45%, ${colors[2]} 100%)`;
const buildMesh = (colors) => {
const primary = toRgba(colors[0], 0.6);
const secondary = toRgba(colors[1], 0.6);
const deep = toRgba(colors[2], 0.9);
const primaryClear = toRgba(colors[0], 0);
const secondaryClear = toRgba(colors[1], 0);
const deepClear = toRgba(colors[2], 0);
return `radial-gradient(circle at 20% 25%, ${primary} 0%, ${primaryClear} 60%), radial-gradient(circle at 80% 30%, ${secondary} 0%, ${secondaryClear} 60%), radial-gradient(circle at 50% 85%, ${deep} 0%, ${deepClear} 60%)`;
};
const resolveColors = (layer, preset) => {
if (layer && Array.isArray(layer.colors) && layer.colors.length >= 3) {
return layer.colors;
}
return preset.colors;
};
const buildLayerBackground = (layer, preset) => {
const colors = resolveColors(layer, preset);
return layer.type === "mesh" ? buildMesh(colors) : buildGradient(colors);
};
const speedToDuration = (speed) => {
const safe = Math.max(1, Number(speed) || 40);
return `${Math.max(4, Math.round(400 / safe))}s`;
};
const getTarget = (element) => {
if (element.classList.contains("elementor-column")) {
return element.querySelector(".elementor-widget-wrap") || element;
}
return element;
};
const clearLayers = (target) => {
target.querySelectorAll(".kng-agm-layer").forEach((layer) => layer.remove());
const exportPanel = target.querySelector(".kng-agm-export");
if (exportPanel) {
exportPanel.remove();
}
};
const isMobile = () => window.matchMedia("(max-width: 767px)").matches;
const isTablet = () => window.matchMedia("(max-width: 1024px)").matches;
const shouldDisableForDevice = (payload) => {
if (payload.disable?.mobile && isMobile()) {
return true;
}
if (payload.disable?.tablet && !isMobile() && isTablet()) {
return true;
}
return false;
};
const applyFallback = (target, preset) => {
target.style.backgroundColor = preset.base;
target.style.backgroundImage = "none";
};
const buildLayerElement = (layer, payload) => {
const preset = getPreset(layer.preset || payload.preset);
const element = document.createElement("span");
element.className = "kng-agm-layer";
element.style.backgroundImage = buildLayerBackground(layer, preset);
element.style.opacity = layer.opacity ?? 0.7;
element.style.filter = `blur(${layer.blur || 0}px)`;
element.style.backgroundSize = `${layer.size || 200}% ${layer.size || 200}%`;
element.style.backgroundPosition = "0% 50%";
element.style.mixBlendMode = layer.blendMode || payload.blendMode || "normal";
element.style.animationDuration = speedToDuration(layer.speed || payload.speed || 40);
element.style.animationTimingFunction = "ease-in-out";
element.style.animationIterationCount = "infinite";
element.dataset.direction = layer.direction || payload.direction || "left-right";
if (!payload.animate || (payload.scroll && payload.scroll.mode !== "off")) {
element.classList.add("is-static");
element.style.animation = "none";
}
return element;
};
const buildExportCss = (payload) => {
const preset = getPreset(payload.preset || "aurora");
const type = payload.type === "mesh" ? "mesh" : "gradient";
const baseGradient = type === "mesh" ? preset.mesh : preset.gradient;
const direction = payload.direction || "left-right";
const range = DIRECTION_MAP[direction] || DIRECTION_MAP["left-right"];
const duration = speedToDuration(payload.speed || 40);
const opacity = payload.opacity ?? 1;
const blur = payload.blur ?? 0;
const blendMode = payload.blendMode || "normal";
const animate = payload.animate && (!payload.scroll || payload.scroll.mode === "off");
const noise = payload.noise || {};
let css = "";
if (payload.export?.includeFallback) {
css += `.kng-animated-bg{background:${preset.base};}\n`;
}
css += `.kng-animated-bg{position:relative;overflow:hidden;}\n`;
css += `.kng-animated-bg::before{content:\"\";position:absolute;inset:0;background-color:${preset.base};background-image:${baseGradient};background-size:200% 200%;background-position:${range.from[0]}% ${range.from[1]}%;opacity:${opacity};filter:blur(${blur}px);mix-blend-mode:${blendMode};}\n`;
if (animate) {
css += `.kng-animated-bg::before{animation:kng-agm-shift ${duration} ease-in-out infinite;}\n`;
}
if (noise.enabled) {
css += `.kng-animated-bg::after{content:\"\";position:absolute;inset:0;pointer-events:none;opacity:${noise.amount ?? 0.18};background-image:repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.14) 1px, transparent 1px, transparent 3px),repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.08) 1px, transparent 1px, transparent 4px);mix-blend-mode:soft-light;}\n`;
}
css += `@keyframes kng-agm-shift{0%{background-position:${range.from[0]}% ${range.from[1]}%;}100%{background-position:${range.to[0]}% ${range.to[1]}%;}}\n`;
if (payload.export?.includeReducedMotion) {
css += `@media (prefers-reduced-motion: reduce){.kng-animated-bg::before{animation:none;}}\n`;
}
return css.trim();
};
const initExportPanel = (target, payload) => {
if (!payload.export?.enabled || !isEditor()) {
return;
}
const css = buildExportCss(payload);
if (!css) {
return;
}
const panel = document.createElement("div");
panel.className = "kng-agm-export";
panel.innerHTML = ``;
target.insertBefore(panel, target.firstChild);
const button = panel.querySelector("button");
const textarea = panel.querySelector("textarea");
if (!button || !textarea) {
return;
}
button.addEventListener("click", () => {
textarea.select();
try {
navigator.clipboard?.writeText(textarea.value);
} catch (error) {
document.execCommand("copy");
}
button.textContent = "Copied";
setTimeout(() => {
button.textContent = "Copy CSS";
}, 1200);
});
};
const scrollRegistry = new Map();
let scrollBound = false;
let rafPending = false;
const getScrollProgress = (element, mode, start, end) => {
const rangeStart = clamp((start || 0) / 100, 0, 1);
const rangeEnd = clamp((end || 100) / 100, 0, 1);
let raw = 0;
if (mode === "page") {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0;
const maxScroll = Math.max(document.documentElement.scrollHeight - window.innerHeight, 1);
raw = scrollTop / maxScroll;
} else {
const rect = element.getBoundingClientRect();
const viewHeight = window.innerHeight || 1;
const total = rect.height + viewHeight;
raw = total > 0 ? (viewHeight - rect.top) / total : 0;
}
if (rangeEnd <= rangeStart) {
return clamp(raw, 0, 1);
}
return clamp((raw - rangeStart) / (rangeEnd - rangeStart), 0, 1);
};
const applyEasing = (value, easing) => {
if (easing === "ease") {
return value * value * (3 - 2 * value);
}
if (easing === "parallax") {
return clamp(value * 1.15, 0, 1);
}
return value;
};
const resolvePosition = (direction, progress) => {
const map = DIRECTION_MAP[direction] || DIRECTION_MAP["left-right"];
const x = map.from[0] + (map.to[0] - map.from[0]) * progress;
const y = map.from[1] + (map.to[1] - map.from[1]) * progress;
return { x, y };
};
const updateScrollEntry = (entry) => {
const { element, payload, layers } = entry;
if (!element.isConnected) {
scrollRegistry.delete(element);
return;
}
const scroll = payload.scroll || {};
let progress = getScrollProgress(element, scroll.mode, scroll.start, scroll.end);
progress = applyEasing(progress, scroll.easing || "linear");
if (scroll.mode === "hybrid") {
progress = clamp(progress * 0.35, 0, 1);
}
const baseDirection = payload.direction || "left-right";
const basePos = resolvePosition(baseDirection, progress);
element.style.setProperty("--kng-agm-scroll-x", `${basePos.x}%`);
element.style.setProperty("--kng-agm-scroll-y", `${basePos.y}%`);
layers.forEach((layer) => {
const dir = layer.dataset.direction || baseDirection;
const pos = resolvePosition(dir, progress);
layer.style.backgroundPosition = `${pos.x}% ${pos.y}%`;
});
};
const updateScrollAll = () => {
rafPending = false;
scrollRegistry.forEach(updateScrollEntry);
};
const scheduleScrollUpdate = () => {
if (rafPending) {
return;
}
rafPending = true;
window.requestAnimationFrame(updateScrollAll);
};
const registerScroll = (element, payload, layers) => {
scrollRegistry.set(element, { element, payload, layers });
if (!scrollBound) {
window.addEventListener("scroll", scheduleScrollUpdate, { passive: true });
window.addEventListener("resize", scheduleScrollUpdate);
scrollBound = true;
}
scheduleScrollUpdate();
};
const unregisterScroll = (element) => {
scrollRegistry.delete(element);
};
const initElement = (element) => {
const payload = parsePayload(element);
const target = getTarget(element);
if (!payload || !payload.enabled) {
element.classList.remove("kng-agm-scroll-sync");
unregisterScroll(element);
clearLayers(target);
return;
}
if (shouldDisableForDevice(payload)) {
element.classList.remove("kng-agm-scroll-sync");
unregisterScroll(element);
clearLayers(target);
return;
}
const preset = getPreset(payload.preset || "aurora");
if (!supportsCssVars() || !supportsGradients()) {
element.classList.remove("kng-agm-scroll-sync");
unregisterScroll(element);
applyFallback(target, preset);
return;
}
clearLayers(target);
let layersData = Array.isArray(payload.layers) ? payload.layers.slice() : [];
if (payload.adaptive && isMobile()) {
layersData = layersData.slice(0, 2);
target.style.setProperty("--kng-agm-noise-opacity", Math.min(payload.noise?.amount ?? 0.18, 0.1));
target.style.setProperty("--kng-agm-blur", "0px");
}
const layers = [];
if (layersData.length) {
const fragment = document.createDocumentFragment();
layersData.forEach((layer) => {
const elementLayer = buildLayerElement(layer, payload);
layers.push(elementLayer);
fragment.appendChild(elementLayer);
});
target.insertBefore(fragment, target.firstChild);
}
const scrollMode = payload.scroll?.mode || "off";
const allowScroll = scrollMode !== "off" && !(payload.scroll?.reduceMobile && isMobile());
if (allowScroll) {
element.classList.add("kng-agm-scroll-sync");
registerScroll(element, payload, layers);
} else {
element.classList.remove("kng-agm-scroll-sync");
unregisterScroll(element);
}
initExportPanel(target, payload);
};
const initAll = (root) => {
if (!root) {
return;
}
const elements = root.querySelectorAll("[data-kng-agm]");
elements.forEach(initElement);
};
const initGlobal = () => {
initAll(document);
if (window.elementorFrontend && elementorFrontend.hooks) {
const handler = ($scope) => {
const scopeElement = $scope[0] || $scope;
if (!scopeElement) {
return;
}
if (scopeElement.hasAttribute && scopeElement.hasAttribute("data-kng-agm")) {
initElement(scopeElement);
} else {
initAll(scopeElement);
}
};
elementorFrontend.hooks.addAction("frontend/element_ready/section", handler);
elementorFrontend.hooks.addAction("frontend/element_ready/container", handler);
elementorFrontend.hooks.addAction("frontend/element_ready/column", handler);
}
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initGlobal);
} else {
initGlobal();
}
})();