PageSourceSearch

https://zipmex.com/assets/js/landing.js?v=CMhMq-kqAlinocqk

js zipmex.com collected 2026-09-28 06:41:13 UTC 83,920 bytes, 1,662 lines download raw bytes

1        
2        document.addEventListener('DOMContentLoaded', function() {
3        (function() {
4            var items = [].slice.call(document.querySelectorAll('#inside-acc .inside-item'));
5            var labels = [].slice.call(document.querySelectorAll('.inside-labels span'));
6            var sceneEl = document.getElementById('inside-scene');
7            var sectionEl = document.querySelector('.inside-section');
8            if (!items.length || !sceneEl) return;
9
10            var STATES = ['ui', 'exec', 'solana'];
11            var SLOTS = { ui: ['uiLeft', 'uiRight'], exec: ['execChain'], solana: ['solanaBase'] };
12
13            (function buildNodes() {
14                var host = sceneEl.querySelector('.xt-nodes');
15                if (!host) return;
16                var SQUASH = 0.58, TILT = -3.3 * Math.PI / 180;
17                var ORBITS = [{ r: 74, n: 6, phase: 0 }, { r: 124, n: 8, phase: 0.4 }, { r: 172, n: 10, phase: 0.2 }];
18                var REACH = 180, WAVE = 2.0;
19                var frag = document.createDocumentFragment();
20                ORBITS.forEach(function (o) {
21                    var ring = document.createElement('b');
22                    ring.style.width = (o.r * 2) + 'px';
23                    ring.style.height = (o.r * 2 * SQUASH) + 'px';
24                    ring.style.margin = (-o.r * SQUASH) + 'px 0 0 ' + (-o.r) + 'px';
25                    frag.appendChild(ring);
26                    for (var k = 0; k < o.n; k++) {
27                        var t = (k / o.n + o.phase) * Math.PI * 2;
28                        var ex = o.r * Math.cos(t), ey = o.r * SQUASH * Math.sin(t);
29                        var dot = document.createElement('i');
30                        dot.style.left = (ex * Math.cos(TILT) - ey * Math.sin(TILT)).toFixed(1) + 'px';
31                        dot.style.top = (ex * Math.sin(TILT) + ey * Math.cos(TILT)).toFixed(1) + 'px';
32                        dot.style.setProperty('--delay', (Math.min(1, o.r / REACH) * WAVE).toFixed(2) + 's');
33                        frag.appendChild(dot);
34                    }
35                });
36                host.appendChild(frag);
37            })();
38            var slabs = {};
39            STATES.forEach(function (s) { slabs[s] = sceneEl.querySelector('.xt-slab[data-state="' + s + '"]'); });
40            var conns = {}, pills = {};
41            
42            var extras = [];
43            [].forEach.call(sceneEl.querySelectorAll('.xt-conn'), function (el) { conns[el.getAttribute('data-slot')] = el; });
44            [].forEach.call(sceneEl.querySelectorAll('.xt-ripple, .xt-nodes'), function (el) { extras.push(el); });
45            [].forEach.call(sceneEl.querySelectorAll('.xt-pill-wrap'), function (el) { pills[el.getAttribute('data-slot')] = el; });
46
47            var DUR = 5900, cur = -1, timer = null, inView = true;
48            var hasGsap = (typeof gsap !== 'undefined');
49
50            function show(i) {
51                if (i === cur) return;
52                cur = i;
53                var st = STATES[i];
54                items.forEach(function (it, k) {
55                    it.classList.toggle('active', k === i);
56                    var h = it.querySelector('.inside-head');
57                    if (h) h.setAttribute('aria-expanded', k === i ? 'true' : 'false');
58                });
59                items.forEach(function (it, k) {
60                    var bar = it.querySelector('.inside-progress > span');
61                    if (!bar) return;
62                    if (hasGsap) {
63                        gsap.killTweensOf(bar);
64                        if (k === i) gsap.fromTo(bar, { width: '0%' }, { width: '100%', duration: DUR / 1000, ease: 'none' });
65                        else gsap.set(bar, { width: '0%' });
66                    } else {
67                        bar.style.transition = 'none'; bar.style.width = '0%';
68                        if (k === i) { void bar.offsetWidth; bar.style.transition = 'width ' + (DUR / 1000) + 's linear'; bar.style.width = '100%'; }
69                    }
70                });
71                STATES.forEach(function (s) { slabs[s].classList.toggle('on', s === st); });
72                Object.keys(conns).forEach(function (key) {
73                    var on = SLOTS[st].indexOf(key) > -1;
74                    conns[key].classList.toggle('on', on);
75                    if (pills[key]) pills[key].classList.toggle('on', on);
76                });
77                extras.forEach(function (el) {
78                    
79                    el.classList.remove('on');
80                    if (SLOTS[st].indexOf(el.getAttribute('data-slot')) > -1) {
81                        void el.offsetWidth;
82                        el.classList.add('on');
83                    }
84                });
85                labels.forEach(function (l, k) { l.classList.toggle('on', k === i); });
86                if (timer) clearTimeout(timer);
87                if (inView) timer = setTimeout(function () { show((cur + 1) % 3); }, DUR);
88            }
89
90            items.forEach(function (it) {
91                it.addEventListener('click', function () { show(+it.getAttribute('data-i')); });
92                var h = it.querySelector('.inside-head');
93                if (h) h.addEventListener('keydown', function (e) {
94                    if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar') { e.preventDefault(); show(+it.getAttribute('data-i')); }
95                });
96            });
97            labels.forEach(function (l, k) { l.addEventListener('click', function () { show(k); }); });
98
99            if (sectionEl && 'IntersectionObserver' in window) {
100                new IntersectionObserver(function (es) {
101                    inView = es[0].isIntersecting;
102                    if (!inView) { if (timer) { clearTimeout(timer); timer = null; } }
103                    else if (!timer && cur !== -1) { timer = setTimeout(function () { show((cur + 1) % 3); }, DUR); }
104                }, { threshold: 0 }).observe(sectionEl);
105            }
106
107            show(0);
108        })();
109
110        (function () {
111            var canvas = document.getElementById('security-3d-canvas');
112            if (!canvas) return;
113            var section = document.getElementById('security');
114
115            function withThree(cb) {
116                if (window.THREE && THREE.GLTFLoader) return cb();
117                var s = document.createElement('script');
118                s.src = '/assets/js/vendor/three.min.js';
119                s.onload = function () {
120                    var script = document.createElement('script');
121                    script.src = '/assets/js/vendor/GLTFLoader.js';
122                    script.onload = cb;
123                    document.head.appendChild(script);
124                };
125                document.head.appendChild(s);
126            }
127
128            var started = false;
129            function start() {
130                if (started) return;
131                started = true;
132
133                var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
134
135                var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true, alpha: true });
136                renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
137                renderer.outputEncoding = THREE.sRGBEncoding;
138                renderer.toneMapping = THREE.ACESFilmicToneMapping;
139                renderer.toneMappingExposure = 0.80;
140
141                var scene = new THREE.Scene();
142
143                var camera = new THREE.PerspectiveCamera(30, 1, 0.1, 100);
144                camera.position.set(0, 1.45, 4.0);
145                camera.lookAt(0, -0.1, 0);
146
147                (function buildEnv() {
148                    var ec = document.createElement('canvas'); ec.width = 128; ec.height = 64;
149                    var x = ec.getContext('2d');
150                    var g = x.createLinearGradient(0, 0, 0, 64);
151                    g.addColorStop(0.00, '#080b11');
152                    g.addColorStop(0.40, '#283242');
153                    g.addColorStop(0.50, '#3c4a5e');  
154                    g.addColorStop(0.60, '#1d242f');
155                    g.addColorStop(1.00, '#05070a');
156                    x.fillStyle = g; x.fillRect(0, 0, 128, 64);
157                    var envTex = new THREE.CanvasTexture(ec);
158                    envTex.mapping = THREE.EquirectangularReflectionMapping;
159                    var pmrem = new THREE.PMREMGenerator(renderer);
160                    var rt = pmrem.fromEquirectangular(envTex);
161                    scene.environment = rt.texture;
162                    envTex.dispose(); pmrem.dispose();
163                })();
164
165                var amb = new THREE.AmbientLight(0x0e141c, 0.16); scene.add(amb);
166                var key = new THREE.DirectionalLight(0xeaf2ff, 3.0); key.position.set(-4.5, 3.2, 3.5); scene.add(key);
167                var rim = new THREE.DirectionalLight(0xffffff, 2.1); rim.position.set(4, 3.5, -4); scene.add(rim);
168                var accent = new THREE.DirectionalLight(0x4cd7f4, 0.28); accent.position.set(-5, 1.5, 3); scene.add(accent);
169
170                var BASE_RX = 0.58, BASE_RY = 0.20;
171                var holder = new THREE.Group();
172                holder.rotation.x = BASE_RX;
173                holder.rotation.y = BASE_RY;
174                scene.add(holder);
175
176                var LOGO_OUTLINE = [[-0.1966,-0.437],[0.2479,-0.4177],[0.1118,-0.0679],[0.1524,-0.0273],
177                    [0.4232,-0.0079],[0.2485,0.3606],[-0.1959,0.3606],[-0.1959,0.3028],[-0.059,-0.0102],
178                    [-0.0995,-0.0507],[-0.3705,-0.07]];
179                function buildRoundedLogoGeo() {
180                    var pts = LOGO_OUTLINE.map(function (p) { return new THREE.Vector2(p[0], -p[1]); });
181                    var shape = new THREE.Shape(), n = pts.length, R = 0.05;
182                    for (var i = 0; i < n; i++) {
183                        var prev = pts[(i - 1 + n) % n], cur = pts[i], next = pts[(i + 1) % n];
184                        var v1 = cur.clone().sub(prev), v2 = next.clone().sub(cur);
185                        var rr = Math.min(R, v1.length() * 0.45, v2.length() * 0.45);
186                        v1.normalize(); v2.normalize();
187                        var pIn = cur.clone().addScaledVector(v1, -rr);
188                        var pOut = cur.clone().addScaledVector(v2, rr);
189                        if (i === 0) shape.moveTo(pIn.x, pIn.y); else shape.lineTo(pIn.x, pIn.y);
190                        shape.quadraticCurveTo(cur.x, cur.y, pOut.x, pOut.y);
191                    }
192                    shape.closePath();
193                    var g = new THREE.ExtrudeGeometry(shape, { depth: 0.03, bevelEnabled: false, curveSegments: 6 });
194                    g.rotateX(-Math.PI / 2);   
195                    g.computeVertexNormals();
196                    return g;
197                }
198
199                var loader = new THREE.GLTFLoader();
200                var basePath = '/assets/inside/';
201                loader.load(basePath + 'platform_shield_zexo.glb', function (gltf) {
202                    var model = gltf.scene;
203                    
204                    model.scale.set(1, 1, 1);
205                    
206                    var box = new THREE.Box3().setFromObject(model);
207                    var center = box.getCenter(new THREE.Vector3());
208                    model.position.sub(center);
209                    
210                    model.traverse(function (o) {
211                        if (!o.isMesh || !o.material) return;
212                        var m = o.material;
213                        if (m.name === 'WhiteLogoMat') {
214                            m.emissive = new THREE.Color(0xffffff);
215                            m.emissiveIntensity = 2.15;  
216                            m.side = THREE.DoubleSide;
217                            o.geometry.dispose();
218                            o.geometry = buildRoundedLogoGeo();  
219                        } else if (m.name === 'ContactShadowMat') {
220                            o.visible = false;            
221                        } else if (m.name === 'ShieldRimMat') {
222                            
223                            m.roughness = 0.23;
224                            m.envMapIntensity = 1.35;
225                        } else {                          
226                            
227                            var pm = new THREE.MeshPhysicalMaterial({
228                                color: m.color.clone(), metalness: m.metalness,
229                                roughness: 0.36, envMapIntensity: 0.62,
230                                clearcoat: 0.7, clearcoatRoughness: 0.26
231                            });
232                            pm.name = 'ShieldBaseMat';
233                            o.material = m = pm;
234                        }
235                        m.needsUpdate = true;
236                    });
237                    holder.add(model);
238                });
239
240                function resize() {
241                    var w = canvas.clientWidth, h = canvas.clientHeight;
242                    if (!w || !h) return;
243                    camera.aspect = w / h;
244                    camera.updateProjectionMatrix();
245                    renderer.setSize(w, h, false);
246                }
247                window.addEventListener('resize', resize);
248                resize();
249
250                var running = true, raf = null;
251                function loop() {
252                    if (!running) { raf = null; return; }
253                    raf = requestAnimationFrame(loop);
254                    if (!reduce) {
255                        
256                        var t = performance.now() * 0.001;
257                        holder.rotation.y = BASE_RY + Math.sin(t * 0.40) * 0.17;
258                        holder.rotation.x = BASE_RX + Math.sin(t * 0.29) * 0.03;
259                    }
260                    renderer.render(scene, camera);
261                }
262                function play() { if (!running) { running = true; } if (!raf) loop(); }
263                function pause() { running = false; }
264
265                if ('IntersectionObserver' in window) {
266                    new IntersectionObserver(function (es) {
267                        es.forEach(function (e) { e.isIntersecting ? play() : pause(); });
268                    }, { rootMargin: '100px' }).observe(section || canvas);
269                }
270                loop();
271            }
272
273            if ('IntersectionObserver' in window) {
274                var io = new IntersectionObserver(function (es) {
275                    es.forEach(function (e) { if (e.isIntersecting) { withThree(start); io.disconnect(); } });
276                }, { rootMargin: '300px' });
277                io.observe(section || canvas);
278
279                var warmThree = function () {
280                    var idle = window.requestIdleCallback || function (f) { return setTimeout(f, 2500); };
281                    idle(function () { withThree(function () {}); }, { timeout: 6000 });
282                };
283                if (document.readyState === 'complete') setTimeout(warmThree, 1500);
284                else window.addEventListener('load', function () { setTimeout(warmThree, 1500); }, { once: true });
285            } else {
286                withThree(start);
287            }
288        })();
289        });
290
291        function toggleMenu() {
292            const panel = document.querySelector('.menu-panel');
293            const overlay = document.querySelector('.menu-overlay');
294            const btn = document.querySelector('.hamburger-btn');
295            const isOpen = panel.classList.contains('active');
296            if (isOpen) {
297                panel.classList.remove('active');
298                overlay.classList.remove('active');
299                btn.classList.remove('active');
300                btn.setAttribute('aria-expanded', 'false');
301                document.body.style.overflow = '';
302            } else {
303                panel.classList.add('active');
304                overlay.classList.add('active');
305                btn.classList.add('active');
306                btn.setAttribute('aria-expanded', 'true');
307                document.body.style.overflow = 'hidden';
308            }
309        }
310
311        document.addEventListener('keydown', function (e) {
312            if (e.key !== 'Escape') return;
313            var panel = document.querySelector('.menu-panel');
314            if (panel && panel.classList.contains('active')) {
315                toggleMenu();
316                var btn = document.querySelector('.hamburger-btn');
317                if (btn) btn.focus();
318            }
319        });
320
321        [].slice.call(document.querySelectorAll('.nav-dropdown')).forEach(function(dd) {
322            var btn = dd.querySelector('.nav-dropdown-btn');
323            if (!btn) return;
324            function sync() {
325                var open = dd.matches(':hover') || dd.contains(document.activeElement);
326                btn.setAttribute('aria-expanded', open ? 'true' : 'false');
327            }
328            ['mouseenter', 'mouseleave', 'focusin', 'focusout'].forEach(function(ev) {
329                dd.addEventListener(ev, sync);
330            });
331            dd.addEventListener('keydown', function(e) {
332                if (e.key === 'Escape') { btn.focus(); document.activeElement.blur(); }
333            });
334        });
335    (function () {
336        var host = document.querySelector('.hero-rays-gl');
337        if (!host) return;
338        
339        if (!(window.matchMedia && window.matchMedia('(max-width: 768px)').matches)) return;
340        
341        var glowZone = document.querySelector('.hero-glow-mobile');
342        if (!glowZone || (window.getComputedStyle && getComputedStyle(glowZone).display === 'none')) return;
343
344        var s = document.createElement('script');
345        s.src = '/assets/js/rays-core.js?v=2529';
346        s.onload = mount;
347        document.head.appendChild(s);
348
349        function mount() {
350        if (typeof JetRays !== 'function') return;
351
352        var rays = JetRays(host, {
353            strips: 'bottom',                 
354            frame: false,                     
355            colors: ['#4cd7f4', '#325249'],   
356            speed: 1.6,                       
357            brightness: 2.6,                  
358            noiseOpacity: 0.4,                
359            stripHeight: 320                  
360        });
361        if (!rays || !rays.supported) return; 
362
363        var fallback = document.querySelector('.hero-rays');
364        if (fallback) fallback.style.display = 'none';
365
366        var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
367        if (!reduce && 'IntersectionObserver' in window) {
368            var io = new IntersectionObserver(function (entries) {
369                entries.forEach(function (e) { if (e.isIntersecting) { rays.play(); } else { rays.pause(); } });
370            }, { rootMargin: '120px' });
371            io.observe(document.getElementById('hero') || host);
372        }
373        }
374    })();
375      (function(){
376        var sec = document.getElementById('callouts');
377        var box = document.getElementById('callouts-lottie');
378        if(!sec || !box) return;
379        
380        var stage = document.getElementById('callouts-lottie-stage') || box;
381        var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
382        var anim = null, started = false;
383        function ensureLottie(cb){
384          if(window.lottie) return cb();
385          var s = document.createElement('script');
386          s.src = '/assets/js/lottie_svg.min.js';
387          s.onload = cb; document.head.appendChild(s);
388        }
389        
390        var coarse = window.matchMedia && window.matchMedia('(hover: none) and (pointer: coarse)').matches;
391        var scenePath = coarse ? '/assets/callouts/hero-touch.json?v=2782'
392                               : '/assets/callouts/hero.json?v=2782';
393        function start(){
394          if(started) return; started = true;
395          ensureLottie(function(){
396            anim = lottie.loadAnimation({ container:stage, renderer:'svg',
397              loop:!reduce, autoplay:false, path:scenePath });
398            window.__calloutsLottie = anim;
399            anim.addEventListener('DOMLoaded', function(){
400              
401              anim.setSubframe(false);
402              if(reduce){ anim.goToAndStop(0, true); return; }
403              
404              resume();
405            });
406          });
407        }
408        
409        if(reduce){ start(); return; }
410
411        var warm = function(){
412          var idle = window.requestIdleCallback || function(f){ return setTimeout(f, 1200); };
413          
414          idle(function(){ start(); }, { timeout: 3000 });
415        };
416        if(document.readyState === 'complete') warm();
417        else window.addEventListener('load', warm, { once:true });
418
419        var inView = false, scrolling = false, idle = 0;
420        
421        var canPark = window.CSS && CSS.supports && CSS.supports('content-visibility', 'hidden');
422        function park(on){ if(canPark) box.classList.toggle('is-parked', !!on); }
423        function resume(){ if(anim && inView && !scrolling) anim.play(); }
424        function suspend(){ if(anim) anim.pause(); }
425        park(true);
426
427        var io = new IntersectionObserver(function(entries){
428          entries.forEach(function(e){
429            inView = e.isIntersecting;
430            if(inView){ park(false); start(); resume(); }
431            else { suspend(); park(true); }
432          });
433        }, { rootMargin:'600px' });
434        io.observe(sec);
435
436        window.addEventListener('scroll', function(){
437          if(!scrolling){ scrolling = true; suspend(); }
438          clearTimeout(idle);
439          idle = setTimeout(function(){ scrolling = false; resume(); }, 180);
440        }, { passive:true });
441      })();
442      (function(){
443        var card = document.querySelector('.signal-card');
444        var svg = document.getElementById('signal-candles');
445        var chart = document.getElementById('signal-chart');
446        if(!card || !svg || !chart) return;
447        var NS='http://www.w3.org/2000/svg';
448        var W=182,H=120,padX=12,padTop=8,padBot=8;
449        var C=[
450          {o:52,c:60,h:64,l:50},{o:60,c:55,h:62,l:52},{o:55,c:68,h:71,l:53},
451          {o:68,c:62,h:70,l:58},{o:62,c:44,h:66,l:40},{o:44,c:34,h:46,l:30},
452          {o:34,c:50,h:53,l:32},{o:50,c:58,h:61,l:48},{o:58,c:65,h:69,l:56}
453        ];
454        var n=C.length, slot=(W-padX*2)/n, bw=Math.min(12, slot*0.5);
455        function y(p){ return padTop + (1-p/100)*(H-padTop-padBot); }
456        function cx(i){ return padX + slot*(i+0.5); }
457        var GREEN='#26d07c', RED='#f6465d';
458        var BASE=y(0);                 
459        var candleEls=[];
460        C.forEach(function(d,i){
461          var up=d.c>=d.o, col=up?GREEN:RED, x=cx(i);
462          var gEl=document.createElementNS(NS,'g');   
463          var wick=document.createElementNS(NS,'line');
464          wick.setAttribute('x1',x); wick.setAttribute('x2',x);
465          wick.setAttribute('y1',y(d.h)); wick.setAttribute('y2',y(d.l));
466          wick.setAttribute('stroke',col); wick.setAttribute('stroke-width','1.2');
467          gEl.appendChild(wick);
468          var top=y(Math.max(d.o,d.c)), bot=y(Math.min(d.o,d.c));
469          var body=document.createElementNS(NS,'rect');
470          body.setAttribute('x',x-bw/2); body.setAttribute('y',top);
471          body.setAttribute('width',bw); body.setAttribute('height',Math.max(2,bot-top));
472          body.setAttribute('rx','1.5'); body.setAttribute('fill',col);
473          gEl.appendChild(body);
474          svg.appendChild(gEl);
475          candleEls.push({el:gEl,x:x});
476        });
477        
478        var volTop=86, volBot=114, VOL=[0.45,0.38,0.66,0.5,0.92,1.0,0.72,0.5,0.8], volEls=[];
479        C.forEach(function(d,i){
480          var up=d.c>=d.o, col=up?GREEN:RED, x=cx(i);
481          var vh=Math.max(2, VOL[i]*(volBot-volTop));
482          var vg=document.createElementNS(NS,'g');
483          var vbar=document.createElementNS(NS,'rect');
484          vbar.setAttribute('x',x-bw/2); vbar.setAttribute('y',volBot-vh);
485          vbar.setAttribute('width',bw); vbar.setAttribute('height',vh);
486          vbar.setAttribute('rx','1'); vbar.setAttribute('fill',col); vbar.setAttribute('opacity','0.4');
487          vg.appendChild(vbar); svg.appendChild(vg);
488          volEls.push({el:vg,x:x});
489        });
490        var avatars=['assets/images/callouts_icon1.webp','assets/images/callouts_icon2.webp','assets/images/callouts_icon3.webp'];
491        var sigIdx=[2,5,7], bubbles=[];
492        sigIdx.forEach(function(ci,k){
493          var x=cx(ci), highY=y(C[ci].h);
494          var b=document.createElement('div'); b.className='signal-bubble';
495          b.style.left=(x/W*100)+'%';
496          var ping=document.createElement('div'); ping.className='signal-bubble-ping';
497          var img=document.createElement('div'); img.className='signal-bubble-av';
498          
499          img.style.backgroundImage='url('+avatars[k%avatars.length]+')';
500          img.style.opacity='0';
501          var line=document.createElement('div'); line.className='signal-bubble-line';
502          line.style.height=Math.max(6, highY-28)+'px'; line.style.transform='scaleY(0)';
503          b.appendChild(ping); b.appendChild(img); b.appendChild(line);
504          chart.appendChild(b);
505          bubbles.push({img:img,line:line,ping:ping});
506        });
507        var imgs=bubbles.map(function(b){return b.img;});
508        var lines=bubbles.map(function(b){return b.line;});
509        var pings=bubbles.map(function(b){return b.ping;});
510        var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
511        if(reduce){ 
512          card.style.opacity='1';
513          imgs.forEach(function(im){ im.style.opacity='1'; });
514          lines.forEach(function(ln){ ln.style.transform='scaleY(1)'; });
515          return;
516        }
517        function whenGsap(cb){ if(window.gsap) return cb(); setTimeout(function(){whenGsap(cb);},120); }
518        whenGsap(function(){
519          var g=window.gsap;
520          
521          g.set(imgs,{scale:0,opacity:0,transformOrigin:'center center'});
522          g.set(lines,{scaleY:0});
523          g.set(pings,{scale:0.5,opacity:0,transformOrigin:'center center'});
524          candleEls.forEach(function(c){ g.set(c.el,{scaleY:0, svgOrigin:c.x+' '+BASE}); });
525          volEls.forEach(function(v){ g.set(v.el,{scaleY:0, svgOrigin:v.x+' '+volBot}); });
526          var content=g.timeline({paused:true});
527          
528          candleEls.forEach(function(c,i){
529            content.to(c.el,{scaleY:1,duration:0.5,ease:'power3.out'}, i*0.05);
530            content.to(volEls[i].el,{scaleY:1,duration:0.45,ease:'power3.out'}, i*0.05+0.04);
531          });
532          
533          bubbles.forEach(function(bb,idx){
534            var at=0.6 + idx*0.42;
535            content.to(bb.line,{scaleY:1,duration:0.3,ease:'power2.out'}, at);
536            content.fromTo(bb.ping,{scale:0.5,opacity:0.6},{scale:2,opacity:0,duration:0.6,ease:'power2.out'}, at+0.06);
537            content.to(bb.img,{scale:1,opacity:1,duration:0.42,ease:'back.out(1.6)'}, at+0.1);
538          });
539          
540          (window.__hubCards||(window.__hubCards=[])).push({el:card, tl:content, frame:11});
541        });
542      })();
543      (function(){
544        function whenGsap(cb){ if(window.gsap) return cb(); setTimeout(function(){whenGsap(cb);},120); }
545        whenGsap(function(){
546          
547          var PATH=[
548          {t:0.0,x:738.0,y:286.0,s:0.0,o:0.0},{t:0.067,x:738.0,y:286.0,s:0.0,o:0.0},{t:0.133,x:738.0,y:286.0,s:0.0,o:0.0},
549          {t:0.2,x:745.7,y:283.0,s:0.053,o:1.0},{t:0.267,x:766.4,y:276.9,s:0.16,o:1.0},{t:0.333,x:787.1,y:270.8,s:0.267,o:1.0},
550          {t:0.4,x:807.8,y:264.7,s:0.373,o:1.0},{t:0.467,x:828.5,y:258.6,s:0.48,o:1.0},{t:0.533,x:849.1,y:252.6,s:0.587,o:1.0},
551          {t:0.6,x:869.8,y:246.5,s:0.693,o:1.0},{t:0.667,x:890.5,y:240.4,s:0.8,o:1.0},{t:0.733,x:901.7,y:239.9,s:0.808,o:1.0},
552          {t:0.8,x:912.7,y:239.5,s:0.816,o:1.0},{t:0.867,x:923.7,y:239.0,s:0.824,o:1.0},{t:0.933,x:934.8,y:238.6,s:0.832,o:1.0},
553          {t:1.0,x:945.8,y:238.1,s:0.84,o:1.0},{t:1.067,x:956.9,y:237.7,s:0.848,o:1.0},{t:1.133,x:967.9,y:237.2,s:0.856,o:1.0},
554          {t:1.2,x:978.9,y:236.8,s:0.864,o:1.0},{t:1.267,x:990.0,y:236.3,s:0.872,o:1.0},{t:1.333,x:1001.0,y:235.8,s:0.88,o:1.0},
555          {t:1.4,x:1012.0,y:235.4,s:0.888,o:1.0},{t:1.467,x:1023.1,y:234.9,s:0.896,o:1.0},{t:1.533,x:1034.1,y:234.5,s:0.904,o:1.0},
556          {t:1.6,x:1045.2,y:234.0,s:0.912,o:1.0},{t:1.667,x:1056.2,y:233.6,s:0.92,o:1.0},{t:1.733,x:1067.2,y:233.1,s:0.928,o:1.0},
557          {t:1.8,x:1078.3,y:232.6,s:0.936,o:1.0},{t:1.867,x:1089.3,y:232.2,s:0.944,o:1.0},{t:1.933,x:1100.3,y:231.7,s:0.952,o:1.0},
558          {t:2.0,x:1111.4,y:231.3,s:0.96,o:1.0},{t:2.067,x:1122.4,y:230.8,s:0.968,o:1.0},{t:2.133,x:1133.5,y:230.4,s:0.976,o:1.0},
559          {t:2.2,x:1144.5,y:229.9,s:0.984,o:1.0},{t:2.267,x:1155.5,y:229.5,s:0.992,o:1.0},{t:2.333,x:1166.6,y:229.0,s:1.0,o:1.0},
560          {t:2.4,x:1177.6,y:228.5,s:1.008,o:1.0},{t:2.467,x:1188.6,y:228.1,s:1.016,o:1.0},{t:2.533,x:1199.7,y:227.6,s:1.024,o:1.0},
561          {t:2.6,x:1210.7,y:227.2,s:1.032,o:1.0},{t:2.667,x:1221.8,y:226.7,s:1.04,o:1.0},{t:2.733,x:1232.8,y:226.3,s:1.048,o:1.0},
562          {t:2.8,x:1243.8,y:225.8,s:1.056,o:1.0},{t:2.867,x:1254.9,y:225.4,s:1.064,o:1.0},{t:2.933,x:1265.9,y:224.9,s:1.072,o:1.0},
563          {t:3.0,x:1276.9,y:224.4,s:1.08,o:1.0},{t:3.067,x:1308.3,y:224.0,s:1.088,o:1.0},{t:3.133,x:1346.4,y:223.5,s:1.096,o:1.0},
564          {t:3.2,x:1384.1,y:223.3,s:1.1,o:1.0},{t:3.267,x:1421.4,y:223.3,s:1.1,o:1.0},{t:3.333,x:1458.7,y:223.3,s:1.1,o:1.0},
565          {t:3.4,x:1496.1,y:223.3,s:1.1,o:1.0},{t:3.467,x:1533.4,y:223.3,s:1.1,o:1.0},{t:3.533,x:1561.4,y:223.3,s:1.1,o:1.0}
566          ];
567          var last=PATH[PATH.length-1];
568          var lot=document.getElementById('callouts-lottie');
569          
570          var CYCLE=8;              
571          var BASE_FRAME=11;        
572          var cards=window.__hubCards||(window.__hubCards=[]);
573          
574          function applyAt(card, content, CONTENT_DUR, T, g){
575            if(!lot) return;
576            var x,y,s,o;
577            if(T>=8.067){ x=last.x; y=last.y; s=last.s; o=0; }
578            else if(T>=3.533){ x=last.x; y=last.y; s=last.s; o=1; }
579            else {
580              var i=0; while(i<PATH.length-1 && PATH[i+1].t<=T) i++;
581              var a=PATH[i], b=PATH[Math.min(i+1,PATH.length-1)];
582              var f=(b.t>a.t)?(T-a.t)/(b.t-a.t):0;
583              x=a.x+(b.x-a.x)*f; y=a.y+(b.y-a.y)*f; s=a.s+(b.s-a.s)*f; o=a.o+(b.o-a.o)*f;
584            }
585            
586            if(x > 1458) o *= Math.max(0, (1528 - x) / 70);
587            
588            content.seek(Math.max(0, Math.min(CONTENT_DUR, T - 0.3)), false);
589            
590            var Y_NUDGE = g.isDesktop ? 42 : -11;
591            
592            var fit = g.isDesktop ? 1 : (g.w/1440);
593            card.style.position='absolute';
594            
595            card.style.width='182px'; card.style.height='182px';
596            card.style.left=(g.left+(x/1440)*g.w)+'px';
597            card.style.top =(g.top +((y+Y_NUDGE)/500)*g.h)+'px';
598            card.style.transform='translate(-50%,-50%) scale('+(s*fit)+')';
599            card.style.transformOrigin='center center';
600            card.style.opacity=o;
601          }
602          
603          var mqDesktop = window.matchMedia('(min-width:1200px)');
604          function tick(T){
605            if(!cards.length || !lot) return;
606            
607            var g={ left:lot.offsetLeft, top:lot.offsetTop, w:lot.offsetWidth, h:lot.offsetHeight,
608                    isDesktop:mqDesktop.matches };
609            for(var i=0;i<cards.length;i++){
610              var c=cards[i];
611              if(c.dur===undefined) c.dur=c.tl.duration();
612              var Tl=T-(c.frame-BASE_FRAME)/60;   
613              if(Tl<0) Tl+=CYCLE;                 
614              applyAt(c.el, c.tl, c.dur, Tl, g);  
615            }
616          }
617          function whenLottie(cb){ var a=window.__calloutsLottie; if(a){cb(a);return;} setTimeout(function(){whenLottie(cb);},120); }
618          if(lot){
619            whenLottie(function(a){
620              a.addEventListener('enterFrame', function(){ tick(a.currentFrame / 90); });
621              tick(a.currentFrame / 90);
622            });
623          }
624          
625        });
626      })();
627      (function(){
628        var card=document.querySelector('.predict-card');
629        if(!card) return;
630        var bets=[].slice.call(card.querySelectorAll('.predict-bet b'));
631        
632        var CENTS=[68,32];
633        var payouts=[].slice.call(card.querySelectorAll('.predict-payout'));
634        
635        payouts.forEach(function(p,i){ p.textContent='$100 → $'+Math.round(100/(CENTS[i]/100)); });
636        function show(i,v){ bets[i].textContent=Math.round(v)+'¢'; }
637        var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
638        if(reduce){ 
639          card.style.opacity='1';
640          CENTS.forEach(function(v,i){ show(i,v); });
641          return;
642        }
643        function whenGsap(cb){ if(window.gsap) return cb(); setTimeout(function(){whenGsap(cb);},120); }
644        whenGsap(function(){
645          var g=window.gsap;
646          var q=card.querySelector('.predict-q'), foot=card.querySelector('.predict-foot');
647          var spark=card.querySelector('.spark-line');
648          var content=g.timeline({paused:true});
649          content.fromTo(q,{opacity:0,y:6},{opacity:1,y:0,duration:0.4,ease:'power2.out'},0.05);
650          if(spark){
651            var len=spark.getTotalLength();
652            g.set(spark,{strokeDasharray:len, strokeDashoffset:len});
653            content.to(spark,{strokeDashoffset:0,duration:0.7,ease:'power2.out'},0.2);
654          }
655          bets.forEach(function(b,i){
656            var at=0.35+i*0.12;
657            content.fromTo([b.parentElement,payouts[i]],{opacity:0,y:6},{opacity:1,y:0,duration:0.4,ease:'power2.out'},at);
658            
659            var n={v:0};
660            content.to(n,{v:CENTS[i],duration:0.7,ease:'power2.out',
661              onUpdate:function(){ show(i,n.v); }},at);
662          });
663          content.fromTo(foot,{opacity:0},{opacity:1,duration:0.35},1.05);
664          (window.__hubCards||(window.__hubCards=[])).push({el:card, tl:content, frame:90});
665        });
666      })();
667      (function(){
668        var card=document.querySelector('.stocks-card');
669        if(!card) return;
670        var rows=[].slice.call(card.querySelectorAll('.stock-row'));
671        var ORDERLY='https://api.orderly.org/v1/public/';
672
673        function paint(row, price, pct){
674          row.querySelector('.stock-price').textContent=
675            isFinite(price) ? '$'+price.toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2}) : '--';
676          var chg=row.querySelector('.stock-chg');
677          chg.textContent=(pct>0?'+':'')+pct.toFixed(2)+'%';
678          
679          chg.className='stock-chg '+(pct>0?'up':pct<0?'down':'');
680        }
681        function json(path){ return fetch(ORDERLY+path).then(function(r){ return r.json(); }); }
682
683        function fromTicker(quotes){
684          rows.forEach(function(row){
685            var t=/^PERP_([A-Z0-9]+)_/.exec(row.getAttribute('data-sym'));
686            var q=t && quotes[t[1]];
687            if(q && isFinite(q.price)) paint(row, q.price, q.change||0);
688          });
689        }
690        document.addEventListener('zexo:quotes', function(e){ fromTicker(e.detail); });
691
692        function load(){
693          rows.forEach(function(row){
694            var sym=row.getAttribute('data-sym');
695            
696            json('info/'+encodeURIComponent(sym)).then(function(d){
697              var m=d&&d.data;
698              
699              if(m && m.base_imr>0) row.querySelector('.stock-lev').textContent=Math.round(1/m.base_imr)+'x';
700            }).catch(function(){});
701          });
702
703          if(window.__zexoQuotes) return fromTicker(window.__zexoQuotes);
704          rows.forEach(function(row){
705            json('futures/'+encodeURIComponent(row.getAttribute('data-sym'))).then(function(d){
706              var m=d&&d.data, open=m&&m['24h_open'], close=m&&m['24h_close'];
707              if(open>0 && close>0) paint(row, close, (close-open)/open*100);
708            }).catch(function(){});
709          });
710        }
711
712        var sec=document.getElementById('callouts');
713        if(sec && 'IntersectionObserver' in window){
714          var io=new IntersectionObserver(function(entries){
715            entries.forEach(function(e){ if(e.isIntersecting){ load(); io.disconnect(); } });
716          }, { rootMargin:'200px' });
717          io.observe(sec);
718        } else { load(); }
719
720        var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
721        if(reduce){ card.style.opacity='1'; return; }
722        function whenGsap(cb){ if(window.gsap) return cb(); setTimeout(function(){whenGsap(cb);},120); }
723        whenGsap(function(){
724          var g=window.gsap;
725          var content=g.timeline({paused:true});
726          rows.forEach(function(row,i){
727            content.fromTo(row,{opacity:0,x:10},{opacity:1,x:0,duration:0.45,ease:'power2.out'},0.1+i*0.14);
728          });
729          (window.__hubCards||(window.__hubCards=[])).push({el:card, tl:content, frame:170});
730        });
731      })();
732      (function(){
733        var perf=document.querySelector('.perf-card'), roi=document.querySelector('.roi-card');
734        if(!perf || !roi) return;
735        var vals=[].slice.call(perf.querySelectorAll('.perf-val'));
736        var roiVal=roi.querySelector('.roi-foot b');
737
738        function fmt(el,v){
739          var kind=el.getAttribute('data-kind');
740          if(kind==='mult') return v.toFixed(1)+'x';
741          return (kind==='gain' ? '+' : '')+Math.round(v)+'%';
742        }
743        function show(el,v){ el.textContent=fmt(el,v); }
744        function target(el){ return parseFloat(el.getAttribute('data-to')); }
745
746        var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
747        if(reduce){
748          perf.style.opacity='1'; roi.style.opacity='1';
749          vals.concat([roiVal]).forEach(function(el){ show(el,target(el)); });
750          return;
751        }
752        function whenGsap(cb){ if(window.gsap) return cb(); setTimeout(function(){whenGsap(cb);},120); }
753        whenGsap(function(){
754          var g=window.gsap, cards=(window.__hubCards||(window.__hubCards=[]));
755
756          var perfTl=g.timeline({paused:true});
757          vals.forEach(function(el,i){
758            var at=0.1+i*0.14;
759            perfTl.fromTo(el.parentElement,{opacity:0,x:10},{opacity:1,x:0,duration:0.45,ease:'power2.out'},at);
760            var n={v:0};
761            perfTl.to(n,{v:target(el),duration:0.7,ease:'power2.out',
762              onUpdate:function(){ show(el,n.v); }},at);
763          });
764          cards.push({el:perf, tl:perfTl, frame:250});
765
766          var roiTl=g.timeline({paused:true});
767          var line=roi.querySelector('.roi-line'), fill=roi.querySelector('.roi-fill');
768          var tabs=[].slice.call(roi.querySelectorAll('.roi-tab'));
769          roiTl.fromTo(tabs,{opacity:0,y:-4},{opacity:1,y:0,duration:0.35,stagger:0.05,ease:'power2.out'},0.05);
770          var len=line.getTotalLength();
771          g.set(line,{strokeDasharray:len, strokeDashoffset:len});
772          roiTl.to(line,{strokeDashoffset:0,duration:0.85,ease:'power2.out'},0.2);
773          
774          roiTl.fromTo(fill,{opacity:0},{opacity:1,duration:0.6,ease:'power1.out'},0.5);
775          var rn={v:0};
776          roiTl.to(rn,{v:target(roiVal),duration:0.8,ease:'power2.out',
777            onUpdate:function(){ show(roiVal,rn.v); }},0.35);
778          cards.push({el:roi, tl:roiTl, frame:330});
779        });
780      })();
781    (function () {
782        if (typeof JetPulser !== "function") return;
783        if (!document.getElementById("trade-circuit")) return;
784        window.__tradePulser = JetPulser('#trade-circuit', {
785            speed: 1,
786            colors: ['#4cd7f4', '#7ce7ff'],
787            carveDir: 'vertical'
788        });
789        
790        if (window.matchMedia('(max-width: 768px)').matches) {
791            window.__tradePulser.setOptions({ carveBand: 22 });
792        }
793    })();
794        (function() {
795            var canvas = document.getElementById('matrix-canvas');
796            
797            if (!canvas) return;
798            var ctx = canvas.getContext('2d');
799            var W, H;
800            var particles = [];
801            var PARTICLE_COUNT = 28;
802
803            var logoPath = new Path2D('M31.527 0.052C32.825 0.13 33.45 1.225 33.091 2.633C33.044 2.93 31.464 6.512 29.557 10.579C27.024 16.006 26.101 18.149 26.101 18.572C26.101 19.338 26.57 20.167 27.211 20.542C27.712 20.84 28.103 20.855 34.076 20.934C40.096 21.012 40.424 21.027 40.831 21.325C41.44 21.763 42.012 22.426 41.847 23.483C41.769 23.984 34.31 40.173 33.826 40.924C33.685 41.127 33.278 41.44 32.903 41.596C32.246 41.894 31.793 41.894 21.285 41.862L10.356 41.815C9.058 41.815 8.12 40.799 8.792 39.234C8.839 38.937 10.418 35.355 12.326 31.288C14.859 25.861 15.781 23.718 15.781 23.295C15.781 22.529 15.312 21.7 14.671 21.325C14.171 21.027 13.78 21.012 7.807 20.934C1.787 20.855 1.458 20.84 1.052 20.542C0.442 20.105 -0.153 19.593 0.036 18.384C0.114 17.883 7.572 1.694 8.057 0.943C8.198 0.74 8.589 0.443 8.948 0.271C9.574 -0.011 10.074 -0.027 20.566 0.02L31.527 0.052Z');
804
805            function resize() {
806                W = canvas.width = canvas.parentElement.offsetWidth;
807                H = canvas.height = canvas.parentElement.offsetHeight;
808                if (particles.length === 0) initParticles();
809            }
810
811            function initParticles() {
812                particles = [];
813                for (var i = 0; i < PARTICLE_COUNT; i++) {
814                    particles.push(createParticle(true));
815                }
816            }
817
818            function createParticle(randomY) {
819                var scale = 0.6 + Math.random() * 1.8;
820                return {
821                    x: Math.random() * W,
822                    y: randomY ? Math.random() * H : H + 50 + Math.random() * 100,
823                    vx: (Math.random() - 0.5) * 0.2,
824                    vy: -0.12 - Math.random() * 0.28,
825                    scale: scale,
826                    alpha: 0.02 + Math.random() * 0.04,
827                    rotation: Math.random() * Math.PI * 2,
828                    rotSpeed: (Math.random() - 0.5) * 0.002
829                };
830            }
831
832            resize();
833            window.addEventListener('resize', resize);
834
835            function renderFrame() {
836                ctx.clearRect(0, 0, W, H);
837
838                for (var i = 0; i < particles.length; i++) {
839                    var p = particles[i];
840
841                    ctx.save();
842                    ctx.translate(p.x, p.y);
843                    ctx.rotate(p.rotation);
844                    ctx.scale(p.scale, p.scale);
845                    
846                    ctx.translate(-21, -21);
847                    ctx.globalAlpha = p.alpha;
848                    ctx.fillStyle = '#4cd7f4';
849                    ctx.fill(logoPath);
850                    ctx.restore();
851
852                    p.x += p.vx;
853                    p.y += p.vy;
854                    p.rotation += p.rotSpeed;
855
856                    if (p.y < -60 * p.scale) {
857                        particles[i] = createParticle(false);
858                    }
859                    if (p.x < -60) p.x = W + 30;
860                    if (p.x > W + 60) p.x = -30;
861                }
862            }
863
864            var inView = true, matrixRaf = 0;
865            function draw() {
866                matrixRaf = 0;
867                if (!inView) return;
868                renderFrame();
869                matrixRaf = requestAnimationFrame(draw);
870            }
871            function wake() { if (inView && !matrixRaf) matrixRaf = requestAnimationFrame(draw); }
872
873            var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
874            if (reduceMotion) {
875                
876                renderFrame();
877            } else {
878                if ('IntersectionObserver' in window) {
879                    var io = new IntersectionObserver(function (entries) {
880                        entries.forEach(function (e) { inView = e.isIntersecting; wake(); });
881                    }, { rootMargin: '120px' });
882                    io.observe(canvas.parentElement);
883                }
884                draw();
885            }
886        })();
887    (function initAnimations() {
888        if (typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined' || document.readyState === 'loading') {
889            setTimeout(initAnimations, 100);
890            return;
891        }
892        gsap.registerPlugin(ScrollTrigger);
893
894        var REDUCED = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
895        var SMALL   = window.matchMedia('(max-width: 768px)').matches;
896        var TRAVEL  = SMALL ? 0.6 : 1;                 
897        var EASE_RISE = 'expo.out', EASE_SOFT = 'power2.out', EASE_CARD = 'power3.out';
898
899        function reveal(el, voice, opts) {
900            if (!el) return;
901            opts = opts || {};
902            var start = opts.start || 'top 84%';
903            var delay = opts.delay || 0;
904            var from, to;
905            if (voice === 'headline') {
906                from = { opacity: 0, clipPath: 'inset(0 0 100% 0)', webkitClipPath: 'inset(0 0 100% 0)' };
907                to   = { opacity: 1, clipPath: 'inset(0 0 0% 0)', webkitClipPath: 'inset(0 0 0% 0)', duration: 0.9, ease: EASE_RISE,
908                         onComplete: function () { gsap.set(el, { clearProps: 'clipPath,webkitClipPath' }); } };
909            } else if (voice === 'title') {
910                
911                from = { opacity: 0, y: 18 * TRAVEL };
912                to   = { opacity: 1, y: 0, duration: 0.85, ease: EASE_CARD };
913            } else if (voice === 'eyebrow') {
914                from = { opacity: 0, y: 10 * TRAVEL };
915                to   = { opacity: 1, y: 0, duration: 0.5, ease: EASE_SOFT };
916            } else if (voice === 'body') {
917                from = { opacity: 0, y: 14 * TRAVEL };
918                to   = { opacity: 1, y: 0, duration: 0.9, ease: EASE_SOFT };
919            } else { 
920                from = { opacity: 0, scale: 0.94 };
921                to   = { opacity: 1, scale: 1, duration: 1.2, ease: 'power2.out' };
922            }
923            gsap.set(el, from);
924            ScrollTrigger.create({
925                trigger: el, start: start, once: true,
926                onEnter: function () { gsap.to(el, Object.assign({ delay: delay }, to)); }
927            });
928        }
929
930        function revealGroup(sel, voice, opts) {
931            gsap.utils.toArray(sel).forEach(function (el) { reveal(el, voice, opts); });
932        }
933
934        function revealStagger(sel, opts) {
935            var items = gsap.utils.toArray(sel);
936            if (!items.length) return;
937            opts = opts || {};
938            var axis = opts.axis || 'y';
939            var dist = (opts.dist != null ? opts.dist : 32) * TRAVEL;
940            var from = axis === 'x'
941                ? { opacity: 0, x: -dist }
942                : { opacity: 0, y: dist, scale: opts.scale === false ? 1 : 0.985 };
943            gsap.set(items, from);
944            ScrollTrigger.batch(items, {
945                start: opts.start || 'top 86%', once: true,
946                onEnter: function (batch) {
947                    var t = axis === 'x' ? { opacity: 1, x: 0 } : { opacity: 1, y: 0, scale: 1 };
948                    t.duration = opts.duration || 0.85;
949                    t.ease = EASE_CARD;
950                    t.stagger = { each: opts.each || 0.09, from: opts.from || 'start' };
951                    
952                    t.onComplete = function () { gsap.set(batch, { clearProps: 'opacity,transform' }); };
953                    gsap.to(batch, t);
954                }
955            });
956        }
957
958        function parallax(sel, amount) {
959            if (SMALL) return;                         
960            gsap.utils.toArray(sel).forEach(function (el) {
961                gsap.to(el, {
962                    yPercent: amount, ease: 'none',
963                    scrollTrigger: { trigger: el, start: 'top bottom', end: 'bottom top', scrub: 0.6 }
964                });
965            });
966        }
967
968        if (!REDUCED) {
969            
970            revealGroup('.coins-badge, .season-badge, .security-badge', 'eyebrow');
971            
972            revealGroup('.products-title, .security-title', 'headline', { delay: 0.06 });
973            
974            revealGroup('.coins-title, .inside-title, .season-title, .trade-title', 'title', { delay: 0.05 });
975            
976            revealGroup('.season-desc, .trade-desc, .security-note', 'body', { delay: 0.16 });
977            revealGroup('.coins-cta', 'body', { delay: 0.2, start: 'top 90%' });
978            
979            revealStagger('.product-card', { each: 0.1, start: 'top 80%' });
980            revealStagger('.security-card', { each: 0.09, from: 'center' });
981            revealStagger('.inside-item', { each: 0.07, dist: 22, scale: false, start: 'top 88%' });
982            
983            revealStagger('.season-step', { axis: 'x', each: 0.1 });
984            revealStagger('.trade-feature', { each: 0.07, dist: 20, scale: false });
985            
986            revealGroup('.security-3d', 'media', { delay: 0.1, start: 'top 82%' });
987            reveal(document.querySelector('.ticker-board'), 'media', { delay: 0.15, start: 'top 84%' });
988            
989            parallax('.security-3d', -4);
990        } else {
991            
992            gsap.set('.coins-badge,.season-badge,.security-badge,.coins-title,.inside-title,.products-title,.season-title,.security-title,.trade-title,.season-desc,.trade-desc,.coins-cta,.product-card,.security-card,.inside-item,.season-step,.trade-feature,.security-3d,.ticker-board',
993                { opacity: 1, x: 0, y: 0, scale: 1, clearProps: 'clipPath' });
994        }
995
996        if (!REDUCED) {
997            gsap.set('.hero-left h1 .line-inner', { yPercent: 120 });
998            gsap.set('.hero-left .hero-desc', { opacity: 0, y: 18 });
999            gsap.set('.hero-buttons', { opacity: 0, y: 18 });
1000            gsap.set('.hero-stats', { opacity: 0, y: 18 });
1001            gsap.set('.screen-frame', { opacity: 0, y: 36, scale: 0.96, rotationX: 13, transformPerspective: 1500, transformOrigin: 'center center' });
1002
1003            var heroTl = gsap.timeline({ defaults: { ease: EASE_SOFT } });
1004            heroTl
1005                .to('.hero-left h1 .line-inner', { yPercent: 0, duration: 1.05, stagger: 0.12, ease: EASE_RISE }, 0.25)
1006                .to('.hero-left .hero-desc', { opacity: 1, y: 0, duration: 0.8 }, 0.75)
1007                .to('.hero-buttons', { opacity: 1, y: 0, duration: 0.7 }, 0.95)
1008                .to('.hero-stats', { opacity: 1, y: 0, duration: 0.7 }, 1.15)
1009                .to('.screen-frame', { opacity: 1, y: 0, scale: 1, duration: 1.3, ease: EASE_CARD }, 0.45);
1010        }
1011
1012        function animateCounters() {
1013            document.querySelectorAll('.stat-value[data-count]').forEach(function(el) {
1014                var target = parseFloat(el.getAttribute('data-count'));
1015                var decimals = parseInt(el.getAttribute('data-decimals')) || 0;
1016                var prefix = el.getAttribute('data-prefix') || '';
1017                var suffix = el.getAttribute('data-suffix') || '';
1018                var obj = { val: 0 };
1019
1020                if (REDUCED) {
1021                    el.textContent = prefix + target.toFixed(decimals) + suffix;
1022                    return;
1023                }
1024
1025                gsap.to(obj, {
1026                    val: target,
1027                    duration: 2.2,
1028                    delay: 1.5,
1029                    ease: 'power2.out',
1030                    onUpdate: function() {
1031                        el.textContent = prefix + obj.val.toFixed(decimals) + suffix;
1032                    }
1033                });
1034            });
1035        }
1036        animateCounters();
1037
1038        (function () {
1039            var beam = document.querySelector('.pts-beam');
1040            if (!beam || REDUCED) return;
1041            if (!('IntersectionObserver' in window)) { beam.classList.add('is-live'); return; }
1042            new IntersectionObserver(function (entries) {
1043                entries.forEach(function (e) { beam.classList.toggle('is-live', e.isIntersecting); });
1044            }, { rootMargin: '150px' }).observe(beam);
1045        })();
1046
1047        var coins = [
1048            { id: 'bitcoin', name: 'Bitcoin', ticker: 'BTC', perp: 'PERP_BTC_USDC', price: '--', change: '', down: false, img: 'assets/images/instruments/btc.svg', binance: 'btcusdt' },
1049            { id: 'ethereum', name: 'Ethereum', ticker: 'ETH', perp: 'PERP_ETH_USDC', price: '--', change: '', down: false, img: 'assets/images/instruments/eth.svg', binance: 'ethusdt' },
1050            { id: 'solana', name: 'Solana', ticker: 'SOL', perp: 'PERP_SOL_USDC', price: '--', change: '', down: false, img: 'assets/images/instruments/sol.svg', binance: 'solusdt' },
1051            { id: 'binancecoin', name: 'BNB', ticker: 'BNB', perp: 'PERP_BNB_USDC', price: '--', change: '', down: false, img: 'assets/images/instruments/bnb.svg', binance: 'bnbusdt' },
1052            { id: 'ripple', name: 'XRP', ticker: 'XRP', perp: 'PERP_XRP_USDC', price: '--', change: '', down: false, img: 'assets/images/instruments/xrp.svg', binance: 'xrpusdt' },
1053        ];
1054
1055        var stocks = [
1056            { sym: 'NVDA',    perp: 'PERP_NVDA_USDC',        name: 'NVIDIA',  ticker: 'NVDA',    img: 'assets/images/instruments/nvda.svg' },
1057            { sym: 'META',    perp: 'PERP_META_USDC_mythos', name: 'Meta',    ticker: 'META',    img: 'assets/images/instruments/meta.svg' },
1058            { sym: 'SPY',     perp: 'PERP_SPY_USDC_mythos',  name: 'S&P 500', ticker: 'SPY',     img: 'assets/images/instruments/spy.svg' },
1059            { sym: 'EUR/USD', perp: 'PERP_EURUSD_USDC',      name: 'Euro',    ticker: 'EUR/USD', img: 'assets/images/instruments/eurusd.svg' },
1060        ];
1061
1062        var cryptoCoins = coins.filter(function (c) { return !!c.binance; });
1063
1064        function marketHref(c) {
1065            return c.perp ? 'https://trade.zipmex.com/perps/' + c.perp : null;
1066        }
1067        
1068        var MARKET_TARGET = ' target="_blank" rel="noopener"';
1069
1070        function buildCoinCard(c, dup) {
1071            var cls = (c.change || '').charAt(0) === '-' ? 'down' : 'up';
1072            var href = marketHref(c);
1073            var hidden = dup ? ' tabindex="-1" aria-hidden="true"' : '';
1074            var open = href
1075                ? '<a class="coin-card" href="' + href + '"' + MARKET_TARGET +
1076                  ' aria-label="Trade ' + c.ticker + ' (opens in a new tab)"' + hidden +
1077                  ' data-inst="' + (c.sym || c.id) + '">'
1078                : '<div class="coin-card" data-inst="' + (c.sym || c.id) + '">';
1079            return open +
1080                '<div class="coin-icon"><img src="' + c.img + '" width="30" height="30" alt="' + c.name + '" loading="lazy"></div>' +
1081                '<div class="coin-info">' +
1082                    '<div class="coin-name-row"><span class="coin-name">' + c.name + '</span><span class="coin-ticker">' + c.ticker + '</span></div>' +
1083                    '<div class="coin-price-row">' +
1084                        '<span class="coin-price">' + c.price + '</span>' +
1085                        '<span class="coin-change ' + cls + '">' + (c.change || '') + '</span>' +
1086                    '</div>' +
1087                '</div>' + (href ? '</a>' : '</div>');
1088        }
1089
1090        function fillRow(id, coinsList) {
1091            var el = document.getElementById(id);
1092            if (!el) return;
1093            var html = '';
1094            for (var r = 0; r < 4; r++) {
1095                coinsList.forEach(function(c) { html += buildCoinCard(c, r > 0); });
1096            }
1097            el.innerHTML = html;
1098        }
1099
1100        fillRow('coins-row-1', coins);
1101        fillRow('coins-row-2', stocks.map(function (x) {
1102            return { sym: x.sym, perp: x.perp, name: x.name, ticker: x.ticker, img: x.img, price: '--', change: '' };
1103        }));
1104
1105        (function() {
1106            var coinsSection = document.querySelector('.coins-section');
1107            if (!coinsSection) return;
1108            var tracks = coinsSection.querySelectorAll('.coins-track');
1109            if ('IntersectionObserver' in window) {
1110                
1111                var obs = new IntersectionObserver(function(entries) {
1112                    entries.forEach(function(e) {
1113                        tracks.forEach(function(t) { t.classList.toggle('running', e.isIntersecting); });
1114                    });
1115                }, { threshold: 0, rootMargin: '200px' });
1116                obs.observe(coinsSection);
1117            } else {
1118                tracks.forEach(function(t) { t.classList.add('running'); });
1119            }
1120        })();
1121
1122        (function () {
1123            var container = document.getElementById('tv-chart');
1124            if (!container) return;
1125
1126            var MARKET_API = 'https://api.orderly.org/v1/tv/history';
1127
1128            var fallbackEl = document.getElementById('chart-fallback');
1129            var nameEl = document.getElementById('chart-quote-name');
1130            var priceEl = document.getElementById('chart-quote-price');
1131            var changeEl = document.getElementById('chart-quote-change');
1132            var tabs = [].slice.call(document.querySelectorAll('.chart-inst'));
1133
1134            var chart = null;
1135            var series = null;
1136            var started = false;
1137            var narrow = window.matchMedia('(max-width: 768px)').matches;
1138
1139            function setState(state, text) {
1140                if (!fallbackEl) return;
1141                fallbackEl.classList.toggle('is-hidden', state === 'ready');
1142                fallbackEl.classList.toggle('is-error', state === 'error');
1143                if (text) {
1144                    var t = fallbackEl.querySelector('.chart-fallback-text');
1145                    if (t) t.textContent = text;
1146                }
1147            }
1148
1149            function fmt(n) {
1150                if (!isFinite(n)) return '--';
1151                if (n >
1151= 1000) return '$' + n.toLocaleString('en-US', { maximumFractionDigits: 2 });
1152                if (n >= 1) return '$' + n.toFixed(2);
1153                return '$' + n.toFixed(4);
1154            }
1155
1156            function initChart() {
1157                chart = LightweightCharts.createChart(container, {
1158                    layout: {
1159                        background: { type: 'solid', color: 'transparent' },
1160                        textColor: 'rgba(255,255,255,0.35)',
1161                        fontFamily: '"Banana Grotesk Mono", monospace',
1162                        fontSize: 10,
1163                        attributionLogo: false
1164                    },
1165                    grid: {
1166                        vertLines: { color: 'rgba(255,255,255,0.03)' },
1167                        horzLines: { color: 'rgba(255,255,255,0.03)' }
1168                    },
1169                    rightPriceScale: { borderColor: 'rgba(255,255,255,0.06)' },
1170                    timeScale: { borderColor: 'rgba(255,255,255,0.06)', timeVisible: !narrow },
1171                    crosshair: { mode: LightweightCharts.CrosshairMode.Normal },
1172                    handleScroll: !narrow,
1173                    handleScale: !narrow
1174                });
1175                series = chart.addCandlestickSeries({
1176                    upColor: '#00c076', downColor: '#ff4d4d',
1177                    borderUpColor: '#00c076', borderDownColor: '#ff4d4d',
1178                    wickUpColor: '#00c076', wickDownColor: '#ff4d4d'
1179                });
1180                new ResizeObserver(function () {
1181                    if (chart) chart.applyOptions({ width: container.clientWidth, height: container.clientHeight });
1182                }).observe(container);
1183            }
1184
1185            var iconEl = document.getElementById('chart-quote-icon');
1186
1187            function paintQuote(label, candles, icon, day) {
1188                if (nameEl) nameEl.textContent = label;
1189                if (iconEl && icon) iconEl.src = icon;
1190                if (!candles.length) return;
1191                var price = day ? day.close : candles[candles.length - 1].close;
1192                var pct = day ? (day.close - day.open) / day.open * 100 : 0;
1193                if (priceEl) priceEl.textContent = fmt(price);
1194                if (changeEl) {
1195                    
1196                    changeEl.textContent = (pct > 0 ? '+' : '') + pct.toFixed(2) + '%';
1197                    changeEl.className = 'chart-quote-change ' + (pct > 0 ? 'up' : pct < 0 ? 'down' : '');
1198                }
1199            }
1200
1201            function iconFor(symbol) {
1202                var btn = document.querySelector('.chart-inst[data-symbol="' + symbol + '"] img');
1203                return btn ? btn.getAttribute('src') : null;
1204            }
1205
1206            function load(symbol, label) {
1207                setState('loading', 'Loading ' + label + '…');
1208                
1209                var step = narrow ? 86400 : 3600;
1210                var to = Math.floor(Date.now() / 1000);
1211                var url = MARKET_API + '?symbol=' + encodeURIComponent(symbol) +
1212                    '&resolution=' + (narrow ? '1D' : '60') +
1213                    '&from=' + (to - 130 * step) + '&to=' + to;
1214                
1215                var day = fetch('https://api.orderly.org/v1/public/futures/' + encodeURIComponent(symbol))
1216                    .then(function (r) { return r.json(); })
1217                    .then(function (d) {
1218                        var m = d && d.data;
1219                        return (m && m['24h_open'] > 0 && m['24h_close'] > 0)
1220                            ? { open: m['24h_open'], close: m['24h_close'] } : null;
1221                    })
1222                    .catch(function () { return null; });
1223
1224                Promise.all([fetch(url).then(function (r) { return r.json(); }), day])
1225                    .then(function (res) {
1226                        var d = res[0];
1227                        if (d.s !== 'ok' || !d.t || !d.t.length) throw new Error('no data');
1228                        var candles = d.t.map(function (t, i) {
1229                            return { time: t, open: d.o[i], high: d.h[i], low: d.l[i], close: d.c[i] };
1230                        }).filter(function (c) { return isFinite(c.close); }).slice(-120);
1231                        if (!candles.length) throw new Error('no data');
1232                        series.setData(candles);
1233                        chart.timeScale().fitContent();
1234                        paintQuote(label, candles, iconFor(symbol), res[1]);
1235                        setState('ready');
1236                    })
1237                    .catch(function () {
1238                        setState('error', 'Market data is unavailable right now');
1239                    });
1240            }
1241
1242            function select(btn) {
1243                tabs.forEach(function (t) {
1244                    var on = t === btn;
1245                    t.classList.toggle('is-active', on);
1246                    t.setAttribute('aria-selected', String(on));
1247                });
1248                load(btn.getAttribute('data-symbol'), btn.getAttribute('data-label'));
1249            }
1250
1251            tabs.forEach(function (btn) {
1252                btn.addEventListener('click', function () { select(btn); });
1253            });
1254
1255            function start() {
1256                if (started || typeof LightweightCharts === 'undefined') return;
1257                started = true;
1258                initChart();
1259                var active = document.querySelector('.chart-inst.is-active') || tabs[0];
1260                if (active) load(active.getAttribute('data-symbol'), active.getAttribute('data-label'));
1261            }
1262
1263            var script = document.createElement('script');
1264            script.src = '/assets/js/vendor/lightweight-charts.standalone.production.js';
1265            script.onload = function () {
1266                if ('IntersectionObserver' in window) {
1267                    var io = new IntersectionObserver(function (entries) {
1268                        entries.forEach(function (e) { if (e.isIntersecting) { start(); io.disconnect(); } });
1269                    }, { rootMargin: '200px' });
1270                    io.observe(container);
1271                } else {
1272                    start();
1273                }
1274            };
1275            script.onerror = function () { setState('error', 'Chart library failed to load'); };
1276            document.head.appendChild(script);
1277        })();
1278
1279        (function () {
1280            var API = 'https://api.orderly.org/v1/public/futures';
1281            var section = document.querySelector('.coins-section');
1282            if (!section) return;
1283
1284            function fmtPrice(n) {
1285                if (!isFinite(n)) return '--';
1286                if (n >= 1000) return '$' + n.toLocaleString('en-US', { maximumFractionDigits: 0 });
1287                if (n >= 1) return '$' + n.toFixed(2);
1288                return '$' + n.toFixed(4);
1289            }
1290
1291            function apply(quotes) {
1292                
1293                window.__zexoQuotes = quotes;
1294                document.dispatchEvent(new CustomEvent('zexo:quotes', { detail: quotes }));
1295                stocks.forEach(function (x) {
1296                    var q = quotes[x.sym];
1297                    if (!q) return;
1298                    var price = fmtPrice(q.price);
1299                    
1300                    var pct = (q.change > 0 ? '+' : '') + (q.change || 0).toFixed(2) + '%';
1301                    var cards = document.querySelectorAll('[data-inst="' + x.sym + '"]');
1302                    cards.forEach(function (card) {
1303                        var priceEl = card.querySelector('.coin-price');
1304                        var changeEl = card.querySelector('.coin-change');
1305                        if (priceEl && priceEl.textContent !== price) {
1306                            
1307                            priceEl.textContent = price;
1308                        }
1309                        if (changeEl) {
1310                            changeEl.textContent = pct;
1311                            changeEl.className = 'coin-change ' + (q.change >= 0 ? 'up' : 'down');
1312                        }
1313                    });
1314                });
1315            }
1316
1317            function load() {
1318                
1319                Promise.all(stocks.map(function (x) {
1320                    return fetch(API + '/' + encodeURIComponent(x.perp))
1321                        .then(function (r) { return r.json(); })
1322                        .then(function (d) { return { sym: x.sym, m: d && d.data }; })
1323                        .catch(function () { return null; });
1324                })).then(function (list) {
1325                    var quotes = {};
1326                    list.forEach(function (row) {
1327                        if (!row || !row.m) return;
1328                        var open = row.m['24h_open'], close = row.m['24h_close'];
1329                        if (!(open > 0) || !(close > 0)) return;
1330                        quotes[row.sym] = { price: close, change: (close - open) / open * 100 };
1331                    });
1332                    if (Object.keys(quotes).length) apply(quotes);
1333                });
1334            }
1335            var timer = null;
1336            function startPolling() {
1337                if (timer) return;
1338                load();
1339                timer = setInterval(load, 2 * 60 * 1000);
1340            }
1341            function stopPolling() {
1342                if (!timer) return;
1343                clearInterval(timer);
1344                timer = null;
1345            }
1346
1347            if ('IntersectionObserver' in window) {
1348                new IntersectionObserver(function (entries) {
1349                    entries.forEach(function (e) { e.isIntersecting ? startPolling() : stopPolling(); });
1350                }, { rootMargin: '200px' }).observe(section);
1351            } else {
1352                startPolling();
1353            }
1354        })();
1355
1356        function fmtPrice(n) {
1357            if (n >= 1000) return '$' + n.toLocaleString('en-US', { maximumFractionDigits: 0 });
1358            if (n >= 1) return '$' + n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
1359            return '$' + n.toLocaleString('en-US', { minimumFractionDigits: 3, maximumFractionDigits: 4 });
1360        }
1361
1362        function buildSparkSvg(prices, isUp) {
1363            if (!prices || prices.length < 2) return '';
1364            var step = Math.max(1, Math.floor(prices.length / 24));
1365            var pts = [];
1366            for (var i = 0; i < prices.length; i += step) pts.push(prices[i]);
1367            var min = Math.min.apply(null, pts);
1368            var max = Math.max.apply(null, pts);
1369            var range = max - min || 1;
1370            var w = 80, h = 28, pad = 2;
1371            var points = pts.map(function(p, i) {
1372                var x = pad + (i / (pts.length - 1)) * (w - pad * 2);
1373                var y = pad + (1 - (p - min) / range) * (h - pad * 2);
1374                return x.toFixed(1) + ',' + y.toFixed(1);
1375            }).join(' ');
1376            var color = isUp ? '#00c076' : '#ff4d4d';
1377            return '<svg viewBox="0 0 ' + w + ' ' + h + '" fill="none"><polyline points="' + points + '" stroke="' + color + '" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
1378        }
1379
1380        var tickerData = {};
1381
1382        function renderTickerBoard() {
1383            var board = document.getElementById('ticker-board-body');
1384            if (!board) return;
1385            var shown = coins.slice(0, 8);
1386            var html = '';
1387            shown.forEach(function(c) {
1388                var d = tickerData[c.id] || {};
1389                var price = d.price || c.price;
1390                var ch = d.change != null ? d.change : 0;
1391                var isUp = ch >= 0;
1392                var spark = d.sparkPrices ? buildSparkSvg(d.sparkPrices, isUp) : '';
1393                
1394                var href = marketHref(c);
1395                html += (href
1396                        ? '<a class="ticker-row" href="' + href + '"' + MARKET_TARGET +
1397                          ' aria-label="Trade ' + c.ticker + ' (opens in a new tab)" data-ticker="' + (c.binance || '') + '">'
1398                        : '<div class="ticker-row" data-ticker="' + (c.binance || '') + '">') +
1399                    '<div class="ticker-asset">' +
1400                        '<img src="' + c.img + '" width="28" height="28" alt="' + c.ticker + '" loading="lazy">' +
1401                        '<span class="ticker-asset-name">' + c.name + '<span class="ticker-asset-ticker">' + c.ticker + '</span></span>' +
1402                    '</div>' +
1403                    '<span class="ticker-price" data-coin-price="' + c.id + '">' + (typeof price === 'number' ? fmtPrice(price) : price) + '</span>' +
1404                    '<span class="ticker-change ' + (isUp ? 'up' : 'down') + '">' + (isUp ? '+' : '') + ch.toFixed(2) + '%</span>' +
1405                    '<span class="ticker-spark">' + spark + '</span>' +
1406                (href ? '</a>' : '</div>');
1407            });
1408            board.innerHTML = html;
1409        }
1410
1411        renderTickerBoard();
1412        connectBinanceWS();
1413
1414        function fetchLivePrices(retries) {
1415            if (typeof retries === 'undefined') retries = 2;
1416            var ids = cryptoCoins.map(function(c) { return c.id; }).join(',');
1417            fetch('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=' + ids + '&sparkline=true&price_change_percentage=24h')
1418                .then(function(r) {
1419                    if (!r.ok) throw new Error(r.status);
1420                    return r.json();
1421                })
1422                .then(function(data) {
1423                    data.forEach(function(d) {
1424                        
1425                        tickerData[d.id] = {
1426                            price: d.current_price,
1427                            change: d.price_change_percentage_24h || 0,
1428                            sparkPrices: d.sparkline_in_7d ? d.sparkline_in_7d.price : null
1429                        };
1430                    });
1431                    cryptoCoins.forEach(function(c) {
1432                        var d = tickerData[c.id];
1433                        if (!d) return;
1434                        c.price = fmtPrice(d.price);
1435                        c.down = d.change < 0;
1436                        c.change = (d.change >= 0 ? '+' : '') + d.change.toFixed(2) + '%';
1437                    });
1438                    fillRow('coins-row-1', coins);
1439                    renderTickerBoard();
1440                })
1441                .catch(function() {
1442                    if (retries > 0) {
1443                        setTimeout(function() { fetchLivePrices(retries - 1); }, 3000);
1444                    }
1445                });
1446        }
1447        fetchLivePrices();
1448
1449        function connectBinanceWS() {
1450            var symbols = cryptoCoins.map(function(c) { return c.binance + '@miniTicker'; });
1451            if (!symbols.length) return;
1452            var ws = new WebSocket('wss://stream.binance.com:9443/stream?streams=' + symbols.join('/'));
1453            ws.onmessage = function(evt) {
1454                var msg = JSON.parse(evt.data);
1455                var d = msg.data;
1456                if (!d || !d.s) return;
1457                var coin = null;
1458                cryptoCoins.forEach(function(c) { if (d.s.toLowerCase() === c.binance) coin = c; });
1459                if (!coin) return;
1460                var newPrice = parseFloat(d.c);
1461                var oldPrice = tickerData[coin.id] ? tickerData[coin.id].price : newPrice;
1462                var ch24 = ((newPrice - parseFloat(d.o)) / parseFloat(d.o) * 100);
1463                if (!tickerData[coin.id]) tickerData[coin.id] = {};
1464                tickerData[coin.id].price = newPrice;
1465                tickerData[coin.id].change = ch24;
1466                var priceEl = document.querySelector('[data-coin-price="' + coin.id + '"]');
1467                if (priceEl) {
1468                    priceEl.textContent = fmtPrice(newPrice);
1469                    priceEl.classList.remove('flash-up', 'flash-down');
1470                    void priceEl.offsetWidth;
1471                    priceEl.classList.add(newPrice >= oldPrice ? 'flash-up' : 'flash-down');
1472                }
1473                var row = priceEl ? priceEl.closest('.ticker-row') : null;
1474                if (row) {
1475                    var changeEl = row.querySelector('.ticker-change');
1476                    if (changeEl) {
1477                        changeEl.textContent = (ch24 >= 0 ? '+' : '') + ch24.toFixed(2) + '%';
1478                        changeEl.className = 'ticker-change ' + (ch24 >= 0 ? 'up' : 'down');
1479                    }
1480                }
1481                coin.price = fmtPrice(newPrice);
1482                coin.down = ch24 < 0;
1483                coin.change = (ch24 >= 0 ? '+' : '') + ch24.toFixed(2) + '%';
1484
1485                document.querySelectorAll('[data-inst="' + coin.id + '"]').forEach(function (card) {
1486                    var p = card.querySelector('.coin-price');
1487                    var ch = card.querySelector('.coin-change');
1488                    if (p && p.textContent !== coin.price) {
1489                        
1490                        p.textContent = coin.price;
1491                    }
1492                    if (ch) {
1493                        ch.textContent = coin.change;
1494                        ch.className = 'coin-change ' + (ch24 >= 0 ? 'up' : 'down');
1495                    }
1496                });
1497            };
1498            ws.onclose = function() { setTimeout(connectBinanceWS, 3000); };
1499            ws.onerror = function() { ws.close(); };
1500        }
1501    })();
1502    (function pageTransitions() {
1503        var docEl = document.documentElement;
1504        var REDUCE = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
1505
1506        var lenis = null;
1507        function initSmoothScroll() {
1508            if (REDUCE || typeof window.Lenis === 'undefined') return;
1509            
1510            if (window.matchMedia && window.matchMedia('(hover: none) and (pointer: coarse)').matches) {
1511                docEl.style.scrollBehavior = 'auto';
1512                return;
1513            }
1514            try {
1515                lenis = new window.Lenis({
1516                    
1517                    duration: 0.6,
1518                    easing: function (x) { return Math.min(1, 1.001 - Math.pow(2, -10 * x)); },
1519                    smoothWheel: true,
1520                    wheelMultiplier: 1.0,
1521                    touchMultiplier: 1.4
1522                });
1523                docEl.style.scrollBehavior = 'auto';
1524                window.__lenis = lenis;
1525                lenis.on('scroll', function () { if (window.ScrollTrigger) window.ScrollTrigger.update(
1525); });
1526                
1527                var raf = function (t) { lenis.raf(t); requestAnimationFrame(raf); };
1528                requestAnimationFrame(raf);
1529                
1530                var backTop = document.querySelector('.footer-back-top');
1531                if (backTop) {
1532                    backTop.onclick = function () { lenis.scrollTo(0, { duration: 1.2 }); return false; };
1533                }
1534            } catch (e) { lenis = null; }
1535        }
1536
1537        function whenReady(cb) {
1538            if (window.gsap && window.ScrollTrigger) return cb();
1539            setTimeout(function () { whenReady(cb); }, 80);
1540        }
1541
1542        whenReady(function () {
1543            initSmoothScroll();
1544            if (window.ScrollTrigger) window.ScrollTrigger.refresh();
1545        });
1546    })();
1547    (function () {
1548        var v = document.getElementById('hero-video');
1549        if (!v) return;
1550        if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
1551            v.removeAttribute('autoplay');
1552            v.pause();
1553            v.style.opacity = '1'; 
1554            return;
1555        }
1556        
1557        v.addEventListener('playing', function () {
1558            v.style.opacity = '1';
1559        }, { once: true });
1560        
1561        v.addEventListener('ended', function () {
1562            v.pause();
1563        }, { once: true });
1564        
1565        var started = false;
1566        function startHeroVideo() {
1567            if (started) return;
1568            started = true;
1569            v.load();          
1570            try { v.currentTime = 0; } catch (e) {}
1571            var p = v.play();
1572            if (p && p.catch) p.catch(function () {});
1573        }
1574        startHeroVideo();
1575    })();
1576    (function () {
1577        if (location.search.indexOf('perf') === -1) return;
1578
1579        var CASES = [
1580            { id: 'lottie',  name: 'Сцена Alpha Suite', css: '' },
1581            { id: 'dust',    name: 'Пыль в луче Season', css: '.beam-dust{display:none!important}' },
1582            { id: 'beam',    name: 'Вся лента Season', css: '.pts-beam{display:none!important}' },
1583            { id: 'headerbg',name: 'Размытие шапки', css: '.header{backdrop-filter:none!important;-webkit-backdrop-filter:none!important;background:#06060c!important}' },
1584            { id: 'masks',   name: 'Маски security и trade', css: '.security-3d,#trade-circuit{-webkit-mask-image:none!important;mask-image:none!important}' },
1585            { id: 'webgl',   name: 'WebGL-кнопки', css: '.lm-canvas{display:none!important}' },
1586            { id: 'shield',  name: 'Щит security (3D)', css: '.security-3d canvas{display:none!important}' },
1587            { id: 'pulser',  name: 'Схема в trade', css: '#trade-circuit{display:none!important}' },
1588            { id: 'coins',   name: 'Лента монет', css: '.coins-track{animation:none!important}' },
1589            { id: 'anim',    name: 'ВСЕ css-анимации', css: '*{animation:none!important;transition:none!important}' }
1590        ];
1591
1592        var style = document.createElement('style');
1593        document.head.appendChild(style);
1594        var off = {};
1595
1596        function applyCases() {
1597            var css = '';
1598            CASES.forEach(function (c) { if (off[c.id] && c.css) css += c.css + '\n'; });
1599            style.textContent = css;
1600            var lot = window.__calloutsLottie;
1601            if (lot) { off.lottie ? lot.pause() : lot.play(); }
1602        }
1603
1604        var panel = document.createElement('div');
1605        panel.setAttribute('style', [
1606            'position:fixed', 'right:8px', 'bottom:8px', 'z-index:99999',
1607            'width:250px', 'max-height:70vh', 'overflow:auto',
1608            'background:rgba(0,0,0,.88)', 'color:#fff', 'border:1px solid rgba(255,255,255,.2)',
1609            'border-radius:10px', 'padding:10px 12px',
1610            'font:12px/1.45 ui-monospace,Menlo,Consolas,monospace',
1611            '-webkit-backdrop-filter:none', 'backdrop-filter:none'
1612        ].join(';'));
1613
1614        var read = document.createElement('div');
1615        read.style.cssText = 'font-size:13px;margin-bottom:8px';
1616        panel.appendChild(read);
1617
1618        var hint = document.createElement('div');
1619        hint.style.cssText = 'color:#869396;margin-bottom:8px';
1620        hint.textContent = 'Крутите страницу. Затем гасите пункты по одному и смотрите, что убирает рывки.';
1621        panel.appendChild(hint);
1622
1623        CASES.forEach(function (c) {
1624            var row = document.createElement('label');
1625            row.style.cssText = 'display:flex;align-items:center;gap:8px;padding:3px 0;color:#cfd6d7';
1626            var cb = document.createElement('input');
1627            cb.type = 'checkbox';
1628            cb.onchange = function () { off[c.id] = cb.checked; applyCases(); reset(); };
1629            row.appendChild(cb);
1630            row.appendChild(document.createTextNode('выключить: ' + c.name));
1631            panel.appendChild(row);
1632        });
1633
1634        var btn = document.createElement('button');
1635        btn.textContent = 'Сбросить счётчики';
1636        btn.style.cssText = 'margin-top:8px;width:100%;padding:7px;border-radius:6px;border:1px solid rgba(255,255,255,.25);background:#1a1a1a;color:#fff;font:inherit';
1637        panel.appendChild(btn);
1638        document.body.appendChild(panel);
1639
1640        var frames = 0, long33 = 0, long100 = 0, worst = 0, t0 = 0, last = 0;
1641        function reset() { frames = 0; long33 = 0; long100 = 0; worst = 0; t0 = performance.now(); last = t0; }
1642        btn.onclick = reset;
1643        reset();
1644
1645        function tick(now) {
1646            var dt = now - last; last = now;
1647            frames++;
1648            if (dt > 33) long33++;
1649            if (dt > 100) long100++;
1650            if (dt > worst) worst = dt;
1651            var sec = (now - t0) / 1000;
1652            if (sec > 0.4) {
1653                read.innerHTML =
1654                    '<b>' + Math.round(frames / sec) + ' fps</b> за ' + sec.toFixed(0) + ' с<br>' +
1655                    'рывков (>33 мс): <b>' + long33 + '</b><br>' +
1656                    'сильных (>100 мс): <b>' + long100 + '</b><br>' +
1657                    'худший кадр: <b>' + Math.round(worst) + ' мс</b>';
1658            }
1659            requestAnimationFrame(tick);
1660        }
1661        requestAnimationFrame(tick);
1662    })();

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.