1(function () { 2 // ââ Random testimonial selection (must run BEFORE reveal setup) ââ 3 // On the homepage, pick a random 3-5 from the full pool each load 4 var homeGrid = document.getElementById('home-testimonials'); 5 if (homeGrid) { 6 var allCards = Array.from(homeGrid.children); 7 var count = 3 + Math.floor(Math.random() * 3); // 3, 4, or 5 8 // Fisher-Yates shuffle 9 for (var i = allCards.length - 1; i > 0; i--) { 10 var j = Math.floor(Math.random() * (i + 1)); 11 var temp = allCards[i]; 12 allCards[i] = allCards[j]; 13 allCards[j] = temp; 14 } 15 // Re-append in shuffled order, hide extras 16 allCards.forEach(function (card, idx) { 17 homeGrid.appendChild(card); 18 if (idx >= count) card.style.display = 'none'; 19 }); 20 } 21 22 // ââ Scroll-reveal setup (runs after DOM is finalized) ââ 23 var targets = '.section-head, .info-card, .card-link, .review-highlight-card, .step, .callout-card, .more-card, .cta-band-inner > div, .split > div, .split > aside, .faq-item, .price-card'; 24 var grids = '.icon-grid, .card-grid, .testimonial-grid, .review-highlight-grid, .steps, .pricing-grid, .faq-list'; 25 26 // Add reveal to non-hidden testimonial cards only 27 document.querySelectorAll(targets).forEach(function (el) { 28 el.classList.add('reveal'); 29 }); 30 document.querySelectorAll('.testimonial-card').forEach(function (card) { 31 if (card.style.display !== 'none') card.classList.add('reveal'); 32 }); 33 34 // Stagger visible grid children with slight jitter 35 document.querySelectorAll(grids).forEach(function (grid) { 36 var visibleIdx = 0; 37 Array.from(grid.children).forEach(function (child) { 38 if (child.style.display === 'none') return; 39 var base = visibleIdx * 0.08; 40 var jitter = (Math.random() - 0.5) * 0.04; 41 child.style.setProperty('--reveal-delay', (base + jitter).toFixed(3) + 's'); 42 visibleIdx++; 43 }); 44 }); 45 46 // IntersectionObserver for reveals 47 var observer = new IntersectionObserver(function (entries) { 48 entries.forEach(function (entry) { 49 if (entry.isIntersecting) { 50 entry.target.classList.add('visible'); 51 observer.unobserve(entry.target); 52 } 53 }); 54 }, { threshold: 0.08, rootMargin: '0px 0px -30px 0px' }); 55 56 document.querySelectorAll('.reveal').forEach(function (el) { 57 observer.observe(el); 58 }); 59 60 // ââ Randomization: subtle variety on hover ââ 61 var tiltTargets = '.info-card, .step, .review-highlight-card'; 62 document.querySelectorAll(tiltTargets).forEach(function (el) { 63 var rot = (Math.random() - 0.5) * 0.8; 64 el.style.setProperty('--hover-rotate', rot.toFixed(2) + 'deg'); 65 }); 66 67 // Testimonial cards: random tilt + varied quote mark size/position 68 document.querySelectorAll('.testimonial-card').forEach(function (card) { 69 if (card.style.display === 'none') return; 70 var rot = (Math.random() - 0.5) * 1.2; 71 var size = 3 + Math.random() * 1.5; 72 var top = 0.3 + Math.random() * 0.6; 73 var right = 0.8 + Math.random() * 0.6; 74 card.style.setProperty('--hover-rotate', rot.toFixed(2) + 'deg'); 75 card.style.setProperty('--quote-size', size.toFixed(1) + 'rem'); 76 card.style.setProperty('--quote-top', top.toFixed(2) + 'rem'); 77 card.style.setProperty('--quote-right', right.toFixed(2) + 'rem'); 78 }); 79 80 // ââ Hero entrance: only animate on first visit per session ââ 81 if (sessionStorage.getItem('hero-seen')) { 82 document.querySelectorAll('.hero-copy, .hero-card, .hero-copy .trust-pills').forEach(function (el) {
83 el.style.animation = 'none'; 84 }); 85 } else { 86 sessionStorage.setItem('hero-seen', '1'); 87 } 88})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.