/* MenuX — Frontend JS. Dynamic config is injected via wp_add_inline_script (see includes/assets.php). */
(function menuxFrontendInit() {
if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', menuxFrontendInit); return; }
    var _d             = window.menuxFrontendData || {};
    var _i18n          = window.menuxI18n || {};
    var supportedCodes = _d.supportedCodes || [];
    var defaultCode    = _d.defaultCode    || '';
    var currentUrl     = window.location.href.split(/[?#]/)[0].replace(/\/$/, "");
    var ajaxUrl        = _d.ajaxUrl        || '';
    var trackNonce     = _d.trackNonce     || '';
    var isLoggedIn     = _d.isLoggedIn     || 0;
    var isSticky       = _d.isSticky       || 0;

    function findBestCode(langAttr, codes) {
        var lang = (langAttr || defaultCode).toLowerCase().replace(/_/g, '-');
        for (var i = 0; i < codes.length; i++) { if (codes[i].toLowerCase() === lang) return codes[i]; }
        var prefix = lang.substring(0, 2);
        for (var i = 0; i < codes.length; i++) { if (codes[i].toLowerCase().startsWith(prefix)) return codes[i]; }
        return codes[0] || defaultCode;
    }

    function applyLanguage() {
        var langAttr = document.documentElement.getAttribute("lang") || defaultCode;
        var bestCode = findBestCode(langAttr, supportedCodes);
        var dataAttr = 'data-lang-' + bestCode.toLowerCase().replace(/-/g, '_');
        document.querySelectorAll(".menux-container").forEach(function(nav) {
            nav.querySelectorAll(".menux-label").forEach(function(span) {
                span.textContent = span.getAttribute(dataAttr) || span.getAttribute('data-default') || '';
            });
        });
    }
    applyLanguage();

    // Announcement bar — check localStorage dismissal, wire up close button
    document.querySelectorAll('.menux-announcement-bar').forEach(function(bar) {
        var version = bar.getAttribute('data-ann-version') || '0';
        var days    = parseInt(bar.getAttribute('data-dismiss-days') || '7', 10);
        var key     = 'menux_ann_' + version;
        try {
            var stored = localStorage.getItem(key);
            if (stored) {
                var exp = parseInt(stored, 10) + days * 86400000;
                if (Date.now() < exp) { bar.classList.add('menux-ann-hidden'); return; }
                localStorage.removeItem(key);
            }
        } catch (e) { /* localStorage unavailable (private browsing / cookie blocked) */ }
        var closeBtn = bar.querySelector('.menux-ann-close');
        if (closeBtn) {
            closeBtn.addEventListener('click', function() {
                bar.classList.add('menux-ann-hidden');
                try { localStorage.setItem(key, String(Date.now())); } catch (e) {}
            });
        }
    });

    // Countdown timers
    document.querySelectorAll('.menux-ann-countdown').forEach(function(cd) {
        var targetTs = parseInt(cd.getAttribute('data-target-ts') || '0', 10) * 1000;
        var expired  = cd.getAttribute('data-expired') || '';
        if (!targetTs) return;

        function pad(n) { return String(n).padStart(2, '0'); }

        function tick() {
            var diff = targetTs - Date.now();
            if (diff <= 0) {
                if (expired) { cd.textContent = expired; }
                else { cd.style.display = 'none'; }
                return;
            }
            var days  = Math.floor(diff / 86400000);
            var hours = Math.floor((diff % 86400000) / 3600000);
            var mins  = Math.floor((diff % 3600000) / 60000);
            var secs  = Math.floor((diff % 60000) / 1000);

            var nums = cd.querySelectorAll('.menux-ann-cd-num');
            var daysWrap = cd.querySelector('.menux-ann-cd-days-wrap');
            if (daysWrap) daysWrap.style.display = days === 0 ? 'none' : '';
            if (days > 0) {
                if (nums[0]) nums[0].textContent = pad(days);
                if (nums[1]) nums[1].textContent = pad(hours);
                if (nums[2]) nums[2].textContent = pad(mins);
                if (nums[3]) nums[3].textContent = pad(secs);
            } else {
                if (nums[1]) nums[1].textContent = pad(hours);
                if (nums[2]) nums[2].textContent = pad(mins);
                if (nums[3]) nums[3].textContent = pad(secs);
            }
            setTimeout(tick, 1000);
        }
        tick();
    });

    // Active link
    var allNavs = document.querySelectorAll('.menux-container');
    allNavs.forEach(function(nav) {
        nav.querySelectorAll("a.menux-link").forEach(function(a) {
            var href = (a.getAttribute("href") || "").replace(/\/$/, "");
            if (currentUrl === href) a.classList.add("active");
        });

        var hamburger  = nav.querySelector(".menux-hamburger");
        var ul         = nav.querySelector(".menux-list");
        var overlay    = document.getElementById('menux-overlay');
        var closeBtn   = document.getElementById('menux-close-btn');
        var openStyle  = nav.getAttribute('data-mobile-open-style') || 'dropdown';
        var bpMode     = nav.getAttribute('data-mobile-bp-mode') || 'manual';
        var bpPx       = parseInt(nav.getAttribute('data-mobile-bp') || '768', 10);

        function bmOpenMenu() {
            if (!ul) return;
            // If a parent element has CSS transform/filter, position:fixed on the <ul>
            // would be contained by that element instead of the viewport (CSS spec §9.3).
            // Portal the <ul> to <body> so fixed positioning always works correctly.
            if (openStyle !== 'dropdown' && !ul._menuxPH) {
                var _p = nav.parentElement;
                while (_p && _p !== document.documentElement) {
                    var _cs = window.getComputedStyle(_p);
                    if (_cs.transform !== 'none' || _cs.filter !== 'none' || _cs.perspective !== 'none') {
                        ul._menuxPH = document.createComment('menux-portal');
                        ul.parentNode.insertBefore(ul._menuxPH, ul);
                        ul.style.position = 'fixed';
                        ul.style.zIndex   = '99999';
                        ul.style.top      = '0';
                        ul.style.bottom   = '0';
                        if (openStyle === 'drawer-right') {
                            ul.style.right = '0';
                        } else {
                            ul.style.left = '0';
                            if (openStyle === 'fullscreen') { ul.style.right = '0'; }
                        }
                        // In auto-bp mode CSS nesting won't match outside the nav; force display.
                        if (bpMode === 'auto') { ul.style.display = 'flex'; }
                        document.body.appendChild(ul);
                        break;
                    }
                    _p = _p.parentElement;
                }
            }
            ul.classList.add('show');
            hamburger && hamburger.classList.add('open');
            hamburger && hamburger.setAttribute('aria-expanded', 'true');
            if (overlay && openStyle !== 'dropdown' && openStyle !== 'fullscreen') {
                overlay.style.display = 'block';
                overlay.getBoundingClientRect();
                overlay.classList.add('visible');
            }
            if (closeBtn && openStyle !== 'dropdown') {
                closeBtn.classList.add('visible');
            }
            if (openStyle !== 'dropdown') {
                document.body.style.overflow = 'hidden';
                nav.style.position = 'relative';
                nav.style.zIndex   = '99999';
            }
        }

        function bmCloseMenu() {
            if (!ul) return;
            ul.classList.remove('show');
            hamburger && hamburger.classList.remove('open');
            hamburger && hamburger.setAttribute('aria-expanded', 'false');
            ul.querySelectorAll('.menux-submenu.mobile-open').forEach(function(sm) {
                sm.classList.remove('mobile-open');
            });
            // Also reset the open-state on the toggling links so their chevron
            // indicator returns to the closed position on the next open.
            ul.querySelectorAll('a.menux-link.mobile-sm-open').forEach(function(l) {
                l.classList.remove('mobile-sm-open');
            });
            // Mega panels use a separate open class — collapse them too, otherwise
            // they stay expanded (with stale aria-expanded) when the menu reopens.
            nav.querySelectorAll('.menux-has-mega.menux-open').forEach(function(li) {
                li.classList.remove('menux-open');
                var ml = li.querySelector(':scope > a.menux-link');
                if (ml) ml.setAttribute('aria-expanded', 'false');
                if (typeof li._menuxRestoreOverflow === 'function') li._menuxRestoreOverflow();
            });
            // Dismiss the mobile sub-screen instantly (no animation — full menu is closing).
            if (nav._menuxSubscreen) {
                clearTimeout(nav._menuxSSCloseTimer);
                nav._menuxSubscreen.classList.remove('menux-ss-open');
                nav._menuxSubscreen.classList.remove('menux-ss-closing');
                nav._menuxSubscreen.setAttribute('aria-hidden', 'true');
            }
            // Return the close button to its fixed slot if the sub-screen had moved it.
            if (typeof nav._menuxRestoreCloseBtn === 'function') nav._menuxRestoreCloseBtn();
            if (overlay && openStyle !== 'fullscreen') {
                overlay.classList.remove('visible');
                setTimeout(function(){ if (!overlay.classList.contains('visible')) overlay.style.display = 'none'; }, 320);
            }
            if (closeBtn) {
                closeBtn.classList.remove('visible');
            }
            document.body.style.overflow = '';
            nav.style.zIndex   = '';
            nav.style.position = '';
            // Restore portaled <ul> to its original position inside the nav.
            if (ul._menuxPH) {
                ul.style.position = '';
                ul.style.zIndex   = '';
                ul.style.top      = '';
                ul.style.left     = '';
                ul.style.right    = '';
                ul.style.bottom   = '';
                if (bpMode === 'auto') { ul.style.display = ''; }
                if (ul._menuxPH.parentNode) {
                    ul._menuxPH.parentNode.insertBefore(ul, ul._menuxPH);
                    ul._menuxPH.parentNode.removeChild(ul._menuxPH);
                }
                delete ul._menuxPH;
            }
        }

        function bmToggleMenu() {
            ul && ul.classList.contains('show') ? bmCloseMenu() : bmOpenMenu();
        }

        if (hamburger && ul) {
            hamburger.addEventListener('click', function(e) {
                e.preventDefault();
                bmToggleMenu();
            });
        }

        // Expose close so global overlay/Escape handlers can reach every nav instance.
        nav._menuxCloseMenu = bmCloseMenu;

        if (overlay && !overlay._menuxBound) {
            overlay._menuxBound = true;
            overlay.addEventListener('click', function() {
                allNavs.forEach(function(c) {
                    if (typeof c._menuxCloseMenu === 'function') c._menuxCloseMenu();
                });
            });
        }

        if (closeBtn && !closeBtn._menuxBound) {
            closeBtn._menuxBound = true;
            closeBtn.addEventListener('click', function() {
                allNavs.forEach(function(c) {
                    if (typeof c._menuxCloseMenu === 'function') c._menuxCloseMenu();
                });
                // Return focus to hamburger so keyboard/screen-reader users don't lose their place.
                var anyHb = document.querySelector('.menux-hamburger');
                if (anyHb) anyHb.focus();
            });
        }

        if (!document._menuxEscBound) {
            document._menuxEscBound = true;
            document.addEventListener('keydown', function(e) {
                if (e.key !== 'Escape' && e.keyCode !== 27) return;
                allNavs.forEach(function(c) {
                    var openUl = c.querySelector('.menux-list.show');
                    if (openUl && typeof c._menuxCloseMenu === 'function') {
                        c._menuxCloseMenu();
                        var hb = c.querySelector('.menux-hamburger');
                        if (hb) hb.focus();
                    }
                });
            });
        }

        var accordion = nav.getAttribute('data-mobile-accordion') === '1';

        nav.querySelectorAll(".menux-has-children > a.menux-link").forEach(function(a) {
            a.addEventListener("click", function(e) {
                var isMobile = bpMode === 'auto'
                    ? nav.classList.contains('menux-is-mobile')
                    : window.innerWidth <= bpPx;
                if (isMobile) {
                    e.preventDefault();
                    var subMenu = a.parentElement.querySelector('.menux-submenu');
                    if (subMenu) {
                        var isOpening = !subMenu.classList.contains('mobile-open');
                        // Accordion: close all siblings at the same level before opening.
                        if (isOpening && accordion) {
                            var parentUl = a.parentElement.parentElement;
                            if (parentUl) {
                                parentUl.querySelectorAll(':scope > .menux-has-children').forEach(function(sib) {
                                    if (sib === a.parentElement) return;
                                    // Collapse the entire sibling branch — including any
                                    // deeper (3rd-level+) submenus left open inside it —
                                    // so reopening it never restores a stale open state.
                                    sib.querySelectorAll('.menux-submenu.mobile-open').forEach(function(s) {
                                        s.classList.remove('mobile-open');
                                    });
                                    sib.querySelectorAll('a.menux-link.mobile-sm-open').forEach(function(l) {
                                        l.classList.remove('mobile-sm-open');
                                    });
                                });
                            }
                        }
                        subMenu.classList.toggle('mobile-open');
                        a.classList.toggle('mobile-sm-open');
                    }
                }
            });
        });

        // ── Mega Menu: desktop hover + mobile click ──
        nav.querySelectorAll('.menux-has-mega').forEach(function(li) {
            var closeTimer = null;
            var panel      = li.querySelector('.menux-mega-panel');
            var link       = li.querySelector(':scope > a.menux-link');

            // Page-builder overflow escape ─────────────────────────────────────
            // Elementor columns (and other page-builder wrappers) often have
            // overflow:hidden which clips the absolutely-positioned mega panel.
            // When clipped, the panel is invisible and mouse events land on the
            // wrapper boundary instead of the panel, causing immediate closure.
            // Fix: neutralise overflow on all ancestors between li and body while
            // the panel is open, then restore the original values on close.
            // Sibling mega items share the same ancestor wrappers, so escape/restore
            // is ref-counted ON the ancestor element itself (el._menuxOfCount). The
            // original inline overflow is captured only the first time an ancestor is
            // escaped (when it still holds the real value), and restored only when the
            // last open panel that needed it releases it — so one panel closing never
            // re-clips another that is still open. _ofList tracks which ancestors THIS
            // li incremented, making restore exactly balanced and idempotent.
            var _ofList = [];
            function _escapeOverflow() {
                _restoreOverflow(); // balance any prior unbalanced escape for this li
                var el = li.parentElement;
                while (el && el !== document.body) {
                    var clips;
                    if (el._menuxOfCount > 0) {
                        clips = true; // already escaped by another panel — join the count
                    } else {
                        var cs = window.getComputedStyle(el);
                        clips = (cs.overflow !== 'visible' || cs.overflowX !== 'visible' || cs.overflowY !== 'visible');
                    }
                    if (clips) {
                        if (!el._menuxOfCount) {
                            el._menuxOfSaved = { ov: el.style.overflow, ox: el.style.overflowX, oy: el.style.overflowY };
                            el._menuxOfCount = 0;
                        }
                        el._menuxOfCount++;
                        el.style.overflow  = 'visible';
                        el.style.overflowX = 'visible';
                        el.style.overflowY = 'visible';
                        _ofList.push(el);
                    }
                    el = el.parentElement;
                }
            }
            function _restoreOverflow() {
                _ofList.forEach(function(el) {
                    el._menuxOfCount--;
                    if (el._menuxOfCount <= 0) {
                        if (el._menuxOfSaved) {
                            el.style.overflow  = el._menuxOfSaved.ov;
                            el.style.overflowX = el._menuxOfSaved.ox;
                            el.style.overflowY = el._menuxOfSaved.oy;
                        }
                        el._menuxOfCount = 0;
                        delete el._menuxOfSaved;
                    }
                });
                _ofList = [];
            }
            // Expose restore on the element so the outside-click handler and the
            // accessibility keyboard module can release overflow when they close
            // the panel without going through megaClose().
            li._menuxRestoreOverflow = _restoreOverflow;
            // ──────────────────────────────────────────────────────────────────

            function isDesktop() {
                return bpMode === 'auto'
                    ? !nav.classList.contains('menux-is-mobile')
                    : window.innerWidth > bpPx;
            }
            // Smart horizontal alignment: a non-full-width panel opens left-aligned
            // by default, but flips to right-aligned if it would overflow the right
            // edge of the viewport (e.g. for menu items near the right side of the
            // bar). The panel is visibility:hidden (not display:none) while closed,
            // so it has a real layout box and can be measured before opening — no
            // visible flash. Skipped for full-width panels, which span the container.
            function _positionPanel() {
                if (!panel || panel.classList.contains('menux-mega-full')) return;
                panel.classList.remove('menux-mega-flip');
                var rect = panel.getBoundingClientRect();
                if (rect.width && rect.right > document.documentElement.clientWidth - 8) {
                    panel.classList.add('menux-mega-flip');
                }
            }
            // Re-evaluate alignment on resize — listener attached once per nav, not per item.
            if (!nav._menuxMegaResizeBound) {
                nav._menuxMegaResizeBound = true;
                window.addEventListener('resize', function() {
                    nav.querySelectorAll('.menux-has-mega.menux-open').forEach(function(openLi) {
                        var p = openLi.querySelector(':scope > .menux-mega-panel');
                        if (!p || p.classList.contains('menux-mega-full')) return;
                        var desktop = bpMode === 'auto' ? !nav.classList.contains('menux-is-mobile') : window.innerWidth > bpPx;
                        if (!desktop) return;
                        p.classList.remove('menux-mega-flip');
                        var rect = p.getBoundingClientRect();
                        if (rect.width && rect.right > document.documentElement.clientWidth - 8) {
                            p.classList.add('menux-mega-flip');
                        }
                    });
                });
            }
            function megaOpen() {
                clearTimeout(closeTimer); closeTimer = null;
                // Close sibling panels first.
                nav.querySelectorAll('.menux-has-mega.menux-open').forEach(function(other) {
                    if (other !== li) {
                        other.classList.remove('menux-open');
                        var ol = other.querySelector(':scope > a.menux-link');
                        if (ol) ol.setAttribute('aria-expanded', 'false');
                    }
                });
                _escapeOverflow();
                if (isDesktop()) _positionPanel();
                li.classList.add('menux-open');
                if (link) link.setAttribute('aria-expanded', 'true');
            }
            function megaClose() {
                clearTimeout(closeTimer);
                var _hoverDelay = (window.menuxFrontendData && window.menuxFrontendData.a11y && typeof window.menuxFrontendData.a11y.hoverDelay === 'number')
                    ? window.menuxFrontendData.a11y.hoverDelay : 300;
                closeTimer = setTimeout(function() {
                    li.classList.remove('menux-open');
                    if (link) link.setAttribute('aria-expanded', 'false');
                    _restoreOverflow();
                }, _hoverDelay);
            }

            // Desktop: hover open/close with gap-bridging delay.
            li.addEventListener('mouseenter', function() { if (isDesktop()) megaOpen(); });
            li.addEventListener('mouseleave', function() { if (isDesktop()) megaClose(); });
            // The panel is a DOM child of <li>, so moving from panel → link stays
            // within <li> and never re-triggers li.mouseenter. We must cancel the
            // close timer on the link's own mouseenter to handle that path.
            if (link) {
                link.addEventListener('mouseenter', function() {
                    if (isDesktop()) { clearTimeout(closeTimer); closeTimer = null; }
                });
            }
            if (panel) {
                panel.addEventListener('mouseenter', function() {
                    if (isDesktop()) { clearTimeout(closeTimer); closeTimer = null; }
                });
                panel.addEventListener('mouseleave', function() { if (isDesktop()) megaClose(); });
            }

            // ── Mobile sub-screen (push navigation, 3.8.0+) ─────────────────
            // Tapping a mega item slides a full-screen overlay in from the right —
            // like mediaworld.it / euronics on mobile. Built once per nav, shared
            // across all mega items on that nav instance.

            // Slide-out animation then hide. nav._menuxSSCloseTimer is stored on the
            // nav so all mega-item scopes share the same timer reference.
            function closeSubscreen() {
                if (!nav._menuxSubscreen) return;
                var ssEl = nav._menuxSubscreen;
                ssEl.classList.remove('menux-ss-open');
                ssEl.classList.add('menux-ss-closing');
                ssEl.setAttribute('aria-hidden', 'true');
                clearTimeout(nav._menuxSSCloseTimer);
                nav._menuxSSCloseTimer = setTimeout(function() {
                    ssEl.classList.remove('menux-ss-closing');
                    // Return the close button to its fixed slot for the regular menu behind.
                    if (nav._menuxRestoreCloseBtn) nav._menuxRestoreCloseBtn();
                }, 300);
            }

            if (!nav._menuxSubscreen && ul) {
                var ssLi = document.createElement('li');
                ssLi.className = 'menux-mega-subscreen-li';
                ssLi.setAttribute('aria-hidden', 'true');
                ssLi.innerHTML =
                    '<div class="menux-mega-subscreen-head">' +
                        '<button class="menux-mega-subscreen-back" type="button" aria-label="' + (_i18n.back || 'Back') + '">&#8592;</button>' +
                        '<span class="menux-mega-subscreen-title"></span>' +
                    '</div>' +
                    '<ul class="menux-mega-subscreen-links"></ul>';
                ul.appendChild(ssLi);
                nav._menuxSubscreen = ssLi;
                nav._menuxSSTitle   = ssLi.querySelector('.menux-mega-subscreen-title');
                nav._menuxSSLinks   = ssLi.querySelector('.menux-mega-subscreen-links');
                ssLi.querySelector('.menux-mega-subscreen-back').addEventListener('click', function() {
                    closeSubscreen();
                });
                ssLi.querySelector('.menux-mega-subscreen-title').addEventListener('click', function() {
                    closeSubscreen();
                });

                // The global close button (X) is position:fixed with a lower z-index
                // than the sub-screen overlay, so it would be hidden behind it. While
                // the sub-screen is open we relocate it into the header (far right);
                // this helper puts it back to its fixed top-right slot afterwards.
                nav._menuxRestoreCloseBtn = function() {
                    if (closeBtn && closeBtn._menuxSSMoved) {
                        closeBtn.classList.remove('menux-ss-close');
                        if (closeBtn._menuxOrigNext && closeBtn._menuxOrigNext.parentNode === closeBtn._menuxOrigParent) {
                            closeBtn._menuxOrigParent.insertBefore(closeBtn, closeBtn._menuxOrigNext);
                        } else if (closeBtn._menuxOrigParent) {
                            closeBtn._menuxOrigParent.appendChild(closeBtn);
                        }
                        closeBtn._menuxSSMoved = false;
                    }
                };
            }

            function openSubscreen() {
                if (!nav._menuxSubscreen) return;
                var title = link ? (link.querySelector('.menux-label') || link).textContent.trim() : '';
                nav._menuxSSTitle.textContent = title;
                var linksUl = nav._menuxSSLinks;
                linksUl.innerHTML = '';
                if (panel) {
                    panel.querySelectorAll('.menux-mega-col').forEach(function(col) {
                        Array.prototype.forEach.call(col.children, function(child) {
                            var lLi = document.createElement('li');
                            if (child.classList.contains('menux-mega-heading')) {
                                var sp = document.createElement('span');
                                sp.className = 'menux-ss-heading';
                                sp.textContent = child.textContent.trim();
                                lLi.appendChild(sp);
                                linksUl.appendChild(lLi);
                            } else if (child.classList.contains('menux-mega-link')) {
                                var cloned = child.cloneNode(true);
                                cloned.addEventListener('click', function() {
                                    // Navigating away: dismiss instantly, then close the whole menu.
                                    if (nav._menuxSubscreen) {
                                        clearTimeout(nav._menuxSSCloseTimer);
                                        nav._menuxSubscreen.classList.remove('menux-ss-open');
                                        nav._menuxSubscreen.classList.remove('menux-ss-closing');
                                        nav._menuxSubscreen.setAttribute('aria-hidden', 'true');
                                    }
                                    if (typeof nav._menuxCloseMenu === 'function') nav._menuxCloseMenu();
                                });
                                lLi.appendChild(cloned);
                                linksUl.appendChild(lLi);
                            }
                            // dividers, images, widgets: not shown in mobile sub-screen
                        });
                    });
                }
                // Relocate the global close button into the header (far right) so it
                // stays visible above the sub-screen overlay.
                if (closeBtn) {
                    if (!closeBtn._menuxSSMoved) {
                        closeBtn._menuxOrigParent = closeBtn.parentNode;
                        closeBtn._menuxOrigNext   = closeBtn.nextSibling;
                    }
                    var ssHead = nav._menuxSubscreen.querySelector('.menux-mega-subscreen-head');
                    ssHead.appendChild(closeBtn);
                    closeBtn.classList.add('menux-ss-close');
                    closeBtn.classList.add('visible');
                    closeBtn._menuxSSMoved = true;
                }
                nav._menuxSubscreen.classList.add('menux-ss-open');
                nav._menuxSubscreen.setAttribute('aria-hidden', 'false');
                // Move focus to the back button for keyboard/screen-reader users.
                var backBtn = nav._menuxSubscreen.querySelector('.menux-mega-subscreen-back');
                if (backBtn) { setTimeout(function() { backBtn.focus(); }, 50); }
            }

            // Mobile: tap opens the sub-screen.
            if (link) {
                link.addEventListener('click', function(e) {
                    if (!isDesktop()) {
                        e.preventDefault();
                        openSubscreen();
                    }
                });
            }
            // Desktop: panel link click closes the panel (user is navigating away).
            if (panel) {
                panel.querySelectorAll('a').forEach(function(panelLink) {
                    panelLink.addEventListener('click', function() {
                        if (isDesktop()) {
                            li.classList.remove('menux-open');
                            if (link) link.setAttribute('aria-expanded', 'false');
                            _restoreOverflow();
                        }
                    });
                });
            }
        });

        // Close mega panels when clicking outside — one handler for ALL navs on the page.
        if (!document._menuxMegaClickBound) {
            document._menuxMegaClickBound = true;
            document.addEventListener('click', function(e) {
                document.querySelectorAll('.menux-has-mega.menux-open').forEach(function(li) {
                    if (!li.contains(e.target)) {
                        li.classList.remove('menux-open');
                        var l = li.querySelector(':scope > a.menux-link');
                        if (l) l.setAttribute('aria-expanded', 'false');
                        if (typeof li._menuxRestoreOverflow === 'function') li._menuxRestoreOverflow();
                    }
                });
            });
        }

        if (bpMode === 'auto') {
            function bmCheckFit() {
                var list = nav.querySelector('.menux-list');
                if (!list) return;
                var wasMobile = nav.classList.contains('menux-is-mobile');
                nav.classList.remove('menux-is-mobile');
                nav.classList.add('menux-is-desktop');
                list.style.visibility = 'hidden';
                list.style.display = 'flex';
                list.style.flexDirection = 'row';

                var containerW = nav.getBoundingClientRect().width;
                var listScrollW = list.scrollWidth;
                var logoW = 0;
                var logo = nav.querySelector('.menux-logo');
                if (logo) logoW = logo.getBoundingClientRect().width + 16;

                var fits = (listScrollW + logoW) <= containerW;

                list.style.visibility = '';
                list.style.display = '';
                list.style.flexDirection = '';

                if (fits) {
                    nav.classList.remove('menux-is-mobile');
                    nav.classList.add('menux-is-desktop');
                    if (wasMobile && ul && ul.classList.contains('show')) bmCloseMenu();
                } else {
                    nav.classList.remove('menux-is-desktop');
                    nav.classList.add('menux-is-mobile');
                }
            }

            if (window.ResizeObserver) {
                new ResizeObserver(function() { bmCheckFit(); }).observe(nav);
            } else {
                window.addEventListener('resize', bmCheckFit, { passive: true });
            }
            bmCheckFit();

        } else {
            window.addEventListener('resize', function() {
                if (window.innerWidth > bpPx && ul && ul.classList.contains('show')) {
                    bmCloseMenu();
                }
            }, { passive: true });
        }
    });

    // Entrance-animation stacking-context cleanup.
    // CSS animations that include transform/opacity in their keyframes promote
    // the element to a compositor layer while running, creating a stacking context
    // with z-index:auto. That traps the mega panel's z-index inside the container,
    // causing it to render behind later-DOM page sections (Elementor, etc.).
    // Once the entrance animation ends we remove the inline animation override so
    // the stylesheet rule no longer applies, collapsing the stacking context.
    document.querySelectorAll('.menux-container').forEach(function(container) {
        container.addEventListener('animationend', function(e) {
            if (e.target === container) {
                container.style.animation = '';
            }
        });
    });

    // Sticky — selected per-instance by the data attribute (not a fixed ID) so
    // it works for both [menux] shortcodes and giuliomax/menu blocks, whose
    // structural IDs are suffixed (menux-nav-main-blk1). Also supports more than
    // one sticky nav on the same page without the old single-getElementById limit.
    document.querySelectorAll('.menux-container[data-menux-sticky="1"]').forEach(function(nav) {
        // The sticky spacer is rendered as a sibling just before this nav; walk
        // back to the nearest .menux-sticky-spacer so each nav pairs with its own.
        var spacer = nav.previousElementSibling;
        while (spacer && !spacer.classList.contains('menux-sticky-spacer')) {
            spacer = spacer.previousElementSibling;
        }

        var navTop = nav.getBoundingClientRect().top + window.scrollY;
        var navH   = nav.offsetHeight;
        var lastScrollY = window.scrollY;
        var scrollThreshold = 5;
        nav.classList.add('menux-autohide');

        // Re-measure the nav's natural offset/height while it is in normal flow
        // (not fixed). Captured once at load it goes stale after web-font reflow,
        // responsive height changes, or content shifting above the nav — making
        // the spacer the wrong height and the page jump when sticky engages.
        function recalcMetrics() {
            if (nav.classList.contains('menux-sticky-fixed')) return;
            navTop = nav.getBoundingClientRect().top + window.scrollY;
            navH   = nav.offsetHeight;
        }

        // Measure the nav's natural top/height even when it is currently fixed.
        // Used after a web-font swap or resize that happens while the user has
        // already scrolled past the nav: recalcMetrics() bails when fixed, so the
        // spacer would keep its pre-font height and shift the page. This briefly
        // restores normal flow to read the real height — all synchronous, so the
        // browser never paints the intermediate state (no flicker).
        function recalcMetricsForce() {
            if (!nav.classList.contains('menux-sticky-fixed')) { recalcMetrics(); return; }
            var wasHidden  = nav.classList.contains('menux-hidden');
            var spacerDisp = spacer ? spacer.style.display : '';
            if (spacer) spacer.style.display = 'none';
            nav.classList.remove('menux-sticky-fixed');
            nav.classList.remove('menux-hidden');
            navH   = nav.offsetHeight;
            navTop = nav.getBoundingClientRect().top + window.scrollY;
            nav.classList.add('menux-sticky-fixed');
            if (wasHidden) nav.classList.add('menux-hidden');
            if (spacer) { spacer.style.display = spacerDisp; spacer.style.height = navH + 'px'; }
        }

        function checkSticky() {
            var currentY = window.scrollY;
            if (currentY >= navTop) {
                var wasFixed = nav.classList.contains('menux-sticky-fixed');
                nav.classList.add('menux-sticky-fixed');
                if (spacer) { spacer.style.display = 'block'; spacer.style.height = navH + 'px'; }

                if (!wasFixed) {
                    // Just became sticky — always show it regardless of scroll direction
                    nav.classList.remove('menux-hidden');
                } else if (currentY > lastScrollY && (currentY - lastScrollY) > scrollThreshold) {
                    nav.classList.add('menux-hidden');
                } else if (currentY < lastScrollY && (lastScrollY - currentY) > scrollThreshold) {
                    nav.classList.remove('menux-hidden');
                }
            } else {
                nav.classList.remove('menux-sticky-fixed');
                nav.classList.remove('menux-hidden');
                if (spacer) spacer.style.display = 'none';
                // In normal flow → refresh natural metrics for the next engage.
                recalcMetrics();
            }
            lastScrollY = currentY;
        }
        window.addEventListener('scroll', checkSticky, { passive: true });
        window.addEventListener('resize', function() { recalcMetricsForce(); checkSticky(); }, { passive: true });
        // Re-measure after web fonts finish loading — a font swap can change nav
        // height, making the spacer wrong until the next scroll or resize. Use the
        // force variant so it also corrects when the nav is already sticky.
        if (document.fonts && document.fonts.ready) {
            document.fonts.ready.then(function() { recalcMetricsForce(); checkSticky(); });
        }
        checkSticky();
    });

    // Scroll progress bar — per-instance; the bar lives inside each nav, so a
    // class selector finds it regardless of the (possibly suffixed) element ID.
    document.querySelectorAll('.menux-progress-bar').forEach(function(progressBar) {
        function menuxUpdateProgress() {
            var docH = document.documentElement.scrollHeight - window.innerHeight;
            var pct  = docH > 0 ? (window.scrollY / docH) * 100 : 0;
            progressBar.style.width = Math.min(100, pct).toFixed(1) + '%';
        }
        window.addEventListener('scroll', menuxUpdateProgress, { passive: true });
        menuxUpdateProgress();
    });

    // Language observer
    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(m) { if (m.attributeName === 'lang') applyLanguage(); });
    });
    observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] });

    // Search modal — open/close delegation runs unconditionally so it works
    // even when searchEnabled is false due to cache or shortcode ordering.
    document.addEventListener('click', function(e) {
        var modal = document.getElementById('menux-search-modal');
        if (!modal) return;
        if (e.target.closest('#menux-search-open')) {
            modal.classList.add('bm-sm-open');
            document.body.style.overflow = 'hidden';
            var inp = document.getElementById('menux-search-input-modal');
            if (inp) setTimeout(function(){ inp.focus(); }, 50);
            return;
        }
        if (e.target.closest('#menux-search-close') || e.target.closest('#menux-search-backdrop')) {
            modal.classList.remove('bm-sm-open');
            document.body.style.overflow = '';
            var inp2 = document.getElementById('menux-search-input-modal');
            if (inp2) inp2.value = '';
        }
    });

    // WooCommerce mini-cart — open/close via event delegation so it survives the
    // add-to-cart fragment replacement (which swaps the whole .menux-woo-cart node).
    // The open state lives on the persistent .menux-woo-cart-wrap, NOT on the
    // inner .menux-woo-cart: WooCommerce's add-to-cart fragments replace the
    // inner node on every cart change (remove item, qty update), which would
    // otherwise drop the open class and collapse the dropdown mid-interaction.
    document.addEventListener('click', function(e) {
        var btn = e.target.closest('.menux-woo-cart-btn');
        if (btn) {
            var wrap   = btn.closest('.menux-woo-cart-wrap');
            var cartEl = btn.closest('.menux-woo-cart');
            if (!wrap || !cartEl) return;
            var mode = cartEl.getAttribute('data-minicart');
            var hasMini = !!cartEl.querySelector('.menux-woo-minicart');
            // Click toggles in 'click' mode, or in 'hover' mode on touch devices
            // where :hover is unavailable; otherwise let the link open the cart page.
            var noHover = window.matchMedia && window.matchMedia('(hover: none)').matches;
            if (hasMini && (mode === 'click' || (mode === 'hover' && noHover))) {
                e.preventDefault();
                document.querySelectorAll('.menux-woo-cart-wrap.menux-woo-open').forEach(function(c) {
                    if (c !== wrap) c.classList.remove('menux-woo-open');
                });
                wrap.classList.toggle('menux-woo-open');
            }
            return;
        }
        // Click outside an open mini-cart closes it (but clicks inside it — e.g.
        // WooCommerce's "remove item" link — keep it open).
        if (!e.target.closest('.menux-woo-minicart')) {
            document.querySelectorAll('.menux-woo-cart-wrap.menux-woo-open').forEach(function(c) {
                c.classList.remove('menux-woo-open');
            });
        }
    });
    document.addEventListener('keydown', function(e) {
        if (e.key === 'Escape') {
            document.querySelectorAll('.menux-woo-cart-wrap.menux-woo-open').forEach(function(c) {
                c.classList.remove('menux-woo-open');
            });
        }
    });

    var searchEnabled = _d.searchEnabled || document.getElementById('menux-search-modal') !== null;
    if (searchEnabled) {
        var _bmSM = {
            modal: document.getElementById('menux-search-modal'),
            input: document.getElementById('menux-search-input-modal'),
            results: document.getElementById('menux-search-results-modal'),
            countEl: document.getElementById('menux-search-count'),
            closeBtn: document.getElementById('menux-search-close'),
            backdrop: document.getElementById('menux-search-backdrop'),
            navBar: document.getElementById('bm-search-nav-bar'),
            navLabel: document.getElementById('bm-snb-label'),
            navPrev: document.getElementById('bm-snb-prev'),
            navNext: document.getElementById('bm-snb-next'),
            navClear: document.getElementById('bm-snb-clear'),
            currentTab: 'menu',
            focusIdx: -1,
            pageMatches: [],
            pageMatchIdx: -1,
            debounceTimer: null
        };

        // Portal modal and nav-bar to <body> so position:fixed always anchors
        // to the viewport — works even when a page-cache plugin serves the old
        // HTML that placed them inside <nav> (which may have a CSS transform).
        if (_bmSM.modal && _bmSM.modal.parentNode !== document.body) {
            document.body.appendChild(_bmSM.modal);
        }
        if (_bmSM.navBar && _bmSM.navBar.parentNode !== document.body) {
            document.body.appendChild(_bmSM.navBar);
        }

        function bmSmOpen() {
            if (!_bmSM.modal) _bmSM.modal = document.getElementById('menux-search-modal');
            if (!_bmSM.modal) return;
            _bmSM.modal.classList.add('bm-sm-open');
            document.body.style.overflow = 'hidden';
            setTimeout(function() { if (_bmSM.input) _bmSM.input.focus(); }, 50);
            bmSmRenderEmpty();
        }
        function bmSmClose() {
            if (!_bmSM.modal) return;
            _bmSM.modal.classList.remove('bm-sm-open');
            document.body.style.overflow = '';
            if (_bmSM.input) _bmSM.input.value = '';
            _bmSM.focusIdx = -1;
            bmSmClearPageHighlights();
            bmSmRenderEmpty();
        }
        // open/close click delegation handled unconditionally above;
        // bmSmClose is used below for keyboard (Esc) and search-result resets.

        document.querySelectorAll('#menux-search-box .bm-sm-tab').forEach(function(tab) {
            tab.addEventListener('click', function() {
                document.querySelectorAll('#menux-search-box .bm-sm-tab').forEach(function(t){ t.classList.remove('active'); });
                tab.classList.add('active');
                _bmSM.currentTab = tab.getAttribute('data-tab');
                _bmSM.focusIdx = -1;
                var q = _bmSM.input ? _bmSM.input.value.trim() : '';
                if (q.length >= 2) bmSmSearch(q);
                else bmSmRenderEmpty();
            });
        });

        function bmSmHL(text, q) {
            var esc = String(text).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
            if (!q) return esc;
            var safe = q.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');
            return esc.replace(new RegExp('(' + safe + ')', 'gi'), '<mark>$1</mark>');
        }

        function bmSmRenderEmpty() {
            if (!_bmSM.results) return;
            _bmSM.results.innerHTML = '<div class="bm-sm-empty">'
                + '<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>'
                + '<div style="font-size:15px;font-weight:600;color:#475569;margin-bottom:6px;">' + (_i18n.startTyping || 'Start typing to search') + '</div>'
                + '<div style="font-size:12px;">' + (_i18n.searchHint || 'Tab Menu: search menu links &middot; Tab In page: find text on the current page') + '</div>'
                + '</div>';
            if (_bmSM.countEl) _bmSM.countEl.textContent = '';
        }

        function bmSmRenderNoResults(q) {
            if (!_bmSM.results) return;
            _bmSM.results.innerHTML = '<div class="bm-sm-empty">'
                + '<svg viewBox="0 0 24 24"><path d="M10 10l4 4M14 10l-4 4"/><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>'
                + '<div style="font-size:15px;font-weight:600;color:#475569;margin-bottom:6px;">'+(_i18n.noResultsFor||'No results for')+' "<em style=\'color:#6366f1;font-style:normal;\'>' + bmSmHL(q, '') + '</em>"</div>'
                + '</div>';
            if (_bmSM.countEl) _bmSM.countEl.textContent = _i18n.zeroResults || '0 results';
        }

        function bmSmSearch(q) {
            if (_bmSM.currentTab === 'menu') bmSmSearchMenu(q);
            else bmSmSearchPage(q);
        }

        function bmSmSearchMenu(q) {
            var items = [];
            document.querySelectorAll('.menux-container a.menux-link').forEach(function(a) {
                var labelEl = a.querySelector('.menux-label');
                var label = labelEl ? labelEl.textContent.trim() : a.textContent.trim();
                var href  = a.getAttribute('href') || '';
                var iconEl = a.querySelector('i[class]');
                var iconClass = iconEl ? iconEl.className : '';
                if (label && href && href !== '#') items.push({ label: label, href: href, icon: iconClass });
            });
            var matches = items.filter(function(it) { return it.label.toLowerCase().indexOf(q.toLowerCase()) !== -1; });
            if (!matches.length) { bmSmRenderNoResults(q); return; }

            var html = '';
            matches.forEach(function(it, i) {
                var safeHref = it.href.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
                var safeIcon = it.icon.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
                var iconHtml = it.icon
                    ? '<div class="bm-sm-result-icon"><i class="' + safeIcon + '" aria-hidden="true"></i></div>'
                    : '<div class="bm-sm-result-icon">🔗</div>';
                html += '<a href="' + safeHref + '" class="bm-sm-result" data-idx="' + i + '">'
                    + iconHtml
                    + '<div><div class="bm-sm-result-title">' + bmSmHL(it.label, q) + '</div>'
                    + '<div class="bm-sm-result-sub">' + safeHref + '</div></div>'
                    + '</a>';
            });
            if (_bmSM.results) {
                _bmSM.results.innerHTML = html;
                // Close the modal on result click via a real listener — the old
                // inline onclick="bmSmClose()" threw a ReferenceError because
                // bmSmClose is function-scoped, not a global.
                _bmSM.results.querySelectorAll('.bm-sm-result').forEach(function(a) {
                    a.addEventListener('click', function() { bmSmClose(); });
                });
            }
            if (_bmSM.countEl) _bmSM.countEl.textContent = matches.length + ' result' + (matches.length===1?'':'s');
            _bmSM.focusIdx = -1;
        }

        function bmSmSearchPage(q) {
            bmSmClearPageHighlights();

            var bodyEl = document.body;
            var walker = document.createTreeWalker(bodyEl, NodeFilter.SHOW_TEXT, {
                acceptNode: function(node) {
                    var p = node.parentNode;
                    while (p) {
                        var tn = (p.tagName || '').toLowerCase();
                        if (tn === 'script' || tn === 'style' || tn === 'noscript') return NodeFilter.FILTER_REJECT;
                        if (p.id === 'menux-search-modal' || p.id === 'bm-search-nav-bar') return NodeFilter.FILTER_REJECT;
                        if (p.classList && (p.classList.contains('menux-container') || p.classList.contains('menux-sticky-spacer'))) return NodeFilter.FILTER_REJECT;
                        p = p.parentNode;
                    }
                    return NodeFilter.FILTER_ACCEPT;
                }
            }, false);

            var re = new RegExp(q.replace(/[.*+?^${}()|[\]\\]/g,'\\$&'), 'gi');

            // Phase 1: collect matching text nodes WITHOUT touching the DOM.
            // Modifying nodes during TreeWalker traversal detaches the current
            // node, causing nextNode() to return null and stopping the walk
            // after only the first match.
            var pending = [];
            var node;
            while ((node = walker.nextNode())) {
                re.lastIndex = 0;
                if (re.test(node.nodeValue)) pending.push(node);
            }

            // Phase 2: now replace each collected node safely.
            var hits = [];
            pending.forEach(function(textNode) {
                if (!textNode.parentNode) return;
                var text = textNode.nodeValue;
                var frag = document.createDocumentFragment();
                var lastIdx = 0;
                var m;
                re.lastIndex = 0;
                while ((m = re.exec(text)) !== null) {
                    if (m.index > lastIdx) frag.appendChild(document.createTextNode(text.slice(lastIdx, m.index)));
                    var mark = document.createElement('mark');
                    mark.className = 'menux-highlight';
                    mark.textContent = m[0];
                    frag.appendChild(mark);
                    hits.push(mark);
                    lastIdx = m.index + m[0].length;
                }
                if (lastIdx < text.length) frag.appendChild(document.createTextNode(text.slice(lastIdx)));
                textNode.parentNode.replaceChild(frag, textNode);
            });

            _bmSM.pageMatches = hits;
            _bmSM.pageMatchIdx = -1;

            if (!hits.length) { bmSmRenderNoResults(q); return; }

            var html = '';
            hits.forEach(function(mark, i) {
                var ctx = '';
                var par = mark.parentNode;
                while (par && !ctx.trim()) {
                    ctx = par.textContent || '';
                    par = par.parentNode;
                }
                ctx = ctx.replace(/\s+/g,' ').trim().slice(0, 120);
                html += '<div class="bm-sm-page-hit" data-hit-idx="' + i + '">'
                    + '<div class="bm-sm-result-title">' + bmSmHL(mark.textContent, q) + '</div>'
                    + '<div class="bm-sm-ph-ctx">' + bmSmHL(ctx, q) + '</div>'
                    + '<div class="bm-sm-ph-pos">' + (_i18n.matchOf || 'Match %1$s of %2$s').replace('%1$s', i+1).replace('%2$s', hits.length) + '</div>'
                    + '</div>';
            });
            if (_bmSM.results) _bmSM.results.innerHTML = html;
            if (_bmSM.countEl) _bmSM.countEl.textContent = (hits.length===1 ? (_i18n.occurrences||'%s occurrence') : (_i18n.occurrencesPlural||'%s occurrences')).replace('%s', hits.length);

            _bmSM.results.querySelectorAll('.bm-sm-page-hit').forEach(function(el) {
                el.addEventListener('click', function() {
                    var idx = parseInt(el.getAttribute('data-hit-idx'));
                    bmSmClose();
                    bmSmGoToHit(idx);
                    bmSmShowNavBar(q);
                });
            });

            if (hits.length > 0) bmSmShowNavBar(q);
        }

        function bmSmGoToHit(idx) {
            if (!_bmSM.pageMatches.length) return;
            idx = ((idx % _bmSM.pageMatches.length) + _bmSM.pageMatches.length) % _bmSM.pageMatches.length;
            _bmSM.pageMatchIdx = idx;
            _bmSM.pageMatches.forEach(function(m) { m.className = 'menux-highlight'; });
            var cur = _bmSM.pageMatches[idx];
            cur.className = 'menux-highlight menux-highlight-current';
            cur.scrollIntoView({ behavior: 'smooth', block: 'center' });
            if (_bmSM.navLabel) _bmSM.navLabel.textContent = (idx+1) + ' / ' + _bmSM.pageMatches.length;
        }

        function bmSmShowNavBar(q) {
            if (!_bmSM.navBar || !_bmSM.pageMatches.length) return;
            _bmSM.navBar.classList.add('show');
            if (_bmSM.navLabel) _bmSM.navLabel.textContent = _bmSM.pageMatchIdx >= 0 ? (_bmSM.pageMatchIdx+1) + ' / ' + _bmSM.pageMatches.length : (_i18n.found||'%s found').replace('%s', _bmSM.pageMatches.length);
            // Honour the already-selected hit (e.g. when the user clicked a specific
            // match in the results list) instead of always snapping back to the first.
            bmSmGoToHit(_bmSM.pageMatchIdx >= 0 ? _bmSM.pageMatchIdx : 0);
        }

        function bmSmClearPageHighlights() {
            var touched = [];
            document.querySelectorAll('mark.menux-highlight,mark.menux-highlight-current').forEach(function(mark) {
                var parent = mark.parentNode;
                var txt = document.createTextNode(mark.textContent);
                parent.replaceChild(txt, mark);
                if (parent && touched.indexOf(parent) === -1) touched.push(parent);
            });
            // Merge the text nodes left behind so repeated searches don't fragment
            // a single text node into pieces a later TreeWalker can't match across.
            touched.forEach(function(p) { p.normalize(); });
            _bmSM.pageMatches = [];
            _bmSM.pageMatchIdx = -1;
            if (_bmSM.navBar) _bmSM.navBar.classList.remove('show');
        }

        if (_bmSM.navPrev) _bmSM.navPrev.addEventListener('click', function() { bmSmGoToHit(_bmSM.pageMatchIdx - 1); });
        if (_bmSM.navNext) _bmSM.navNext.addEventListener('click', function() { bmSmGoToHit(_bmSM.pageMatchIdx + 1); });
        if (_bmSM.navClear) _bmSM.navClear.addEventListener('click', function() { bmSmClearPageHighlights(); });

        if (_bmSM.input) {
            _bmSM.input.addEventListener('input', function() {
                clearTimeout(_bmSM.debounceTimer);
                var q = _bmSM.input.value.trim();
                if (q.length < 2) { bmSmRenderEmpty(); return; }
                _bmSM.debounceTimer = setTimeout(function() { bmSmSearch(q); }, 220);
            });

            _bmSM.input.addEventListener('keydown', function(e) {
                if (e.key === 'Escape') { bmSmClose(); return; }
                var items = _bmSM.results ? _bmSM.results.querySelectorAll('.bm-sm-result,.bm-sm-page-hit') : [];
                if (!items.length) return;
                if (e.key === 'ArrowDown') {
                    e.preventDefault();
                    _bmSM.focusIdx = (_bmSM.focusIdx + 1) % items.length;
                    items.forEach(function(el,i){ el.classList.toggle('bm-sm-focused', i === _bmSM.focusIdx); });
                    items[_bmSM.focusIdx].scrollIntoView({ block: 'nearest' });
                } else if (e.key === 'ArrowUp') {
                    e.preventDefault();
                    _bmSM.focusIdx = (_bmSM.focusIdx - 1 + items.length) % items.length;
                    items.forEach(function(el,i){ el.classList.toggle('bm-sm-focused', i === _bmSM.focusIdx); });
                    items[_bmSM.focusIdx].scrollIntoView({ block: 'nearest' });
                } else if (e.key === 'Enter' && _bmSM.focusIdx >= 0) {
                    e.preventDefault();
                    items[_bmSM.focusIdx].click();
                }
            });
        }

        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape' && _bmSM.modal && _bmSM.modal.classList.contains('bm-sm-open')) { bmSmClose(); }
        });
    }
})(); // end menuxFrontendInit

