PageSourceSearch

https://www.quarkslab.com/wp-content/themes/auregon/elements/widgets/js/elementor.js

js quarkslab.com collected 2026-10-02 02:15:31 UTC 81,013 bytes, 1,990 lines download raw bytes

1(function ($) {
2
3    (function () {
4        function addStyle() {
5            if (document.head) {
6                var style = document.createElement('style');
7                style.textContent = '.pxl-animate { opacity: 0 !important; visibility: hidden !important; }';
8                document.head.appendChild(style);
9            } else {
10                setTimeout(addStyle, 10);
11            }
12        }
13        addStyle();
14    })();
15
16    function auregon_animation_handler($scope) {
17        var $elements = $scope ? $scope.find('.pxl-animate') : $(document).find('.pxl-animate');
18
19        $elements.each(function () {
20            var $el = $(this);
21            if (!$el.hasClass('pxl-invisible')) {
22                $el.addClass('pxl-invisible');
23            }
24        });
25
26        if (window.elementorFrontend && typeof elementorFrontend.waypoint === 'function') {
27            elementorFrontend.waypoint($elements, function () {
28                var $animate_el = $(this),
29                    data = $animate_el.data('settings');
30                if (typeof data !== 'undefined' && typeof data['animation'] !== 'undefined') {
31                    setTimeout(function () {
32                        $animate_el.removeClass('pxl-invisible').addClass('animated ' + data['animation']);
33                    }, data['animation_delay'] || 0);
34                } else {
35                    setTimeout(function () {
36                        $animate_el.removeClass('pxl-invisible').addClass('animated fadeInUp');
37                    }, 300);
38                }
39            });
40        }
41
42        if ($scope && window.elementorFrontend && typeof elementorFrontend.waypoint === 'function') {
43            elementorFrontend.waypoint($scope.find('.pxl-border-animated'), function () {
44                $(this).addClass('pxl-animated');
45            });
46            elementorFrontend.waypoint($scope.find('.pxl-section-divider'), function () {
47                $(this).addClass('pxl-animated');
48            });
49            elementorFrontend.waypoint($scope.find('.TextOutlineAnimation'), function () {
50                $(this).addClass('pxl-animated');
51            });
52            elementorFrontend.waypoint($scope.find('.PXLfadeInUp'), function () {
53                $(this).addClass('pxl-animated');
54            });
55            elementorFrontend.waypoint($scope.find('.pxl-icon1.style-balloon'), function () {
56                $(this).addClass('pxl-animated');
57            });
58        }
59    }
60
61    const PXLDIV_MAX_DIST = 140;
62    const PXLDIV_PEAK = 0.75;
63    const PXLDIV_SPREAD_MIN = 170;
64    const PXLDIV_SPREAD_MAX = 250;
65
66    const PXLBORDER_MAX_DIST = 300;
67    const PXLBORDER_PEAK = 0.75;
68    const PXLBORDER_SPREAD_MIN = 170;
69    const PXLBORDER_SPREAD_MAX = 300;
70
71    function pxl_divider_clamp(v, a, b) {
72        return Math.max(a, Math.min(b, v));
73    }
74
75    function pxl_divider_smoothstep(t) {
76        return t * t * (3 - 2 * t);
77    }
78
79    function bind_divider_glow(container) {
80        if (!container || container.getAttribute('data-divider-glow-bound') === '1') return;
81
82        var dividers = container.querySelectorAll('.pxl-section-divider');
83        if (!dividers.length) return;
84
85        container.setAttribute('data-divider-glow-bound', '1');
86
87        var state = {
88            x: 0,
89            y: 0,
90            inside: false,
91            raf: null
92        };
93
94        function render() {
95            state.raf = null;
96            var rect = container.getBoundingClientRect();
97            if (!rect || rect.width === 0 || rect.height === 0) return;
98
99            var x = pxl_divider_clamp(state.x - rect.left, 0, rect.width);
100            var y = pxl_divider_clamp(state.y - rect.top, 0, rect.height);
101
102            dividers.forEach(function (divider) {
103                var isHorizontal = divider.classList.contains('pxl-section-divider--top') || divider.classList.contains('pxl-section-divider--bottom');
104                var target = isHorizontal ? (divider.classList.contains('pxl-section-divider--top') ? 0 : rect.height) : (divider.classList.contains('pxl-section-divider--left') ? 0 : rect.width);
105                var dist = Math.abs((isHorizontal ? y : x) - target);
106                var t = state.inside ? pxl_divider_clamp(1 - dist / PXLDIV_MAX_DIST, 0, 1) : 0;
107                var eased = pxl_divider_smoothstep(t);
108                var alpha = PXLDIV_PEAK * eased;
109                var spread = PXLDIV_SPREAD_MAX - (PXLDIV_SPREAD_MAX - PXLDIV_SPREAD_MIN) * eased;
110
111                divider.style.setProperty('--pxl-divider-gx', x + 'px');
112                divider.style.setProperty('--pxl-divider-gy', y + 'px');
113                divider.style.setProperty('--pxl-divider-alpha', alpha.toFixed(3));
114                divider.style.setProperty('--pxl-divider-spread', spread.toFixed(1) + 'px');
115                divider.setAttribute('data-glow', state.inside && alph
115a > 0.003 ? '1' : '0');
116            });
117        }
118
119        function schedule() {
120            if (state.raf) return;
121            state.raf = requestAnimationFrame(render);
122        }
123
124        function handleMove(e) {
125            state.x = e.clientX;
126            state.y = e.clientY;
127            state.inside = true;
128            schedule();
129        }
130
131        function handleLeave() {
132            state.inside = false;
133            schedule();
134        }
135
136        var rect = container.getBoundingClientRect();
137        state.x = rect.left + rect.width / 2;
138        state.y = rect.top + rect.height / 2;
139
140        container.addEventListener('mousemove', handleMove);
141        container.addEventListener('mouseenter', handleMove);
142        container.addEventListener('mouseleave', handleLeave);
143
144        schedule();
145    }
146
147    function auregon_section_divider_glow($scope) {
148        var $context = $scope && $scope.length ? $scope : $(document);
149        var hosts = [];
150
151        $context.find('.pxl-section-divider').each(function () {
152            var host = this.closest('.elementor-element');
153            if (host && hosts.indexOf(host) === -1) {
154                hosts.push(host);
155            }
156        });
157
158        hosts.forEach(function (host) {
159            bind_divider_glow(host);
160        });
161    }
162
163    function bind_border_glow(host) {
164        if (!host || host.getAttribute('data-border-glow-bound') === '1') return;
165
166        var glowHost = host.querySelector('.pxl-border-glow');
167        if (!glowHost) return;
168
169        host.setAttribute('data-border-glow-bound', '1');
170
171        var topGlow = glowHost.querySelector('.pxl-bd-glow.top');
172        var rightGlow = glowHost.querySelector('.pxl-bd-glow.right');
173        var bottomGlow = glowHost.querySelector('.pxl-bd-glow.bottom');
174        var leftGlow = glowHost.querySelector('.pxl-bd-glow.left');
175
176        var state = {
177            x: 0,
178            y: 0,
179            inViewport: false,
180            raf: 0,
181            rect: null,
182            obs: null,
183            onMove: null,
184            onResize: null
185        };
186
187        function clamp(v, a, b) { return v < a ? a : (v > b ? b : v); }
188        function smoothstep(t) { return t * t * (3 - 2 * t); } // nếu bạn đã có pxl_divider_smoothstep thì dùng cái đó
189
190        function updateRect() {
191            state.rect = host.getBoundingClientRect();
192        }
193
194        // Calculate distance from point to rectangle
195        // Returns 0 if point is inside rectangle, otherwise distance to nearest edge
196        function distanceToRect(px, py, rect) {
197            var dx = Math.max(0, Math.max(rect.left - px, px - rect.right));
198            var dy = Math.max(0, Math.max(rect.top - py, py - rect.bottom));
199            return Math.sqrt(dx * dx + dy * dy);
200        }
201
202        function render() {
203            state.raf = 0;
204
205            if (!state.inViewport) {
206                // out viewport -> tắt sạch
207                host.style.setProperty('--pxl-bd-alpha', '0');
208                if (topGlow) topGlow.style.opacity = 0;
209                if (rightGlow) rightGlow.style.opacity = 0;
210                if (bottomGlow) bottomGlow.style.opacity = 0;
211                if (leftGlow) leftGlow.style.opacity = 0;
212                return;
213            }
214
215            if (!state.rect) updateRect();
216            var rect = state.rect;
217            if (!rect || !rect.width || !rect.height) return;
218
219            // Calculate distance from mouse to rectangle
220            var distance = distanceToRect(state.x, state.y, rect);
221
222            // If distance > MAX_DIST, turn off
223            if (distance > PXLBORDER_MAX_DIST) {
224                host.style.setProperty('--pxl-bd-alpha', '0');
225                if (topGlow) topGlow.style.opacity = 0;
226                if (rightGlow) rightGlow.style.opacity = 0;
227                if (bottomGlow) bottomGlow.style.opacity = 0;
228                if (leftGlow) leftGlow.style.opacity = 0;
229                return;
230            }
231
232            // Calculate distance to each edge
233            var x = clamp(state.x - rect.left, 0, rect.width);
234            var y = clamp(state.y - rect.top, 0, rect.height);
235
236            var distTop = y;
237            var distRight = rect.width - x;
238            var distBottom = rect.height - y;
239            var distLeft = x;
240
241            // Alpha based on distance to rectangle: 1 - distance / MAX_DIST
242            var baseAlpha = clamp(1 - distance / PXLBORDER_MAX_DIST, 0, 1);
243            var easedBase = smoothstep(baseAlpha);
244
245            // Each edge's intensity based on its distance (closer = brighter)
246            var tTop = clamp(1 - distTop / PXLBORDER_MAX_DIST, 0, 1);
247            var tRight = clamp(1 - distRight / PXLBORDER_MAX_DIST, 0, 1);
248            var tBottom = clamp(1 - distBottom / PXLBORDER_MAX_DIST, 0, 1);
249            var tLeft = clamp(1 - distLeft / PXLBORDER_MAX_DIST, 0, 1);
250
251            var easedTop = smoothstep(tTop);
252            var easedRight = smoothstep(tRight);
253            var easedBottom = smoothstep(tBottom);
254            var easedLeft = smoothstep(tLeft);
255
256            // Main alpha uses base distance
257            var alpha = PXLBORDER_PEAK * easedBase;
258            var spread = PXLBORDER_SPREAD_MAX - (PXLBORDER_SPREAD_MAX - PXLBORDER_SPREAD_MIN) * easedBase;
259
260            host.style.setProperty('--pxl-bd-gx', x + 'px');
261            host.style.setProperty('--pxl-bd-gy', y + 'px');
262            host.style.setProperty('--pxl-bd-alpha', alpha.toFixed(3));
263            host.style.setProperty('--pxl-bd-spread', spread.toFixed(1) + 'px');
264
265            // Edge closest to mouse glows brightest
266            if (topGlow) topGlow.style.opacity = easedTop;
267            if (rightGlow) rightGlow.style.opacity = easedRight;
268            if (bottomGlow) bottomGlow.style.opacity = easedBottom;
269            if (leftGlow) leftGlow.style.opacity = easedLeft;
270        }
271
272        function schedule(forceRect) {
273            if (forceRect) state.rect = null;
274            if (state.raf) return;
275            state.raf = requestAnimationFrame(render);
276        }
277
278        state.onMove = function (e) {
279            state.x = e.clientX;
280            state.y = e.clientY;
281            schedule(false);
282        };
283
284        state.onResize = function () {
285            // khi resize/scroll layout đổi -> refresh rect
286            schedule(true);
287        };
288
289        // IntersectionObserver
290        state.obs = new IntersectionObserver(function (entries) {
291            for (var i = 0; i < entries.length; i++) {
292                if (entries[i].target !== host) continue;
293                state.inViewport = !!entries[i].isIntersecting;
294                schedule(true); // vào/ra viewport đều render để bật/tắt ngay
295            }
296        }, { threshold: 0.1 });
297
298        state.obs.observe(host);
299
300        // PROXIMITY MODE: Listen to pointermove on document to detect mouse near border
301        document.addEventListener('pointermove', state.onMove, { passive: true });
302
303        window.addEventListener('resize', state.onResize, { passive: true });
304        window.addEventListener('scroll', state.onResize, { passive: true });
305
306        // init center
307        updateRect();
308        var r = state.rect;
309        state.x = r.left + r.width / 2;
310        state.y = r.top + r.height / 2;
311
312        schedule(false);
313
314        // cleanup để tránh leak (Elementor re-render)
315        host._pxlBorderGlowCleanup = function () {
316            if (state.raf) cancelAnimationFrame(state.raf);
317            if (state.obs) state.obs.disconnect();
318
319            document.removeEventListener('pointermove', state.onMove);
320
321            window.removeEventListener('resize', state.onResize);
322            window.removeEventListener('scroll', state.onResize);
323
324            host.removeAttribute('data-border-glow-bound');
325            delete host._pxlBorderGlowCleanup;
326        };
327    }
328
329
330    function auregon_border_glow($scope) {
331        var $context = $scope && $scope.length ? $scope : $(document);
332        $context.find('.pxl-border-section-anm').each(function () {
333            bind_border_glow(this);
334        });
335    }
336
337    function auregon_polyfill_waypoint() {
338        if (!window.elementorFrontend || typeof elementorFrontend.waypoint === 'function') return;
339        elementorFrontend.waypoint = function ($elements, handler, options) {
340            options = options || {};
341            var triggerOnce = typeof options.triggerOnce === 'boolean' ? options.triggerOnce : true;
342            var offset = options.offset;
343            var rootMargin = '0px 0px 0px 0px';
344            if (typeof offset === 'string' && /%$/.test(offset)) {
345                var percent = parseFloat(offset);
346                if (!isNaN(percent)) {
347                    var bottomPercent = Math.max(0, 100 - percent);
348                    rootMargin = '0px 0px -' + bottomPercent + '% 0px';
349                }
350            } else if (typeof offset === 'number') {
351                rootMargin = '0px 0px -' + offset + 'px 0px';
352            }
353            if ('IntersectionObserver' in window) {
354                var observer = new IntersectionObserver(function (entries) {
355                    entries.forEach(function (entry) {
356                        if (entry.isIntersecting || entry.intersectionRatio > 0) {
357                            handler.call(entry.target);
358                            if (triggerOnce) {
359                                observer.unobserve(entry.target);
360                            }
361                        }
362                    });
363                }, { root: null, rootMargin: rootMargin, threshold: 0 });
364                $($elements).each(function () {
365                    var dom = this instanceof Element ? this : (this && this[0] instanceof Element ? this[0] : null);
366                    if (dom) observer.observe(dom);
367                });
368            } else {
369                $($elements).each(function () { handler.call(this); });
370            }
371        };
372    }
373
374    function auregon_section_start_render() {
375        var _elementor = typeof elementor !== 'undefined' ? elementor : elementorFrontend;
376
377        _elementor.hooks.addFilter('pxl_element_container/before-render', function (html, settings) {
378            if (typeof settings.pxl_parallax_bg_img !== 'undefined' && settings.pxl_parallax_bg_img && settings.pxl_parallax_bg_img.url !== '') {
379                html += '<div class="pxl-section-bg-parallax"></div>';
380            }
381
382            if (typeof settings.pxl_color_offset !== 'undefined' && settings.pxl_color_offset !== 'none') {
383                html += '<div class="pxl-section-overlay-color"></div>';
384            }
385
386            if (typeof settings.pxl_overlay_img !== 'undefined' && settings.pxl_overlay_img && settings.pxl_overlay_img.url !== '') {
387                html += '<div class="pxl-overlay--image pxl-overlay--imageLeft"><div class="bg-image"></div></div>';
388            }
389
390            if (typeof settings.pxl_overlay_img2 !== 'undefined' && settings.pxl_overlay_img2 && settings.pxl_overlay_img2.url !== '') {
391                html += '<div class="pxl-overlay--image pxl-overlay--imageRight"><div class="bg-image"></div></div>';
392            }
393
394            return html;
395        });
396
397        // Chờ DOM ready trước khi tìm elements
398        $(document).ready(function () {
399            $('.pxl-section-bg-parallax').closest('.elementor-element').addClass('pxl-section-parallax-overflow');
400        });
401    }
402
403    function auregon_css_inline_js() {
404        var _inline_css = "<style>";
405        $(document).find('.pxl-inline-css').each(function () {
406            var _this = $(this);
407            _inline_css += _this.attr("data-css") + " ";
408            _this.remove();
409        });
410        _inline_css += "</style>";
411        $('head').append(_inline_css);
412    }
413
414    function auregon_section_before_render() {
415        var _elementor = typeof elementor !== 'undefined' ? elementor : elementorFrontend;
416        _elementor.hooks.addFilter('pxl-custom-section/before-render', function (html, settings, el) {
417            if (typeof settings['row_divider'] !== 'undefined') {
418                if (settings['row_divider'] === 'angle-top' || settings['row_divider'] === 'angle-bottom' || settings['row_divider'] === 'angle-top-right' || settings['row_divider'] === 'angle-bottom-left') {
419                    html = '<svg class="pxl-row-angle" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg>';
420                    return html;
421                }
422                if (settings['row_divider'] === 'angle-top-bottom' || settings['row_divider'] === 'angle-top-bottom-left') {
423                    html = '<svg class="pxl-row-angle pxl-row-angle-top" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg><svg class="pxl-row-angle pxl-row-angle-bottom" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewB
423ox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg>';
424                    return html;
425                }
426                if (settings['row_divider'] === 'wave-animation-top' || settings['row_divider'] === 'wave-animation-bottom') {
427                    html = '<svg class="pxl-row-angle" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 1440 150" fill="#fff"><path d="M 0 26.1978 C 275.76 83.8152 430.707 65.0509 716.279 25.6386 C 930.422 -3.86123 1210.32 -3.98357 1439 9.18045 C 2072.34 45.9691 2201.93 62.4429 2560 26.198 V 172.199 L 0 172.199 V 26.1978 Z"><animate repeatCount="indefinite" fill="freeze" attributeName="d" dur="10s" values="M0 25.9086C277 84.5821 433 65.736 720 25.9086C934.818 -3.9019 1214.06 -5.23669 1442 8.06597C2079 45.2421 2208 63.5007 2560 25.9088V171.91L0 171.91V25.9086Z; M0 86.3149C316 86.315 444 159.155 884 51.1554C1324 -56.8446 1320.29 34.1214 1538 70.4063C1814 116.407 2156 188.408 2560 86.315V232.317L0 232.316V86.3149Z; M0 53.6584C158 11.0001 213 0 363 0C513 0 855.555 115.001 1154 115.001C1440 115.001 1626 -38.0004 2560 53.6585V199.66L0 199.66V53.6584Z; M0 25.9086C277 84.5821 433 65.736 720 25.9086C934.818 -3.9019 1214.06 -5.23669 1442 8.06597C2079 45.2421 2208 63.5007 2560 25.9088V171.91L0 171.91V25.9086Z"></animate></path></svg>';
428                    return html;
429                }
430                if (settings['row_divider'] === 'curved-top' || settings['row_divider'] === 'curved-bottom') {
431                    html = '<svg class="pxl-row-angle" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 1920 128" version="1.1" preserveAspectRatio="none" style="fill:#ffffff"><path stroke-width="0" d="M-1,126a3693.886,3693.886,0,0,1,1921,2.125V-192H-7Z"></path></svg>';
432                    return html;
433                }
434            }
435        });
436    }
437
438    var PXL_Icon_Contact_Form = function ($scope, $) {
439
440        setTimeout(function () {
441            $('.pxl--item').each(function () {
442                var icon_input = $(this).find(".pxl--form-icon"),
443                    control_wrap = $(this).find('.wpcf7-form-control');
444                control_wrap.before(icon_input.clone());
445                icon_input.remove();
446            });
447        }, 10);
448
449    };
450
451
452    function auregon_split_text($scope) {
453        var st = $scope.find(".pxl-split-text");
454        if (st.length === 0) return;
455
456        // Kiểm tra GSAP và SplitText có tồn tại
457        if (typeof gsap === 'undefined' || typeof SplitText === 'undefined') {
458            console.warn('GSAP or SplitText plugin not loaded');
459            return;
460        }
461
462        gsap.registerPlugin(SplitText);
463
464        st.each(function (index, el) {
465            var els = $(el).find('p').length > 0 ? $(el).find('p')[0] : el;
466            const pxl_split = new SplitText(els, {
467                type: "lines, words, chars",
468                lineThreshold: 0.5,
469                linesClass: "split-line"
470            });
471            var split_type_set = pxl_split.chars;
472
473            gsap.set(els, { perspective: 400 });
474
475            var settings = {
476                scrollTrigger: {
477                    trigger: els,
478                    toggleActions: "play none none none",
479                    start: "top 86%",
480                    once: true
481                },
482                duration: 0.35,
483                stagger: 0.02,
484                ease: "Expo.out"
485            };
486            if ($(el).hasClass('split-in-fade')) {
487                settings.opacity = 0;
488            }
489            if ($(el).hasClass('split-in-right')) {
490                settings.opacity = 0;
491                settings.x = "50";
492            }
493            if ($(el).hasClass('split-in-left')) {
494                settings.opacity = 0;
495                settings.x = "-50";
496            }
497            if ($(el).hasClass('split-in-up')) {
498                settings.opacity = 0;
499                settings.y = "80";
500            }
501            if ($(el).hasClass('split-in-down')) {
502                settings.opacity = 0;
503                settings.y = "-80";
504            }
505            if ($(el).hasClass('split-in-rotate')) {
506                settings.opacity = 0;
507                settings.rotateX = "50deg";
508            }
509            if ($(el).hasClass('split-in-scale')) {
510                settings.opacity = 0;
511                settings.scale = "0.5";
512            }
513
514            if ($(el).hasClass('split-up')) {
515                pxl_split.split({ type: "words" });
516                split_type_set = pxl_split.words;
517
518                $(split_type_set).each(function (index, elw) {
519                    gsap.from(elw, {
520                        opacity: 0,
521                        duration: 0.65,
522                        y: 60,
523                        delay: 0.25 + index * 0.065,
524                        ease: "expo.out",
525                        scrollTrigger: {
526                            trigger: el,
527                            start: "top 86%",
528                            toggleActions: "play none none none",
529                        },
530                    });
531                });
532            }
533
534            if ($(el).hasClass('split-words-scale')) {
535                pxl_split.split({ type: "words" });
536                split_type_set = pxl_split.words;
537
538                $(split_type_set).each(function (index, elw) {
539                    gsap.set(elw, {
540                        opacity: 0,
541                        scale: index % 2 === 0 ? 0 : 2,
542                        force3D: true,
543                        duration: 0.1,
544                        ease: "Linear.easeNone",
545                        stagger: 0.02,
546                    }, index * 0.01);
547                });
548
549                var pxl_anim = gsap.to(split_type_set, {
550                    scrollTrigger: {
551                        trigger: el,
552                        toggleActions: "play reverse play reverse",
553                        start: "top 86%",
554                    },
555                    rotateX: "0",
556                    scale: 1,
557                    opacity: 1,
558                });
559
560            } else {
561                var pxl_anim = gsap.from(split_type_set, settings);
562            }
563
564            if ($(el).hasClass('hover-split-text')) {
565                $(el).mouseenter(function (e) {
566                    pxl_anim.restart();
567                });
568            }
569        });
570    }
571
572    function auregon_scroll_trigger($scope) {
573        if (typeof ScrollTrigger === 'undefined' || typeof gsap === 'undefined') {
574            console.warn('GSAP or ScrollTrigger not loaded');
575            return;
576        }
577
578        ScrollTrigger.matchMedia({
579            "(min-width: 1401px)": function () {
580                let t2 = gsap.timeline({
581                    scrollTrigger: {
582                        trigger: ".pxl-section-scale",
583                        scrub: true,
584                        start: "top top",
585                        end: "bottom bottom",
586                        pin: ".pxl-section-sticky",
587                    },
588                });
589                t2.to(".pxl-section-slide", {
590                    padding: "7.5rem"
591                }, ">");
592                t2.to(".pxl-sticky-mask", {
593                    borderRadius: "2rem"
594                }, "<");
595                t2.from(".is-shape-1", {
596                    right: "-10%"
597                }, "<");
598                t2.from(".is-shape-2", {
599                    left: "-10%"
600                }, "<");
601            },
602            "(max-width: 1400px)": function () {
603                let t2 = gsap.timeline({
604                    scrollTrigger: {
605                        trigger: ".pxl-section-scale",
606                        scrub: true,
607                        start: "top top",
608                        end: "bottom bottom",
609                        pin: ".pxl-section-sticky",
610                    },
611                });
612                t2.to(".pxl-section-slide", {
613                    padding: "4.8rem"
614                }, ">");
615                t2.to(".pxl-sticky-mask", {
616                    borderRadius: "1.6rem"
617                }, "<");
618                t2.from(".is-shape-1", {
619                    right: "-10%"
620                }, "<");
621                t2.from(".is-shape-2", {
622                    left: "-10%"
623                }, "<");
624            },
625            "(max-width: 991px)": function () {
626                let t2 = gsap.timeline({
627                    scrollTrigger: {
628                        trigger: ".pxl-section-scale",
629                        scrub: true,
630                        start: "top bottom",
631                        end: "bottom top",
632                    },
633                });
634                t2.to(".pxl-section-slide", {
635                    padding: "2rem"
636                }, ">");
637                t2.to(".pxl-sticky-mask", {
638                    borderRadius: "2rem"
639                }, "<");
640                t2.from(".is-shape-1", {
641                    right: "-10%"
642                }, "<");
643                t2.from(".is-shape-2", {
644                    left: "-10%"
645                }, "<");
646
647            },
648        });
649        const rotatingStickerSelector = ".pxl-sticker-shape.is-rotate";
650        if (document.querySelector(rotatingStickerSelector)) {
651            gsap.to(rotatingStickerSelector, {
652                rotation: "800",
653                scrollTrigger: {
654                    trigger: "#pxl-content-main",
655                    scrub: true,
656                    start: "top top",
657                    end: "bottom bottom",
658                },
659            });
660        }
661    }
662
663    function auregon_zoom_point() {
664        if (!window.elementorFrontend || typeof elementorFrontend.waypoint !== 'function') return;
665
666        var $zoomPoints = $(document).find('.pxl-zoom-point');
667        if ($zoomPoints.length === 0) return;
668
669        elementorFrontend.waypoint($zoomPoints, function () {
670            var $el = $(this);
671            // Thêm logic zoom point nếu cần
672            $el.addClass('pxl-zoom-active');
673        }, {
674            offset: -100,
675            triggerOnce: true
676        });
677    }
678
679    function auregon_text_marquee($scope) {
680        if (typeof gsap === 'undefined') {
681            console.warn('GSAP not loaded');
682            return;
683        }
684
685        const text_marquee = $scope.find('.pxl-text--marquee');
686        if (text_marquee.length === 0) return;
687
688        const boxes = gsap.utils.toArray(text_marquee);
689
690        const loop = text_horizontalLoop(boxes, { paused: false, repeat: -1, });
691
692        function text_horizontalLoop(items, config) {
693            items = gsap.utils.toArray(items);
694            config = config || {};
695            let tl = gsap.timeline({ repeat: config.repeat, paused: config.paused, defaults: { ease: "none" }, onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100) }),
696                length = items.length,
697                startX = items[0].offsetLeft,
698                times = [],
699                widths = [],
700                xPercents = [],
701                curIndex = 0,
702                pixelsPerSecond = (config.speed || 1) * 100,
703                snap = config.snap === false ? v => v : gsap.utils.snap(config.snap || 1),
704                totalWidth, curX, distanceToStart, distanceToLoop, item, i;
705            gsap.set(items, {
706                xPercent: (i, el) => {
707                    let w = widths[i] = parseFloat(gsap.getProperty(el, "width", "px"));
708                    xPercents[i] = snap(parseFloat(gsap.getProperty(el, "x", "px")) / w * 100 + gsap.getProperty(el, "xPercent"));
709                    return xPercents[i];
710                }
711            });
712            gsap.set(items, { x: 0 });
713            totalWidth = items[length - 1].offsetLeft + xPercents[length - 1] / 100 * widths[length - 1] - startX + items[length - 1].offsetWidth * gsap.getProperty(items[length - 1], "scaleX") + (parseFloat(config.paddingRight) || 0);
714            for (i = 0; i < length; i++) {
715                item = items[i];
716                curX = xPercents[i] / 100 * widths[i];
717                distanceToStart = item.offsetLeft + curX - startX;
718                distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, "scaleX");
719                tl.to(item, { xPercent: snap((curX - distanceToLoop) / widths[i] * 100), duration: distanceToLoop / pixelsPerSecond }, 0)
720                    .fromTo(item, { xPercent: snap((curX - distanceToLoop + totalWidth) / widths[i] * 100) }, { xPercent: xPercents[i], duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond, immediateRender: false }, distanceToLoop / pixelsPerSecond)
721                    .add("label" + i, distanceToStart / pixelsPerSecond);
722                times[i] = distanceToStart / pixelsPerSecond;
723            }
724            function toIndex(index, vars) {
725                vars = vars || {};
726                (Math.abs(index - curIndex) > length / 2) && (index += index > curIndex ? -length : length);
727                let newIndex = gsap.utils.wrap(0, length, index),
728                    time = times[newIndex];
729                if (time > tl.time() !== index > curIndex) {
730                    vars.modifiers = { time: gsap.utils.wrap(0, tl.duration()) };
731                    time += tl.duration() * (index > curIndex ? 1 : -1);
732                }
733                curIndex = newIndex;
734                vars.overwrite = true;
735                return tl.tweenTo(time, vars);
736            }
737            tl.next = vars => toIndex(curIndex + 1, vars);
738            tl.previous = vars => toIndex(curIndex - 1, vars);
739            tl.current = () => curIndex;
740            tl.toIndex = (index, vars) => toIndex(index, vars);
741            tl.times = times;
742            tl.progress(1, true).progress(0, true);
743            if (config.reversed) {
744                tl.vars.onReverseComplete();
745                tl.reverse();
746            }
747            return tl;
748        }
749    }
750
751    function auregon_scroll_fixed_section() {
752        if (typeof ScrollTrigger === 'undefined' || typeof gsap === 'undefined') {
753            console.warn('GSAP or ScrollTrigger not loaded');
754            return;
755        }
756
757        const fixed_section_top = $('.pxl-section-fix-top');
758        const fixedSectionBottomSelector = ".pxl-section-fix-bottom";
759        const hasFixedBottom = document.querySelector(fixedSectionBottomSelector);
760        if (fixed_section_top.length > 0 && hasFixedBottom) {
761            ScrollTrigger.matchMedia({
762                "(min-width: 991px)": function () {
763                    const pinnedSections = ['.pxl-section-fix-top'];
764                    pinnedSections.forEach(className => {
765                        gsap.to(fixedSectionBottomSelector, {
766                            scrollTrigger: {
767                                trigger: fixedSectionBottomSelector,
768                                scrub: true,
769                                pin: className,
770                                pinSpacing: false,
771                                start: 'top bottom',
772                                end: "bottom top",
773                            },
774                        });
775                        const bottomOverlaySelector = ".pxl-section-fix-bottom .pxl-section-overlay-color";
776                        if (!document.querySelector(bottomOverlaySelector)) {
777                            return;
778                        }
779                        gsap.to(bottomOverlaySelector, {
780                            scrollTrigger: {
781                                trigger: fixedSectionBottomSelector,
782                                scrub: true,
783                                pin: className,
784                                pinSpacing: false,
785                                start: 'top bottom',
786                                end: "bottom top",
787                            },
788                        });
789                    });
790                }
791            });
792        }
793
794        const section_overlay_color = $('.pxl-section-overlay-color');
795        const overlayScrollSelector = ".overlay-type-scroll";
796        if (section_overlay_color.length > 0 && document.querySelector(overlayScrollSelector)) {
797            const space_top = section_overlay_color.data('space-top') || 0;
798            const space_left = section_overlay_color.data('space-left') || 0;
799            const space_right = section_overlay_color.data('space-right') || 0;
800            const space_bottom = section_overlay_color.data('space-bottom') || 0;
801
802            const radius_top = section_overlay_color.data('radius-top') || 0;
803            const radius_left = section_overlay_color.data('radius-left') || 0;
804            const radius_right = section_overlay_color.data('radius-right') || 0;
805            const radius_bottom = section_overlay_color.data('radius-bottom') || 0;
806
807            const overlay_radius = radius_top + 'px ' + radius_right + 'px ' + radius_bottom + 'px ' + radius_left + 'px ';
808
809            ScrollTrigger.matchMedia({
810                "(min-width: 991px)": function () {
811                    const pinnedSections = ['.pxl-bg-color-scroll'];
812                    pinnedSections.forEach(className => {
813                        gsap.to(overlayScrollSelector, {
814                            scrollTrigger: {
815                                trigger: ".pxl-bg-color-scroll",
816                                scrub: true,
817                                pinSpacing: false,
818                                start: 'top bottom',
819                                end: "bottom top",
820                            },
821                            left: space_left + "px",
822                            right: space_right + "px",
823                            top: space_top + "px",
824                            bottom: space_bottom + "px",
825                            borderRadius: overlay_radiu
825s,
826                        });
827                    });
828                }
829            });
830        }
831    }
832    function auregon_scroll_checkp($scope) {
833        $scope.find('.pxl-el-divider').each(function () {
834            var wcont1 = $(this);
835            var scrollHandler = null;
836
837            function checkScrollPosition() {
838                if (!wcont1.length || !wcont1.is(':visible')) return;
839
840                var pxl_scroll_top = $(window).scrollTop(),
841                    viewportBottom = pxl_scroll_top + $(window).height(),
842                    elementTop = wcont1.offset().top,
843                    elementBottom = elementTop + wcont1.outerHeight();
844
845                if (elementTop < viewportBottom && elementBottom > pxl_scroll_top) {
846                    wcont1.addClass('visible');
847                    // Cleanup sau khi đã visible
848                    if (scrollHandler) {
849                        $(window).off('scroll', scrollHandler);
850                        scrollHandler = null;
851                    }
852                }
853            }
854
855            checkScrollPosition();
856
857            scrollHandler = function () {
858                checkScrollPosition();
859            };
860            $(window).on('scroll', scrollHandler);
861
862            // Cleanup khi element bị remove
863            wcont1.on('remove', function () {
864                if (scrollHandler) {
865                    $(window).off('scroll', scrollHandler);
866                }
867            });
868        });
869    }
870
871    function renderOrbit($scope) {
872        $scope.find(".orbit").each(function () {
873            const $orbit = $(this);
874            const settings = $orbit.data("settings") || {};
875            const size = settings.size || 70;
876            const count = settings.count || 1;
877            const icons = Array.isArray(settings.icons) ? settings.icons : [];
878            const itemClasses = Array.isArray(settings.itemClasses) ? settings.itemClasses : [];
879            const iconClass = settings.iconClass || "green";
880            const randomStart = !!settings.randomStart;
881            const useRandomColor = !!settings.randomColor;
882            const borderColor = settings.borderColor || null;
883
884            $orbit.css("--d", size + "%").empty();
885            if (borderColor) {
886                $orbit.css("--orbit-border-color", borderColor);
887            }
888
889            const fragment = $(document.createDocumentFragment());
890
891            const createItem = (idx) => {
892                const dur = (6 + Math.random() * 6).toFixed(1) + "s";
893                const $rot = $("<div>", { class: "rotator" }).css("--dur", dur);
894                if (Math.random() > .5) $rot.addClass("reverse");
895
896                let $item;
897                let iconChar = icons.length ? icons[idx % icons.length] : "⭐";
898                const iconStr = (typeof iconChar === "string") ? iconChar.trim() : "";
899                const isSvg = iconStr.startsWith("<svg");
900                const isImg = iconStr.startsWith("<img");
901                let classes = ["item", "icon", iconClass];
902                if (isSvg) classes.push("is-svg");
903                if (isImg) classes.push("is-media");
904                // Add class from itemClasses array if available
905                if (itemClasses.length > 0) {
906                    const itemClass = itemClasses[idx % itemClasses.length];
907                    if (itemClass && itemClass.trim() !== '') {
908                        classes.push(itemClass);
909                    }
910                }
911                $item = $("<div>", {
912                    class: classes.join(" ")
913                }).html(iconChar);
914
915                return $rot.append($item);
916            };
917
918            for (let i = 0; i < count; i++) {
919                fragment.append(createItem(i));
920            }
921
922            $orbit.append(fragment);
923
924            const $rotators = $orbit.find(".rotator");
925            const c = $rotators.length;
926            if (c) {
927                const baseAngles = Array.from({ length: c }, (_, idx) => (360 / c) * idx);
928                if (randomStart) {
929                    for (let i = baseAngles.length - 1; i > 0; i--) {
930                        const j = Math.floor(Math.random() * (i + 1));
931                        [baseAngles[i], baseAngles[j]] = [baseAngles[j], baseAngles[i]];
932                    }
933                }
934                $rotators.each(function (i) {
935                    $(this).css("--start", baseAngles[i] + "deg");
936                });
937
938                const orbitWidth = $orbit.innerWidth();
939                if (orbitWidth > 0) {
940                    const radius = orbitWidth / 2;
941                    const arcLength = (2 * Math.PI * radius) / c;
942                    const maxIconSize = Math.max(28, Math.min(60, arcLength - 8));
943                    $orbit.css("--orbit-icon-size", `${maxIconSize}px`);
944                }
945            }
946
947            const randCol = () => '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
948            $orbit.find('.item').each(function () {
949                const $it = $(this);
950                let color = null;
951
952                if (useRandomColor) {
953                    color = randCol();
954                }
955
956                if (color && !$it.hasClass('is-media')) {
957                    if ($it.hasClass('is-svg')) {
958                        $it.find('svg, path, circle, rect, polygon, polyline, ellipse, line')
959                            .css({ fill: color, color });
960                    } else {
961                        $it.css('color', color);
962                    }
963                }
964            });
965        });
966    }
967
968    function pxl_widget_sphere_handler($scope) {
969        const canvas = $scope.find(".pxl-sphere canvas");
970        if (!canvas.length) return;
971
972        const sphereEl = $scope.find(".pxl-sphere");
973        const size = parseInt(sphereEl.data("size")) || 950;
974        const radius = parseInt(sphereEl.data("radius")) || size * 0.5;
975        const sphereColor = sphereEl.data("color") || "rgba(255, 255, 255, 0.15)";
976        const rotationType = sphereEl.data("rotation") || "y_axis";
977        const rotationSpeed = parseFloat(sphereEl.data("speed")) || 0.005;
978        const customXSpeed = parseFloat(sphereEl.data("xspeed")) || 0.003;
979        const customYSpeed = parseFloat(sphereEl.data("yspeed")) || 0.005;
980        const tiltAngle =
981            ((parseFloat(sphereEl.data("tilt")) || -30) * Math.PI) / 180;
982
983        const ctx = canvas[0].getContext("2d");
984        if (!ctx) return;
985
986        canvas[0].width = size;
987        canvas[0].height = size;
988
989        let angleX = tiltAngle;
990        let angleY = 0;
991        let animationId = null;
992        let isRunning = true;
993
994        function rotate(point, angleX, angleY) {
995            let cosX = Math.cos(angleX),
996                sinX = Math.sin(angleX);
997            let cosY = Math.cos(angleY),
998                sinY = Math.sin(angleY);
999
1000            let y = point.y * cosX - point.z * sinX;
1001            let z = point.y * sinX + point.z * cosX;
1002            let x = point.x * cosY - z * sinY;
1003            z = point.x * sinY + z * cosY;
1004            return { x, y, z };
1005        }
1006
1007        function drawSphere() {
1008            ctx.clearRect(0, 0, canvas[0].width, canvas[0].height);
1009            ctx.strokeStyle = sphereColor;
1010            ctx.lineWidth = 1;
1011            const cx = canvas[0].width / 2;
1012            const cy = canvas[0].height / 2;
1013
1014            for (
1015                let lat = -Math.PI / 2;
1016                lat <= Math.PI / 2;
1017                lat += Math.PI / 10
1018            ) {
1019                let circlePoints = [];
1020                for (let lon = 0; lon < 2 * Math.PI; lon += Math.PI / 20) {
1021                    let x = Math.cos(lat) * Math.cos(lon);
1022                    let y = Math.sin(lat);
1023                    let z = Math.cos(lat) * Math.sin(lon);
1024                    let rotatedPoint = rotate({ x, y, z }, angleX, angleY);
1025                    circlePoints.push(rotatedPoint);
1026                }
1027                ctx.beginPath();
1028                circlePoints.forEach((p, i) => {
1029                    if (i === 0) {
1030                        ctx.moveTo(cx + p.x * radius, cy + p.y * radius);
1031                    } else {
1032                        ctx.lineTo(cx + p.x * radius, cy + p.y * radius);
1033                    }
1034                });
1035                ctx.closePath();
1036                ctx.stroke();
1037            }
1038
1039            for (let lon = 0; lon < 2 * Math.PI; lon += Math.PI / 10) {
1040                let circlePoints = [];
1041                for (
1042                    let lat = -Math.PI / 2;
1043                    lat <= Math.PI / 2;
1044                    lat += Math.PI / 20
1045                ) {
1046                    let x = Math.cos(lat) * Math.cos(lon);
1047                    let y = Math.sin(lat);
1048                    let z = Math.cos(lat) * Math.sin(lon);
1049                    let rotatedPoint = rotate({ x, y, z }, angleX, angleY);
1050                    circlePoints.push(rotatedPoint);
1051                }
1052                ctx.beginPath();
1053                circlePoints.forEach((p, i) => {
1054                    if (i === 0) {
1055                        ctx.moveTo(cx + p.x * radius, cy + p.y * radius);
1056                    } else {
1057                        ctx.lineTo(cx + p.x * radius, cy + p.y * radius);
1058                    }
1059                });
1060                ctx.stroke();
1061            }
1062        }
1063
1064        function updateRotation() {
1065            switch (rotationType) {
1066                case "y_axis":
1067                    angleY += rotationSpeed;
1068                    break;
1069                case "x_axis":
1070                    angleX += rotationSpeed;
1071                    break;
1072                case "both_axis":
1073                    angleX += rotationSpeed;
1074                    angleY += rotationSpeed;
1075                    break;
1076                case "custom":
1077                    angleX += customXSpeed;
1078                    angleY += customYSpeed;
1079                    break;
1080            }
1081        }
1082
1083        function animate() {
1084            if (!isRunning) return;
1085            updateRotation();
1086            drawSphere();
1087            animationId = requestAnimationFrame(animate);
1088        }
1089
1090        animate();
1091
1092        // Cleanup khi element bị remove
1093        sphereEl.on('remove', function () {
1094            isRunning = false;
1095            if (animationId) {
1096                cancelAnimationFrame(animationId);
1097            }
1098        });
1099
1100        // Lưu reference để có thể cleanup từ bên ngoài
1101        sphereEl.data('sphere-animation-id', animationId);
1102        sphereEl.data('sphere-is-running', isRunning);
1103    };
1104
1105    function auregon_parallax_bg() {
1106        // Kiểm tra plugin parallaxBackground có tồn tại
1107        if (typeof $.fn.parallaxBackground === 'undefined') {
1108            console.warn('parallaxBackground plugin not loaded');
1109            return;
1110        }
1111
1112        $(document).find('.pxl-parallax-background').parallaxBackgroun
1112d({
1113            event: 'mouse_move',
1114            animation_type: 'shift',
1115            animate_duration: 2
1116        });
1117        $(document).find('.pxl-pll-basic').parallaxBackground();
1118        $(document).find('.pxl-pll-rotate').parallaxBackground({
1119            animation_type: 'rotate',
1120            zoom: 50,
1121            rotate_perspective: 500
1122        });
1123        $(document).find('.pxl-pll-mouse-move').parallaxBackground({
1124            event: 'mouse_move',
1125            animation_type: 'shift',
1126            animate_duration: 2
1127        });
1128        $(document).find('.pxl-pll-mouse-move-rotate').parallaxBackground({
1129            event: 'mouse_move',
1130            animation_type: 'rotate',
1131            animate_duration: 1,
1132            zoom: 70,
1133            rotate_perspective: 1000
1134        });
1135
1136        $(document).find('.pxl-bg-prx-effect-pinned-zoom-clipped').each(function (index, el) {
1137            // Kiểm tra GSAP và ScrollTrigger có tồn tại
1138            if (typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined') {
1139                return;
1140            }
1141
1142            var $el = $(el);
1143            const clipped_bg_pinned = $el.find('.clipped-bg-pinned');
1144            const clipped_bg = $el.find('.clipped-bg');
1145
1146            if (!clipped_bg_pinned.length || !clipped_bg.length) return;
1147
1148            var clipped_bg_animation = gsap.to(clipped_bg, {
1149                clipPath: 'inset(0% 0% 0%)',
1150                scale: 1,
1151                duration: 1,
1152                ease: 'Linear.easeNone'
1153            });
1154
1155            var clipped_bg_scene = ScrollTrigger.create({
1156                trigger: clipped_bg_pinned,
1157                start: function () {
1158                    const start_pin = 350;
1159                    return "top +=" + start_pin;
1160                },
1161                end: function () {
1162                    const end_pin = 0;
1163                    return "+=" + end_pin;
1164                },
1165                animation: clipped_bg_animation,
1166                scrub: 1,
1167                pin: true,
1168                pinSpacing: false,
1169            });
1170
1171            function set_clipped_bg_wrapper_height() {
1172                if (typeof gsap !== 'undefined' && clipped_bg.length) {
1173                    gsap.set(clipped_bg, { height: window.innerHeight });
1174                }
1175            }
1176
1177            var resizeHandler = set_clipped_bg_wrapper_height;
1178            window.addEventListener('resize', resizeHandler);
1179
1180            // Cleanup khi element bị remove
1181            $el.on('remove', function () {
1182                window.removeEventListener('resize', resizeHandler);
1183                if (clipped_bg_scene && typeof ScrollTrigger !== 'undefined') {
1184                    clipped_bg_scene.kill();
1185                }
1186            });
1187        });
1188
1189
1190
1191        $(document).find('.pxl-bg-prx-effect-pinned-circle-zoom-clipped').each(function (index, el) {
1192            // Kiểm tra GSAP và ScrollTrigger có tồn tại
1193            if (typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined') {
1194                return;
1195            }
1196
1197            const $el = $(el);
1198
1199            var svg = $el.find('.circle-zoom-mask-svg');
1200            var img = $el.find('.clipped-bg-circle-pinned');
1201            let circle = $el.find('.circle-zoom');
1202
1203            // Kiểm tra null/undefined
1204            if (!circle.length || !circle[0] || !img.length || !img[0]) return;
1205
1206            let radiusAttr = circle[0].getAttribute("r");
1207            let radius = radiusAttr ? parseFloat(radiusAttr) : 0;
1208            if (isNaN(radius)) radius = 0;
1209
1210            gsap.set(img[0], {
1211                scale: 2
1212            });
1213
1214            var tl = gsap.timeline({
1215                scrollTrigger: {
1216                    trigger: el,
1217                    start: "50% 90%",
1218                    end: "80% 100%",
1219                    scrub: 2,
1220                },
1221                defaults: {
1222                    duration: 2
1223                }
1224            })
1225                .to(circle[0], {
1226                    attr: {
1227                        r: () => radius
1228                    }
1229                }, 0)
1230                .to(img[0], {
1231                    scale: 1,
1232                }, 0)
1233                .to(".circle-inner-layer", {
1234                    alpha: 0,
1235                    ease: "power1.in",
1236                    duration: 1 - 0.25
1237                }, 0.25);
1238
1239
1240            window.addEventListener("load", auregon_circle_init);
1241            window.addEventListener("resize", auregon_circle_resize);
1242
1243            function auregon_circle_init() {
1244                auregon_circle_resize();
1245            }
1246
1247            function auregon_circle_resize() {
1248                if (typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined') return;
1249
1250                tl.progress(0);
1251                var rect = $(el)[0].getBoundingClientRect();
1252                const rectWidth = rect.width;
1253                const rectHeight = rect.height;
1254                const dx = rectWidth / 2;
1255                const dy = rectHeight / 2;
1256                radius = Math.sqrt(dx * dx + dy * dy);
1257
1258                tl.invalidate();
1259                ScrollTrigger.refresh();
1260            }
1261
1262            // Cleanup khi element bị remove
1263            $el.on('remove', function () {
1264                window.removeEventListener("load", auregon_circle_init);
1265                window.removeEventListener("resize", auregon_circle_resize);
1266                if (tl && typeof ScrollTrigger !== 'undefined') {
1267                    tl.kill();
1268                }
1269            });
1270        });
1271    }
1272
1273    function auregon_logo_marquee($scope) {
1274        const logos = $scope.find('.pxl-item--marquee');
1275        gsap.set(logos, { autoAlpha: 1 })
1276
1277        logos.each(function (index, el) {
1278            gsap.set(el, { xPercent: 100 * index });
1279        });
1280
1281        if (logos.length > 2) {
1282            const logosWrap = gsap.utils.wrap(-100, ((logos.length - 1) * 100));
1283            const durationNumber = logos.data('duration');
1284            const slipType = logos.data('slip-type');
1285            var slipResult = `-=${logos.length * 100}`;
1286            if (slipType == 'right') {
1287                slipResult = `+=${logos.length * 100}`;
1288            }
1289            gsap.to(logos, {
1290                xPercent: slipResult,
1291                duration: durationNumber,
1292                repeat: -1,
1293                ease: 'none',
1294                modifiers: {
1295                    xPercent: xPercent => logosWrap(parseFloat(xPercent))
1296                }
1297            });
1298        }
1299    }
1300
1301    function auregon_progressbar_handler($scope) {
1302        if (!window.elementorFrontend || typeof elementorFrontend.waypoint !== 'function') return;
1303
1304        elementorFrontend.waypoint($scope.find('.pxl-progress-bar'), function () {
1305            if (typeof $(this).progressbar === 'function') {
1306                $(this).progressbar();
1307            }
1308        });
1309        elementorFrontend.waypoint($scope.find('.pxl-progressbar.circle'), function () {
1310            var $progressbarElem = $scope.find(".pxl-progressbar-container"),
1311                $progressbarElemInner = $scope.find(".pxl-progressbar-inner"),
1312                settings = $progressbarElem.data("settings");
1313
1314            // Kiểm tra settings có tồn tại
1315            if (!settings || typeof settings !== 'object') return;
1316
1317            var length = settings.circle_percent || 0,
1318                number = settings.circle_number || 0,
1319                prefix = settings.prefix || '',
1320                suffix = settings.suffix || '',
1321                speed = settings.speed || 1000;
1322
1323            if (length > 100)
1324                length = 100;
1325
1326            $progressbarElem.prop({
1327                'percent': 0
1328            }).animate({
1329                percent: number
1330            }, {
1331                duration: speed,
1332                easing: 'linear',
1333                step: function (percent) {
1334                    var rotate = (100 - percent);
1335                    var rotate1 = (percent + 8);
1336                    $progressbarElem.find(".js-progress-bar").css('stroke-dashoffset', rotate);
1337                    $progressbarElem.find(".js-progress-bar1").css('stroke-dashoffset', rotate1);
1338                }
1339            });
1340
1341            $progressbarElemInner.prop({
1342                'counter': 0,
1343            }).animate({
1344                counter: number,
1345            }, {
1346                duration: speed,
1347                easing: 'linear',
1348                step: function (counter) {
1349                    var $numberEl = $progressbarElem.find(".progress-number");
1350                    if ($numberEl.length) {
1351                        $numberEl.text(Math.ceil(counter));
1352                    } else {
1353                        $progressbarElem.find(".progress-percentage").text(prefix + Math.
1353ceil(counter) + suffix);
1354                    }
1355                }
1356            });
1357
1358        });
1359    }
1360
1361    function auregon_care_orbit_tabs_handler($scope) {
1362
1363        var px1209_width = $(window).width();
1364
1365        const root = $scope && $scope[0] ? $scope[0] : ($scope || document);
1366        const svgTexts = root.querySelectorAll('.svg-tab-text');
1367        const tabColumns = root.querySelectorAll('.care-orbit-col.tab-pane');
1368        const svgEl = root.querySelector('.pxl-care-orbit-tabs .pxl-tabs--title svg');
1369
1370        // Chỉ chạy dots cho màn hình lớn
1371        let dotsLeft = null;
1372        let dotsRight = null;
1373        if (px1209_width >= 1281) {
1374            dotsLeft = svgEl ? svgEl.querySelector('.orbit-dots-left') : null;
1375            dotsRight = svgEl ? svgEl.querySelector('.orbit-dots-right') : null;
1376
1377            if (!svgEl || !dotsLeft || !dotsRight) {
1378                return;
1379            }
1380        }
1381
1382        // Kiểm tra svgEl có tồn tại (cần thiết cho cả trường hợp width < 1281)
1383        if (!svgEl) return;
1384
1385        const vb = svgEl.viewBox && svgEl.viewBox.baseVal ? svgEl.viewBox.baseVal : null;
1386        if (!vb || vb.width === 0 || vb.height === 0) return;
1387
1388        const centerX = vb.x + vb.width / 2;
1389        const centerY = vb.y + vb.height / 2;
1390        const outerR = Math.min(vb.width, vb.height) / 2;
1391        const inset = 3;
1392        const dotRpx = 9.5;
1393
1394        function pxToVb() {
1395            const rect = svgEl.getBoundingClientRect();
1396            return {
1397                sx: vb.width / rect.width,
1398                sy: vb.height / rect.height
1399            };
1400        }
1401
1402        function clearDots() {
1403            dotsLeft.innerHTML = '';
1404            dotsRight.innerHTML = '';
1405        }
1406
1407        let rafId = null;
1408        function schedulePlaceDots() {
1409            if (rafId) cancelAnimationFrame(rafId);
1410            rafId = requestAnimationFrame(placeDots);
1411        }
1412
1413        function placeDots() {
1414            // Chỉ chạy dots nếu có dotsLeft và dotsRight
1415            if (!dotsLeft || !dotsRight) return;
1416
1417            clearDots();
1418
1419            const activePanes = root.querySelectorAll('.pxl-care-orbit-tabs .tab-pane.active');
1420            if (!activePanes.length) return;
1421
1422            const rect = svgEl.getBoundingClientRect();
1423            const { sx, sy } = pxToVb();
1424
1425            const dotRv = dotRpx * ((sx + sy) / 2);
1426
1427            activePanes.forEach(pane => {
1428                const isLeft = pane.classList.contains('care-orbit-col-left');
1429                const entries = pane.querySelectorAll('.entry-body');
1430
1431                entries.forEach(entry => {
1432                    const r = entry.getBoundingClientRect();
1433                    const yScreen = r.top + r.height / 2;
1434
1435                    const ySvg = (yScreen - rect.top) * sy + vb.y;
1436
1437                    const dy = ySvg - centerY;
1438                    const clamp = Math.max(outerR * outerR - dy * dy, 0);
1439                    const xOn = Math.sqrt(clamp);
1440                    const xSvg = isLeft ? (centerX - xOn + inset) : (centerX + xOn - inset);
1441
1442                    const g = isLeft ? dotsLeft : dotsRight;
1443                    const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
1444                    circle.setAttribute('cx', xSvg);
1445                    circle.setAttribute('cy', ySvg);
1446                    circle.setAttribute('r', dotRv);
1447                    circle.setAttribute('fill', '#192273');
1448                    circle.setAttribute('stroke', '#D3DDFF');
1449                    circle.setAttribute('stroke-width', (2.5 * ((sx + sy) / 2)));
1450                    circle.setAttribute('vector-effect', 'non-scaling-stroke');
1451                    g.appendChild(circle);
1452                });
1453            });
1454        }
1455
1456        svgTexts.forEach(svgText => {
1457            svgText.addEventListener('click', function () {
1458                const targetId = this.getAttribute('data-target');
1459
1460                svgTexts.forEach(t => t.classList.remove('active'));
1461                this.classList.add('active');
1462
1463                tabColumns.forEach(c => {
1464                    c.classList.remove('active');
1465                    c.style.display = 'none';
1466                });
1467
1468                const matchCols = root.querySelectorAll('.care-orbit-col.tab-pane[data-tab="' + targetId + '"]');
1469                matchCols.forEach(c => {
1470                    c.classList.add('active');
1471                    c.style.display = 'flex';
1472                });
1473
1474                // Chỉ gọi schedulePlaceDots nếu có dots
1475                if (dotsLeft && dotsRight) {
1476                    schedulePlaceDots();
1477                }
1478            });
1479        });
1480
1481        // Chỉ setup dots observers nếu có dots
1482        let ro = null;
1483        if (dotsLeft && dotsRight) {
1484            ro = new ResizeObserver(schedulePlaceDots);
1485            ro.observe(svgEl);
1486            const contentHost = root.querySelector('.pxl-care-orbit-tabs');
1487            if (contentHost) ro.observe(contentHost);
1488
1489            if (document.fonts && document.fonts.ready) {
1490                document.fonts.ready.then(schedulePlaceDots).catch(() => { });
1491            }
1492
1493            window.addEventListener('resize', schedulePlaceDots, { passive: true });
1494
1495            requestAnimationFrame(schedulePlaceDots);
1496        }
1497
1498        return function cleanup() {
1499            if (dotsLeft && dotsRight) {
1500                window.removeEventListener('resize', schedulePlaceDots);
1501                if (ro) ro.disconnect();
1502                if (rafId) cancelAnimationFrame(rafId);
1503                clearDots();
1504            }
1505        };
1506    }
1507
1508    function auregon_post_carousel_handler($scope) {
1509        const rootEl = $scope && $scope[0] ? $scope[0] : document;
1510        const stepsContainer = rootEl.querySelector(".pxl-grid-filter.style-3");
1511        const pill = rootEl.querySelector("#pxl-item-step-active-pill");
1512        const steps = Array.from(rootEl.querySelectorAll(".filter-item"));
1513
1514        if (!stepsContainer || !pill || !steps.length) return;
1515
1516        const getActiveIndex = () => {
1517            const i = steps.findIndex((b) => b.classList.contains("active"));
1518            return i === -1 ? 0 : i;
1519        };
1520
1521        const setActive = (index) => {
1522            index = Math.min(Math.max(index, 0), steps.length - 1);
1523            steps.forEach((b) => b.classList.remove("active"));
1524            steps[index].classList.add("active");
1525            updatePill(index);
1526        };
1527
1528        const updatePill = (index = getActiveIndex()) => {
1529            index = Math.min(Math.max(index, 0), steps.length - 1);
1530            const containerRect = stepsContainer.getBoundingClientRect();
1531            const stepRect = steps[index].getBoundingClientRect();
1532            const stepWidth = stepRect.width || steps[index].offsetWidth || 0;
1533            const translateX = stepRect.left - containerRect.left;
1534
1535            pill.style.width = `${Math.max(0, stepWidth - 2)}px`;
1536            pill.style.transform = `translateX(${translateX}px)`;
1537        };
1538
1539        steps.forEach((btn, index) => {
1540            btn.addEventListener("click", () => {
1541                setActive(index);
1542            });
1543        });
1544
1545        setActive(getActiveIndex());
1546
1547        const onResize = () => {
1548            if (rootEl !== document && !rootEl.isConnected) {
1549                window.removeEventListener("resize", onResize);
1550                return;
1551            }
1552            updatePill();
1553        };
1554
1555        window.addEventListener("resize", onResize, { passive: true });
1556
1557    }
1558
1559    // function auregon_text_carousel_style2_handler($scope) {
1560    //     if (typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined') {
1561    //         console.warn('GSAP or ScrollTrigger not loaded');
1562    //         return;
1563    //     }
1564
1565    //     const widget = $scope.find('.pxl-text-carousel3.style-2');
1566    //     if (!widget.length) return;
1567
1568    //     const steps = widget.find('.pxl-item--step');
1569    //     const cards = widget.find('.pxl-item--inner');
1570
1571    //     if (!steps.length || !cards.length) return;
1572
1573    //     // Initialize first item active
1574    //     steps.removeClass('is-active');
1575    //     cards.removeClass('is-active');
1576    //     steps.first().addClass('is-active');
1577    //     cards.first().addClass('is-active');
1578
1579    //     // Pin the section
1580    //     ScrollTrigger.create({
1581    //         trigger: widget,
1582    //         start: "top 20%",
1583    //         end: "+=" + (steps.length * 500), // Adjust scroll distance per step
1584    //         pin: true,
1585    //         scrub: true,
1586    //         onUpdate: (self) => {
1587    //             const progress = self.progress;
1588    //             const totalSteps = steps.length;
1589    //             let activeIndex = Math.floor(progress * totalSteps);
1590
1591    //             // Ensure index is within bounds
1592    //             if (activeIndex >= totalSteps) activeIndex = totalSteps - 1;
1593
1594    //             // Update active classes if changed
1595    //             if (!steps.eq(activeIndex).hasClass('is-active')) {
1596    //                 steps.removeClass('is-active');
1597    //                 cards.removeClass('is-active');
1598
1599    //                 steps.eq(activeIndex).addClass('is-active');
1600    //                 cards.eq(activeIndex).addClass('is-active');
1601    //             }
1602    //         }
1603    //     });
1604    // }
1605
1606function auregon_text_carousel_handler($scope) {
1607  const root = $scope && $scope[0] ? $scope[0] : document;
1608
1609  const stepsContainer = root.querySelector(".pxl-item--steps");
1610  const pill =
1611    root.querySelector("#pxl-item-step-active-pill") ||
1612    root.querySelector(".pxl-item-step-active-pill");
1613
1614  const steps = Array.from(root.querySelectorAll(".pxl-item--step"));
1615  const cards = Array.from(root.querySelectorAll(".pxl-item--inner"));
1616
1617  if (!stepsContainer || !pill || !steps.length || !cards.length) return;
1618
1619  // Prevent duplicate init (Elementor re-render)
1620  if (root.__auregonTextCarouselDestroy) {
1621    root.__auregonTextCarouselDestroy();
1622    root.__auregonTextCarouselDestroy = null;
1623  }
1624
1625  // ---------------- Utils ----------------
1626  const clamp = (n, min, max) => Math.min(Math.max(n, min), max);
1627
1628  const stepIdByIndex = (i) => steps[i]?.getAttribute("data-step") || null;
1629
1630  const findIndexByStepId = (stepId) => {
1631    let i = steps.findIndex((s) => s.getAttribute("data-step") === stepId);
1632    if (i !== -1) return i;
1633    i = cards.findIndex((c) => c.getAttribute("data-step") === stepId);
1634    return i;
1635  };
1636
1637  const getActiveIndex = () => {
1638    const i = steps.findIndex((s) => s.classList.contains("is-active"));
1639    return i === -1 ? 0 : i;
1640  };
1641
1642  // Measure once per “update cycle”
1643  let metrics = null;
1644  const measure = () => {
1645    const containerRect = stepsContainer.getBoundingClientRect();
1646    const firstRect = steps[0].getBoundingClientRect();
1647
1648    const stepWidth = firstRect.width || steps[0].offsetWidth || 0;
1649
1650    // Compute gap: prefer actual distance between step[0] and step[1]
1651    let gapPx = 6;
1652    if (steps.length > 1) {
1653      const secondRect = steps[1].getBoundingClientRect();
1654      const raw = secondRect.left - firstRect.left - stepWidth;
1655      if (raw > 0) gapPx = raw;
1656    } else {
1657      const cs = getComputedStyle(stepsContainer);
1658      const g = parseFloat(cs.columnGap || cs.gap || "6");
1659      if (!Number.isNaN(g)) gapPx = g;
1660    }
1661
1662    const baseOffset = firstRect.left - containerRect.left;
1663    metrics = { stepWidth, gapPx, baseOffset };
1664  };
1665
1666  const updatePill = (index = getActiveIndex()) => {
1667    index = clamp(index, 0, steps.length - 1);
1668    if (!metrics) measure();
1669
1670    const { stepWidth, gapPx, baseOffset } = metrics;
1671    const translateX = baseOffset + index * (stepWidth + gapPx);
1672
1673    pill.style.width = `${Math.max(0, stepWidth - 2)}px`;
1674    pill.style.transform = `translateX(${translateX}px)`;
1675  };
1676
1677  const setActive = (index) => {
1678    index = clamp(index, 0, steps.length - 1);
1679    const stepId = stepIdByIndex(index);
1680    if (!stepId) return;
1681
1682    steps.forEach((s, i) => s.classList.toggle("is-active", i === index));
1683    cards.forEach((c) =>
1684      c.classList.toggle("is-active", c.getAttribute("data-step") === stepId)
1685    );
1686
1687    updatePill(index);
1688  };
1689
1690  const activateByStepId = (stepId) => {
1691    if (!stepId) return;
1692    const index = findIndexByStepId(stepId);
1693    if (index === -1) return;
1694    setActive(index);
1695  };
1696
1697  // ---------------- Init ----------------
1698  const initialStepId =
1699    steps.find((s) => s.classList.contains("is-active"))?.getAttribute("data-step") ||
1700    cards.find((c) => c.classList.contains("is-active"))?.getAttribute("data-step") ||
1701    steps[0].getAttribute("data-step") ||
1702    cards[0].getAttribute("data-step");
1703
1704  steps.forEach((s) => s.classList.remove("is-active"));
1705  cards.forEach((c) => c.classList.remove("is-active"));
1706
1707  metrics = null; // ensure fresh measurement
1708  if (initialStepId) activateByStepId(initialStepId);
1709  else setActive(0);
1710
1711  // ---------------- Events ----------------
1712  const onStepClick = (e) => {
1713    const step = e.target.closest(".pxl-item--step");
1714    if (!step || !stepsContainer.contains(step)) return;
1715    activateByStepId(step.getAttribute("data-step"));
1716  };
1717  stepsContainer.addEventListener("click", onStepClick);
1718
1719  let lastStepId = null;
1720  const cardEnterHandlers = new Map();
1721
1722  cards.forEach((card) => {
1723    const fn = () => {
1724      const stepId = card.getAttribute("data-step");
1725      if (!stepId || stepId === lastStepId) return;
1726      lastStepId = stepId;
1727      activateByStepId(stepId);
1728    };
1729    cardEnterHandlers.set(card, fn);
1730    card.addEventListener("pointerenter", fn, { passive: true });
1731  });
1732
1733  const onResize = () => {
1734    if (root !== document && !root.isConnected) return;
1735    metrics = null; // re-measure on next update
1736    updatePill();
1737  };
1738  window.addEventListener("resize", onResize, { passive: true });
1739
1740  // Layout settle (fonts/Elementor)
1741  const t = setTimeout(() => {
1742    metrics = null;
1743    updatePill();
1744  }, 0);
1745
1746  // ---------------- Destroy ----------------
1747  root.__auregonTextCarouselDestroy = () => {
1748    stepsContainer.removeEventListener("click", onStepClick);
1749
1750    cards.forEach((card) => {
1751      const fn = cardEnterHandlers.get(card);
1752      if (fn) card.removeEventListener("pointerenter", fn);
1753    });
1754    cardEnterHandlers.clear();
1755
1756    window.removeEventListener("resize", onResize);
1757    clearTimeout(t);
1758
1759    metrics = null;
1760  };
1761}
1762
1763    function setupGlowAnimation($scope) {
1764        var $wrapper = $scope.find(".pxl-section-mouse-follower");
1765        if (!$wrapper.length) return;
1766
1767        // Check if already initialized
1768        if ($wrapper.data("glow-animation-initialized")) return;
1769
1770        var $mouseGlow = $wrapper.find(".pxl-section-mouse-follower-shape1");
1771        var $blobPurple = $wrapper.find(".pxl-section-mouse-follower-shape2");
1772
1773        // Create HTML elements if they don't exist
1774        if (!$mouseGlow.length) {
1775            $mouseGlow = $('<div class="pxl-section-mouse-follower-shape1"></div>');
1776            $wrapper.append($mouseGlow);
1777        }
1778        if (!$blobPurple.length) {
1779            $blobPurple = $('<div class="pxl-section-mouse-follower-shape2"></div>');
1780            $wrapper.append($blobPurple);
1781        }
1782
1783        var state = {
1784            glowIntensity: 0,
1785            mouseX: 0,
1786            mouseY: 0,
1787            isActive: false,
1788            rafId: null,
1789            isRunning: true
1790        };
1791
1792        // Unique namespace for this wrapper
1793        var namespace = "pxlGlow_" + ($wrapper[0] ? $wrapper[0].getAttribute('data-id') || Date.now() : Date.now());
1794
1795        function handleMouseMove(e) {
1796            if (!state.isRunning) return;
1797
1798            var rect = $wrapper[0] ? $wrapper[0].getBoundingClientRect() : null;
1799            if (!rect) return;
1800
1801            var inside = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
1802            if (!inside) {
1803                state.isActive = false;
1804                $mouseGlow.css("opacity", 0);
1805                return;
1806            }
1807
1808            state.isActive = true;
1809            state.mouseX = e.clientX - rect.left;
1810            state.mouseY = e.clientY - rect.top;
1811
1812            $mouseGlow.css({
1813                left: state.mouseX + "px",
1814                top: state.mouseY + "px",
1815                opacity: 1
1816            });
1817            $blobPurple.css("opacity", 1);
1818        }
1819
1820        // Bind mouse move event with unique namespace
1821        $(document).on("mousemove." + namespace, handleMouseMove);
1822
1823        function animate() {
1824            if (!state.isRunning) return;
1825
1826            state.glowIntensity = (state.glowIntensity + 0.06) % (Math.PI * 2);
1827
1828            if (!state.isActive) {
1829                state.rafId = requestAnimationFrame(animate);
1830                return;
1831            }
1832
1833            var scale = 1 + Math.sin(state.glowIntensity) * 0.2;
1834            $mouseGlow.css("transform", "translate(-50%, -50%) scale(" + scale + ")");
1835
1836            var blobScale = 1 + Math.cos(state.glowIntensity) * 0.15;
1837            $blobPurple.css("transform", "translate(-50%, -50%) scale(" + blobScale + ")");
1838
1839            state.rafId = requestAnimationFrame(animate);
1840        }
1841
1842        // Start animation
1843        state.rafId = requestAnimationFrame(animate);
1844
1845        // Mark as initialized
1846        $wrapper.data("glow-animation-initialized", true);
1847
1848        // Cleanup function
1849        $wrapper.data("glow-animation-cleanup", function () {
1850            state.isRunning = false;
1851            if (state.rafId) {
1852                cancelAnimationFrame(state.rafId);
1853                state.rafId = null;
1854            }
1855            $(document).off("mousemove." + namespace);
1856            $wrapper.removeData("glow-animation-initialized");
1857            $wrapper.removeData("glow-animation-cleanup");
1858        });
1859
1860        // Cleanup when element is removed
1861        $wrapper.on('remove', function () {
1862            var cleanup = $wrapper.data("glow-animation-cleanup");
1863            if (cleanup && typeof cleanup === 'function') {
1864                cleanup();
1865            }
1866        });
1867    }
1868
1869    function auregon_text_hover_image($scope) {
1870
1871        if ($scope.find('.pxl-awards-list,.pxl-portfolio-grid-layout3').length <= 0) return;
1872        var mouseX = 0,
1873            mouseY = 0;
1874
1875        $scope.find('.pxl-awards-list .content-inner,.pxl-portfolio-grid-layout3 .pxl-grid-inner').mousemove(function (e) {
1876            var offset = $(this).offset();
1877            mouseX = (e.pageX - offset.left);
1878            mouseY = (e.pageY - offset.top);
1879
1880        });
1881        gsap.utils.toArray(".pxl-awards-list .fade-in-up, .pxl-portfolio-grid-layout3 .fade-in-up").forEach((element) => {
1882            gsap.from(element, {
1883                scrollTrigger: {
1884                    trigger: element,
1885                    start: "top 80%",
1886                    toggleActions: "play none none none"
1887                },
1888                duration: 1,
1889                opacity: 0,
1890                y: 80,
1891                ease: "power4.out"
1892            });
1893        });
1894
1895        $scope.find('.pxl-awards-list .pxl--item,.pxl-portfolio-grid-layout3 .pxl-grid-item').on("mouseenter", function () {
1896            $(this).removeClass('deactive').addClass('active');
1897            var target = $(this).attr('data-target');
1898            $(this).closest('.content-inner,.pxl-grid-inner').find(target).removeClass('deactive').addClass('active');
1899        });
1900        $scope.find('.pxl-awards-list .pxl--item,.pxl-portfolio-grid-layout3 .pxl-grid-item').on("mouseleave", function () {
1901            $(this).addClass('deactive').removeClass('active');
1902            var target = $(this).attr('data-target');
1903            $(this).closest('.content-inner,.pxl-grid-inner').find(target).addClass('deactive').removeClass('active');
1904        });
1905        const s = {
1906            x: window.innerWidth / 2,
1907            y: window.innerHeight / 2
1908        },
1909            t = gsap.quickSetter($scope.find('.pxl-awards-list .content-inner,.pxl-portfolio-grid-layout3 .pxl-grid-inner'), "css"),
1910            e = gsap.quickSetter($scope.find('.pxl-awards-list .content-inner,.pxl-portfolio-grid-layout3 .pxl-grid-inner'), "css");
1911
1912        gsap.ticker.add((() => {
1913            const o = .15,
1914                i = 1 - Math.pow(.85, gsap.ticker.deltaRatio());
1915            s.x += (mouseX - s.x) * i,
1916                s.y += (mouseY - s.y) * i,
1917                t({
1918                    "--pxl-mouse-x": `${s.x}px`
1919                }), e({
1920                    "--pxl-mouse-y": `${s.y}px`
1921                })
1922        }))
1923    }
1924
1925
1926    $(document).ready(function () {
1927        if (window.elementorFrontend && typeof elementorFrontend.waypoint === 'function') {
1928            auregon_animation_handler();
1929        }
1930        auregon_section_divider_glow();
1931        auregon_border_glow();
1932    });
1933
1934    $(window).on('elementor/frontend/init', function () {
1935        // Bổ sung waypoint nếu thiếu
1936        auregon_polyfill_waypoint();
1937        elementorFrontend.hooks.addAction('frontend/element_ready/global', function ($scope) {
1938            auregon_scroll_checkp($scope);
1939            auregon_animation_handler($scope);
1940            auregon_section_divider_glow($scope);
1941            auregon_border_glow($scope);
1942            renderOrbit($scope);
1943            setupGlowAnimation($scope);
1944        });
1945        auregon_section_start_render();
1946        auregon_parallax_bg();
1947        auregon_css_inline_js();
1948        auregon_section_before_render();
1949        auregon_zoom_point();
1950        auregon_scroll_fixed_section();
1951        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_contact_form.default', PXL_Icon_Contact_Form);
1952        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_heading.default', function ($scope) {
1953            auregon_split_text($scope);
1954        });
1955        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_post_c
1955arousel.default', function ($scope) {
1956            auregon_post_carousel_handler($scope);
1957        });
1958        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_sphere.default', function ($scope) {
1959            pxl_widget_sphere_handler($scope);
1960        });
1961        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_text_carousel.default', function ($scope) {
1962            auregon_text_carousel_handler($scope);
1963            // auregon_text_carousel_style2_handler($scope);
1964        });
1965        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_post_slip.default', function ($scope) {
1966            auregon_split_text($scope);
1967        });
1968        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_section_scale.default', function ($scope) {
1969            auregon_scroll_trigger($scope);
1970        });
1971        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_progressbar.default', function ($scope) {
1972            auregon_progressbar_handler($scope);
1973        });
1974        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_logo_marquee.default', function ($scope) {
1975            auregon_logo_marquee($scope);
1976        });
1977        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_awards_list.default', function ($scope) {
1978            auregon_text_hover_image($scope);
1979        });
1980
1981        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_text_marquee.default', function ($scope) {
1982            auregon_text_marquee($scope);
1983        });
1984        elementorFrontend.hooks.addAction('frontend/element_ready/pxl_care_orbit_tabs.default', function ($scope) {
1985            setTimeout(function () {
1986                auregon_care_orbit_tabs_handler($scope);
1987            }, 0);
1988        });
1989    });
1990})(jQuery);

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.