/**
 * Fichier  : assets/js/app.js
 * Auteur   : KREMER Régis
 * Version  : 2.6.112
 * Date     : 2026-07-11
 * Description : JS — Application principale : init, routing, pagination, helpers UI
 *
 * Changelog :
 *   v2.1.0 (2026-02-21) — Version initiale auditée et sécurisée
 *   v2.1.1 (2026-02-21) — Corrections sécurité, utils.js centralisé
 *   v2.2.0 (2026-02-21) — Permissions magasins, bons de commande, rapport d'écart,
 *                      import CSV, historique prix, bon de livraison multi-lignes
 *   v2.6.25 (2026-07-09) — PLAN 1 : dispatch de la page Plans.
 *   v2.6.73 (2026-07-11) — I18N MODULES SAFE ARCHI1 : libellés thème explicites et cookie portable.
 *   v2.6.112 (2026-07-22) — Icônes et dispatch du centre de documentation.
 */
// ================================================================
// app.js — MageStock core framework
// Theme · Toasts · Modal · Icons · Slide Menu · Page dispatch
// ================================================================

// ── SVG ICON LIBRARY ──────────────────────────────────────────
const Icons = {
    home:     '<svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>',
    scan:     '<svg viewBox="0 0 24 24"><rect x="5" y="2" width="14" height="20" rx="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>',
    move:     '<svg viewBox="0 0 24 24"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/></svg>',
    box:      '<svg viewBox="0 0 24 24"><path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>',
    warehouse:'<svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>',
    check:    '<svg viewBox="0 0 24 24"><path d="M9 12l2 2 4-4"/><circle cx="12" cy="12" r="10"/></svg>',
    bell:     '<svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg>',
    barcode:  '<svg viewBox="0 0 24 24"><rect x="1" y="4" width="2" height="16"/><rect x="5" y="4" width="1" height="16"/><rect x="8" y="4" width="2" height="16"/><rect x="12" y="4" width="1" height="16"/><rect x="15" y="4" width="2" height="16"/><rect x="19" y="4" width="1" height="16"/><rect x="22" y="4" width="1" height="16"/></svg>',
    users:    '<svg viewBox="0 0 24 24"><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/></svg>',
    report:   '<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>',
    gear:     '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/></svg>',
    dots:     '<svg viewBox="0 0 24 24"><circle cx="12" cy="5" r="1.5" fill="currentColor" stroke="none"/><circle cx="12" cy="12" r="1.5" fill="currentColor" stroke="none"/><circle cx="12" cy="19" r="1.5" fill="currentColor" stroke="none"/></svg>',
    logout:   '<svg viewBox="0 0 24 24"><path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>',
    plus:     '<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>',
    minus:    '<svg viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/></svg>',
    arrows:   '<svg viewBox="0 0 24 24"><polyline points="7 16 12 21 17 16"/><line x1="12" y1="21" x2="12" y2="3"/><polyline points="17 8 12 3 7 8"/></svg>',
    search:   '<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>',
    trash:    '<svg viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2"/></svg>',
    edit:     '<svg viewBox="0 0 24 24"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>',
    toggle:   '<svg viewBox="0 0 24 24"><circle cx="17" cy="12" r="5"/><path d="M7 12h10"/><circle cx="7" cy="12" r="5" fill="none"/></svg>',
    ok:       '<svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>',
    warn:     '<svg viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
    info:     '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
    err:      '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',
    img:      '<svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>',
    cam:      '<svg viewBox="0 0 24 24"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg>',
    tag:      '<svg viewBox="0 0 24 24"><path d="M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>',
    pin:      '<svg viewBox="0 0 24 24"><path d="M21 10c0 7-9 13-9 13S3 17 3 10a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>',
    chart:    '<svg viewBox="0 0 24 24"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>',
    clipboard:'<svg viewBox="0 0 24 24"><path d="M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2"/><rect x="8" y="2" width="8" height="4" rx="1" ry="1"/><line x1="9" y1="12" x2="15" y2="12"/><line x1="9" y1="16" x2="13" y2="16"/></svg>',
    help:     '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
    book:     '<svg viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 016.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z"/></svg>',
    list:     '<svg viewBox="0 0 24 24"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>',
    print:    '<svg viewBox="0 0 24 24"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 01-2-2v-5a2 2 0 012-2h16a2 2 0 012 2v5a2 2 0 01-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg>',
    download: '<svg viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>',
};

