<?php
/**
 * MenuX Free — Frontend Shortcode
 * Renders the [menux] shortcode on the frontend.
 * @package MenuX
 */

if ( ! defined( 'ABSPATH' ) ) exit;

add_shortcode('menux', 'menux_render_shortcode');
function menux_render_shortcode($atts = array()) {
    $atts = shortcode_atts(array(
        'location' => 'primary',   // ──── FEATURE 11: multi-menu location ────
    ), $atts, 'menux');

    $all_menu_items  = get_option('menux_menu_items', array());
    $menux_style   = get_option('menux_style', array());
    $s               = wp_parse_args($menux_style, menux_style_defaults());
    $supported_langs = menux_get_supported_languages();

    // ──── FEATURE 11: filtra per location ────
    $requested_location = sanitize_key($atts['location']);
    $menu_items = array();
    foreach ($all_menu_items as $item) {
        $item_loc = !empty($item['menu_location']) ? $item['menu_location'] : 'primary';
        if ($item_loc === $requested_location) {
            $menu_items[] = $item;
        }
    }
    // Fallback: se nessun item ha location settato, mostra tutti (retrocompatibilità)
    if (empty($menu_items) && $requested_location === 'primary') {
        $menu_items = $all_menu_items;
    }
    if (empty($menu_items)) return '';

    $is_logged_in = is_user_logged_in();
    $nav_class    = $is_logged_in ? 'menux-user-logged-in' : 'menux-user-guest';
    $is_sticky    = ($s['sticky'] === '1');

    // ──── Accessibility settings ────
    $a11y = class_exists( 'Menux_Accessibility' ) ? Menux_Accessibility::get_settings() : array();

    // ──── FEATURE 10: pre-calcola condizioni globali ────
    $current_user_roles = array();
    if ($is_logged_in) {
        $cur_user = wp_get_current_user();
        $current_user_roles = $cur_user->roles;
    }
    $current_page_id = get_queried_object_id();
    $current_hour_min = current_time('H:i');
    $current_utm = isset($_GET['utm_source']) ? sanitize_text_field( wp_unslash( $_GET['utm_source'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    $is_mobile_device = wp_is_mobile();

    // ──── FEATURE 4+10: Funzione di filtraggio item ────
    $should_show_item = function($raw) use ($is_logged_in, $current_user_roles, $current_page_id, $current_hour_min, $current_utm, $is_mobile_device) {
        // Role-based visibility
        $vis = $raw['visibility'] ?? 'all';
        if ( $vis === 'all' ) {
            // visible to everyone
        } elseif ( $vis === 'logged_in' ) {
            if ( ! $is_logged_in ) return false;
        } elseif ( $vis === 'logged_out' ) {
            if ( $is_logged_in ) return false;
        } elseif ( $vis === 'auth' ) {
            // legacy value — treat as logged_in
            if ( ! $is_logged_in ) return false;
        } elseif ( $vis === 'non-auth' ) {
            // legacy value — treat as logged_out
            if ( $is_logged_in ) return false;
        } else {
            // Specific WP role: must be logged in AND have that exact role
            if ( ! $is_logged_in ) return false;
            if ( ! in_array( $vis, (array) $current_user_roles, true ) ) return false;
        }

        // ──── FEATURE 4: Scheduled items ────
        $now = current_time('Y-m-d\TH:i');
        if (!empty($raw['schedule_start']) && $now < $raw['schedule_start']) return false;
        if (!empty($raw['schedule_end'])   && $now > $raw['schedule_end'])   return false;

        // ──── FEATURE 10: Condizionali avanzati ────
        // Ruoli utente — only applies to logged-in users; guests have no roles to match.
        if (!empty($raw['cond_roles']) && $is_logged_in) {
            $allowed_roles = array_map('trim', explode(',', $raw['cond_roles']));
            if (empty(array_intersect($current_user_roles, $allowed_roles))) return false;
        }
        // Device — wp_is_mobile() returns true for both phones and tablets, so we
        // treat mobile as matching both 'mobile' and 'tablet' in the allowed list.
        if (!empty($raw['cond_devices'])) {
            $allowed_devices = array_map('trim', explode(',', $raw['cond_devices']));
            $current_devices = $is_mobile_device ? array('mobile', 'tablet') : array('desktop');
            if (empty(array_intersect($current_devices, $allowed_devices))) return false;
        }
        // Pagina corrente
        if (!empty($raw['cond_pages'])) {
            $allowed_pages = array_map('intval', explode(',', $raw['cond_pages']));
            if (!in_array($current_page_id, $allowed_pages)) return false;
        }
        // Fascia oraria — supports midnight-crossing windows (e.g. 22:00–02:00)
        if (!empty($raw['cond_time_from']) && !empty($raw['cond_time_to'])) {
            $from = $raw['cond_time_from'];
            $to   = $raw['cond_time_to'];
            if ( $from <= $to ) {
                // Normal window: hide if outside [from, to]
                if ($current_hour_min < $from || $current_hour_min > $to) return false;
            } else {
                // Midnight-crossing: hide only if between to and from (the gap outside the window)
                if ($current_hour_min > $to && $current_hour_min < $from) return false;
            }
        }
        // UTM source
        if (!empty($raw['cond_utm'])) {
            if (strtolower($current_utm) !== strtolower($raw['cond_utm'])) return false;
        }

        return true;
    };

    // Costruisce label da un raw item, con supporto multilingua
    $get_label = function($raw) use ($supported_langs) {
        $is_page = ($raw['type'] === 'page');
        if (!empty($supported_langs)) {
            foreach ($supported_langs as $lang) {
                $key = menux_code_to_key($lang['code']);
                if (!empty($raw[$key])) return $raw[$key];
            }
        }
        if (!empty($raw['it'])) return $raw['it'];
        return $is_page ? get_the_title($raw['id'] ?? 0) : ($raw['url'] ?? '');
    };

    // Costruisce HTML <li> con supporto sottomenu ricorsivo
    $render_item_html = null;
    $render_item_html = function($raw, $depth = 0) use (&$render_item_html, $supported_langs, $get_label, $is_logged_in, $should_show_item, $current_page_id, $a11y) {
        // ──── FEATURE 4+10: check visibilità ────
        if (!$should_show_item($raw)) return '';

        $is_page  = ($raw['type'] === 'page');
        $url      = $is_page ? get_permalink($raw['id'] ?? 0) : ($raw['url'] ?? '#');
        // aria-hidden on icons (WCAG 1.1.1) — controlled by accessibility setting
        $icon_aria = ( ( $a11y['icon_aria_hidden'] ?? '1' ) === '1' ) ? ' aria-hidden="true"' : '';
        $icon     = !empty($raw['icon']) ? '<i class="'.esc_attr($raw['icon']).'"'.$icon_aria.' style="margin-right:6px;"></i>' : '';
        $target   = !empty($raw['target']) ? ' target="'.esc_attr($raw['target']).'" rel="noopener"' : '';
        if (!empty($raw['target']) && $raw['target'] === '_blank') {
            $target .= ' aria-label="'.esc_attr($get_label($raw)).' ('.esc_attr__( 'opens in new window', 'giuliomax-menu-builder' ).')"';
        }
        $vis      = $raw['visibility'] ?? 'all';
        $item_key = $raw['item_key'] ?? ($is_page ? 'page_'.($raw['id']??0) : 'c_'.md5($url));
        // Pre-filter children by visibility so we don't render a dropdown arrow
        // pointing to an empty submenu when all children are hidden.
        $raw_children = (!empty($raw['children']) && is_array($raw['children'])) ? $raw['children'] : array();
        $raw_children = array_values( array_filter( $raw_children, $should_show_item ) );
        $has_children = count($raw_children) > 0;

        $li_classes = array();
        if ($has_children) $li_classes[] = 'menux-has-children';

        // ──── FEATURE 2: Notification Dot ────
        $notif_dot_html = '';
        if (!empty($raw['notif_dot']) && $raw['notif_dot'] === '1') {
            $dot_sr_text = esc_html( $a11y['badge_sr_text'] ?? 'New notification' );
            $notif_dot_html = '<span class="menux-notif-dot" aria-hidden="true"></span>'
                            . '<span class="menux-sr-only">' . $dot_sr_text . '</span>';
            $li_classes[] = 'menux-has-notif';
        }

        // Badge
        $badge_html = '';
        if (!empty($raw['badge'])) {
            $bc  = !empty($raw['badge_color']) ? $raw['badge_color'] : '#ffffff';
            $bbg = !empty($raw['badge_bg'])    ? $raw['badge_bg']    : '#ef4444';
            $badge_html = '<span class="menux-badge" aria-hidden="true" style="color:'.esc_attr($bc).';background:'.esc_attr($bbg).';">'.esc_html($raw['badge']).'</span>';
        }

        // Labels multilingua
        $labels = array();
        if (!empty($supported_langs)) {
            foreach ($supported_langs as $lang) {
                $key   = menux_code_to_key($lang['code']);
                $short = strtolower(substr($lang['code'], 0, 2));
                $labels[$lang['code']] = !empty($raw[$key]) ? $raw[$key] : (!empty($raw[$short]) ? $raw[$short] : ($is_page ? get_the_title($raw['id']??0) : $url));
            }
        } else {
            $labels['it-IT'] = !empty($raw['it']) ? $raw['it'] : ($is_page ? get_the_title($raw['id']??0) : $url);
            $labels['en-US'] = $raw['en'] ?? $labels['it-IT'];
        }

        $lang_attrs = '';
        foreach ($labels as $code => $lbl) {
            $attr = 'data-lang-' . strtolower(str_replace('-','_',$code));
            $lang_attrs .= ' '.esc_attr($attr).'="'.esc_attr($lbl).'"';
        }
        $first_label = reset($labels);

        // Mega menu flag (first level only)
        $is_mega = ( $depth === 0 && ! empty( $raw['mega_menu'] ) && $raw['mega_menu'] === '1'
                    && ! empty( $raw['mega_columns'] ) && is_array( $raw['mega_columns'] ) );
        if ( $is_mega ) {
            $li_classes[] = 'menux-has-mega';
        }

        // aria-current on current page (WCAG 4.1.2 / best practice)
        $aria_current_attr = '';
        $aria_current_setting = $a11y['aria_current'] ?? 'page';
        if ( $aria_current_setting !== 'disabled' && ! empty( $current_page_id ) ) {
            $is_current = false;
            if ( $is_page && ! empty( $raw['id'] ) && intval( $raw['id'] ) === intval( $current_page_id ) ) {
                $is_current = true;
            }
            if ( ! $is_current && ! $is_page && ! empty( $url ) ) {
                $cp_url = get_permalink( $current_page_id );
                if ( $cp_url && rtrim( $url, '/' ) === rtrim( $cp_url, '/' ) ) {
                    $is_current = true;
                }
            }
            if ( $is_current ) {
                $aria_current_attr = ' aria-current="' . esc_attr( $aria_current_setting ) . '"';
            }
        }

        // aria-haspopup: use 'dialog' for mega menu, 'true' for standard submenus
        $haspopup_val = '';
        if ( $is_mega ) {
            $hp = $a11y['aria_haspopup_mega'] ?? 'dialog';
            $haspopup_val = ( $hp !== 'false' ) ? ' aria-haspopup="' . esc_attr( $hp ) . '" aria-expanded="false"' : '';
        } elseif ( $has_children ) {
            $haspopup_val = ' aria-haspopup="true" aria-expanded="false"';
        }

        // CTA button style — per-item colours injected as CSS custom properties.
        $cta_class = '';
        $cta_vars  = '';
        if ( ! empty( $raw['cta_style'] ) && $raw['cta_style'] === '1' ) {
            $cta_class = ' menux-cta-btn';
            $cta_bg    = ! empty( $raw['cta_bg'] )       ? sanitize_hex_color( $raw['cta_bg'] )       : '#667eea';
            $cta_color = ! empty( $raw['cta_color'] )    ? sanitize_hex_color( $raw['cta_color'] )    : '#ffffff';
            $cta_hover = ! empty( $raw['cta_hover_bg'] ) ? sanitize_hex_color( $raw['cta_hover_bg'] ) : $cta_bg;
            $cta_r     = isset( $raw['cta_border_radius'] ) ? absint( $raw['cta_border_radius'] ) : 6;
            $cta_vars  = ' style="--cta-bg:' . $cta_bg . ';--cta-color:' . $cta_color . ';--cta-hover:' . $cta_hover . ';--cta-r:' . $cta_r . 'px;"';
        }

        $out  = '<li class="'.esc_attr(implode(' ', $li_classes)).'" role="none">';
        $out .= '<a href="'.esc_url($url).'" class="menux-link'.esc_attr($cta_class).'"'.$cta_vars.$target
               .' role="menuitem"'
               .$aria_current_attr
               .$haspopup_val
               .' data-item-key="'.esc_attr($item_key).'"'
               .' data-item-label="'.esc_attr($first_label).'"'
               .' data-item-url="'.esc_attr($url).'">';
        $out .= $icon;
        $out .= '<span class="menux-label"'.$lang_attrs.' data-default="'.esc_attr($first_label).'"></span>';
        $out .= $badge_html;
        $out .= $notif_dot_html;
        $out .= '</a>';

        if ( $is_mega ) {
            // Render mega menu panel instead of standard submenu.
            $out .= Menux_MegaMenu::render_panel( $raw );
        } elseif ($has_children) {
            // Standard submenu (2° e 3° livello).
            $out .= '<ul class="menux-submenu" role="menu">';
            foreach ($raw_children as $child) {
                $out .= $render_item_html($child, $depth + 1);
            }
            $out .= '</ul>';
        }
        $out .= '</li>';
        return $out;
    };

    $lang_codes   = empty($supported_langs) ? array('it-IT','en-US') : array_column($supported_langs, 'code');
    $default_lang = !empty($lang_codes) ? $lang_codes[0] : 'it-IT';

    // Dark mode
    $dark_mode     = $s['dark_mode'] ?? 'light';
    $dm_attr       = '';
    if ($dark_mode === 'dark')  $dm_attr = ' data-bs-theme="dark" data-bm-theme="dark"';
    elseif ($dark_mode === 'light') $dm_attr = ' data-bs-theme="light"';
    // auto: no attribute, CSS media query handles it

    // Search — split into button (position-dependent) and modal (always at end)
    // Search HTML — echoed directly (not through wp_kses_post) because wp_kses_post
    // strips <input> and SVG child elements; all values here are built from sanitized PHP.
    $search_btn_html   = '';
    $search_modal_html = '';
    $search_position   = $s['search_position'] ?? 'right';
    if (!empty($s['search_enabled']) && $s['search_enabled'] === '1') {
        $search_btn_html = '<div class="menux-search-wrap">'
            . '<button type="button" class="menux-search-btn" aria-label="' . esc_attr__( 'Open search', 'giuliomax-menu-builder' ) . '" id="menux-search-open">'
            . '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>'
            . '</button>'
            . '</div>';
        $search_modal_html = '<div id="menux-search-modal" role="dialog" aria-modal="true" aria-label="' . esc_attr__( 'Search', 'giuliomax-menu-builder' ) . '">'
            . '<div id="menux-search-backdrop"></div>'
            . '<div id="menux-search-box">'
            . '  <div class="bm-sm-header">'
            . '    <span class="bm-sm-icon"><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></span>'
            . '    <input type="search" id="menux-search-input-modal" autocomplete="off" spellcheck="false">'
            . '    <button id="menux-search-close" title="' . esc_attr__( 'Close (Esc)', 'giuliomax-menu-builder' ) . '" aria-label="' . esc_attr__( 'Close search', 'giuliomax-menu-builder' ) . '">&#x2715;</button>'
            . '  </div>'
            . '  <div class="bm-sm-tabs">'
            . '    <button class="bm-sm-tab active" data-tab="menu" type="button">&#x1F517; ' . esc_html__( 'Menu', 'giuliomax-menu-builder' ) . '</button>'
            . '    <button class="bm-sm-tab" data-tab="page" type="button">&#x1F4C4; ' . esc_html__( 'In page', 'giuliomax-menu-builder' ) . '</button>'
            . '  </div>'
            . '  <div class="bm-sm-body" id="menux-search-results-modal"></div>'
            . '  <div class="bm-sm-footer">'
            . '    <span class="bm-sm-kbd"><kbd>&#x2191;</kbd><kbd>&#x2193;</kbd> ' . esc_html__( 'navigate', 'giuliomax-menu-builder' ) . '</span>'
            . '    <span class="bm-sm-kbd"><kbd>&#x21B5;</kbd> ' . esc_html__( 'open', 'giuliomax-menu-builder' ) . '</span>'
            . '    <span class="bm-sm-kbd"><kbd>Esc</kbd> ' . esc_html__( 'close', 'giuliomax-menu-builder' ) . '</span>'
            . '    <span class="bm-sm-count" id="menux-search-count"></span>'
            . '  </div>'
            . '</div>'
            . '</div>'
            . '<div id="bm-search-nav-bar">'
            . '  <span id="bm-snb-label">0 / 0</span>'
            . '  <button type="button" id="bm-snb-prev">&#x2191; ' . esc_html__( 'Previous', 'giuliomax-menu-builder' ) . '</button>'
            . '  <button type="button" id="bm-snb-next">&#x2193; ' . esc_html__( 'Next', 'giuliomax-menu-builder' ) . '</button>'
            . '  <button type="button" class="bm-snb-close" id="bm-snb-clear" aria-label="' . esc_attr__( 'Clear highlights', 'giuliomax-menu-builder' ) . '">&#x2715; ' . esc_html__( 'Close', 'giuliomax-menu-builder' ) . '</button>'
            . '</div>';
    }

    // WooCommerce cart button (empty string when the feature is off or Woo is absent).
    $woo_cart_html     = function_exists( 'menux_woo_cart_html' ) ? menux_woo_cart_html( $s ) : '';
    $woo_cart_position = in_array( $s['woo_cart_position'] ?? 'right', array( 'left', 'right' ), true ) ? $s['woo_cart_position'] : 'right';

    // Logo HTML — uses Menux_Logo for advanced multi-context rendering.
    // Falls back to legacy menux_style[logo_url] if no new logo is configured.
    $logo_settings = class_exists( 'Menux_Logo' ) ? Menux_Logo::get_settings() : array();
    $logo_position = $logo_settings['position'] ?? ( $s['logo_position'] ?? 'left' );
    $logo_html     = class_exists( 'Menux_Logo' ) ? Menux_Logo::render() : '';

    // Build separate mobile logo if configured.
    $logo_mobile_html = '';
    if ( class_exists( 'Menux_Logo' ) ) {
        $has_mobile_logo = ! empty( $logo_settings['mobile_id'] ) || ! empty( $logo_settings['mobile_url'] );
        if ( $has_mobile_logo ) {
            $logo_mobile_html = Menux_Logo::render( true );
        }
    }

    // Sticky spacer height viene calcolato via JS
    $aria_label  = ! empty( $a11y['nav_aria_label'] ) ? $a11y['nav_aria_label'] : 'Main navigation';
    $hamburger_label_open = ! empty( $a11y['hamburger_label_open'] ) ? $a11y['hamburger_label_open'] : 'Open menu';

    // ──── Variabili necessarie nell'HTML del nav ────
    $open_style = $s['mobile_open_style']      ?? 'dropdown';
    $bp_mode    = $s['mobile_breakpoint_mode'] ?? 'manual';
    $bp         = ($s['mobile_breakpoint'] !== '') ? intval($s['mobile_breakpoint']) : 768;

    // ── Announcement bar ──────────────────────────────────────────────────────
    // Page-level banner: render once per page even with multiple [menux] instances
    // (mirrors the overlay/search-modal once-per-page guard further down).
    static $menux_ann_rendered = false;
    $ann_enabled  = ! $menux_ann_rendered
                    && ! empty( $s['announcement_enabled'] ) && $s['announcement_enabled'] === '1'
                    && ! empty( $s['announcement_text'] );
    $ann_position = $s['announcement_position'] ?? 'above';
    $ann_html     = '';
    if ( $ann_enabled ) {
        $menux_ann_rendered = true;
        $ann_text       = esc_html( $s['announcement_text'] );
        $ann_link       = ! empty( $s['announcement_link'] ) ? esc_url( $s['announcement_link'] ) : '';
        $ann_target     = ( ( $s['announcement_link_target'] ?? '_self' ) === '_blank' ) ? '_blank' : '_self';
        $ann_rel        = $ann_target === '_blank' ? ' rel="noopener"' : '';
        $ann_dismissible= ! empty( $s['announcement_dismissible'] ) && $s['announcement_dismissible'] === '1';
        $ann_days       = max( 1, intval( $s['announcement_dismiss_days'] ?? 7 ) );
        $ann_version    = (string) ( abs( crc32( $s['announcement_text'] ) ) % 100000000 );
        $ann_inner      = $ann_link
            ? '<a href="' . $ann_link . '" target="' . esc_attr( $ann_target ) . '"' . $ann_rel . '>' . $ann_text . '</a>'
            : '<span>' . $ann_text . '</span>';

        // Countdown widget HTML (server-side initial values avoid a flash of 00:00:00 on load)
        $ann_cd_html = '';
        $cd_enabled  = ! empty( $s['announcement_countdown_enabled'] ) && $s['announcement_countdown_enabled'] === '1';
        $cd_date     = $s['announcement_countdown_date'] ?? '';
        if ( $cd_enabled && $cd_date !== '' ) {
            $cd_ts      = strtotime( $cd_date );
            $cd_diff    = max( 0, $cd_ts - time() );
            $cd_days    = (int) floor( $cd_diff / 86400 );
            $cd_hours   = (int) floor( ( $cd_diff % 86400 ) / 3600 );
            $cd_mins    = (int) floor( ( $cd_diff % 3600 ) / 60 );
            $cd_secs    = (int) ( $cd_diff % 60 );
            $cd_label   = esc_html( $s['announcement_countdown_label'] ?? 'Ends in:' );
            $cd_expired = esc_attr( $s['announcement_countdown_expired'] ?? '' );
            $cd_pad     = function( $n ) { return str_pad( (string) $n, 2, '0', STR_PAD_LEFT ); };
            $days_style = $cd_days === 0 ? ' style="display:none"' : '';
            $ann_cd_html = '<span class="menux-ann-countdown" data-target-ts="' . intval( $cd_ts ) . '" data-expired="' . $cd_expired . '">'
                . ( $cd_label !== '' ? '<span class="menux-ann-cd-label">' . $cd_label . '</span>' : '' )
                . '<span class="menux-ann-cd-time">'
                . '<span class="menux-ann-cd-days-wrap"' . $days_style . '>'
                .   '<span class="menux-ann-cd-seg"><span class="menux-ann-cd-num">' . $cd_pad( $cd_days )  . '</span><span class="menux-ann-cd-unit">d</span></span>'
                .   '<span class="menux-ann-cd-sep">:</span>'
                . '</span>'
                . '<span class="menux-ann-cd-seg"><span class="menux-ann-cd-num">' . $cd_pad( $cd_hours ) . '</span><span class="menux-ann-cd-unit">h</span></span>'
                . '<span class="menux-ann-cd-sep">:</span>'
                . '<span class="menux-ann-cd-seg"><span class="menux-ann-cd-num">' . $cd_pad( $cd_mins )  . '</span><span class="menux-ann-cd-unit">m</span></span>'
                . '<span class="menux-ann-cd-sep">:</span>'
                . '<span class="menux-ann-cd-seg"><span class="menux-ann-cd-num">' . $cd_pad( $cd_secs )  . '</span><span class="menux-ann-cd-unit">s</span></span>'
                . '</span>'
                . '</span>';
        }

        $ann_close = $ann_dismissible ? '<button class="menux-ann-close" aria-label="' . esc_attr__( 'Close announcement', 'giuliomax-menu-builder' ) . '">&#215;</button>' : '';
        $ann_html  = '<div class="menux-announcement-bar" data-ann-version="' . esc_attr( $ann_version ) . '" data-dismiss-days="' . $ann_days . '">' . $ann_inner . $ann_cd_html . $ann_close . '</div>';
    }

    ob_start();
    ?>
    <?php // Skip navigation link — output before the sticky spacer so it's first in DOM ?>
    <?php if ( class_exists( 'Menux_Accessibility' ) ) echo wp_kses( Menux_Accessibility::output_skip_link( $a11y ), array( 'a' => array( 'class' => true, 'href' => true ) ) ); ?>

    <?php if ($is_sticky): ?><div class="menux-sticky-spacer" id="menux-spacer" style="display:none;"></div><?php endif; ?>

    <?php
    /* ──── Overlay backdrop + close button — una sola volta per pagina ──── */
    static $menux_overlay_rendered = false;
    $needs_overlay = in_array($open_style, array('fullscreen','drawer-left','drawer-right'), true);
    if ($needs_overlay && !$menux_overlay_rendered):
        $menux_overlay_rendered = true;
    ?>
    <div class="menux-overlay" id="menux-overlay" aria-hidden="true"></div>
    <button type="button" class="menux-close-btn" id="menux-close-btn" aria-label="<?php esc_attr_e( 'Close menu', 'giuliomax-menu-builder' ); ?>">×</button>
    <?php endif; ?>

    <div class="menux-wrap">
    <?php if ( $ann_enabled && $ann_position === 'above' ) echo $ann_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
    <nav class="menux-container <?php echo esc_attr($nav_class); ?>"<?php if ($is_sticky) echo ' data-menux-sticky="1"'; ?><?php if ($dark_mode === 'dark') echo ' data-bs-theme="dark" data-bm-theme="dark"'; elseif ($dark_mode === 'light') echo ' data-bs-theme="light"'; ?> id="menux-nav-main"
         role="navigation" aria-label="<?php echo esc_attr($aria_label); ?>"
         data-mobile-open-style="<?php echo esc_attr($open_style); ?>"
         data-mobile-bp-mode="<?php echo esc_attr($bp_mode); ?>"
         data-mobile-bp="<?php echo intval($bp); ?>"<?php if ( ! empty( $s['mobile_accordion'] ) && $s['mobile_accordion'] === '1' ) echo ' data-mobile-accordion="1"'; ?>>
        <?php if (!empty($s['progress_bar_enabled']) && $s['progress_bar_enabled'] === '1'): ?>
        <div class="menux-progress-bar" id="menux-progress-bar" aria-hidden="true"></div>
        <?php endif; ?>
        <?php
        // Logo kses uses an expanded tag list to allow inline SVG elements.
        $logo_kses = class_exists( 'Menux_Logo' ) ? Menux_Logo::kses_allowed_tags() : wp_kses_allowed_html( 'post' );
        ?>
        <?php if (!empty($logo_html) && in_array($logo_position, array('left','center-split'), true)): ?>
            <?php echo wp_kses( $logo_html, $logo_kses ); ?>
            <?php echo wp_kses( $logo_mobile_html, $logo_kses ); ?>
        <?php endif; ?>
        <?php if ($search_position === 'left' && $search_btn_html): echo $search_btn_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        endif; ?>
        <?php if ($woo_cart_position === 'left' && $woo_cart_html): echo $woo_cart_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        endif; ?>
        <button type="button" class="menux-hamburger" aria-expanded="false" aria-controls="menux-list-main" aria-label="<?php echo esc_attr( $hamburger_label_open ); ?>">
            <span aria-hidden="true"></span><span aria-hidden="true"></span><span aria-hidden="true"></span>
        </button>
        <?php if (!empty($logo_html) && $logo_position === 'center'): ?>
            <div class="menux-logo-center-wrap" style="flex:1;display:flex;justify-content:center;">
                <?php echo wp_kses( $logo_html, $logo_kses ); ?>
                <?php echo wp_kses( $logo_mobile_html, $logo_kses ); ?>
            </div>
        <?php endif; ?>
        <ul class="menux-list" id="menux-list-main" role="menubar">
            <?php foreach ($menu_items as $raw): echo Menux_MegaMenu::restore_widgets( wp_kses_post( $render_item_html($raw, 0) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            endforeach; ?>
        </ul>
        <?php if (!empty($logo_html) && $logo_position === 'right'): ?>
            <?php echo wp_kses( $logo_html, $logo_kses ); ?>
            <?php echo wp_kses( $logo_mobile_html, $logo_kses ); ?>
        <?php endif; ?>
        <?php if ($search_position === 'right' && $search_btn_html): echo $search_btn_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        endif; ?>
        <?php if ($woo_cart_position === 'right' && $woo_cart_html): echo $woo_cart_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        endif; ?>
    </nav>
    <?php if ( $ann_enabled && $ann_position === 'below' ) echo $ann_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
    </div>
    <?php
    /* Search modal — rendered once per page (like the overlay). A single shared
       modal searches the whole page, so multiple menu instances reuse it. This
       prevents duplicate IDs (and dead second-instance controls) when more than
       one [menux] / giuliomax/menu block has search enabled on the same page. */
    static $menux_search_modal_rendered = false;
    if ($search_modal_html && !$menux_search_modal_rendered):
        $menux_search_modal_rendered = true;
        echo $search_modal_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    endif; ?>

    <?php // ARIA live region for screen reader announcements (WCAG 4.1.3) ?>
    <?php if ( class_exists( 'Menux_Accessibility' ) ) {
        $lr_html = Menux_Accessibility::output_live_region( $a11y );
        if ( $lr_html ) {
            echo wp_kses( $lr_html, array( 'div' => array( 'id' => true, 'class' => true, 'role' => true, 'aria-live' => true, 'aria-atomic' => true ) ) );
        }
    } ?>

    <?php
    /* Enqueue frontend script and inject dynamic config via WP APIs (no inline <script>/<style>) */
    static $menux_script_done = false;

    if ( ! $menux_script_done ) {
        wp_enqueue_script( 'menux-frontend' );
        $frontend_data = wp_json_encode( array(
            'supportedCodes' => $lang_codes,
            'defaultCode'    => $default_lang,
            'ajaxUrl'        => admin_url( 'admin-ajax.php' ),
            'trackNonce'     => wp_create_nonce( 'menux_track_nonce' ),
            'isLoggedIn'     => $is_logged_in ? 1 : 0,
            'isSticky'       => $is_sticky    ? 1 : 0,
            'searchEnabled'  => ( ! empty( $s['search_enabled'] ) && $s['search_enabled'] === '1' ),
            'spyEnabled'     => ! empty( $s['scroll_spy'] ) && $s['scroll_spy'] === '1',
            'spyOffset'      => isset( $s['scroll_spy_offset'] ) ? max( 0, intval( $s['scroll_spy_offset'] ) ) : 80,
            'spySmooth'      => ! isset( $s['scroll_spy_smooth'] ) || $s['scroll_spy_smooth'] === '1',
            'a11y'           => class_exists( 'Menux_Accessibility' ) ? Menux_Accessibility::get_js_config( $a11y ) : array(),
        ) );
        wp_add_inline_script( 'menux-frontend', 'window.menuxFrontendData = ' . $frontend_data . ';', 'before' );
        $menux_script_done = true;
    }
    ?>
    <?php
    static $menux_sc_instance = 0;
    $menux_sc_instance++;
    $html = ob_get_clean();

    // Multiple [menux] shortcodes on the same page would share structural IDs —
    // the same suffix strategy used in block.php keeps IDs unique per instance.
    if ( $menux_sc_instance > 1 ) {
        $suffix  = 'sc' . $menux_sc_instance;
        $ids     = array( 'menux-nav-main', 'menux-list-main', 'menux-spacer', 'menux-progress-bar' );
        $search  = array();
        $replace = array();
        foreach ( $ids as $id ) {
            $search[]  = 'id="' . $id . '"';
            $replace[] = 'id="' . $id . '-' . $suffix . '"';
            $search[]  = 'aria-controls="' . $id . '"';
            $replace[] = 'aria-controls="' . $id . '-' . $suffix . '"';
        }
        $html = str_replace( $search, $replace, $html );
    }

    return $html;
}
