1/* Club16 hero â smooth crossfade compilation of club-area clips. 2 Two stacked <video> elements crossfade into each other so the hero 3 plays a continuous tour of the club with no hard cuts or black flashes. 4 Reduced-motion: falls back to a single looping clip, no crossfade. */ 5(function () { 6 var FADE_MS = 900; 7 8 function setup() { 9 var v1 = document.querySelector('.hero-video[data-video-playlist]'); 10 if (!v1) return; 11 12 var clips = (v1.dataset.videoPlaylist || '') 13 .split('|') 14 .map(function (c) { return c.trim(); }) 15 .filter(Boolean); 16 if (!clips.length) return; 17 18 var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; 19 20 // Reduced-motion or single clip: just loop the first clip quietly. 21 if (reduce || clips.length < 2) { 22 v1.loop = true; 23 v1.muted = true; 24 v1.src = clips[0]; 25 v1.load(); 26 var p0 = v1.play && v1.play(); 27 if (p0 && p0.catch) p0.catch(function () {}); 28 return; 29 } 30 31 // Build the crossfade partner. 32 var v2 = v1.cloneNode(false); 33 v2.removeAttribute('data-video-playlist'); 34 v2.removeAttribute('poster'); 35 v1.parentNode.insertBefore(v2, v1.nextSibling); 36 37 [v1, v2].forEach(function (v) { 38 v.loop = false; 39 v.muted = true; 40 v.playsInline = true; 41 v.autoplay = true; 42 v.removeAttribute('loop'); 43 // inline !important beats the stylesheet's `opacity:1 !important` 44 v.style.setProperty('transition', 'opacity ' + FADE_MS + 'ms ease', 'important'); 45 }); 46 v1.style.setProperty('opacity', '1', 'important'); 47 v2.style.setProperty('opacity', '0', 'important'); 48 49 var front = v1, back = v2; 50 var idx = 0; 51 var transitioning = false; 52 53 function load(v, i) { 54 if (v.getAttribute('data-clip') === String(i)) return; 55 v.setAttribute('data-clip', String(i)); 56 v.src = clips[i]; 57 v.load(); 58 } 59 60 function play(v) { 61 var p = v.play && v.play(); 62 if (p && p.catch) p.catch(function () {}); 63 } 64 65 load(front, 0); 66 play(front); 67 load(back, 1 % clips.length); // preload next 68 69 function crossfade() { 70 if (transitioning) return; 71 transitioning = true; 72 var nextIdx = (idx + 1) % clips.length; 73 load(back, nextIdx); 74 try { back.currentTime = 0; } catch (e) {} 75 play(back); 76 back.style.setProperty('opacity', '1', 'important'); 77 front.style.setProperty('opacity', '0', 'important'); 78 var prevFront = front; 79 front = back; 80 back = prevFront; 81 idx = nextIdx; 82 setTimeout(function () { 83 try { back.pause(); } catch (e) {} 84 load(back, (idx + 1) % clips.length); // preload following clip 85 transitioning = false; 86 }, FADE_MS + 60); 87 } 88 89 function maybeFade() { 90 if (transitioning || !front.duration) return; 91 if (front.currentTime >= front.duration - (FADE_MS / 1000) - 0.05) crossfade(); 92 } 93 94 v1.addEventListener('timeupdate', maybeFade); 95 v2.addEventListener('timeupdate', maybeFade); 96 v1.addEventListener('ended', function () { if (!transitioning) crossfade(); }); 97 v2.addEventListener('ended', function () { if (!transitioning) crossfade(); }); 98 } 99 100 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', setup); 101 else setup(); 102})();
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.