/* ═══════════════════════════════════════════════════════════════════════════
   MenuX — Accessibility Module (WCAG 2.2 AA)
   Keyboard navigation, focus management, ARIA live region, focus trap.
   Config injected via window.menuxFrontendData.a11y (see shortcode.php).
   ═══════════════════════════════════════════════════════════════════════════ */
(function menuxA11yInit() {
if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', menuxA11yInit); return; }
    var _a = (window.menuxFrontendData || {}).a11y || {};

    /* ── Master toggle: do nothing if accessibility features are disabled ─── */
    if (!_a.enabled) return;

    /* ── Helpers ─────────────────────────────────────────────────────────── */

    /** All focusable elements inside a container. */
    function getFocusable(container) {
        return Array.from(container.querySelectorAll(
            'a[href]:not([tabindex="-1"]), button:not([disabled]):not([tabindex="-1"]), [tabindex="0"]'
        ));
    }

    /** Announce text to screen readers via the live region. */
    function announce(text) {
        if (!_a.liveRegion || _a.liveRegion === 'off') return;
        var lr = document.getElementById('menux-live-region');
        if (!lr) return;
        lr.textContent = '';
        // Defer so that DOM mutation is detected as a change.
        setTimeout(function () { lr.textContent = text; }, 50);
    }

    /* ── 1. Hamburger: semantic button + dynamic aria-label ─────────────── */
    document.querySelectorAll('.menux-hamburger').forEach(function (hb) {
        // Ensure role=button even if it's a <div> (legacy markup).
        if (hb.tagName !== 'BUTTON' && !hb.getAttribute('role')) {
            hb.setAttribute('role', 'button');
        }
        if (hb.tagName !== 'BUTTON' && !hb.getAttribute('tabindex')) {
            hb.setAttribute('tabindex', '0');
        }

        // Space/Enter on non-button hamburger (backwards compat).
        hb.addEventListener('keydown', function (e) {
            if (hb.tagName !== 'BUTTON' && (e.key === 'Enter' || e.key === ' ')) {
                e.preventDefault();
                hb.click();
            }
        });

        // Dynamic aria-label: "Open menu" ↔ "Close menu".
        var openLabel  = _a.hamburgerLabelOpen  || 'Open menu';
        var closeLabel = _a.hamburgerLabelClose || 'Close menu';
        hb.setAttribute('aria-label', openLabel);

        new MutationObserver(function () {
            var isOpen = hb.classList.contains('open') ||
                         hb.getAttribute('aria-expanded') === 'true';
            hb.setAttribute('aria-label', isOpen ? closeLabel : openLabel);
        }).observe(hb, { attributes: true, attributeFilter: ['class', 'aria-expanded'] });
    });

    /* ── 2. aria-current on active link ─────────────────────────────────── */
    if (_a.ariaCurrent && _a.ariaCurrent !== 'disabled') {
        document.querySelectorAll('.menux-container a.menux-link.active').forEach(function (a) {
            if (!a.getAttribute('aria-current')) {
                a.setAttribute('aria-current', _a.ariaCurrent);
            }
        });
    }

    /* ── 3. Full keyboard navigation (WCAG 2.1.1) ───────────────────────── */
    if (_a.keyboardNav) {
        document.querySelectorAll('.menux-container').forEach(function (nav) {
            var bpMode = nav.getAttribute('data-mobile-bp-mode') || 'manual';
            var bpPx   = parseInt(nav.getAttribute('data-mobile-bp') || '768', 10);
            var menubar = nav.querySelector('ul.menux-list[role="menubar"]');
            if (!menubar) return;

            function isDesktopView() {
                return bpMode === 'auto'
                    ? !nav.classList.contains('menux-is-mobile')
                    : window.innerWidth > bpPx;
            }

            /* Collect top-level <a> links. */
            function topLinks() {
                return Array.from(menubar.querySelectorAll(':scope > li > a.menux-link'));
            }

            /* Collect submenu/mega-panel links for a given <li>. */
            function subLinks(li) {
                var container = li.querySelector('.menux-submenu, .menux-mega-panel');
                if (!container) return [];
                return Array.from(container.querySelectorAll('a[href], button:not([disabled])'));
            }

            /* ── Roving tabindex: only one top-level link in tab order at a time. ── */
            function initRovingTabindex() {
                if (_a.tabBehavior !== 'top_level_only') return;
                var links = topLinks();
                links.forEach(function (a, i) {
                    a.setAttribute('tabindex', i === 0 ? '0' : '-1');
                });
                // Remove submenu links from the natural tab order.
                menubar.querySelectorAll('.menux-submenu a, .menux-mega-panel a').forEach(function (a) {
                    a.setAttribute('tabindex', '-1');
                });
            }
            initRovingTabindex();

            function setActiveTop(link) {
                if (_a.tabBehavior !== 'top_level_only') return;
                topLinks().forEach(function (a) {
                    a.setAttribute('tabindex', a === link ? '0' : '-1');
                });
            }

            /* ── Submenu open / close via JS (keyboard) ── */
            function openSub(li, triggerLink) {
                li.classList.add('menux-open');
                if (triggerLink) triggerLink.setAttribute('aria-expanded', 'true');
                // Make sub-links focusable.
                subLinks(li).forEach(function (a) { a.setAttribute('tabindex', '0'); });
                var label = triggerLink ? (triggerLink.querySelector('.menux-label') || triggerLink).textContent.trim() : '';
                announce(label + ' expanded');
            }

            function closeSub(li, triggerLink) {
                li.classList.remove('menux-open');
                if (triggerLink) triggerLink.setAttribute('aria-expanded', 'false');
                // Release any page-builder overflow escape held by a mega panel.
                if (typeof li._menuxRestoreOverflow === 'function') li._menuxRestoreOverflow();
                // Remove sub-links from tab order if using roving tabindex.
                if (_a.tabBehavior === 'top_level_only') {
                    subLinks(li).forEach(function (a) { a.setAttribute('tabindex', '-1'); });
                }
                var label = triggerLink ? (triggerLink.querySelector('.menux-label') || triggerLink).textContent.trim() : '';
                announce(label + ' collapsed');
            }

            function closeAllSubs() {
                menubar.querySelectorAll('li.menux-has-children, li.menux-has-mega').forEach(function (li) {
                    if (li.classList.contains('menux-open')) {
                        closeSub(li, li.querySelector(':scope > a.menux-link'));
                    }
                });
            }

            /* ── Keydown handler on the entire menubar ── */
            menubar.addEventListener('keydown', function (e) {
                if (!isDesktopView()) return;

                var focused = document.activeElement;
                var allTop  = topLinks();
                var topLis  = Array.from(menubar.querySelectorAll(':scope > li'));

                // Find which top-level <li> owns the current focus.
                var activeLi   = topLis.find(function (li) { return li.contains(focused); });
                var activeTop  = activeLi ? activeLi.querySelector(':scope > a.menux-link') : null;
                var topIdx     = allTop.indexOf(activeTop);
                var isAtTop    = allTop.indexOf(focused) !== -1;
                var inSub      = activeLi && !isAtTop;

                switch (e.key) {

                    // ── Horizontal navigation at top level ──
                    case 'ArrowRight':
                        if (!isAtTop && !inSub) break;
                        e.preventDefault();
                        if (isAtTop) {
                            closeAllSubs();
                            var next = allTop[(topIdx + 1) % allTop.length];
                            setActiveTop(next);
                            next.focus();
                        } else if (inSub) {
                            // Close submenu and move to the next top-level item (WAI-ARIA pattern).
                            closeSub(activeLi, activeTop);
                            var nextTop = allTop[(topIdx + 1) % allTop.length];
                            setActiveTop(nextTop);
                            nextTop.focus();
                        }
                        break;

                    case 'ArrowLeft':
                        if (!isAtTop && !inSub) break;
                        e.preventDefault();
                        if (isAtTop) {
                            closeAllSubs();
                            var prev = allTop[(topIdx - 1 + allTop.length) % allTop.length];
                            setActiveTop(prev);
                            prev.focus();
                        } else if (inSub) {
                            // Close submenu, return to trigger.
                            closeSub(activeLi, activeTop);
                            if (activeTop) { setActiveTop(activeTop); activeTop.focus(); }
                        }
                        break;

                    // ── Open submenu / navigate down ──
                    case 'ArrowDown':
                        e.preventDefault();
                        if (isAtTop) {
                            var hasSub = activeLi && (
                                activeLi.classList.contains('menux-has-children') ||
                                activeLi.classList.contains('menux-has-mega')
                            );
                            if (hasSub) {
                                openSub(activeLi, focused);
                                var slinks = subLinks(activeLi);
                                if (slinks.length) { slinks[0].setAttribute('tabindex', '0'); slinks[0].focus(); }
                            }
                        } else if (inSub) {
                            var slinks = subLinks(activeLi);
                            var sidx   = slinks.indexOf(focused);
                            if (sidx < slinks.length - 1) slinks[sidx + 1].focus();
                        }
                        break;

                    // ── Open submenu at last item / navigate up ──
                    case 'ArrowUp':
                        e.preventDefault();
                        if (isAtTop) {
                            var hasSub = activeLi && (
                                activeLi.classList.contains('menux-has-children') ||
                                activeLi.classList.contains('menux-has-mega')
                            );
                            if (hasSub) {
                                openSub(activeLi, focused);
                                var slinks = subLinks(activeLi);
                                if (slinks.length) {
                                    var last = slinks[slinks.length - 1];
                                    last.setAttribute('tabindex', '0');
                                    last.focus();
                                }
                            }
                        } else if (inSub) {
                            var slinks = subLinks(activeLi);
                            var sidx   = slinks.indexOf(focused);
                            if (sidx > 0) {
                                slinks[sidx - 1].focus();
                            } else {
                                // First item — go back to trigger.
                                closeSub(activeLi, activeTop);
                                if (activeTop) { setActiveTop(activeTop); activeTop.focus(); }
                            }
                        }
                        break;

                    // ── Jump to first item ──
                    case 'Home':
                        if (!_a.homeEndKeys) break;
                        e.preventDefault();
                        if (isAtTop) {
                            closeAllSubs();
                            setActiveTop(allTop[0]);
                            allTop[0].focus();
                        } else if (inSub) {
                            var slinks = subLinks(activeLi);
                            if (slinks.length) slinks[0].focus();
                        }
                        break;

                    // ── Jump to last item ──
                    case 'End':
                        if (!_a.homeEndKeys) break;
                        e.preventDefault();
                        if (isAtTop) {
                            closeAllSubs();
                            var lastTop = allTop[allTop.length - 1];
                            setActiveTop(lastTop);
                            lastTop.focus();
                        } else if (inSub) {
                            var slinks = subLinks(activeLi);
                            if (slinks.length) slinks[slinks.length - 1].focus();
                        }
                        break;

                    // ── Close submenu / return to trigger ──
                    case 'Escape':
                        if (!_a.escapeCloses) break;
                        if (inSub) {
                            e.preventDefault();
                            closeSub(activeLi, activeTop);
                            if (activeTop) { setActiveTop(activeTop); activeTop.focus(); }
                        } else if (isAtTop) {
                            closeAllSubs();
                        }
                        break;

                    // ── Tab: close submenu when tabbing away ──
                    case 'Tab':
                        closeAllSubs();
                        break;
                }
            });

            // Close open submenus when focus leaves the menubar entirely.
            menubar.addEventListener('focusout', function () {
                setTimeout(function () {
                    if (!menubar.contains(document.activeElement)) {
                        closeAllSubs();
                    }
                }, 100);
            });
        });
    } // end keyboardNav

    /* ── 4. Focus trap in mobile overlay (WCAG 2.1.2) ───────────────────── */
    if (_a.focusTrapMobile) {
        document.querySelectorAll('.menux-container').forEach(function (nav) {
            var ul       = nav.querySelector('.menux-list');
            var closeBtn = document.getElementById('menux-close-btn');

            nav.addEventListener('keydown', function (e) {
                if (e.key !== 'Tab') return;
                if (!ul || !ul.classList.contains('show')) return;

                var openStyle = nav.getAttribute('data-mobile-open-style') || 'dropdown';
                if (openStyle === 'dropdown') return; // Not a modal overlay.

                // Build list of focusable elements inside the menu.
                var focusable = getFocusable(ul);
                var hb = nav.querySelector('.menux-hamburger');
                if (hb) focusable.unshift(hb);
                if (closeBtn && document.body.contains(closeBtn)) focusable.push(closeBtn);

                if (focusable.length === 0) return;

                var first = focusable[0];
                var last  = focusable[focusable.length - 1];
                var active = document.activeElement;

                if (e.shiftKey) {
                    if (active === first || !ul.contains(active)) {
                        e.preventDefault();
                        last.focus();
                    }
                } else {
                    if (active === last || (closeBtn && active === closeBtn)) {
                        e.preventDefault();
                        first.focus();
                    }
                }
            });

            // Move focus into the menu when it opens.
            var hb = nav.querySelector('.menux-hamburger');
            if (hb) {
                hb.addEventListener('click', function () {
                    var openStyle = nav.getAttribute('data-mobile-open-style') || 'dropdown';
                    if (openStyle === 'dropdown') return;
                    setTimeout(function () {
                        if (ul && ul.classList.contains('show')) {
                            var firstLink = ul.querySelector('a.menux-link, button');
                            if (firstLink) firstLink.focus();
                        }
                    }, 80);
                });
            }
        });
    } // end focusTrapMobile

    /* ── 5. Focus not obscured by sticky header (WCAG 2.4.12) ───────────── */
    if (_a.focusNotObscured) {
        document.addEventListener('focusin', function (e) {
            // Find a currently-fixed sticky nav by class so this works for both
            // shortcode- and block-rendered menus (whose IDs may be suffixed).
            var stickyNav = document.querySelector('.menux-container.menux-sticky-fixed');
            if (!stickyNav) return;
            if (stickyNav.contains(e.target)) return; // Focus is inside the nav itself.

            requestAnimationFrame(function () {
                var navBottom = stickyNav.getBoundingClientRect().bottom;
                var rect      = e.target.getBoundingClientRect();
                var margin    = 8; // px breathing room

                if (rect.top < navBottom + margin) {
                    window.scrollBy({
                        top: rect.top - navBottom - margin,
                        behavior: 'smooth'
                    });
                }
            });
        }, true);
    } // end focusNotObscured

    /* ── 6. prefers-reduced-motion: disable JS-driven animations ────────── */
    if (_a.reducedMotion) {
        var mq = window.matchMedia('(prefers-reduced-motion: reduce)');
        if (mq.matches) {
            // Override the hover delay to 0 when reduced motion is active.
            // The CSS media query already handles transition durations.
            document.querySelectorAll('.menux-container').forEach(function (nav) {
                nav.setAttribute('data-menux-reduced-motion', '1');
            });
        }
    }

    /* ── 7. Animation multiplier via CSS custom property ────────────────── */
    if (typeof _a.animMultiplier === 'number' && _a.animMultiplier !== 1) {
        document.documentElement.style.setProperty('--menux-anim-mult', _a.animMultiplier);
    }

})(); // end menuxA11yInit

