(function () { const splideScripts = [ "https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/js/splide.min.js", "https://cdn.jsdelivr.net/npm/@splidejs/splide-extension-auto-scroll@0.5.3/dist/js/splide-extension-auto-scroll.min.js" ]; const heroCanvasScripts = [ "https://cdn.prod.website-files.com/66477ba6aef90272351460cc/6a0798ca217f63cb4377bba2_matter.min.txt", "https://cdn.prod.website-files.com/66477ba6aef90272351460cc/696945cab04e62007d0caaee_canvas3.txt" ]; let interactionPromise = null; let splidePromise = null; let heroCanvasPromise = null; function waitForInteraction() { if (interactionPromise) return interactionPromise; interactionPromise = new Promise(resolve => { const events = ["pointerdown", "mousemove", "touchstart", "scroll", "keydown"]; const opts = { once: true, passive: true }; function done() { events.forEach(evt => window.removeEventListener(evt, done, opts)); resolve(); } events.forEach(evt => window.addEventListener(evt, done, opts)); }); return interactionPromise; } function loadScriptOnce(src) { return new Promise(resolve => { const existing = document.querySelector(`script[src="${src}"]`); if (existing) { if (existing.dataset.loaded === "true") return resolve(); existing.addEventListener("load", resolve, { once: true }); existing.addEventListener("error", resolve, { once: true }); return; } const script = document.createElement("script"); script.src = src; script.async = true; script.onload = () => { script.dataset.loaded = "true"; resolve(); }; script.onerror = resolve; document.body.appendChild(script); }); } window.sherLoadSplide = function () { if (window.Splide && window.splide && window.splide.Extensions) return Promise.resolve(); if (splidePromise) return splidePromise; splidePromise = waitForInteraction().then(() => { return splideScripts.reduce((chain, src) => chain.then(() => loadScriptOnce(src)), Promise.resolve()); }); return splidePromise; }; window.sherLoadHeroCanvas = function () { if (window.innerWidth <= 767) return Promise.resolve(); if (heroCanvasPromise) return heroCanvasPromise; heroCanvasPromise = heroCanvasScripts.reduce((chain, src) => chain.then(() => loadScriptOnce(src)), Promise.resolve()); return heroCanvasPromise; }; window.sherLoadHeroCanvas(); })(); function animateCounter(el, target, duration = 2000) { let start = 0; const startTime = performance.now(); function formatNumber(num, decimals, useCommas = true) { if (useCommas) { return num.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); } else { return num.toFixed(decimals); } } function update(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); const current = start + (target.number - start) * progress; const formatted = formatNumber(current, target.decimals, target.useCommas); el.textContent = `${target.prefix || ''}${formatted}${target.suffix || ''}`; if (progress < 1) { requestAnimationFrame(update); } else { el.textContent = `${target.prefix || ''}${formatNumber(target.number, target.decimals, target.useCommas)}${target.suffix || ''}`; } } requestAnimationFrame(update); } document.addEventListener('DOMContentLoaded', () => { const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const el = entry.target; const rawText = el.textContent.trim(); // Safely match number with optional prefix/suffix const match = rawText.match(/([^0-9.,]*)([\d,.]+)([^\d]*)/); if (match) { const prefix = match[1] || ''; const numStr = match[2].replace(/,/g, ''); const suffix = match[3] || ''; const number = parseFloat(numStr); const decimals = (numStr.split('.')[1] || '').length; const useCommas = el.getAttribute('counter-pr') !== 'no-coma'; if (!isNaN(number)) { animateCounter(el, { number, prefix, suffix, decimals, useCommas }); observer.unobserve(el); } else { console.warn(`Invalid number in element:`, el); } } else { console.warn(`No number found in:`, rawText); } } }); }, { threshold: 0.6 }); document.querySelectorAll('.counter-number-pr').forEach(el => { observer.observe(el); }); }); document.addEventListener('DOMContentLoaded', function () { window.sherLoadSplide().then(() => { const baSliders = document.querySelectorAll('.ba-slider'); baSliders.forEach(slider => { const splide = new Splide(slider, { type: 'loop', perPage: 1, focus: 'center', arrows: false, pagination: true, drag: true, // Dragging is enabled by default speed: 600, gap: '20px', autoplay: true, interval: 4000, pauseOnHover: true, pauseOnFocus: true, // Focus on the range input specifically noDrag: 'input, .bas-handle-h', }); splide.mount(); // TARGET THE BEFORE/AFTER INPUTS const inputs = slider.querySelectorAll('input[type="range"]'); inputs.forEach(input => { // 1. When user starts sliding the handle, kill Splide drag and autoplay input.addEventListener('mousedown', () => { splide.Components.Drag.disable(true); splide.Components.Autoplay.pause(); }); input.addEventListener('touchstart', () => { splide.Components.Drag.disable(true); splide.Components.Autoplay.pause(); }, { passive: true }); // 2. When user lets go, give control back to Splide const enableSplide = () => { splide.Components.Drag.disable(false); splide.Components.Autoplay.play(); }; input.addEventListener('mouseup', enableSplide); input.addEventListener('touchend', enableSplide); input.addEventListener('mouseleave', enableSplide); }); }); }); }); document.addEventListener('DOMContentLoaded', function () { // --- 1. CONFIGURATIONS --- const configs = { 'auto-scroll': { type: 'loop', drag: 'free', focus: 'center', arrows: false, pagination: false, autoScroll: { pauseOnHover: true, pauseOnFocus: false, autoStart: true } }, 'video-marquee': { type: 'loop', drag: 'free', focus: 'center', arrows: false, pagination: false, dragAngleThreshold: 30, autoScroll: { pauseOnHover: true, pauseOnFocus: false, autoStart: true } }, 'standard': { type: 'loop', perPage: 1, focus: 'center', arrows: false, pagination: true, autoplay: true, interval: 4000, speed: 600, breakpoints: { 767: { perPage: 1, focus: 0, padding: '0px', gap: '20px' } } } }; window.sherLoadSplide().then(() => { // --- 2. INITIALIZE AUTO-SCROLL SLIDERS --- const autoSelectors = '.vieo-slide-main-wrap, .website-slider-main, .testimonial-wrap-slide'; document.querySelectorAll(autoSelectors).forEach(slider => { const isVideo = slider.classList.contains('vieo-slide-main-wrap'); const isLTR = slider.classList.contains('ltr-slide'); const isTestimonial = slider.classList.contains('testimonial-wrap-slide'); const splide = new Splide(slider, { ...(isVideo ? configs['video-marquee'] : configs['auto-scroll']), perPage: isTestimonial ? 2 : 1, gap: '40px', autoScroll: { ...(isVideo ? configs['video-marquee'].autoScroll : configs['auto-scroll'].autoScroll), speed: (isVideo || !isLTR) ? 0.5 : -0.5, }, breakpoints: { 767: { perPage: 1, gap: '20px' } } }); splide.mount(window.splide.Extensions); // Force instant start splide.on('mounted ready', () => { if (splide.Components.AutoScroll) splide.Components.AutoScroll.play(); }); }); // --- 3. INITIALIZE STANDARD SLIDERS --- const standardSelectors = '.slider-ss-con-wrap, .clients-slider-wrapper-main, .clients-slider-wrapper-main-web'; document.querySelectorAll(standardSelectors).forEach(slider => { const isTestimonialSS = slider.classList.contains('slider-ss-con-wrap'); const splide = new Splide(slider, { ...configs['standard'], interval: isTestimonialSS ? 7000 : 4000, gap: isTestimonialSS ? '50px' : '5px' }); splide.mount(); }); }); // Video click controller for original slides and clones. document.addEventListener('click', async function (e) { const playBtn = e.target.closest('.plyr_cover-icon'); if (!playBtn) return; e.preventDefault(); e.stopPropagation(); const container = playBtn.closest('.video-container'); if (!container) return; const vimeoWrap = container.querySelector('.vimeo-wrapper'); const videoFallback = container.querySelector('.local-video'); const vimeoId = container.getAttribute('data-sher-vimeo-id') || container.getAttribute('data-vimeo-id'); if (!vimeoWrap || !vimeoId) { console.warn("Vimeo ID missing on .video-container"); return; } if (window.sherLoadVimeoPlayerApi) await window.sherLoadVimeoPlayerApi(); if (videoFallback) { videoFallback.pause(); videoFallback.style.display = "none"; } container.classList.add("video-play"); vimeoWrap.innerHTML = ` `; playBtn.style.display = "none"; }); // Fix layout shifts on full page load window.addEventListener('load', () => { document.querySelectorAll('.splide').forEach(s => { if (s.splide) s.splide.refresh(); }); }); }); /** * Force local videos to play ONLY within the Video Marquee. * Scoped to .vieo-slide-main-wrap to prevent site-wide interference. */ function forceMarqueeVideoAutoplay() { const marqueeVideos = document.querySelectorAll('.vieo-slide-main-wrap .local-video'); marqueeVideos.forEach(video => { let hydrated = false; video.querySelectorAll('source[data-src]').forEach(source => { source.src = source.dataset.src; source.removeAttribute('data-src'); hydrated = true; }); video.muted = true; video.setAttribute('muted', ''); if (hydrated) video.load(); const playPromise = video.play(); if (playPromise !== undefined) { playPromise.catch(() => {}); } }); } function bindMarqueeVideoAutoplay() { const marqueeSplide = document.querySelector('.vieo-slide-main-wrap'); ['pointerdown', 'mousemove', 'touchstart', 'scroll', 'keydown'].forEach(evt => { window.addEventListener(evt, forceMarqueeVideoAutoplay, { once: true, passive: true }); }); if (marqueeSplide && marqueeSplide.splide) { marqueeSplide.splide.on('moved updated refresh', () => { forceMarqueeVideoAutoplay(); }); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', bindMarqueeVideoAutoplay, { once: true }); } else { bindMarqueeVideoAutoplay(); } /* ==================================================================== CONDITIONAL JS LOADER + PAGE-SCOPED INLINE FUNCTIONS • Drop this