// ── RENDER ICONS into [data-icon] elements ──
function renderIcons(root){
    (root||document).querySelectorAll('[data-icon]').forEach(el=>{
        if(!el.innerHTML && Icons[el.dataset.icon])
            el.innerHTML = Icons[el.dataset.icon];
    });
}

// ================================================================
// TOAST SYSTEM
// ================================================================
let _toastId = 0;
function toast(msg, type='info', duration=3000){
    const wrap = document.getElementById('toastWrap');
    const id = ++_toastId;

    // ── Détection message blocage stock → overlay alerte grand format ──
    if(type === 'error' && typeof msg === 'string' && msg.includes('Stock') && msg.includes('Réservé')){
        _showStockBlockAlert(msg);
        return id;
    }

    const iconMap = {success:'ok', error:'err', info:'info', warning:'warn'};
    const t = document.createElement('div');
    t.className = 'toast';
    t.setAttribute('data-type', type);
    t.id = 'toast-'+id;
    t.innerHTML = `<div class="toast-icon">${Icons[iconMap[type]]||Icons.info}</div>
        <div class="toast-text"><strong>${msg}</strong></div>`;
    wrap.appendChild(t);
    setTimeout(()=>{
        t.classList.add('exit');
        setTimeout(()=>t.remove(),250);
    }, duration);
    return id;
}

/** Overlay plein format pour blocage stock/réservation */
function _showStockBlockAlert(msg){
    // Parse les chiffres du message serveur
    const num = (label) => { const m = msg.match(new RegExp(label + '\\s*:\\s*(\\d+)')); return m ? parseInt(m[1]) : 0; };
    const physical  = num('Stock physique');
    const reserved  = num('Réservé');
    const available = num('Disponible');
    const requested = num('Demandé');

    // Remove previous if any
    document.getElementById('stockBlockAlert')?.remove();

    const overlay = document.createElement('div');
    overlay.id = 'stockBlockAlert';
    overlay.className = 'sba-overlay';
    overlay.innerHTML = `
        <div class="sba-card">
            <div class="sba-icon-row">
                <div class="sba-icon">
                    <svg viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
                </div>
            </div>
            <h2 class="sba-title">Sortie de stock bloquée</h2>
            <p class="sba-desc">Des produits sont réservés sur ce stock. La quantité demandée dépasse le stock disponible.</p>
            <div class="sba-grid">
                <div class="sba-item">
                    <div class="sba-val">${physical}</div>
                    <div class="sba-label">Stock physique</div>
                </div>
                <div class="sba-item sba-orange">
                    <div class="sba-val">${reserved}</div>
                    <div class="sba-label">Réservé</div>
                </div>
                <div class="sba-item sba-green">
                    <div class="sba-val">${available}</div>
                    <div class="sba-label">Disponible</div>
                </div>
                <div class="sba-item sba-red">
                    <div class="sba-val">${requested}</div>
                    <div class="sba-label">Demandé</div>
                </div>
            </div>
            <p class="sba-hint">Vous pouvez sortir <strong>${available} unité${available !== 1 ? 's' : ''}</strong> maximum, ou annuler/modifier les réservations depuis la page Réservations.</p>
            <button class="sba-btn" onclick="document.getElementById('stockBlockAlert')?.remove()">Compris</button>
        </div>`;
    document.body.appendChild(overlay);
    // Focus le bouton pour accessibilité
    setTimeout(()=> overlay.querySelector('.sba-btn')?.focus(), 100);
    // Close on backdrop click
    overlay.addEventListener('click', (e) => { if(e.target === overlay) overlay.remove(); });
    // Close on Escape
    const onEsc = (e) => { if(e.key === 'Escape'){ overlay.remove(); document.removeEventListener('keydown', onEsc); }};
    document.addEventListener('keydown', onEsc);
}

