(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