/*Disable all dev mods for complex components if the user forgot to disable them in the admin area*/ document.addEventListener("DOMContentLoaded", () => { document.querySelectorAll(".dev-edite-mode").forEach((el) => { if (el.classList.contains("is-on")) { el.classList.remove("is-on"); } }); }); /* ============================================================================= Wistia Play/Pause On View (ultra-lazy mount, LOOP, NO UI) START ============================================================================= */ window.__DF_UTILS__ = window.__DF_UTILS__ || { onReady(fn) { if (document.readyState !== "loading") fn(); else document.addEventListener("DOMContentLoaded", fn); }, debounce(fn, delay) { let t; return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), delay); }; }, }; (() => { const { onReady, debounce } = window.__DF_UTILS__; const SELECTOR_WRAP = "[data-external-video-play-on-view]"; const SELECTOR_ID = ".video-data-id"; const SELECTOR_MOUNT = ".auto-wistia-start"; const prefersReducedMotion = window.matchMedia( "(prefers-reduced-motion: reduce)" ).matches; const saveData = !!(navigator.connection && navigator.connection.saveData); const SHOULD_AUTOPLAY = !(prefersReducedMotion || saveData); const WISTIA = { corePromise: null, mediaPromises: new Map(), // hashedId -> Promise }; function loadScriptOnce(src) { return new Promise((resolve, reject) => { const existing = Array.from(document.scripts).find((s) => s.src === src); if (existing) return resolve(true); const s = document.createElement("script"); s.src = src; s.async = true; s.onload = () => resolve(true); s.onerror = () => reject(new Error("Failed to load script: " + src)); document.head.appendChild(s); }); } function ensureWistiaCore() { if (WISTIA.corePromise) return WISTIA.corePromise; WISTIA.corePromise = loadScriptOnce( "https://fast.wistia.com/assets/external/E-v1.js" ); return WISTIA.corePromise; } function ensureWistiaMediaJsonp(hashedId) { if (!hashedId) return Promise.resolve(false); if (WISTIA.mediaPromises.has(hashedId)) return WISTIA.mediaPromises.get(hashedId); const p = loadScriptOnce( `https://fast.wistia.com/embed/medias/${hashedId}.jsonp` ); WISTIA.mediaPromises.set(hashedId, p); return p; } function getWistiaId(wrap) { return (wrap.querySelector(SELECTOR_ID)?.textContent || "").trim(); } function getMount(wrap) { return wrap.querySelector(SELECTOR_MOUNT); } function buildEmbedEl(hashedId) { const el = document.createElement("div"); // Try to disable UI via embed options (plus CSS below will hard-hide it). el.className = `wistia_embed wistia_async_${hashedId}` + ` videoFoam=true` + ` muted=true` + ` silentAutoPlay=allow` + ` controlsVisibleOnLoad=false` + ` playButton=false` + ` smallPlayButton=false` + ` volumeControl=false` + ` fullscreenButton=false` + ` settingsControl=false`; el.style.width = "100%"; el.style.height = "100%"; return el; } function whenWistiaReady(hashedId) { return new Promise((resolve) => { window._wq = window._wq || []; window._wq.push({ id: hashedId, onReady: function (video) { resolve(video); }, }); }); } async function mountPlayer(state) { if (state.isMounted) return state.player; const mountEl = state.mountEl; if (!mountEl) return null; state.isMounted = true; await ensureWistiaCore(); await ensureWistiaMediaJsonp(state.wistiaId); mountEl.innerHTML = ""; mountEl.appendChild(buildEmbedEl(state.wistiaId)); const player = await whenWistiaReady(state.wistiaId); state.player = player; // Force mute for background playback try { player.mute(); } catch (e) {} // Bind loop once (guarded) if (!state._loopBound) { state._loopBound = true; // When video ends -> restart (loop) try { player.bind("end", () => { // Only loop if still "active" (in view) if (!state.isActive) return; try { player.time(0); } catch (e) {} if (SHOULD_AUTOPLAY) { try { player.play(); } catch (e) {} } }); } catch (e) {} } return player; } function safePause(state) { try { state.player?.pause?.(); } catch (e) {} } function safePlay(state) { if (!SHOULD_AUTOPLAY) return; try { state.player?.play?.(); } catch (e) {} } class WistiaPlayOnView { constructor(wrap) { this.wrap = wrap; this.wistiaId = getWistiaId(wrap); this.mountEl = getMount(wrap); this.player = null; this.isMounted = false; this.isActive = false; this._loopBound = false; this._onResize = debounce(() => {}, 150); this.init(); } init() { if (!this.wistiaId || !this.mountEl) return; const margin = this.wrap.getAttribute("data-io-root-margin") || "0px 0px -10% 0px"; const threshold = parseFloat(this.wrap.getAttribute("data-io-threshold")) || 0.1; this._io = new IntersectionObserver( async (entries) => { const entry = entries[0]; if (!entry) return; if (entry.isIntersecting) { this.isActive = true; await mountPlayer(this); // Start playback on enter safePlay(this); } else { this.isActive = false; // Pause when leaving safePause(this); } }, { root: null, rootMargin: margin, threshold } ); this._io.observe(this.wrap); window.addEventListener("resize", this._onResize, { passive: true }); } } function initAll() { const wraps = Array.from(document.querySelectorAll(SELECTOR_WRAP)); wraps.forEach((w) => { if (w.dataset.dfWistiaPlayOnViewInited === "true") return; w.dataset.dfWistiaPlayOnViewInited = "true"; new WistiaPlayOnView(w); }); } onReady(initAll); })(); /**************************************** * Slider card-liner START ***************************************/ document.addEventListener("DOMContentLoaded", () => { const sliders = document.querySelectorAll(".card-swiper-felx-wrapper"); if (!sliders.length) return; sliders.forEach((sliderEl) => { let scrollbarEl = sliderEl.querySelector(".swiper-scrollbar"); if (!scrollbarEl) { const parent = sliderEl.closest(".card-swiper-felx-wrapper-pagination"); if (parent) { scrollbarEl = parent.querySelector(".swiper-scrollbar"); } } if (!scrollbarEl) { console.warn("РІС™ пёЏ noscrollbar found:", sliderEl); return; } const swiper = new Swiper(sliderEl, { loop: false, preloadImages: false, updateOnImagesReady: false, lazy: false, slidesPerView: "auto", spaceBetween: 24, grabCursor: true, scrollbar: { el: scrollbarEl, hide: false, draggable: true, }, }); const drag = scrollbarEl.querySelector(".swiper-scrollbar-drag"); if (!drag) return; drag.style.transform = "none"; drag.style.left = "0"; drag.style.position = "absolute"; drag.style.pointerEvents = "none"; function updateScrollbarFill() { const progress = Math.max(0, Math.min(1, swiper.progress || 0)); drag.style.width = progress * 100 + "%"; } updateScrollbarFill(); swiper.on("setTranslate", updateScrollbarFill); swiper.on("slideChange", updateScrollbarFill); swiper.on("resize", updateScrollbarFill); }); }); /**************************************** * Slider card-liner END ***************************************/ /**************************************** * Lightbox video START ***************************************/ /**************************************** * Lightbox video START ***************************************/ document.addEventListener("DOMContentLoaded", function () { const lightboxes = document.querySelectorAll("[class*='lightbox-video']"); lightboxes.forEach((lb) => { const jsonScript = lb.querySelector(".w-json"); const videoEl = lb.querySelector(".video-data-url"); if (!jsonScript || !videoEl) return; const raw = videoEl.textContent || ""; const videoUrl = raw .replace(/&/g, "&") .replace(/\s+/g, "") .replace(/\.+$/, "") .trim(); if (!videoUrl) return; // ------------------------------------ // Vimeo ID // ------------------------------------ function getVimeoId(url) { try { const u = new URL(url); const parts = u.pathname.split("/").filter(Boolean); for (let i = parts.length - 1; i >= 0; i--) { if (/^\d+$/.test(parts[i])) return parts[i]; } } catch {} return /^\d+$/.test(url) ? url : null; } // ------------------------------------ // YouTube ID // ------------------------------------ function getYouTubeId(url) { try { const parsed = new URL(url); if (parsed.searchParams.get("v")) { return parsed.searchParams.get("v"); } const parts = parsed.pathname.split("/"); const embedIndex = parts.indexOf("embed"); if (embedIndex !== -1 && parts[embedIndex + 1]) { return parts[embedIndex + 1].split("?")[0]; } } catch {} const match = url.match(/youtu\.be\/([^?]+)/); return match?.[1] || null; } // ------------------------------------ // Wistia ID // ------------------------------------ function getWistiaId(url) { try { const u = new URL(url); const parts = u.pathname.split("/").filter(Boolean); const mediasIndex = parts.indexOf("medias"); if (mediasIndex !== -1 && parts[mediasIndex + 1]) { return parts[mediasIndex + 1]; } } catch {} return null; } let embedUrl = ""; let htmlCode = ""; const vimeoId = getVimeoId(videoUrl); const youtubeId = getYouTubeId(videoUrl); const wistiaId = getWistiaId(videoUrl); // ------------------------------------ // Vimeo EMBED // ------------------------------------ if (vimeoId) { embedUrl = `https://player.vimeo.com/video/${vimeoId}?autoplay=1&muted=1&loop=1&autopause=0&playsinline=1&title=0&byline=0&portrait=0`; htmlCode = ``; } // ------------------------------------ // YouTube EMBED // ------------------------------------ else if (youtubeId) { embedUrl = `https://www.youtube.com/embed/${youtubeId}?autoplay=1&mute=1&loop=1&playlist=${youtubeId}&playsinline=1&controls=1`; htmlCode = ``; } // ------------------------------------ // Wistia EMBED // ------------------------------------ else if (wistiaId) { embedUrl = `https://fast.wistia.net/embed/iframe/${wistiaId}?autoplay=1&muted=1&playsinline=1`; htmlCode = ` `; } // ------------------------------------ // MP4 / DIRECT VIDEO // ------------------------------------ else if (videoUrl.endsWith(".mp4")) { embedUrl = videoUrl; htmlCode = ` `; } // ------------------------------------ // Unsupported format в†’ пропускаєРСР С• // ------------------------------------ else { return; } const jsonData = { items: [ { type: "video", url: embedUrl, html: htmlCode, thumbnailUrl: "", width: 940, height: 528, }, ], group: "", }; jsonScript.textContent = JSON.stringify(jsonData); }); }); /**************************************** * Lightbox video END ***************************************/ /**************************************** * Lightbox video END ***************************************/ /**************************************** * Start code Reveal text from opacity code ***************************************/ const splitTypes = document.querySelectorAll("[reveal-type-color]"); if (splitTypes.length > 0) { splitTypes.forEach((char) => { const text = new SplitType(char, { types: ["chars", "words"] }); gsap.fromTo( text.chars, { opacity: 0.5, }, { scrollTrigger: { trigger: char, start: "top 90%", end: "bottom 40%", scrub: true, markers: false, }, opacity: 1, // кінцеве значення stagger: 0.05, ease: "power2.out", } ); }); } /**************************************** * End code Reveal text from opacity code ***************************************/ /* ============================================================================= 6. Marquee (safe init + no double-run) START ============================================================================= */ window.Webflow ||= []; window.Webflow.push(() => { const SELECTOR = ".marquee"; const DEFAULT_SPEED = 0.6; // px per frame at ~60fps (keeps your current behavior) // Respect reduced motion if ( window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches ) return; const marquees = document.querySelectorAll(SELECTOR); if (!marquees.length) return; marquees.forEach((parent) => { // Prevent double initialization (common reason for console noise + duplicated content) if (parent.dataset.marqueeInit === "1") return; parent.dataset.marqueeInit = "1"; const track = parent.querySelector(".marquee_track"); if (!track) return; const originalChildren = Array.from(track.children); const originalCount = originalChildren.length; if (!originalCount) return; // Duplicate content safely (cloning nodes avoids HTML parsing edge-cases) const frag1 = document.createDocumentFragment(); const frag2 = document.createDocumentFragment(); originalChildren.forEach((node) => { frag1.appendChild(node.cloneNode(true)); frag2.appendChild(node.cloneNode(true)); }); track.appendChild(frag1); track.appendChild(frag2); const speedAttr = parseFloat(parent.getAttribute("data-speed")); const speedPerFrame = Number.isFinite(speedAttr) ? speedAttr : DEFAULT_SPEED; const direction = parent.dataset.direction === "right" ? 1 : -1; let offset = 0; let cycleWidth = 0; let rafId = 0; let lastTs = 0; function computeCycleWidth() { const kids = Array.from(track.children); if (kids.length < originalCount) return 0; let sum = 0; for (let i = 0; i < originalCount; i++) { sum += kids[i].getBoundingClientRect().width; } return sum; } function normalizeOffset() { if (!cycleWidth) return; if (direction === -1) { while (Math.abs(offset) > cycleWidth) offset += cycleWidth; } else { while (offset > 0) offset -= cycleWidth; } } function refresh() { cycleWidth = computeCycleWidth(); normalizeOffset(); } // Initial measure after layout is ready requestAnimationFrame(() => { refresh(); const tick = (ts) => { if (!lastTs) lastTs = ts; const dt = Math.min(64, ts - lastTs); // clamp for tab switching lastTs = ts; if (cycleWidth) { const delta = speedPerFrame * (dt / 16.6667) * direction; offset += delta; if (direction === -1 && Math.abs(offset) > cycleWidth) offset += cycleWidth; if (direction === 1 && offset > 0) offset -= cycleWidth; track.style.transform = `translate3d(${offset}px, 0, 0)`; } rafId = requestAnimationFrame(tick); }; rafId = requestAnimationFrame(tick); }); // Recalculate on resize (font swap, responsive changes) const onResize = () => refresh(); window.addEventListener("resize", onResize, { passive: true }); // Stop animation on pagehide (prevents rAF leaks / warnings in some setups) const onPageHide = () => { if (rafId) cancelAnimationFrame(rafId); window.removeEventListener("resize", onResize); window.removeEventListener("pagehide", onPageHide); }; window.addEventListener("pagehide", onPageHide, { passive: true }); }); }); /* ============================================================================= 6. Marquee (safe init + no double-run) END ============================================================================= */ /**************************************** * Slider testimonial START ***************************************/ document.addEventListener("DOMContentLoaded", () => { const testimonialSliders = document.querySelectorAll( ".testimonial-swiper-slider" ); if (!testimonialSliders.length) return; testimonialSliders.forEach((sliderEl) => { const scrollbarEl = sliderEl.querySelector(".swiper-scrollbar"); const swiper = new Swiper(sliderEl, { loop: false, preloadImages: false, updateOnImagesReady: false, lazy: false, slidesPerView: 1, effect: "fade", fadeEffect: { crossFade: true, }, spaceBetween: 0, centeredSlides: true, grabCursor: true, scrollbar: { el: scrollbarEl, hide: false, }, pagination: { el: sliderEl.querySelector(".swiper-pagination"), clickable: true, }, on: { init: () => { // fade-in ефект РїСЂРё завантаженні const slides = sliderEl.querySelectorAll(".swiper-slide"); slides.forEach((slide, i) => { slide.style.opacity = "0"; slide.style.transform = "translateY(20px)"; setTimeout(() => { slide.style.transition = "opacity 0.6s ease, transform 0.6s ease"; slide.style.opacity = "1"; slide.style.transform = "translateY(0)"; }, 150 * i); }); }, }, }); // ==== КастоРСР Р…Р В° лінія заповнення ==== const drag = scrollbarEl?.querySelector(".swiper-scrollbar-drag"); if (!drag) return; drag.style.transform = "none"; drag.style.left = "0"; drag.style.position = "absolute"; drag.style.pointerEvents = "none"; function updateScrollbarFill() { const progress = Math.max(0, Math.min(1, swiper.progress || 0)); drag.style.width = progress * 100 + "%"; } updateScrollbarFill(); swiper.on("setTranslate", updateScrollbarFill); swiper.on("slideChange", updateScrollbarFill); swiper.on("resize", updateScrollbarFill); }); }); /**************************************** * Slider testimonial END ***************************************/ /* ============================================================================= Open FAQ START ============================================================================= */ document.addEventListener("click", function (event) { const element = event.target.closest('[js-faq-collapse="true"]'); if (element) { if (!element.classList.contains("open")) { document .querySelectorAll('[js-faq-collapse="true"].open') .forEach(function (item) { if (item !== element) { item.click(); } }); element.classList.add("open"); } else { element.classList.remove("open"); } } }); /* ============================================================================= Open FAQ END ============================================================================= */ /* ============================================================================= Slider for scorecard block mobile devices with timeline START ============================================================================= */ document.addEventListener("DOMContentLoaded", () => { let heroSwiper = null; let progressInterval = null; let observer = null; let isInView = false; function initHeroSwiper() { const heroSlider = document.querySelector(".hero-block-swiper-scorecard"); const progressLine = document.querySelector(".active-scrolle-slide"); if (!heroSlider || !progressLine) return; if (window.innerWidth <= 767 && !heroSwiper) { heroSwiper = new Swiper(heroSlider, { slidesPerView: 1, preloadImages: false, updateOnImagesReady: false, lazy: false, loop: true, effect: "fade", fadeEffect: { crossFade: true }, allowTouchMove: true, grabCursor: true, }); const progressTime = 4000; function startProgress() { if (!isInView) return; clearInterval(progressInterval); progressLine.style.transition = "none"; progressLine.style.width = "0%"; setTimeout(() => { progressLine.style.transition = `width ${progressTime}ms linear`; progressLine.style.width = "100%"; }, 50); progressInterval = setInterval(() => { heroSwiper.slideNext(); startProgress(); }, progressTime); } function stopProgress() { clearInterval(progressInterval); progressLine.style.transition = "none"; } heroSlider.addEventListener("mouseenter", stopProgress); heroSlider.addEventListener("mouseleave", startProgress); observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { isInView = entry.isIntersecting; if (isInView) { startProgress(); } else { stopProgress(); } }); }, { threshold: 0.3, } ); observer.observe(heroSlider); heroSwiper.on("init", startProgress); heroSwiper.on("slideChange", startProgress); heroSwiper.init(); } else if (window.innerWidth > 767 && heroSwiper) { heroSwiper.destroy(true, true); heroSwiper = null; clearInterval(progressInterval); if (observer) observer.disconnect(); progressLine.style.width = "0%"; } } initHeroSwiper(); window.addEventListener("resize", () => { clearTimeout(window.__heroResizeTimer); window.__heroResizeTimer = setTimeout(initHeroSwiper, 300); }); }); /* ============================================================================= Slider for scorecard block mobile devices with timeline END ============================================================================= */ /* ============================================================================= 8. Simple Custom Tabs (.tab-wrapper) START /* ============================================================ AUTO TABS + PROGRESS + MOBILE SWIPER (≤800px) Fully rebuilt, optimized, with complete mobile support =============================================================== */ (() => { const { onReady } = window.__DF_UTILS__ || { onReady: (fn) => { if (document.readyState !== "loading") fn(); else document.addEventListener("DOMContentLoaded", fn); }, }; onReady(() => { const tabs = Array.from(document.querySelectorAll(".menu_tab")); const panels = Array.from(document.querySelectorAll(".content_tab")); const progressLine = document.querySelector(".active-progress-line"); if (!tabs.length || !panels.length || !progressLine) return; // Mobile slider container const mobileSlider = document.querySelector(".menu-tabs-slider"); let currentIndex = 0; const duration = 11500; let rAF = null; let startTs = 0; let elapsedBeforePause = 0; let paused = false; let swiper = null; /* ---------------------------- RESET PROGRESS -----------------------------*/ function resetProgress() { progressLine.style.width = "0%"; cancelAnimationFrame(rAF); elapsedBeforePause = 0; startTs = 0; } /* ---------------------------- START PROGRESS -----------------------------*/ function startProgress() { cancelAnimationFrame(rAF); startTs = 0; const tick = (ts) => { if (paused) return (rAF = requestAnimationFrame(tick)); if (!startTs) startTs = ts; const elapsed = elapsedBeforePause + (ts - startTs); const pct = Math.min((elapsed / duration) * 100, 100); progressLine.style.width = pct + "%"; if (pct >= 100) { goToNextTab(); return; } rAF = requestAnimationFrame(tick); }; rAF = requestAnimationFrame(tick); } /* ---------------------------- SWITCH TAB -----------------------------*/ function switchTab(index) { currentIndex = index; tabs.forEach((t) => t.classList.remove("is-active")); panels.forEach((p) => p.classList.remove("is-active", "visible-anime")); const tab = tabs[index]; const panel = panels[index]; if (tab) tab.classList.add("is-active"); if (panel) { panel.classList.add("is-active"); void panel.offsetWidth; panel.classList.add("visible-anime"); } if (swiper && swiper.activeIndex !== index) { swiper.slideTo(index); } resetProgress(); startProgress(); } /* ---------------------------- NEXT TAB -----------------------------*/ function goToNextTab() { const next = currentIndex + 1 < panels.length ? currentIndex + 1 : 0; switchTab(next); } /* ---------------------------- TAB CLICK (desktop + mobile) -----------------------------*/ tabs.forEach((tab, i) => { tab.addEventListener("click", () => switchTab(i)); }); /* ---------------------------- MOBILE SWIPER (≤800) -----------------------------*/ function initMobileSwiper() { if (!mobileSlider || window.innerWidth > 800) return; mobileSlider.classList.add("swiper"); swiper = new Swiper(".menu-tabs-slider", { slidesPerView: "auto", preloadImages: false, updateOnImagesReady: false, lazy: false, spaceBetween: 14, freeMode: false, resistanceRatio: 0.8, }); swiper.on("slideChange", () => { const idx = swiper.activeIndex; switchTab(idx); }); } /* ---------------------------- PAUSE ON HOVER (desktop only) -----------------------------*/ const hoverTarget = document.querySelector(".block-card-design") || document.querySelector(".content_tab_wrap"); if (hoverTarget && window.innerWidth > 800) { hoverTarget.addEventListener("mouseenter", () => { paused = true; const w = parseFloat(progressLine.style.width) || 0; elapsedBeforePause = (w / 100) * duration; }); hoverTarget.addEventListener("mouseleave", () => { paused = false; startTs = 0; }); } /* ---------------------------- INIT -----------------------------*/ initMobileSwiper(); switchTab(0); }); })(); /* ============================================================================= 8. Simple Custom Tabs (.tab-wrapper) END ============================================================================= */ /* ========================================================================== Show More / Show Less Team (mobile only, CTA-aware) ========================================================================== */ (function () { const LIMIT_ROWS = 2; const BREAKPOINT = 767; const BUTTON_HTML = `
`; function updateTeamGrid() { document.querySelectorAll(".content-grid-team").forEach((container) => { const items = Array.from( container.querySelectorAll(".card-team:not(.card-team-cta)") ); const cta = container.querySelector(".card-team-cta"); if (!items.length) return; /* ----------------------------------------- Calculate visible limit based on grid cols ----------------------------------------- */ const cols = getComputedStyle(container).gridTemplateColumns.split(" ").length; const limit = cols * LIMIT_ROWS; /* ----------------------------------------- Cleanup previous button ----------------------------------------- */ const next = container.nextElementSibling; if (next?.classList.contains("show-more-wrapper")) { next.remove(); } /* ----------------------------------------- Reset state ----------------------------------------- */ items.forEach((i) => (i.style.display = "")); if (cta) cta.style.display = ""; /* ----------------------------------------- Mobile logic only ----------------------------------------- */ if (window.innerWidth <= BREAKPOINT && items.length > limit) { const hiddenItems = items.slice(limit); // Hide extra cards hiddenItems.forEach((i) => (i.style.display = "none")); // Hide CTA initially if (cta) cta.style.display = "none"; // Insert button const wrapper = document.createElement("div"); wrapper.innerHTML = BUTTON_HTML; const btnWrap = wrapper.firstElementChild; container.parentNode.insertBefore(btnWrap, container.nextSibling); const btn = btnWrap.querySelector(".show-more"); const label = btn.querySelector(".button-md"); btn.addEventListener("click", (e) => { e.preventDefault(); const isExpanded = btn.classList.toggle("expanded"); if (isExpanded) { // SHOW ALL hiddenItems.forEach((i) => (i.style.display = "")); if (cta) cta.style.display = ""; label.textContent = "Show less team"; } else { // HIDE BACK hiddenItems.forEach((i) => (i.style.display = "none")); if (cta) cta.style.display = "none"; label.textContent = "Show more team"; container.scrollIntoView({ behavior: "smooth", block: "start", }); } }); } }); } /* ----------------------------------------- Init + resize ----------------------------------------- */ window.addEventListener("resize", updateTeamGrid); if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", updateTeamGrid); } else { updateTeamGrid(); } })(); /* ========================================================================== 13. “Show More/Less” Button END ========================================================================== */ /* ========================================================================== Visual-solution-tabs START ========================================================================== */ window.Webflow ||= []; window.Webflow.push(() => { const tabWrapper = document.querySelector(".visual-solution-tabs"); if (!tabWrapper) return; const tabs = tabWrapper.querySelectorAll(".switch-visual-solution-tab"); const contents = tabWrapper.querySelectorAll( ".item-block-content-visual-tab" ); if (!tabs.length || !contents.length) return; contents.forEach((c) => c.classList.remove("is-active", "is-visible")); tabs[0].classList.add("is-active"); contents[0].classList.add("is-active", "is-visible"); tabs.forEach((tab, index) => { tab.addEventListener("click", () => { if (tab.classList.contains("is-active")) return; tabs.forEach((t) => t.classList.remove("is-active")); contents.forEach((c) => c.classList.remove("is-active", "is-visible")); tab.classList.add("is-active"); const target = contents[index]; if (target) { target.classList.add("is-active"); setTimeout(() => target.classList.add("is-visible"), 50); } }); }); }); /* ========================================================================== Visual-solution-tabs END ========================================================================== */ /**************************************** * Slider TESTIMONIAL TIME LINE mob START ***************************************/ document.addEventListener("DOMContentLoaded", () => { const sliders = document.querySelectorAll( ".flex-block-testimonial-and-pagin, .flex-block-testimonial-and-pagin-type-2" ); if (!sliders.length) return; sliders.forEach((slider) => { const AUTOPLAY_DURATION = 11500; const swiper = new Swiper(slider, { slidesPerView: 1, preloadImages: false, updateOnImagesReady: false, lazy: false, effect: "fade", fadeEffect: { crossFade: true }, loop: true, autoplay: { delay: AUTOPLAY_DURATION, disableOnInteraction: false, }, speed: 400, }); const progressLine = slider.querySelector(".active-progress-line"); const swiperWrapper = slider.querySelector( ".swiper-wrapper.is-testimonial-line, .swiper-wrapper.is-tab" ); if (!progressLine || !swiperWrapper) return; let interval; let paused = false; function startProgressBar() { clearInterval(interval); progressLine.style.width = "0%"; const step = 100 / (AUTOPLAY_DURATION / 20); let progress = 0; interval = setInterval(() => { if (paused) return; progress += step; if (progress >= 100) progress = 100; progressLine.style.width = progress + "%"; }, 20); } swiper.on("autoplay", startProgressBar); swiper.on("slideChange", startProgressBar); swiperWrapper.addEventListener("mouseenter", () => { paused = true; swiper.autoplay.stop(); }); swiperWrapper.addEventListener("mouseleave", () => { paused = false; swiper.autoplay.start(); }); startProgressBar(); }); }); /**************************************** * Slider TESTIMONIAL TIME LINE mob END ***************************************/ /**************************************** * Slider TAB TIME LINE mob START ***************************************/ document.addEventListener("DOMContentLoaded", () => { const sliders = document.querySelectorAll( ".flex-block-testimonial-and-pagin-tab" ); sliders.forEach((slider) => { if (slider.classList.contains("swiper-initialized")) return; const swiper = new Swiper(slider, { slidesPerView: 1, preloadImages: false, updateOnImagesReady: false, lazy: false, effect: "fade", fadeEffect: { crossFade: true }, loop: true, autoplay: { delay: 11500, disableOnInteraction: false, }, speed: 400, }); const progressLine = slider.parentElement.querySelector( ".active-progress-line" ); const wrapper = slider.querySelector(".swiper-wrapper.is-tab"); if (!progressLine || !wrapper) return; let progress = 0; const duration = 11500; let interval; let paused = false; function startProgress() { clearInterval(interval); progress = 0; progressLine.style.width = "0%"; interval = setInterval(() => { if (paused) return; progress += 100 / (duration / 20); progressLine.style.width = `${progress}%`; if (progress >= 100) clearInterval(interval); }, 20); } swiper.on("slideChangeTransitionStart", () => { progressLine.style.width = "0%"; }); swiper.on("slideChangeTransitionEnd", startProgress); wrapper.addEventListener("mouseenter", () => { paused = true; swiper.autoplay.stop(); }); wrapper.addEventListener("mouseleave", () => { paused = false; swiper.autoplay.start(); }); startProgress(); }); }); /* ============================================================================= 16. New scroll block component (pairs): desktop scrub & mobile reveal (safe) ============================================================================= */ (() => { // Local utils (so we don't depend on window.__DF_UTILS__) const onReady = (fn) => { if (document.readyState !== "loading") fn(); else document.addEventListener("DOMContentLoaded", fn, { once: true }); }; const waitFor = (checkFn, interval = 100, timeout = 5000) => new Promise((resolve, reject) => { const start = Date.now(); (function loop() { try { if (checkFn()) return resolve(true); } catch (e) { // ignore check errors and continue polling } if (Date.now() - start > timeout) return reject(new Error("waitFor timeout")); setTimeout(loop, interval); })(); }); onReady(() => { // Early exit if there are no blocks on the page const wrappers = document.querySelectorAll( ".scrolling_content-and-media-new" ); const fallbackBoxes = document.querySelectorAll( ".scrolling_content-box-new" ); if (!wrappers.length && !fallbackBoxes.length) return; waitFor( () => typeof gsap !== "undefined" && typeof ScrollTrigger !== "undefined", 100, 7000 ) .then(() => { gsap.registerPlugin(ScrollTrigger); const pairs = []; // Primary structure: wrapper contains content + media gsap.utils .toArray(".scrolling_content-and-media-new") .forEach((wrapper) => { const content = wrapper.querySelector(".scrolling_content-box-new"); const media = wrapper.querySelector(".scrolling_media_wrap-new"); if (content && media) pairs.push({ wrapper, content, media }); }); // Fallback: content followed by media if (!pairs.length) { gsap.utils.toArray(".scrolling_content-box-new").forEach((box) => { const next = box.nextElementSibling; if (next && next.matches(".scrolling_media_wrap-new")) { const wrapper = box.closest(".scrolling_content-and-media-new") || box.parentElement; pairs.push({ wrapper, content: box, media: next }); } }); } if (!pairs.length) return; const getOffset = (c, m) => (m && m.getAttribute("data-media-offset")) || (c && c.getAttribute("data-media-offset")) || "3rem"; // Initial state pairs.forEach(({ content, media }) => { const off = getOffset(content, media); gsap.set(content, { opacity: 0 }); gsap.set(media, { opacity: 0, y: off }); }); function setupDesktop({ content, media }) { const D1 = 20, D2 = 40, D3 = 30; const offset = getOffset(content, media); gsap .timeline({ defaults: { ease: "none", overwrite: "auto" }, scrollTrigger: { trigger: content, start: "top 50%", end: "top 0%", scrub: true, invalidateOnRefresh: true, }, }) .fromTo(content, { opacity: 0 }, { opacity: 1, duration: D1 }) .to(content, { opacity: 1, duration: D2 }) .to(content, { opacity: 0, duration: D3 }); ScrollTrigger.create({ trigger: content, start: "top 50%", end: "top -11%", invalidateOnRefresh: true, onEnter: () => gsap.fromTo( media, { opacity: 0, y: offset }, { opacity: 1, y: 0, duration: 0.5, ease: "power2.out", overwrite: "auto", } ), onEnterBack: () => gsap.fromTo( media, { opacity: 0, y: offset }, { opacity: 1, y: 0, duration: 0.5, ease: "power2.out", overwrite: "auto", } ), onLeave: () => gsap.to(media, { opacity: 0, y: offset, duration: 0.3, ease: "power2.out", overwrite: "auto", }), onLeaveBack: () => gsap.to(media, { opacity: 0, y: offset, duration: 0.3, ease: "power2.out", overwrite: "auto", }), }); } function setupMobile({ wrapper, content, media }) { const offset = getOffset(content, media); gsap.set([content, media], { opacity: 0 }); gsap.set(media, { y: offset }); gsap .timeline({ defaults: { ease: "power2.out", overwrite: "auto" }, scrollTrigger: { trigger: wrapper || content, start: "top 50%", toggleActions: "play none none none", once: true, invalidateOnRefresh: true, }, }) .fromTo( [content, media], { opacity: 0, y: (i, el) => (el === media ? offset : "3rem") }, { opacity: 1, y: 0, duration: 0.8, stagger: 0 } ); } const mm = gsap.matchMedia(); mm.add("(min-width: 992px)", () => pairs.forEach(setupDesktop)); mm.add("(max-width: 991px)", () => pairs.forEach(setupMobile)); // Refresh after full load (images/fonts can shift layout) window.addEventListener("load", () => ScrollTrigger.refresh(), { passive: true, }); }) .catch(() => { // GSAP/ScrollTrigger not available; do nothing }); }); })(); /* ============================================================================= 14. Pagination hide state (robust observers) ============================================================================= */ (() => { const { onReady } = window.__DF_UTILS__; const PAGINATION_SELECTOR = ".pagination"; const COUNT_SELECTOR = ".w-page-count"; function normalize(text) { return (text || "") .replace(/\u00A0/g, " ") .replace(/\s+/g, " ") .trim(); } function readTotalPages(paginationEl) { const countEl = paginationEl.querySelector(COUNT_SELECTOR); if (!countEl) return null; const text = normalize(countEl.textContent); const m = text.match(/^(\d+)\s*\/\s*(\d+)$/); if (m) { const total = parseInt(m[2], 10); if (!Number.isNaN(total)) return total; } const aria = countEl.getAttribute("aria-label") || ""; const ariaMatch = aria.match(/of\s+(\d+)/i); if (ariaMatch) { const total = parseInt(ariaMatch[1], 10); if (!Number.isNaN(total)) return total; } return null; } function updateVisibility(paginationEl) { const total = readTotalPages(paginationEl); if (total === null) { paginationEl.removeAttribute("data-hidden"); return; } total <= 1 ? paginationEl.setAttribute("data-hidden", "true") : paginationEl.removeAttribute("data-hidden"); } function observeCount(paginationEl) { const countEl = paginationEl.querySelector(COUNT_SELECTOR); if (!countEl) return; updateVisibility(paginationEl); const mo = new MutationObserver(() => setTimeout(() => updateVisibility(paginationEl), 0) ); mo.observe(countEl, { subtree: true, childList: true, characterData: true, }); } function attach() { const paginationEl = document.querySelector(PAGINATION_SELECTOR); if (!paginationEl) return; observeCount(paginationEl); } onReady(attach); const outer = new MutationObserver(() => { const paginationEl = document.querySelector(PAGINATION_SELECTOR); if (!paginationEl) return; observeCount(paginationEl); }); outer.observe(document.body, { childList: true, subtree: true }); [ "fs-cmsfilter-update", "fs-cmsfilter-reset", "fs-cmsfilter-change", "fs-cmsload", ].forEach((evt) => { window.addEventListener(evt, () => setTimeout(attach, 0), { passive: true, }); }); })(); /**************************************** * Slider featured-new mob START ***************************************/ document.addEventListener("DOMContentLoaded", () => { const solutionSliders = document.querySelectorAll(".list-item-featured"); const featuredSliders = document.querySelectorAll(".list-item-featured-new"); const MOBILE_BREAKPOINT = 980; function initSlider(sliderEl) { const scrollbarEl = sliderEl.parentElement.querySelector(".swiper-scrollbar"); let swiperInstance = null; function createSwiper() { swiperInstance = new Swiper(sliderEl, { loop: false, preloadImages: false, updateOnImagesReady: false, lazy: false, slidesPerView: "auto", spaceBetween: 32, scrollbar: { el: scrollbarEl, hide: false, }, }); const drag = scrollbarEl.querySelector(".swiper-scrollbar-drag"); if (!drag) return; drag.style.transform = "none"; drag.style.left = "0"; drag.style.position = "absolute"; drag.style.pointerEvents = "none"; function updateScrollbarFill() { const progress = Math.max(0, Math.min(1, swiperInstance.progress || 0)); drag.style.width = progress * 100 + "%"; } updateScrollbarFill(); swiperInstance.on("setTranslate", updateScrollbarFill); swiperInstance.on("slideChange", updateScrollbarFill); swiperInstance.on("resize", updateScrollbarFill); } function destroySwiper() { if (!swiperInstance) return; swiperInstance.destroy(true, true); swiperInstance = null; const wrapper = sliderEl.querySelector(".swiper-wrapper"); if (wrapper) { wrapper.style.transform = ""; wrapper.style.transition = ""; } sliderEl.classList.remove( "swiper-initialized", "swiper-horizontal", "swiper-backface-hidden", "swiper-android" ); } function checkWidth() { if (window.innerWidth <= MOBILE_BREAKPOINT) { if (!swiperInstance) createSwiper(); } else { destroySwiper(); } } checkWidth(); window.addEventListener("resize", checkWidth); } solutionSliders.forEach(initSlider); featuredSliders.forEach(initSlider); }); /**************************************** * Sticky scroll anime CTA START ***************************************/ document.addEventListener("DOMContentLoaded", () => { // Early exit if the block does not exist on the page const wrappers = document.querySelectorAll( ".scrolling-block-animation-wrapper" ); if (!wrappers.length) return; // Guard: if GSAP or ScrollTrigger are not available, do nothing if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") return; gsap.registerPlugin(ScrollTrigger); wrappers.forEach((wrapper) => { // Scope targets inside the current wrapper const widthTarget = wrapper.querySelector(".medium-item-image-scrolling"); // Collect ALL fade targets that should behave the same way const fadeTargets = [ wrapper.querySelector(".scrolling-active-content"), wrapper.querySelector(".mask-black-scrolling"), ].filter(Boolean); // remove nulls // Guard clause in case structure is incomplete if (!widthTarget || !fadeTargets.length) return; // Ensure fade targets start hidden (safe even if CSS already sets this) gsap.set(fadeTargets, { opacity: 0 }); // Build a scrubbed timeline tied to the scroll progress of the wrapper const tl = gsap.timeline({ defaults: { ease: "none" }, scrollTrigger: { trigger: wrapper, start: "top bottom", end: "bottom bottom", scrub: true, invalidateOnRefresh: true, // markers: true, }, }); // 0% → 80% of the timeline: grow width 40% → 100% // NOTE: Initial width (40%) should be set in CSS on .medium-item-image-scrolling tl.to(widthTarget, { width: "100%", duration: 0.8 }); // Fade in both elements in the same phase (like the original fadeTarget) tl.to(fadeTargets, { opacity: 1, duration: 0.3 }, 0.5); }); // Refresh after images/fonts load to get correct ScrollTrigger measurements window.addEventListener("load", () => { if (typeof ScrollTrigger !== "undefined") ScrollTrigger.refresh(); }); }); /**************************************** * GSAP SCROLL SECTION HERO SECTION PLATFORM (safe) *****************************************/ window.Webflow ||= []; window.Webflow.push(() => { // Early exit if targets are not on the page const marqueeEl = document.querySelector(".group-marguee"); if (!marqueeEl) return; // Guard: GSAP / ScrollTrigger must exist if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") return; gsap.registerPlugin(ScrollTrigger); // Optional: avoid double-init if Webflow re-runs scripts if (marqueeEl.dataset.gsapPlatformInit === "1") return; marqueeEl.dataset.gsapPlatformInit = "1"; gsap.set(marqueeEl, { rotate: 0, scale: 1 }); gsap.to(marqueeEl, { rotate: -7, scale: 1.25, ease: "none", scrollTrigger: { trigger: marqueeEl, start: "top 40%", end: "bottom top", scrub: 1.3, invalidateOnRefresh: true, }, }); const logoEl = document.querySelector(".logo-platform"); if (logoEl) { gsap.to(logoEl, { opacity: 0, duration: 3, ease: "none", scrollTrigger: { trigger: marqueeEl, start: "top 40%", end: "top 20%", scrub: true, invalidateOnRefresh: true, }, }); } }); /*Code for Sticky card START */ document.addEventListener("DOMContentLoaded", function () { var wrapper = document.querySelector(".sticky-features_stack-wrapper"); if (!wrapper) return; // No wrapper - no script var stacks = Array.prototype.slice.call( wrapper.querySelectorAll(".sticky-features_stack") ); if (!stacks.length) return; var baseStepVh = 100; // 100vh per stack segment var extraTailVh = 50; // extra 20vh at the end var BLUR_MAX = 15; // max blur var totalStacks = stacks.length; var BREAKPOINT = 991; var stackData = []; var wrapperTop = 0; var wrapperHeightPx = 0; var stepHeightPx = 0; var enabled = false; var ticking = false; // Prepare internal data: index, z-index, image & content refs function buildStackData() { stackData = []; stacks.forEach(function (stack, i) { var index = i + 1; stack.classList.add("index-" + index); stack.dataset.index = index; // first stack on top stack.style.zIndex = String(totalStacks - i); // Move image itself var imageEl = stack.querySelector(".sticky-feature_image"); // Wrapper around image - used for blur effect (preferred) var imageWrapper = stack.querySelector(".sticky-feature_image-wrapper"); var content = stack.querySelector(".flex-content-left-media"); // Initial state for content: // - first item visible immediately // - others hidden & slightly to the right if (content) { if (index === 1) { content.style.opacity = "1"; content.style.transform = "translate3d(0px, 0, 0)"; } else { content.style.opacity = "0"; content.style.transform = "translate3d(40px, 0, 0)"; } } var isLast = index === totalStacks; stackData.push({ el: stack, image: imageEl, imageWrapper: imageWrapper, content: content, index: index, isLast: isLast, }); }); } function enableDesktop() { if (enabled) return; enabled = true; buildStackData(); // Set wrapper height: n * 100vh + 20vh wrapper.style.height = totalStacks * baseStepVh + extraTailVh + "vh"; recalc(); update(); // initial state } function disableDesktop() { if (!enabled) return; enabled = false; // Remove inline styles so mobile layout is clean wrapper.style.height = ""; stackData.forEach(function (item) { if (!item) return; if (item.el) { item.el.style.zIndex = ""; } if (item.image) { item.image.style.transform = ""; } if (item.imageWrapper) { item.imageWrapper.style.filter = ""; } if (item.content) { item.content.style.opacity = ""; item.content.style.transform = ""; } }); } function recalc() { if (!enabled) return; var rect = wrapper.getBoundingClientRect(); wrapperTop = rect.top + window.scrollY; wrapperHeightPx = rect.height; stepHeightPx = wrapperHeightPx / totalStacks || 1; } // Content fade/slide animation based on local progress 0..1 function animateContent(item, local) { if (!item.content) return; var el = item.content; // SPECIAL CASE: first item (index === 1) // It starts visible (no fade-in), stays visible most of the segment, // and only fades out near the end. if (item.index === 1) { var disappearStartFirst = 0.7; var disappearEndFirst = 1.0; var opacityFirst = 1; var xFirst = 0; if (local <= 0) { // Before segment: keep fully visible (matches initial state) opacityFirst = 1; xFirst = 0; } else if (local >= 1) { // After segment: fully hidden to the left opacityFirst = 0; xFirst = -40; } else if (local < disappearStartFirst) { // Inside main part: stay fully visible without extra animation opacityFirst = 1; xFirst = 0; } else { // Fade out + slide left only in 0.9..1 var tOutFirst = (local - disappearStartFirst) / (disappearEndFirst - disappearStartFirst || 0.0001); opacityFirst = 1 - tOutFirst; xFirst = -40 * tOutFirst; } el.style.opacity = opacityFirst.toFixed(3); el.style.transform = "translate3d(" + xFirst.toFixed(1) + "px, 0, 0)"; return; // do not run generic animation for first item } // GENERIC CASE: all other items (2, 3, ...) var opacity = 0; var x = 100; // slide from right if (local <= 0) { opacity = 0; x = 100; } else if (local >= 1) { opacity = 0; x = -40; } else { var appearStart = 0.0; var appearEnd = 0.01; var disappearStart = 0.7; var disappearEnd = 1.0; if (local < appearStart) { opacity = 0; x = 100; } else if (local < appearEnd) { var tIn = (local - appearStart) / (appearEnd - appearStart || 0.0001); opacity = tIn; x = 100 * (1 - tIn); // 40 -> 0 } else if (local < disappearStart) { opacity = 1; x = 0; } else if (local < disappearEnd) { var tOut = (local - disappearStart) / (disappearEnd - disappearStart || 0.0001); opacity = 1 - tOut; x = -40 * tOut; // 0 -> -40 } else { opacity = 0; x = -40; } } el.style.opacity = opacity.toFixed(3); el.style.transform = "translate3d(" + x.toFixed(1) + "px, 0, 0)"; } function update() { if (!enabled) { ticking = false; return; } ticking = false; var scrollTop = window.scrollY || window.pageYOffset; var relative = scrollTop - wrapperTop; // scroll inside wrapper (in px) // Above the wrapper: reset all images and content if (relative <= 0) { stackData.forEach(function (item, i) { if (item.image) { item.image.style.transform = "translate3d(0, 0%, 0)"; } if (item.content) { if (i === 0) { // First item visible before scroll item.content.style.opacity = "1"; item.content.style.transform = "translate3d(0px, 0, 0)"; } else { item.content.style.opacity = "0"; item.content.style.transform = "translate3d(40px, 0, 0)"; } } var blurTarget = item.imageWrapper || item.image; if (blurTarget) { // First stack clear, others blurred with BLUR_MAX var blurValue = i === 0 ? 0 : BLUR_MAX; blurTarget.style.filter = "blur(" + blurValue.toFixed(1) + "px)"; } }); return; } // Below the wrapper: lock all images at final state and remove blur if (relative >= wrapperHeightPx) { stackData.forEach(function (item) { if (item.image) { if (item.isLast) { item.image.style.transform = "translate3d(0, 0%, 0)"; } else { item.image.style.transform = "translate3d(0, -100%, 0)"; } } if (item.content) { item.content.style.opacity = "0"; item.content.style.transform = "translate3d(-40px, 0, 0)"; } var blurTarget = item.imageWrapper || item.image; if (blurTarget) { blurTarget.style.filter = "blur(0px)"; } }); return; } // Inside the wrapper: animate step by step var segmentIndex = Math.floor(relative / stepHeightPx); // 0..totalStacks-1 if (segmentIndex < 0) segmentIndex = 0; if (segmentIndex > totalStacks - 1) segmentIndex = totalStacks - 1; var segStart = segmentIndex * stepHeightPx; var localSeg = (relative - segStart) / stepHeightPx; var segProgress = Math.max(0, Math.min(localSeg, 1)); // 0..1 stackData.forEach(function (item, i) { var start = i * stepHeightPx; var local = (relative - start) / stepHeightPx; var clamped = Math.max(0, Math.min(local, 1)); // 0..1 per stack // Image Y animation (except last stack) if (item.image) { if (item.isLast) { item.image.style.transform = "translate3d(0, 0%, 0)"; } else { var yPercent = -100 * clamped; // 0 -> -100 item.image.style.transform = "translate3d(0," + yPercent + "%,0)"; } } // Content fade/slide (with special case for first item) animateContent(item, clamped); // Blur animation for current / next stack var blurTarget = item.imageWrapper || item.image; if (!blurTarget) return; var blurValue; if (i < segmentIndex) { // All previous stacks fully revealed blurValue = 0; } else if (i === segmentIndex) { // Current stack clear blurValue = 0; } else if (i === segmentIndex + 1 && segmentIndex < totalStacks - 1) { // Next stack: blur BLUR_MAX -> 0 in sync with current segment progress blurValue = BLUR_MAX * (1 - segProgress); } else { // Others still blurred blurValue = BLUR_MAX; } blurTarget.style.filter = "blur(" + blurValue.toFixed(1) + "px)"; }); } function onScroll() { if (!enabled) return; if (!ticking) { window.requestAnimationFrame(update); ticking = true; } } function handleResizeOrInit() { var isDesktop = window.innerWidth > BREAKPOINT; if (isDesktop && !enabled) { enableDesktop(); } else if (!isDesktop && enabled) { disableDesktop(); } else if (isDesktop && enabled) { recalc(); update(); } } // Listeners window.addEventListener("scroll", onScroll); window.addEventListener("resize", handleResizeOrInit); // Initial run handleResizeOrInit(); }); /*Code for Sticky card end */ /*Code SLIDER OLD TAB START */ document.addEventListener("DOMContentLoaded", () => { const sliders = document.querySelectorAll( ".flex-block-testimonial-and-pagin-slider" ); if (!sliders.length) return; sliders.forEach((slider) => { const wrapper = slider.querySelector(".swiper-wrapper"); if (!wrapper) return; const swiper = new Swiper(slider, { slidesPerView: 1, preloadImages: false, updateOnImagesReady: false, lazy: false, effect: "fade", fadeEffect: { crossFade: true }, loop: true, autoplay: { delay: 11500, disableOnInteraction: false, }, speed: 400, }); // Pause Swiper on hover wrapper.addEventListener("mouseenter", () => swiper.autoplay.stop()); wrapper.addEventListener("mouseleave", () => swiper.autoplay.start()); }); }); /*Code SLIDER OLD TAB END */ /*Form insert code attribute START*/ document.addEventListener("DOMContentLoaded", () => { // Find the wrapper const wrapper = document.querySelector(".form-request-wrapper"); if (!wrapper) return; // Find source element with URL const srcEl = wrapper.querySelector(".data-button-submit-url-src"); if (!srcEl) return; // Extract the URL text const urlValue = srcEl.textContent.trim(); if (!urlValue) return; // Find the submit button inside the form const submitBtn = wrapper.querySelector("[data-button-submit-url]"); if (!submitBtn) return; // Apply URL into data-button-submit-url attribute submitBtn.setAttribute("data-button-submit-url", urlValue); }); /*Form insert code attribute END*/