// ================================================================
// MODAL SYSTEM
// ================================================================
const Modal = {
    show(title, bodyHtml, footerBtns=[], iconType='info'){
        // Compat: accepte aussi une signature objet {title, sub, html, footerBtns/buttons, icon/iconType}
        let subText = '';
        if(title && typeof title === 'object'){
            const o = title;
            title = o.title || '';
            subText = o.sub || '';
            bodyHtml = (o.html ?? o.bodyHtml ?? o.body ?? '');
            footerBtns = (o.footerBtns ?? o.buttons ?? []);
            const icon = (o.iconType || o.icon);
            if(icon){
                const map = {check:'success', ok:'success', success:'success', warn:'warning', warning:'warning', error:'error', info:'info'};
                iconType = map[String(icon)] || String(icon);
            }
        }
        const ov = document.getElementById('modalOverlay');
        const iconMap = {info:'info', success:'ok', warning:'warn', error:'err'};
        document.getElementById('modalIcon').innerHTML = Icons[iconMap[iconType]]||Icons.info;
        document.getElementById('modalIcon').parentElement.style.background = 'var(--'+iconType+'-pale)';
        document.getElementById('modalIcon').querySelector('svg').style.stroke = 'var(--'+iconType+')';
        document.getElementById('modalTitle').textContent = title;
        document.getElementById('modalSub').textContent = subText || '';
        document.getElementById('modalBody').innerHTML = bodyHtml;
        const footer = document.getElementById('modalFooter');
        footer.innerHTML = '';
        footerBtns.forEach(b=>{
            const btn = document.createElement('button');
            btn.className = 'btn '+(b.cls||'btn-secondary');
            btn.textContent = b.label;
            btn.onclick = b.onclick;
            footer.appendChild(btn);
        });
        ov.classList.add('visible');
        // Focus first input if any, unless the modal content explicitly disables autofocus.
        // Important for mobile/tablet scanner modals: focusing a text input opens the keyboard
        // and can resize/interrupt the camera preview while Html5Qrcode starts.
        setTimeout(()=>{
            const noAutoFocus = ov.querySelector('[data-modal-no-autofocus="1"], [data-no-autofocus="1"]');
            if (noAutoFocus) return;
            const inp=ov.querySelector('input:not([type=hidden])');
            if(inp)inp.focus();
        },180);
    },
    close(){
        document.getElementById('modalOverlay').classList.remove('visible');
    }
};

// Alias compat (anciennes pages)
Modal.open = (...args)=> Modal.show(...args);
window.Modal = Modal;