/* ═══════════════════════════════════════════════════════════════════════════
   MenuX — Scroll Spy
   Highlights the nav link matching the page section currently in the viewport.
   Uses a rAF-throttled scroll listener (no constant DOM reads, no timers).

   How it works:
   - Collects every <a class="menux-link"> that points to a same-page #anchor.
   - On each scroll frame, finds the last section whose top edge has crossed
     a configurable trigger line (default: 80px + sticky-nav height from viewport
     top) and marks its link menux-spy-active.
   - Page-bottom edge case: if the user has scrolled to the very end, activates
     the last section even if its top never crossed the trigger line.
   - Trigger line auto-accounts for the sticky nav height at runtime, so the
     spy never fires a beat late when the sticky bar is covering the section.
   - Smooth-scroll on anchor click (optional, default: on) with history.pushState
     so the URL hash updates without a native jump.
   ═══════════════════════════════════════════════════════════════════════════ */
(function menuxScrollSpyInit() {
if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', menuxScrollSpyInit); return; }
    var _sd = window.menuxFrontendData || {};
    if (!_sd.spyEnabled) return;

    var spyOffset = parseInt(_sd.spyOffset || 80, 10);
    var spySmooth = !!_sd.spySmooth;

    // ── Collect anchor targets from every menux nav on the page ─────────────
    // Dedup by section id: if two navs link to the same #anchor, register once.
    var seen    = {};
    var targets = []; // [{a, section, id}]

    document.querySelectorAll('.menux-container').forEach(function(nav) {
        nav.querySelectorAll('a.menux-link').forEach(function(a) {
            var href = (a.getAttribute('href') || '').trim();
            var hash = '';

            if (href.charAt(0) === '#') {
                hash = href.slice(1);
            } else if (href.indexOf('#') !== -1) {
                try {
                    var u = new URL(href, window.location.href);
                    if (u.origin === window.location.origin &&
                        u.pathname.replace(/\/$/, '') === window.location.pathname.replace(/\/$/, '') &&
                        u.hash) {
                        hash = u.hash.slice(1);
                    }
                } catch (e) { /* malformed href — skip */ }
            }

            if (!hash || seen[hash]) return;
            var section = document.getElementById(hash);
            if (!section) return;
            seen[hash] = true;
            targets.push({ a: a, section: section, id: hash });
        });
    });

    if (targets.length === 0) return;

    // ── Sort by vertical DOM order (ascending) ───────────────────────────────
    targets.sort(function(a, b) {
        var rel = a.section.compareDocumentPosition(b.section);
        return (rel & 4) ? -1 : (rel & 2) ? 1 : 0; // 4=FOLLOWING, 2=PRECEDING
    });

    // ── State ────────────────────────────────────────────────────────────────
    var rafPending    = false;
    var currentActive = null; // reference to the active entry in targets[]

    // ── Effective trigger offset ─────────────────────────────────────────────
    // Re-read the sticky nav height on every scroll tick so the trigger line
    // automatically adjusts when the nav becomes/ceases to be sticky.
    function effectiveOffset() {
        var stickyEl = document.querySelector('.menux-container.menux-sticky-fixed');
        return spyOffset + (stickyEl ? stickyEl.offsetHeight : 0);
    }

    // ── Apply active state ────────────────────────────────────────────────────
    function setActive(newEntry) {
        if (newEntry === currentActive) return;
        currentActive = newEntry;
        targets.forEach(function(t) {
            var on = (t === newEntry);
            t.a.classList.toggle('menux-spy-active', on);
            if (on) {
                t.a.setAttribute('aria-current', 'location');
            } else {
                t.a.removeAttribute('aria-current');
            }
        });
    }

    // ── Core update function (runs inside rAF) ────────────────────────────────
    function update() {
        rafPending   = false;
        var scrollY  = window.scrollY;
        var vpH      = window.innerHeight;
        var docH     = document.documentElement.scrollHeight;
        var offset   = effectiveOffset();
        var triggerY = scrollY + offset; // absolute Y of the trigger line

        // Before the first section: clear all highlights.
        var firstAbsTop = targets[0].section.getBoundingClientRect().top + scrollY;
        if (triggerY < firstAbsTop) { setActive(null); return; }

        var newEntry = null;

        // Page-bottom edge case: the last section may never fully cross the
        // trigger line if the page is shorter than the viewport minus the offset.
        // Activating it when the user has scrolled to the bottom ensures it is
        // always reachable.
        if (scrollY + vpH >= docH - 10) {
            newEntry = targets[targets.length - 1];
        } else {
            // Walk from last to first, pick the lowest section whose absolute
            // top is at or above (≤) the trigger line.
            for (var i = targets.length - 1; i >= 0; i--) {
                var absTop = targets[i].section.getBoundingClientRect().top + scrollY;
                if (absTop <= triggerY) { newEntry = targets[i]; break; }
            }
        }

        setActive(newEntry);
    }

    // ── Scroll + resize listeners (passive, rAF-throttled) ───────────────────
    function onScroll() {
        if (!rafPending) { rafPending = true; requestAnimationFrame(update); }
    }
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll, { passive: true });
    update(); // set initial state without waiting for first scroll

    // ── Smooth-scroll on anchor click ─────────────────────────────────────────
    // Only intercepts clicks on the same-page anchors we registered above.
    // For every other link (different page, external) the default behaviour
    // is preserved.
    if (spySmooth) {
        targets.forEach(function(t) {
            t.a.addEventListener('click', function(e) {
                e.preventDefault();
                var off      = effectiveOffset();
                var absTop   = t.section.getBoundingClientRect().top + window.scrollY;
                var scrollTo = Math.max(0, absTop - off + 4); // 4px breathing room
                window.scrollTo({ top: scrollTo, behavior: 'smooth' });
                try { history.pushState(null, '', '#' + t.id); } catch (ex) {}
                // Announce to screen readers
                try {
                    var lr = document.getElementById('menux-live-region');
                    if (lr) { lr.textContent = ''; setTimeout(function(){ lr.textContent = t.section.getAttribute('aria-label') || t.id; }, 50); }
                } catch (ex2) {}
            });
        });
    }
})(); // end menuxScrollSpyInit