// ================================================================
// MAIN APP OBJECT
// ================================================================
const App = {
    init(){
        // ── Theme ──
        this.initTheme();
        // ── Render all [data-icon] on page ──
        renderIcons();
        // ── Modal close handlers ──
        document.getElementById('modalCloseBtn').onclick = () => Modal.close();
        document.getElementById('modalOverlay').addEventListener('click', (e)=>{ if(e.target===document.getElementById('modalOverlay')) Modal.close(); });
        // ── Slide menu ──
        this.initSlideMenu();
        // ── Sidebar collapse (desktop) ──
        // IMPORTANT: initSidebarCollapse est exposée via window.initSidebarCollapse (scope IIFE)
        // et doit fonctionner même si le script est chargé après DOMContentLoaded.
        if (typeof window.initSidebarCollapse === 'function') {
            window.initSidebarCollapse();
        }
// ── Print overlay close ──
        document.getElementById('btnClosePrint').onclick = ()=>{ document.getElementById('printOverlay').style.display='none'; };
        // ── Dispatch page module ──
        this.dispatchPage();
    },

    // ── THEME TOGGLE ────────────────────────────────────────
    initTheme(){
        const btn = document.getElementById('btnTheme');
        if(!btn) return;
        const cookiePath = (window.MageStockRuntime && window.MageStockRuntime.cookiePath) || '/';
        const updateLabel = (theme)=>{
            const key = theme === 'light' ? 'shell.theme.dark' : 'shell.theme.light';
            const fallback = theme === 'light' ? 'Passer en thème sombre' : 'Passer en thème clair';
            const label = typeof window.t === 'function' ? window.t(key, {}, fallback) : fallback;
            btn.title = label;
            btn.setAttribute('aria-label', label);
        };
        const currentTheme = document.documentElement.getAttribute('data-theme') || 'dark';
        updateLabel(currentTheme);
        btn.onclick = ()=>{
            const html = document.documentElement;
            const current = html.getAttribute('data-theme') || 'dark';
            const next = current === 'dark' ? 'light' : 'dark';
            html.setAttribute('data-theme', next);
            document.cookie = 'sm_theme=' + next + ';path=' + cookiePath + ';max-age=31536000;SameSite=Lax';
            const metaTheme = document.getElementById('metaThemeColor');
            if(metaTheme) metaTheme.content = next === 'dark' ? '#080c14' : '#f0f2f5';
            updateLabel(next);
        };
    },

    // ── SLIDE MENU ──────────────────────────────────────────
    initSlideMenu(){
        const backdrop  = document.getElementById('slideBackdrop');
        const menu      = document.getElementById('slideMenu');
        const btnMore   = document.getElementById('btnBnavMore');
        const btnHam    = document.getElementById('btnHamburger');
        const btnClose  = document.getElementById('btnSlideClose');

        const open  = ()=>{ backdrop.classList.add('active'); menu.classList.add('open'); };
        const close = ()=>{ backdrop.classList.remove('active'); menu.classList.remove('open'); };

        if(btnMore) btnMore.onclick = open;
        if(btnHam)  btnHam.onclick  = open;
        backdrop.onclick = close;
        btnClose.onclick = close;
    },

    // ── PAGE DISPATCH ───────────────────────────────────────
    dispatchPage(){
        const page = window.SM_PAGE;
        if (document.body) document.body.dataset.page = page || '';
        const modules = {
            dashboard:  ()=> typeof DashPage!=='undefined' && DashPage.init(),
            products:   ()=> typeof ProdPage!=='undefined' && ProdPage.init(),
            warehouses: ()=> typeof WarehousesPage!=='undefined' && WarehousesPage.init(),
            movements:  ()=> typeof MvPage!=='undefined'   && MvPage.init(),
            inventory:  ()=> typeof InvPage!=='undefined'  && InvPage.init(),
            scanner:    ()=> typeof ScanPage!=='undefined' && ScanPage.init(),
            barcodes:   ()=> typeof BcPage!=='undefined'   && BcPage.init(),
            reports:    ()=> typeof ReportPage!=='undefined'  && ReportPage.init(),
            settings:   ()=> typeof SetPage!=='undefined' && SetPage.init(),
            users:      ()=> typeof UsrPage!=='undefined' && UsrPage.init(),
            alerts:     ()=> typeof AltPage!=='undefined' && AltPage.init(),
            suppliers:  ()=> typeof SupplierPage!=='undefined' && SupplierPage.init(),
            brands:     ()=> typeof BrandPage!=='undefined' && BrandPage.init(),
            orders:     ()=> typeof OrdersPage!=='undefined' && OrdersPage.init(),
            locations:  ()=> typeof LocationsPage!=='undefined' && LocationsPage.init(),
            plans:      ()=> typeof PlansPage!=='undefined' && PlansPage.init(),
            'plans-edit':()=> typeof PlansPage!=='undefined' && PlansPage.init(),
            lots:       ()=> typeof LotsPage!=='undefined' && LotsPage.init(),
            analytics:  ()=> typeof AnalyticsPage!=='undefined' && AnalyticsPage.init(),
            kits:       ()=> { /* kits.js est auto-bind */ },
            reservations: ()=> { /* reservations.js est auto-bind */ },
        };
        if(modules[page]) modules[page]();
    }
};

// ── Exported helpers (used by page modules) ──
window.toast       = toast;
window.Modal       = Modal;
window.Icons       = Icons;
window.renderIcons = renderIcons;

// ── DEMANDE #1: Global movement modal with prefill ──
window.openMovementModal = function(type, productId = null, warehouseId = null) {
    // Navigate to movements page and open modal with prefill
    if(window.SM_PAGE !== 'movements') {
        // Store context in sessionStorage
        sessionStorage.setItem('mvModalType', type);
        if(productId) sessionStorage.setItem('mvModalProduct', productId);
        if(warehouseId) sessionStorage.setItem('mvModalWarehouse', warehouseId);
        // URL propre (fallback géré côté .htaccess)
        window.location.href = 'movements';
    } else {
        // Already on movements page - open directly
        if(typeof MvPage !== 'undefined' && MvPage.openMvModal) {
            MvPage.openMvModal(type, productId, warehouseId);
        }
    }
};


/* === ScrollTop + Progress Ring (global) === */
(function(){
  function qs(id){ return document.getElementById(id); }

  function initScrollTop(){
    var btn = qs('scrollTopBtn');
    if(!btn) return;

    var ring = btn.querySelector('.scrolltop__ring-fg');
    var circumference = 2 * Math.PI * 18; // r=18 => ~113.097

    function update(){
      var doc = document.documentElement;
      var scrollTop = window.pageYOffset || doc.scrollTop || 0;
      var scrollHeight = doc.scrollHeight || 0;
      var clientHeight = doc.clientHeight || 0;
      var max = Math.max(1, scrollHeight - clientHeight);
      var progress = Math.min(1, Math.max(0, scrollTop / max));

      // show/hide
      if(scrollTop > 160) btn.classList.add('is-visible');
      else btn.classList.remove('is-visible');

      // ring
      if(ring){
        var offset = circumference * (1 - progress);
        ring.style.strokeDasharray = String(circumference);
        ring.style.strokeDashoffset = String(offset);
      }
    }

    window.addEventListener('scroll', update, { passive:true });
    window.addEventListener('resize', update);
    btn.addEventListener('click', function(){
      window.scrollTo({ top: 0, behavior: 'smooth' });
    });

    update();
  }

  
  // ── SIDEBAR COLLAPSE (desktop) ───────────────────────────────
  function initSidebarCollapse(){
    const sidebar = document.getElementById('sidebar');
    const iconToggle = document.getElementById('sidebarToggle')
      || document.querySelector('.sidebar .logo-icon');
    const logoToggle = document.querySelector('.sidebar .sidebar-logo');
    if(!sidebar || !iconToggle) return;

    // Anti-régression :
    // - une seule initialisation autorisée
    // - évite les doubles listeners (App.init + DOMContentLoaded en bas du fichier)
    if(sidebar.dataset.sidebarCollapseInit === '1') return;
    sidebar.dataset.sidebarCollapseInit = '1';

    const KEY = 'sm_sidebar_collapsed';

    const applyState = (collapsed)=>{
      const isCollapsed = !!collapsed;
      sidebar.classList.toggle('is-collapsed', isCollapsed);
      sidebar.setAttribute('data-collapsed', isCollapsed ? '1' : '0');
      iconToggle.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');
      iconToggle.setAttribute('aria-pressed', isCollapsed ? 'true' : 'false');
      iconToggle.setAttribute('title', isCollapsed ? 'Ouvrir le menu' : 'Fermer le menu');
      if(logoToggle){
        logoToggle.setAttribute('title', isCollapsed ? 'Ouvrir le menu' : 'Fermer le menu');
      }
    };

    let restoredCollapsed = false;
    try {
      restoredCollapsed = localStorage.getItem(KEY) === '1';
    } catch(e){}
    applyState(restoredCollapsed);

    const doToggle = ()=>{
      const next = !sidebar.classList.contains('is-collapsed');
      applyState(next);
      try {
        localStorage.setItem(KEY, next ? '1' : '0');
      } catch(e){}
    };

    const handleToggleClick = (e)=>{
      if(e && typeof e.preventDefault === 'function') e.preventDefault();
      if(e && typeof e.stopPropagation === 'function') e.stopPropagation();
      doToggle();
    };

    // Toggle principal : icône/logo
    iconToggle.addEventListener('click', handleToggleClick);

    // Zone logo complète cliquable pour fiabiliser l'UX desktop
    if(logoToggle && logoToggle !== iconToggle){
      logoToggle.addEventListener('click', (e)=>{
        if(e.target && e.target.closest && e.target.closest('a, button, input, select, textarea')) return;
        handleToggleClick(e);
      });
    }

    // Accessibilité clavier
    const handleToggleKeydown = (e)=>{
      if(e.key === 'Enter' || e.key === ' '){
        e.preventDefault();
        doToggle();
      }
    };
    iconToggle.addEventListener('keydown', handleToggleKeydown);
    if(logoToggle && logoToggle !== iconToggle){
      logoToggle.setAttribute('role', 'button');
      logoToggle.setAttribute('tabindex', '0');
      logoToggle.addEventListener('keydown', handleToggleKeydown);
    }

    // Si l'image capte le clic, on sécurise aussi sans double-bascule
    const img = iconToggle.querySelector && iconToggle.querySelector('img');
    if(img){
      img.addEventListener('click', (e)=>{
        if(e && typeof e.preventDefault === 'function') e.preventDefault();
        if(e && typeof e.stopPropagation === 'function') e.stopPropagation();
        doToggle();
      });
    }
  }

  // Expose global (utilisé par App.init) sans casser le scope actuel
  window.initSidebarCollapse = initSidebarCollapse;

  // ── Lang Picker (dropdown header) ─────────────────────────────
  function initLangPicker(){
    const btn   = document.getElementById('langPickerBtn');
    const flagEl = document.getElementById('langFlag');
    if(!btn) return;

    const I18N      = window.I18N || {};
    const FLAGS     = I18N.FLAGS     || {};
    const NAMES     = I18N.NAMES     || {};
    const SUPPORTED = I18N.SUPPORTED || ['fr','en'];

    // Créer le dropdown directement dans <body> pour échapper
    // à tout stacking context (transform, will-change, etc.)
    const dropdown = document.createElement('div');
    dropdown.id = 'langPickerDropdown';
    dropdown.className = 'lang-picker-dropdown';
    document.body.appendChild(dropdown);

    // Supprimer l'ancien placeholder dans le header s'il existe
    const old = document.querySelector('.lang-picker .lang-picker-dropdown');
    if(old) old.remove();

    function positionDropdown(){
      const rect = btn.getBoundingClientRect();
      dropdown.style.top   = (rect.bottom + 6) + 'px';
      const isRtl = document.documentElement.dir === 'rtl';
      if(isRtl){
        dropdown.style.left = Math.max(8, rect.left) + 'px';
        dropdown.style.right = 'auto';
      } else {
        const rightFromEdge = window.innerWidth - rect.right;
        dropdown.style.right = Math.max(8, rightFromEdge) + 'px';
        dropdown.style.left = 'auto';
      }
    }

    function buildDropdown(){
      const cur = window.SM_LANG || 'fr';
      dropdown.innerHTML = SUPPORTED.map(lang => `
        <button class="lang-option${lang===cur?' active':''}" data-lang="${lang}">
          <span class="lang-option-flag">${FLAGS[lang]||'🌐'}</span>
          <span class="lang-option-name">${NAMES[lang]||lang}</span>
          ${lang===cur ? '<span class="lang-option-check">✓</span>' : ''}
        </button>
      `).join('');
    }

    function openPicker(){
      buildDropdown();
      positionDropdown();
      dropdown.classList.add('open');
      setTimeout(()=>{
        document.addEventListener('click', closePicker, {once:true});
      }, 0);
    }

    function closePicker(){
      dropdown.classList.remove('open');
    }

    btn.addEventListener('click', (e)=>{
      e.stopPropagation();
      dropdown.classList.contains('open') ? closePicker() : openPicker();
    });

    dropdown.addEventListener('click', (e)=>{
      const opt = e.target.closest('[data-lang]');
      if(!opt) return;
      const lang = opt.dataset.lang;
      closePicker();
      if(lang === window.SM_LANG) return;
      if(flagEl) flagEl.textContent = FLAGS[lang] || '🌐';
      window.setLang(lang).catch(()=>{});
    });

    // Flag initial
    if(window._i18nReady){
      window._i18nReady.then(()=>{
        if(flagEl) flagEl.textContent = FLAGS[window.SM_LANG] || '🌐';
      });
    }
  }

  if(document.readyState === 'loading'){
    document.addEventListener('DOMContentLoaded', function(){
      initScrollTop();
      initSidebarCollapse();
      initLangPicker();
    });
  } else {
    initScrollTop();
    initSidebarCollapse();
    initLangPicker();
  }
})();
