Mudanças entre as edições de "Widget:C.Skills"

De Wiki Gla
Ir para navegação Ir para pesquisar
m (rft otimizado)
m
 
(38 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
<!-- WEAPON TOGGLE SYSTEM - Estado global + popup i18n -->
<!-- MAIN SKILLS SYSTEM -->
<script>
<script>
     (() => {
     (function () {
         let modalListenersBound = false;
        const $ = (s, root = document) => root.querySelector(s);
        const $$ = (s, root = document) => Array.from(root.querySelectorAll(s));
        const ensureRemoved = sel => {
            Array.from(document.querySelectorAll(sel)).forEach(n => n.remove());
        };
        const onceFlag = (el, key) => {
            if (!el) return false;
            if (el.dataset[key]) return false;
            el.dataset[key] = '1';
            return true;
        };
        const addOnce = (el, ev, fn, options = {}) => {
            if (!el) return;
            const attr = `data-wired-${ev}`;
            if (el.hasAttribute(attr)) return;
            el.addEventListener(ev, fn, options);
            el.setAttribute(attr, '1');
        };
        const FLAG_ICON_FILES = {
            aggro: 'Enemyaggro-icon.png', bridge: 'Bridgemaker-icon.png', wall: 'Destroywall-icon.png', quickcast: 'Quickcast-icon.png', wallpass: 'Passthroughwall-icon.png'
        };
        const subBarTemplateCache = window.__skillSubBarTemplateCache || (window.__skillSubBarTemplateCache = new Map());
        const imagePreloadCache = window.__skillImagePreloadCache || (window.__skillImagePreloadCache = new Map());
        const videoPreloadCache = window.__skillVideoPreloadCache || (window.__skillVideoPreloadCache = new Set());
        const flagRowCache = window.__skillFlagRowCache || (window.__skillFlagRowCache = new Map());
        const flagIconURLCache = window.__skillFlagIconURLCache || (window.__skillFlagIconURLCache = new Map());
 
        // Sistema de múltiplas formas (genérico)
        let currentForm = null; // null = primeira forma, depois nome da forma atual
         let formsData = {};
        let fixedSkills = []; // Skills que sempre aparecem (Change Form, Guard Point, etc.)


         // Variável global para o ícone do weapon toggle
         function showFormTransitionVideo(changeFormIconEl) {
        let globalWeaponToggleIcon = null;
            const skillsRoot = document.getElementById('skills');
            if (!skillsRoot) return;


        // Função helper para construir URL de arquivo (mesmo sistema usado em Character.Skills.html)
            // Busca videoBox
        function filePathURL(fileName) {
            let videoBox = skillsRoot.querySelector('.video-container');
            // Evita requisições para Nada.png que não existe
            if (!videoBox) {
            if (!fileName || fileName.trim() === '' || fileName === 'Nada.png' || fileName.toLowerCase() === 'nada.png') {
                const skillsContainer = skillsRoot.querySelector('.skills-container');
                 return '';
                if (skillsContainer) {
                    videoBox = skillsContainer.querySelector('.video-container');
                 }
             }
             }
             // Remove prefixos e decodifica se já estiver codificado (evita double encoding)
             if (!videoBox) return;
            let cleanName = fileName.replace(/^Arquivo:|^File:/, '');
 
             try {
             try {
                 // Tenta decodificar primeiro (caso já venha codificado como %27)
                 // Lê dados de forms para determinar forma atual e próxima
                cleanName = decodeURIComponent(cleanName);
                const formsJSON = skillsRoot.dataset.forms || '{}';
                if (formsJSON && formsJSON !== '{}') {
                    const tempFormsData = JSON.parse(formsJSON);
                    const formNames = Object.keys(tempFormsData);
 
                    // Determina forma atual e próxima
                    const currentIdx = currentForm ? formNames.indexOf(currentForm) : -1;
                    const nextIdx = (currentIdx + 1) % formNames.length;
                    const nextForm = formNames[nextIdx];
 
                    // Busca vídeo de transição na skill Change Form
                    // form_videos[forma_atual] = "video.mp4" (vídeo da transição atual → próxima)
                    const formVideosRaw = changeFormIconEl.dataset.formVideos || changeFormIconEl.getAttribute('data-form-videos');
                    if (formVideosRaw) {
                        try {
                            const videos = JSON.parse(formVideosRaw);
                            const transitionVideo = videos[currentForm] || '';
 
                            if (transitionVideo && transitionVideo.trim() !== '') {
                                const videoURL = filePathURL(transitionVideo);
                                if (videoURL) {
                                    // Busca ou cria elemento de vídeo para esta transição
                                    const videoKey = `form_transition:${currentForm}:${nextForm}`;
                                    let v = videosCache.get(videoKey);
 
                                    if (!v) {
                                        // Cria novo elemento de vídeo
                                        v = document.createElement('video');
                                        v.className = 'skill-video';
                                        v.src = videoURL;
                                        v.preload = 'auto';
                                        v.controls = false;
                                        v.muted = false;
                                        v.loop = false;
                                        v.playsInline = true;
                                        videoBox.appendChild(v);
                                        videosCache.set(videoKey, v);
                                    }
 
                                    // Mostra e reproduz o vídeo
                                    Array.from(videoBox.querySelectorAll('video.skill-video')).forEach(vid => {
                                        try {
                                            vid.pause();
                                        } catch (e) {
                                        }
                                        vid.style.display = 'none';
                                    });
 
                                    videoBox.style.display = 'block';
                                    v.style.display = 'block';
                                    try {
                                        v.currentTime = 0;
                                        v.play().catch(() => { });
                                    } catch (e) {
                                    }
                                }
                            }
                        } catch (e) {
                            console.error('[Forms] Erro ao parsear form_videos:', e);
                        }
                    }
                }
             } catch (e) {
             } catch (e) {
                 // Se falhar, usa o nome original
                 console.error('[Forms] Erro ao processar vídeo de transição:', e);
             }
             }
            // Agora codifica corretamente
        }
             const f = encodeURIComponent(cleanName);
 
             const base = (window.mw && mw.util && typeof mw.util.wikiScript === 'function') ? mw.util.wikiScript() : (window.mw && window.mw.config ? (mw.config.get('wgScript') || '/index.php') : '/index.php');
        // Detecta qual forma está atualmente visível no DOM
             // Garante HTTPS para evitar Mixed Content
        function detectCurrentForm() {
             let url = `${base}?title=Especial:FilePath/${f}`;
             const iconBar = document.querySelector('.icon-bar');
            if (window.location.protocol === 'https:' && url.startsWith('http://')) {
             if (!iconBar || !formsData || Object.keys(formsData).length === 0) return null;
                url = url.replace('http://', 'https://');
 
            // Coleta todas as skills de form que estão visíveis no DOM
            const allFormSkillNames = new Set();
            Object.values(formsData).forEach(form => {
                if (form.order && Array.isArray(form.order)) {
                    form.order.forEach(skillName => allFormSkillNames.add(skillName));
                }
            });
 
            const visibleFormSkillNames = new Set();
            Array.from(iconBar.querySelectorAll('.skill-icon[data-index]')).forEach(icon => {
                const name = (icon.dataset.nome || '').trim();
                if (name && allFormSkillNames.has(name)) {
                    visibleFormSkillNames.add(name);
                }
            });
 
             // Compara com cada forma para ver qual corresponde
             for (const [formName, formData] of Object.entries(formsData)) {
                if (formData.order && Array.isArray(formData.order)) {
                    const formSkillSet = new Set(formData.order);
                    // Verifica se todas as skills desta forma estão visíveis
                    let allMatch = true;
                    for (const skillName of formData.order) {
                        if (!visibleFormSkillNames.has(skillName)) {
                            allMatch = false;
                            break;
                        }
                    }
                    if (allMatch && formData.order.length === visibleFormSkillNames.size) {
                        return formName;
                    }
                }
             }
             }
             return url;
 
             return null;
         }
         }


        // Função para resolver o ícone do weapon toggle do character-box
         function switchForm() {
         function resolveCharacterWeaponIcon() {
             const skillsRoot = document.getElementById('skills');
             const root = document.querySelector('.character-box');
             if (!skillsRoot) return;
             if (!root) return;
 
             const raw = root.dataset.weaponicon;
            // Lê dados de forms do atributo data-forms
            if (!raw || raw.trim() === '' || raw === 'Nada.png') {
             try {
                 globalWeaponToggleIcon = null;
                const formsJSON = skillsRoot.dataset.forms || '{}';
                if (formsJSON && formsJSON !== '{}') {
                    formsData = JSON.parse(formsJSON);
                }
            } catch (e) {
                 console.error('[Forms] Erro ao parsear forms:', e);
                 return;
                 return;
             }
             }
            globalWeaponToggleIcon = filePathURL(raw.trim());
            // console.log('[WeaponToggle] Resolved weaponicon:', raw, '->', globalWeaponToggleIcon);
        }


        // Textos i18n para o popup
            if (!formsData || Object.keys(formsData).length === 0) {
        const i18nTexts = {
                return; // Não tem forms, não faz nada
             pt: {
            }
                title: 'Visualização com Arma Especial',
 
                body1: 'Este modo ativa a visualização do personagem equipado com sua <strong>arma especial</strong>.',
            // Identifica skills fixas (sempre presentes)
                 body2: 'Algumas habilidades são diferentes enquanto estão com a arma equipada, essas habilidades ficam <strong>destacadas com borda vermelha</strong>.',
            const iconBar = document.querySelector('.icon-bar');
                dontShow: 'Não mostrar novamente',
             if (!iconBar) return;
                ok: 'Entendi',
 
                 weaponLink: 'Ver página da arma:'
            // Busca a skill com form_switch dinamicamente (genérico)
             },
            const changeFormIcon = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'))
             en: {
                 .find(icon => icon.dataset.formSwitch === 'true' || icon.getAttribute('data-form-switch') === 'true');
                 title: 'Special Weapon View',
            if (changeFormIcon) {
                body1: 'This mode activates the view of the character equipped with their <strong>special weapon</strong>.',
                 changeFormIcon.classList.add('active');
                body2: 'Some abilities are different while equipped with the weapon, these abilities are <strong>highlighted with a red border</strong>.',
             }
                 dontShow: "Don't show again",
 
                ok: 'Got it',
             // Determina skills fixas dinamicamente: todas que não estão em nenhuma forms
                weaponLink: 'View weapon page:'
            const allFormSkillNames = new Set();
             },
            Object.values(formsData).forEach(form => {
             es: {
                 if (form.order && Array.isArray(form.order)) {
                title: 'Visualización con Arma Especial',
                    form.order.forEach(skillName => allFormSkillNames.add(skillName));
                 body1: 'Este modo activa la visualización del personaje equipado con su <strong>arma especial</strong>.',
                 }
                body2: 'Algunas habilidades son diferentes mientras están con el arma equipada, estas habilidades quedan <strong>destacadas con borde rojo</strong>.',
            });
                 dontShow: 'No mostrar de nuevo',
 
                 ok: 'Entendido',
             // Skills fixas = todas as skills na barra que não estão em nenhuma forms
                weaponLink: 'Ver página del arma:'
             fixedSkills = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'))
             },
                 .filter(icon => {
             pl: {
                    const name = (icon.dataset.nome || '').trim();
                title: 'Widok z Bronią Specjalną',
                    return name && !allFormSkillNames.has(name);
                body1: 'Ten tryb aktywuje widok postaci wyposażonej w <strong>broń specjalną</strong>.',
                 })
                body2: 'Niektóre umiejętności różnią się podczas posiadania broni, te umiejętności są <strong>podświetlone czerwoną obwódką</strong>.',
                 .map(icon => snapshotIconData(icon));
                dontShow: 'Nie pokazuj ponownie',
 
                 ok: 'Rozumiem',
            // Obtém lista de formas disponíveis
                weaponLink: 'Zobacz stronę broni:'
             const formNames = Object.keys(formsData);
             if (formNames.length === 0) return;
 
            // Determina próxima forma
            // Se currentForm é null, detecta qual forma está atualmente visível no DOM
            if (currentForm === null) {
                 currentForm = detectCurrentForm();
             }
             }
        };


        const getCurrentLang = () => {
             // Se ainda não conseguiu detectar, usa a primeira forma como fallback
             const html = document.documentElement.lang || 'pt-br';
             if (!currentForm && formNames.length > 0) {
             const norm = html.toLowerCase().split('-')[0];
                currentForm = formNames[0];
             return i18nTexts[norm] ? norm : 'pt';
             }
        };


        const bindModalEvents = () => {
            // Cria ordem circular fixa baseada na forma atual detectada
             if (modalListenersBound) return;
            // Se detectamos "Brain Point", ordem é: Brain → Kung Fu → Heavy → Brain
             modalListenersBound = true;
            // Se detectamos "Kung Fu Point", ordem é: Kung Fu → Heavy → Brain → Kung Fu
             document.addEventListener('click', (ev) => {
             // Se detectamos "Heavy Point", ordem é: Heavy → Brain → Kung Fu → Heavy
                 if (ev.target.closest('.weapon-modal-close') || ev.target.closest('.weapon-modal-btn')) {
             let orderedFormNames = [];
                     const checkbox = document.getElementById('weapon-dont-show');
             if (currentForm === "Brain Point" && formNames.length === 3) {
                    if (checkbox && checkbox.checked) {
                // Ordem conhecida: Brain → Kung Fu → Heavy
                        try { localStorage.setItem('glaWeaponPopupDismissed', '1'); } catch (x) { }
                 if (formNames.includes("Kung Fu Point") && formNames.includes("Heavy Point")) {
                     }
                     orderedFormNames = ["Brain Point", "Kung Fu Point", "Heavy Point"];
                    hidePopup();
                }
                    return;
            } else if (currentForm === "Kung Fu Point" && formNames.length === 3) {
                // Ordem conhecida: Kung Fu → Heavy → Brain
                if (formNames.includes("Heavy Point") && formNames.includes("Brain Point")) {
                     orderedFormNames = ["Kung Fu Point", "Heavy Point", "Brain Point"];
                 }
                 }
                 if (ev.target.classList.contains('weapon-modal-overlay')) {
            } else if (currentForm === "Heavy Point" && formNames.length === 3) {
                     hidePopup();
                // Ordem conhecida: Heavy → Brain → Kung Fu
                 if (formNames.includes("Brain Point") && formNames.includes("Kung Fu Point")) {
                     orderedFormNames = ["Heavy Point", "Brain Point", "Kung Fu Point"];
                 }
                 }
             });
             }
        };


        const applyWeaponState = (enabled) => {
            // Se não conseguiu criar ordem conhecida, usa ordem alfabética como fallback
            if (typeof window.__setGlobalWeaponEnabled === 'function') {
            if (orderedFormNames.length === 0) {
                window.__setGlobalWeaponEnabled(enabled);
                orderedFormNames = [...formNames].sort();
                // Se sabemos a forma atual, reorganiza para começar por ela
                if (currentForm) {
                    const currentIdx = orderedFormNames.indexOf(currentForm);
                    if (currentIdx !== -1) {
                        orderedFormNames = [
                            ...orderedFormNames.slice(currentIdx),
                            ...orderedFormNames.slice(0, currentIdx)
                        ];
                    }
                }
             }
             }


            const currentIdx = orderedFormNames.indexOf(currentForm);
            if (currentIdx === -1) return; // Forma não encontrada
            const nextIdx = (currentIdx + 1) % orderedFormNames.length;
            const nextForm = orderedFormNames[nextIdx];
            currentForm = nextForm;
            // Atualiza barra de skills (que vai remover o active depois da animação)
            updateSkillsBarForForm(nextForm, formsData[nextForm], changeFormIcon);
        }
        function snapshotIconData(icon) {
            const img = icon.querySelector('img');
            const iconURL = img ? img.src : '';
            const subsRaw = icon.dataset.subs || icon.getAttribute('data-subs') || '';
            let subs = null;
             try {
             try {
                 localStorage.setItem('glaWeaponEnabled', enabled ? '1' : '0');
                 subs = subsRaw ? JSON.parse(subsRaw) : null;
             } catch (x) { }
            } catch {
                subs = null;
            }
            let flags = null;
            if (icon.dataset.flags) {
                try {
                    flags = JSON.parse(icon.dataset.flags);
                } catch (e) {
                }
            }
            let weapon = null;
            if (icon.dataset.weapon) {
                try {
                    weapon = JSON.parse(icon.dataset.weapon);
                } catch (e) {
                }
            }
            return {
                name: icon.dataset.nome || icon.dataset.name || '',
                index: icon.dataset.index || '',
                level: icon.dataset.level || '',
                desc: icon.dataset.desc || '',
                descPt: icon.dataset.descPt || '',
                descEn: icon.dataset.descEn || '',
                descEs: icon.dataset.descEs || '',
                descPl: icon.dataset.descPl || '',
                attrs: icon.dataset.atr || icon.dataset.attrs || '',
                video: icon.dataset.video || '',
                iconURL,
                iconFile: icon.dataset.iconFile || '',
                subs,
                flags,
                weapon,
                formSwitch: icon.dataset.formSwitch || ''
            };
        }
 
        function updateSkillsBarForForm(formName, formData, changeFormIconEl) {
            const iconBar = document.querySelector('.icon-bar');
             if (!iconBar || !formData || !formData.skills) return;
 
            // Determina skills fixas dinamicamente: todas que não estão em nenhuma forms
            const allFormSkillNames = new Set();
            Object.values(formsData).forEach(form => {
                if (form.order && Array.isArray(form.order)) {
                    form.order.forEach(skillName => allFormSkillNames.add(skillName));
                }
            });


             // Dispara evento para atualizar subskills
             // Remove skills de forma antigas (que não são fixas) com animação de saída
            window.dispatchEvent(new CustomEvent('gla:weaponToggled', { detail: { enabled } }));


             // SISTEMA UNIFICADO: Aplica toggle em skills E subskills
             const existingIcons = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'));
            // Skills principais e subskills usam data-weapon (padronizado)
            const iconsToRemove = [];
            document.querySelectorAll('.skill-icon[data-weapon], .subicon[data-weapon]').forEach(el => {
            existingIcons.forEach(icon => {
                 if (enabled) {
                 const name = (icon.dataset.nome || '').trim();
                    el.classList.add('has-weapon-available');
                if (name && allFormSkillNames.has(name)) {
                } else {
                     iconsToRemove.push(icon);
                    el.classList.remove('has-weapon-available');
                    el.classList.remove('weapon-equipped');
                    el.style.removeProperty('--weapon-badge-url');
                    const ind = el.querySelector('.weapon-indicator');
                     if (ind) ind.remove();
                 }
                 }
             });
             });


             // Atualiza descrição da skill/subskill selecionada (se houver) para refletir estado da arma
             // Anima saída das skills antigas
             // Aguarda um pouco mais para garantir que o estado global foi sincronizado
            iconsToRemove.forEach(icon => {
                icon.style.transition = 'opacity .15s ease, transform .15s ease';
                icon.style.opacity = '0';
                icon.style.transform = 'translateY(-6px)';
            });
 
            // Encontra a skill com form_switch dinamicamente (genérico)
            const changeFormIcon = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'))
                .find(icon => icon.dataset.formSwitch === 'true' || icon.getAttribute('data-form-switch') === 'true');
 
            // Encontra a próxima skill fixa depois do form_switch dinamicamente
            let nextFixedSkillIcon = null;
            if (changeFormIcon) {
                const allIcons = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]')).sort((a, b) => {
                    return parseInt(a.dataset.index || '0', 10) - parseInt(b.dataset.index || '0', 10);
                });
                const changeFormIndex = allIcons.indexOf(changeFormIcon);
                const allFormSkillNames = new Set();
                Object.values(formsData).forEach(form => {
                    if (form.order && Array.isArray(form.order)) {
                        form.order.forEach(skillName => allFormSkillNames.add(skillName));
                    }
                });
 
                // Procura a próxima skill fixa (que não está em forms)
                for (let i = changeFormIndex + 1; i < allIcons.length; i++) {
                    const icon = allIcons[i];
                    const name = (icon.dataset.nome || '').trim();
                    if (name && !allFormSkillNames.has(name)) {
                        nextFixedSkillIcon = icon;
                        break;
                    }
                }
            }
 
            if (!changeFormIcon || !nextFixedSkillIcon) {
                console.warn('[Forms] Skill com form_switch ou próxima skill fixa não encontrada');
                return;
            }
 
            const formSkills = formData.skills || [];
            const formOrder = formData.order || [];
 
            // Primeira skill da forma (vai ANTES do Change Form)
            const firstSkillName = formOrder[0];
            const firstSkillData = formSkills.find(s => s.name === firstSkillName);
 
            // Terceira skill da forma (vai DEPOIS do Change Form, ANTES do Guard Point)
            const thirdSkillName = formOrder[1]; // Segunda na ordem = terceira skill (índice 1)
            const thirdSkillData = formSkills.find(s => s.name === thirdSkillName);
 
            // Quinta skill da forma (vai DEPOIS do Guard Point)
             const fifthSkillName = formOrder[2]; // Terceira na ordem = quinta skill (índice 2)
            const fifthSkillData = formSkills.find(s => s.name === fifthSkillName);
 
            // Cria fragments para inserir
            const firstFragment = document.createDocumentFragment();
            const thirdFragment = document.createDocumentFragment();
            const fifthFragment = document.createDocumentFragment();
 
            if (firstSkillData) {
                const iconElement = createSkillIconElement(firstSkillData, 1);
                firstFragment.appendChild(iconElement);
            }
            if (thirdSkillData) {
                const changeFormIndex = parseInt(changeFormIcon.dataset.index || '2', 10);
                const iconElement = createSkillIconElement(thirdSkillData, changeFormIndex + 1);
                thirdFragment.appendChild(iconElement);
            }
            if (fifthSkillData) {
                const nextFixedSkillIndex = parseInt(nextFixedSkillIcon.dataset.index || '4', 10);
                const iconElement = createSkillIconElement(fifthSkillData, nextFixedSkillIndex + 1);
                fifthFragment.appendChild(iconElement);
            }
 
            // Remove os ícones antigos do DOM após animação
             setTimeout(() => {
             setTimeout(() => {
                 // Atualiza skill principal se houver - força reativação completa incluindo vídeo
                 iconsToRemove.forEach(icon => {
                const sel = document.querySelector('.skill-icon.active:not(.weapon-bar-toggle)');
                     if (icon.parentNode) {
                if (sel) {
                         icon.remove();
                    // Força uma reativação completa da skill para garantir que vídeo seja atualizado
                     if (typeof window.__subskills !== 'undefined' && window.__subskills.hideAll) {
                         const videoBox = document.querySelector('.video-container') || document.querySelector('.skills-video-box');
                        if (videoBox) window.__subskills.hideAll(videoBox);
                     }
                     }
                     // Reativa a skill para atualizar vídeo, descrição e atributos
                });
                     if (typeof window.__lastActiveSkillIcon !== 'undefined' && window.__lastActiveSkillIcon === sel) {
 
                         sel.dispatchEvent(new Event('click', { bubbles: true }));
                // Insere a primeira skill ANTES da skill com form_switch
                if (firstFragment.hasChildNodes()) {
                     iconBar.insertBefore(firstFragment, changeFormIcon);
                }
 
                // Insere a terceira skill DEPOIS da skill com form_switch, ANTES da próxima skill fixa
                if (thirdFragment.hasChildNodes()) {
                     iconBar.insertBefore(thirdFragment, nextFixedSkillIcon);
                }
 
                // Insere a quinta skill DEPOIS da próxima skill fixa
                if (fifthFragment.hasChildNodes()) {
                    if (nextFixedSkillIcon.nextSibling) {
                         iconBar.insertBefore(fifthFragment, nextFixedSkillIcon.nextSibling);
                     } else {
                     } else {
                         sel.dispatchEvent(new Event('click', { bubbles: true }));
                         iconBar.appendChild(fifthFragment);
                     }
                     }
                 }
                 }
                // Atualiza subskill ativa se houver - força reativação completa incluindo vídeo
                const activeSub = document.querySelector('.subicon.active');
                if (activeSub) {
                    activeSub.dispatchEvent(new Event('click', { bubbles: true }));
                }
            }, 100);
        };


        const updateModalTexts = (modal) => {
                // Anima entrada das novas skills (similar a animateIconsBarEntrance)
            const lang = getCurrentLang();
                const newIconsInBar = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'))
            const t = i18nTexts[lang];
                    .filter(icon => {
                        const name = (icon.dataset.nome || '').trim();
                        return name && allFormSkillNames.has(name);
                    });


            const title = modal.querySelector('.weapon-modal-header h3');
                newIconsInBar.forEach((icon, idx) => {
            if (title) title.textContent = t.title;
                    icon.style.opacity = '0';
                    icon.style.transform = 'translateY(6px)';
                    requestAnimationFrame(() => {
                        setTimeout(() => {
                            icon.style.transition = 'opacity .18s ease, transform .18s ease';
                            icon.style.opacity = '1';
                            icon.style.transform = 'translateY(0)';
                        }, idx * 24);
                    });
                });


            const body = modal.querySelector('.weapon-modal-body');
                // Remove slots de descrição das skills de forma antigas e cria novos
            if (body) {
                const descBox = document.querySelector('.skills-details .desc-box');
                const p1 = body.querySelector('p:first-child');
                if (descBox) {
                const p2 = body.querySelector('p:nth-child(2)');
                    // Encontra os slots de descrição dos elementos fixos
                if (p1) p1.innerHTML = t.body1;
                    const changeFormIndex = parseInt(changeFormIcon.dataset.index || '1', 10);
                if (p2) p2.innerHTML = t.body2;
                    const nextFixedSkillIndex = parseInt(nextFixedSkillIcon.dataset.index || '1', 10);
            }
                    const changeFormDescSlot = descBox.querySelector(`.skill-desc[data-index="${changeFormIndex}"]`);
                    const nextFixedSkillDescSlot = descBox.querySelector(`.skill-desc[data-index="${nextFixedSkillIndex}"]`);


            const checkbox = modal.querySelector('.weapon-modal-checkbox span');
                    // Cria slot para primeira skill (antes do Change Form)
            if (checkbox) checkbox.textContent = t.dontShow;
                    if (firstSkillData && changeFormDescSlot) {
                        const descSlot = document.createElement('div');
                        descSlot.className = 'skill-desc';
                        descSlot.setAttribute('data-index', changeFormIndex);
                        descBox.insertBefore(descSlot, changeFormDescSlot);
                    }


            const btn = modal.querySelector('.weapon-modal-btn');
                    // Cria slot para terceira skill (depois da skill com form_switch, antes da próxima skill fixa)
            if (btn) btn.textContent = t.ok;
                    if (thirdSkillData && nextFixedSkillDescSlot) {
                        const descSlot = document.createElement('div');
                        descSlot.className = 'skill-desc';
                        descSlot.setAttribute('data-index', nextFixedSkillIndex);
                        descBox.insertBefore(descSlot, nextFixedSkillDescSlot);
                    }


            // Atualiza link da arma se existir
                    // Cria slot para quinta skill (depois da próxima skill fixa)
            try {
                    if (fifthSkillData && nextFixedSkillDescSlot) {
                const firstWithWeapon = document.querySelector('.skill-icon[data-weapon]');
                        const descSlot = document.createElement('div');
                if (firstWithWeapon) {
                        descSlot.className = 'skill-desc';
                    const raw = firstWithWeapon.getAttribute('data-weapon');
                         descSlot.setAttribute('data-index', nextFixedSkillIndex + 1);
                    const obj = JSON.parse(raw || '{}');
                         if (nextFixedSkillDescSlot.nextSibling) {
                    const nm = (obj && obj.name) ? String(obj.name).trim() : '';
                             descBox.insertBefore(descSlot, nextFixedSkillDescSlot.nextSibling);
                    if (nm) {
                        } else {
                         const linkHost = (window.mw && mw.util && typeof mw.util.getUrl === 'function') ? mw.util.getUrl(nm) : ('/index.php?title=' + encodeURIComponent(nm));
                            descBox.appendChild(descSlot);
                         const holder = modal.querySelector('.weapon-info-link');
                        if (holder) {
                             holder.style.display = 'block';
                            holder.innerHTML = `<a href="${linkHost}">${t.weaponLink} ${nm}</a>`;
                         }
                         }
                     }
                     }
                 }
                 }
            } catch (_) { }
        };


         const ensureModal = () => {
                // Re-numera todas as skills na ordem do DOM
             let modal = document.getElementById('weapon-info-modal');
                const allIcons = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'));
             if (modal) {
                let currentIndex = 1;
                 updateModalTexts(modal);
                allIcons.forEach(icon => {
                 return modal;
                    const oldIndex = icon.dataset.index;
                    icon.setAttribute('data-index', currentIndex);
 
                    // Atualiza slot de descrição
                    if (descBox && oldIndex) {
                        const descSlot = descBox.querySelector(`.skill-desc[data-index="${oldIndex}"]`);
                        if (descSlot) {
                            descSlot.setAttribute('data-index', currentIndex);
                        }
                    }
                    currentIndex++;
                });
 
                // Re-wire eventos
                wireClicksForCurrentBar();
                wireTooltipsForNewIcons();
 
                // Remove active do Change Form após animação completar
                setTimeout(() => {
                    if (changeFormIconEl) {
                        changeFormIconEl.classList.remove('active');
                    }
                }, (newIconsInBar.length * 24) + 180);
            }, 150);
        }
 
         function createSkillIconElement(skill, index) {
            const iconWrap = document.createElement('div');
            iconWrap.className = 'skill-icon';
            iconWrap.setAttribute('data-index', index);
            iconWrap.setAttribute('data-nome', skill.name || '');
            iconWrap.setAttribute('data-desc', '');
            iconWrap.setAttribute('data-atr', makeAttrString(skill.powerpve, skill.powerpvp, skill.energy, skill.cooldown));
            iconWrap.setAttribute('data-video', skill.video ? filePathURL(skill.video) : '');
            iconWrap.setAttribute('data-video-preload', 'auto');
            iconWrap.setAttribute('data-icon-file', skill.icon || 'Nada.png');
            iconWrap.setAttribute('data-video-file', skill.video || '');
 
            if (skill.level && skill.level !== '' && skill.level.toUpperCase() !== 'NIVEL') {
                iconWrap.setAttribute('data-level', skill.level);
            }
 
            if (skill.desc_i18n) {
                if (skill.desc_i18n.pt) iconWrap.setAttribute('data-desc-pt', skill.desc_i18n.pt);
                if (skill.desc_i18n.en) iconWrap.setAttribute('data-desc-en', skill.desc_i18n.en);
                if (skill.desc_i18n.es) iconWrap.setAttribute('data-desc-es', skill.desc_i18n.es);
                if (skill.desc_i18n.pl) iconWrap.setAttribute('data-desc-pl', skill.desc_i18n.pl);
            }
 
            if (skill.subs && Array.isArray(skill.subs) && skill.subs.length > 0) {
                iconWrap.setAttribute('data-subs', JSON.stringify(skill.subs));
            }
            if (skill.suborder && Array.isArray(skill.suborder) && skill.suborder.length > 0) {
                iconWrap.setAttribute('data-suborder', JSON.stringify(skill.suborder));
            }
 
            if (skill.flags && Array.isArray(skill.flags) && skill.flags.length > 0) {
                iconWrap.setAttribute('data-flags', JSON.stringify(skill.flags));
            }
 
            if (skill.weapon && typeof skill.weapon === 'object' && Object.keys(skill.weapon).length > 0) {
                iconWrap.setAttribute('data-weapon', JSON.stringify(skill.weapon));
            }
 
            const img = document.createElement('img');
            img.className = 'skill-icon-img';
             img.src = filePathURL(skill.icon || 'Nada.png');
            img.alt = '';
            iconWrap.appendChild(img);
 
            return iconWrap;
        }
 
        function createSkillIcon(skill, index, container) {
            // Cria ícone similar ao que é gerado pelo servidor
            const iconWrap = document.createElement('div');
            iconWrap.className = 'skill-icon';
            iconWrap.setAttribute('data-index', index);
            iconWrap.setAttribute('data-nome', skill.name || '');
            iconWrap.setAttribute('data-desc', '');
            iconWrap.setAttribute('data-atr', makeAttrString(skill.powerpve, skill.powerpvp, skill.energy, skill.cooldown));
            iconWrap.setAttribute('data-video', skill.video ? filePathURL(skill.video) : '');
            iconWrap.setAttribute('data-video-preload', 'auto');
            iconWrap.setAttribute('data-icon-file', skill.icon || 'Nada.png');
            iconWrap.setAttribute('data-video-file', skill.video || '');
 
            if (skill.level && skill.level !== '' && skill.level.toUpperCase() !== 'NIVEL') {
                iconWrap.setAttribute('data-level', skill.level);
            }
 
             if (skill.desc_i18n) {
                 if (skill.desc_i18n.pt) iconWrap.setAttribute('data-desc-pt', skill.desc_i18n.pt);
                 if (skill.desc_i18n.en) iconWrap.setAttribute('data-desc-en', skill.desc_i18n.en);
                if (skill.desc_i18n.es) iconWrap.setAttribute('data-desc-es', skill.desc_i18n.es);
                if (skill.desc_i18n.pl) iconWrap.setAttribute('data-desc-pl', skill.desc_i18n.pl);
             }
             }


             // Insere dentro da character-box para isolar completamente
             if (skill.subs && Array.isArray(skill.subs) && skill.subs.length > 0) {
             const container = document.querySelector('.character-box') || document.querySelector('#mw-content-text') || document.body;
                iconWrap.setAttribute('data-subs', JSON.stringify(skill.subs));
             }
            if (skill.suborder && Array.isArray(skill.suborder) && skill.suborder.length > 0) {
                iconWrap.setAttribute('data-suborder', JSON.stringify(skill.suborder));
            }


             modal = document.createElement('div');
             if (skill.flags && Array.isArray(skill.flags) && skill.flags.length > 0) {
            modal.id = 'weapon-info-modal';
                iconWrap.setAttribute('data-flags', JSON.stringify(skill.flags));
            modal.className = 'weapon-modal';
             }
            modal.innerHTML = `
            <div class="weapon-modal-overlay"></div>
            <div class="weapon-modal-content">
                <div class="weapon-modal-header">
                    <h3></h3>
                    <button class="weapon-modal-close" type="button" aria-label="Fechar">&times;</button>
                </div>
                <div class="weapon-modal-body">
                    <p></p>
                    <p></p>
                    <p class="weapon-info-link"></p>
                </div>
                <div class="weapon-modal-footer">
                    <label class="weapon-modal-checkbox">
                        <input type="checkbox" id="weapon-dont-show">
                        <span></span>
                    </label>
                    <button class="weapon-modal-btn" type="button"></button>
                </div>
            </div>
        `;
            container.appendChild(modal);
            updateModalTexts(modal);
             bindModalEvents();
            return modal;
        };


        const showPopup = () => {
            if (skill.weapon && typeof skill.weapon === 'object' && Object.keys(skill.weapon).length > 0) {
            const modal = ensureModal();
                 iconWrap.setAttribute('data-weapon', JSON.stringify(skill.weapon));
            if (modal) {
                 updateModalTexts(modal);
                // Força reflow antes de adicionar classe para garantir transição
                void modal.offsetHeight;
                modal.classList.add('show');
             }
             }
        };


        const hidePopup = () => {
            const img = document.createElement('img');
             const m = document.getElementById('weapon-info-modal');
             img.className = 'skill-icon-img';
             if (m) m.classList.remove('show');
             img.src = filePathURL(skill.icon || 'Nada.png');
        };
            img.alt = '';
            iconWrap.appendChild(img);


        window.__applyWeaponState = applyWeaponState;
             container.appendChild(iconWrap);
        window.__glaWeaponShowPopup = showPopup;
        window.__glaWeaponHidePopup = hidePopup;
        try {
             window.dispatchEvent(new CustomEvent('weapon:ready', { detail: { applyWeaponState, showPopup, hidePopup } }));
        } catch (err) {
         }
         }


         // Escuta mudanças de idioma
         function makeAttrString(pve, pvp, energy, cd) {
        window.addEventListener('gla:langChanged', () => {
            const parts = [
            const modal = document.getElementById('weapon-info-modal');
                (pve !== undefined && pve !== null && pve !== '') ? String(pve) : '-',
             if (modal) updateModalTexts(modal);
                (pvp !== undefined && pvp !== null && pvp !== '') ? String(pvp) : '-',
         });
                (energy !== undefined && energy !== null && energy !== '') ? String(energy) : '-',
                (cd !== undefined && cd !== null && cd !== '') ? String(cd) : '-'
            ];
             return parts.join(', ');
         }


         // Função para obter o nome da arma
         function filePathURL(fileName) {
         function getWeaponName() {
            // Evita requisições para Nada.png que não existe
             let weaponName = 'Arma Especial';
            if (!fileName || fileName.trim() === '' || fileName === 'Nada.png' || fileName.toLowerCase() === 'nada.png') {
                return '';
            }
            const f = encodeURIComponent(fileName.replace(/^Arquivo:|^File:/, ''));
            const base = (window.mw && mw.util && typeof mw.util.wikiScript === 'function') ? mw.util.wikiScript() : (window.mw && window.mw.config ? (mw.config.get('wgScript') || '/index.php') : '/index.php');
            // Garante HTTPS para evitar Mixed Content
            let url = `${base}?title=Especial:FilePath/${f}`;
            if (window.location.protocol === 'https:' && url.startsWith('http://')) {
                url = url.replace('http://', 'https://');
            }
            return url;
        } function slugify(s) {
            if (!s) return '';
            return String(s).toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^\w\s-]/g, '').replace(/[\s:/\-]+/g, '-').replace(/^-+|-+$/g, '').replace(/-+/g, '-');
        } window.__skillSlugify = slugify;
        function getLangKey() {
            const skillsRoot = document.getElementById('skills');
            const raw = (document.documentElement.lang || skillsRoot?.dataset.i18nDefault || 'pt').toLowerCase();
            return raw === 'pt-br' ? 'pt' : (raw.split('-')[0] || 'pt');
        } function chooseDescFrom(obj) {
            const lang = getLangKey();
            // Aceita tanto desc_i18n quanto desc para compatibilidade
            const pack = obj.desc_i18n || obj.desc || {
                pt: obj.descPt, en: obj.descEn, es: obj.descEs, pl: obj.descPl
            };
            return (pack && (pack[lang] || pack.pt || pack.en || pack.es || pack.pl)) || '';
         } function renderSubAttributesFromObj(s, L) {
            const chip = (label, val) => (val ? `<div class="attr-row"><span class="attr-label">${label}</span><span class="attr-value">${val}</span></div>` : '');
            const pve = (s.powerpve || '').toString().trim();
            const pvp = (s.powerpvp || '').toString().trim();
             const en = (s.energy || '').toString().trim();
            const cd = (s.cooldown || '').toString().trim();
            const rows = [cd ? chip(L.cooldown, cd) : '', en ? chip((en.startsWith('-') ? L.energy_cost : L.energy_gain), en.startsWith('-') ? en.replace(/^-/, '') : en.replace(/^\+?/, '')) : '', pve ? chip(L.power, pve) : '', pvp ? chip(L.power_pvp, pvp) : '',].filter(Boolean);
            return rows.length ? `<div class="attr-list">${rows.join('')}</div>` : '';
        } function getFlagIconURL(key) {
            if (!FLAG_ICON_FILES[key]) return '';
            if (!flagIconURLCache.has(key)) {
                flagIconURLCache.set(key, filePathURL(FLAG_ICON_FILES[key]));
            } return flagIconURLCache.get(key);
        } function renderFlagsRow(flags) {
            const arr = (flags || []).filter(Boolean);
            if (!arr.length) return '';
            const cacheKey = arr.join('|');
            if (flagRowCache.has(cacheKey)) {
                return flagRowCache.get(cacheKey);
            } const items = arr.map(k => {
                const url = getFlagIconURL(k);
                return url ? `<img class="skill-flag" data-flag="${k}" alt="" src="${url}">` : '';
            }).join('');
            const html = items ? `<div class="skill-flags" role="group" aria-label="Características">${items}</div>` : '';
            if (html) flagRowCache.set(cacheKey, html);
            return html;
        } function applyFlagTooltips(container) {
            const skillsRoot = document.getElementById('skills');
            if (!skillsRoot) return;
            let pack = {
            };
             try {
             try {
                 const firstWithWeapon = document.querySelector('.skill-icon[data-weapon]');
                 pack = JSON.parse(skillsRoot.dataset.i18nFlags || '{}');
                if (firstWithWeapon) {
            } catch (e) {
                    const raw = firstWithWeapon.getAttribute('data-weapon');
            } const lang = getLangKey();
                    const obj = JSON.parse(raw || '{}');
            const dict = pack[lang] || pack.pt || {
                     if (obj && obj.name) {
            };
                        weaponName = String(obj.name).trim();
            const flags = container.querySelectorAll('.skill-flags .skill-flag[data-flag]');
            const tooltip = window.__globalSkillTooltip;
            if (!tooltip) return;
            flags.forEach(el => {
                const key = el.getAttribute('data-flag');
                const tip = (dict && dict[key]) || '';
                if (!tip) return;
                if (el.dataset.flagTipWired) return;
                el.dataset.flagTipWired = '1';
                el.setAttribute('aria-label', tip);
                if (el.hasAttribute('title')) el.removeAttribute('title');
                el.addEventListener('mouseenter', () => {
                    const tipEl = document.querySelector('.skill-tooltip');
                     if (tipEl) tipEl.classList.add('flag-tooltip');
                    tooltip.show(el, tip);
                });
                el.addEventListener('mousemove', () => {
                    if (performance.now() >= tooltip.lockUntil.value) {
                        tooltip.measureAndPos(el);
                     }
                     }
                 }
                 });
            } catch (e) { }
                el.addEventListener('click', () => {
             return weaponName;
                    tooltip.lockUntil.value = performance.now() + 240;
                    tooltip.measureAndPos(el);
                });
                el.addEventListener('mouseleave', () => {
                    const tipEl = document.querySelector('.skill-tooltip');
                    if (tipEl) tipEl.classList.remove('flag-tooltip');
                    tooltip.hide();
                });
             });
         }
         }


         // Função para criar o novo toggle abaixo do char-translator
         // ====== Skill/Subskill inheritance helpers ======
         function createWeaponToggle() {
         const mainSkillsMeta = {
             // Remove toggle antigo se existir
             byIndex: new Map(),
             const oldToggle = document.querySelector('.weapon-bar-toggle');
             byName: new Map(),
             if (oldToggle) oldToggle.remove();
             ready: false
        };


             const existingContainer = document.querySelector('.weapon-toggle-container');
        function normalizeFileURL(raw, fallback = '') {
             if (existingContainer) return existingContainer;
            if (!raw) return fallback;
             const val = String(raw).trim();
            if (!val) return fallback;
            if (/^(https?:)?\/\//i.test(val) || val.startsWith('data:') || val.includes('Especial:FilePath/')) {
                return val;
             } return filePathURL(val);
        }


             const characterHeader = document.querySelector('.character-header');
        function extractFileNameFromURL(url) {
             if (!characterHeader) return null;
            if (!url) return '';
             const match = String(url).match(/(?:FilePath\/)([^&?]+)/i);
             return match ? decodeURIComponent(match[1]) : '';
        }


            // Resolve o ícone
        function parseAttrString(raw) {
             resolveCharacterWeaponIcon();
             const parts = (raw || '').split(',').map(v => v.trim());
             const weaponName = getWeaponName();
             const safe = idx => {
                const val = parts[idx] || '';
                return (val && val !== '-') ? val : '';
            };
            return {
                powerpve: safe(0),
                powerpvp: safe(1),
                energy: safe(2),
                cooldown: safe(3)
            };
        }


            // Cria o container do toggle
        function hasText(value) {
            const container = document.createElement('div');
             return typeof value === 'string' ? value.trim() !== '' : value !== undefined && value !== null;
             container.className = 'weapon-toggle-container';
        }
            container.setAttribute('role', 'button');
            container.setAttribute('aria-pressed', 'false');
            container.setAttribute('aria-label', weaponName);


            // Cria o sprite (círculo com imagem)
        function pickFilled(current, fallback) {
             const sprite = document.createElement('div');
             if (current === 0 || current === '0') return current;
             sprite.className = 'weapon-toggle-sprite';
             if (!hasText(current)) return fallback;
            return current;
        }


            if (globalWeaponToggleIcon) {
        function buildMainSkillsMeta(nodes) {
                const img = document.createElement('img');
            if (mainSkillsMeta.ready) {
                img.src = globalWeaponToggleIcon;
                 return mainSkillsMeta;
                img.alt = weaponName;
                img.className = 'weapon-toggle-icon';
                img.decoding = 'async';
                img.loading = 'eager'; // Ícone do toggle é crítico - carrega imediatamente
                img.onerror = function () {
                    // console.error('[WeaponToggle] Erro ao carregar imagem:', globalWeaponToggleIcon);
                };
                img.onload = function () {
                    // console.log('[WeaponToggle] Imagem carregada com sucesso:', globalWeaponToggleIcon);
                 };
                sprite.appendChild(img);
             }
             }
 
             (nodes || []).forEach(icon => {
            // Cria a barra com texto
                const index = (icon.dataset.index || '').trim();
             const bar = document.createElement('div');
                if (!index) return;
            bar.className = 'weapon-toggle-bar';
                const name = (icon.dataset.nome || icon.dataset.name || '').trim();
            const nameSpan = document.createElement('span');
                const attrs = parseAttrString(icon.dataset.atr || '');
            nameSpan.className = 'weapon-toggle-name';
                 let iconFile = (icon.dataset.iconFile || '').trim();
            nameSpan.setAttribute('data-lang', getCurrentLang());
                 if (!iconFile) {
            bar.appendChild(nameSpan);
                     const imgSrc = icon.querySelector('img')?.src || '';
 
                    const iconMatch = imgSrc.match(/(?:FilePath|images)\/([^\/?]+)$/);
            container.appendChild(sprite);
                     iconFile = iconMatch ? decodeURIComponent(iconMatch[1]) : '';
            container.appendChild(bar);
                }
 
                let videoFile = (icon.dataset.videoFile || '').trim();
            // Adiciona evento de clique
                if (!videoFile) {
            container.addEventListener('click', () => {
                     videoFile = extractFileNameFromURL(icon.dataset.video || '');
                 let currentState = false;
                 try {
                     currentState = localStorage.getItem('glaWeaponEnabled') === '1';
                } catch (e) { }
                const nextState = !currentState;
                if (nextState) {
                    // Verifica se o popup foi dispensado antes de mostrar
                     let shouldShowPopup = true;
                    try {
                        if (localStorage.getItem('glaWeaponPopupDismissed') === '1') {
                            shouldShowPopup = false;
                        }
                    } catch (e) { }
                     if (shouldShowPopup && typeof window.__glaWeaponShowPopup === 'function') {
                        window.__glaWeaponShowPopup();
                    }
                 }
                 }
                 if (typeof window.__applyWeaponState === 'function') {
                 const meta = {
                     window.__applyWeaponState(nextState);
                    index,
                    name,
                    icon: iconFile || 'Nada.png',
                    level: icon.dataset.level || '',
                    video: videoFile || '',
                    powerpve: attrs.powerpve || '',
                    powerpvp: attrs.powerpvp || '',
                    energy: attrs.energy || '',
                    cooldown: attrs.cooldown || '',
                    desc: icon.dataset.desc || '',
                    descPt: icon.dataset.descPt || '',
                    descEn: icon.dataset.descEn || '',
                    descEs: icon.dataset.descEs || '',
                    descPl: icon.dataset.descPl || ''
                };
                mainSkillsMeta.byIndex.set(index, meta);
                mainSkillsMeta.byIndex.set(parseInt(index, 10), meta);
                if (name) {
                     mainSkillsMeta.byName.set(name, meta);
                 }
                 }
             });
             });
            mainSkillsMeta.ready = true;
            return mainSkillsMeta;
        }
        function inheritSubskillFromMain(sub, meta) {
            if (!sub || !meta) return sub;
            // Verifica se herança está desabilitada
            const shouldInherit = !(sub.inherit === false || sub.inherit === 'no' || sub.inherit === 'false');
            // Suporta refS (novo) e refM (legado)
            const refS = ((sub.refS || sub.S || sub.s || '') + '').trim();
            const refIndex = ((sub.refM || sub.M || sub.m || '') + '').trim();
            let name = (sub.name || sub.n || '').trim();
            let main = null;


             // Insere no container de controles (character-header-controls)
             // Se herança está desabilitada, não busca a skill principal
            const controlsContainer = document.querySelector('.character-header-controls');
             if (!shouldInherit) {
             if (controlsContainer) {
                 return { ...sub };
                 controlsContainer.appendChild(container);
            } else {
                // Fallback: insere no character-header se o container não existir
                characterHeader.appendChild(container);
             }
             }


             // Atualiza estado visual inicial
             // Primeiro tenta por refS
             updateToggleVisualState();
             if (refS) {
                main = meta.byIndex.get(refS) || meta.byIndex.get(parseInt(refS, 10));
            }
            // Depois por refM
            if (!main && refIndex) {
                main = meta.byIndex.get(refIndex) || meta.byIndex.get(parseInt(refIndex, 10));
            }
            // Por último pelo nome
            if (!main && name) {
                main = meta.byName.get(name);
            }
            if (!main) {
                return sub;
            }


             return container;
             const hydrated = { ...sub };
        }
            if (!name && main.name) {
                name = main.name;
            }
            hydrated.name = name || hydrated.name || main.name || '';
            hydrated.icon = pickFilled(hydrated.icon, main.icon || 'Nada.png');
            hydrated.level = pickFilled(hydrated.level, main.level || '');


        // Função para atualizar o estado visual do toggle
            // Vídeo NUNCA é herdado da skill principal
        function updateToggleVisualState() {
             const hasOwnVideo = Object.prototype.hasOwnProperty.call(sub, 'video');
             const container = document.querySelector('.weapon-toggle-container');
             hydrated.video = hasOwnVideo ? (sub.video || '') : '';
             if (!container) return;


             let isEnabled = false;
             hydrated.powerpve = pickFilled(hydrated.powerpve, main.powerpve || '');
             try {
             hydrated.powerpvp = pickFilled(hydrated.powerpvp, main.powerpvp || '');
                isEnabled = localStorage.getItem('glaWeaponEnabled') === '1';
            hydrated.energy = pickFilled(hydrated.energy, main.energy || '');
             } catch (e) { }
             hydrated.cooldown = pickFilled(hydrated.cooldown, main.cooldown || '');


             if (isEnabled) {
            // Descrição: sempre vem da subskill, nunca herda
                 container.classList.add('weapon-active');
            // PROTEÇÃO TOTAL: Remove qualquer descrição que possa ter sido copiada do main
                 container.setAttribute('aria-pressed', 'true');
             if (!sub.desc && !sub.descPt && !sub.descEn && !sub.descEs && !sub.descPl && !sub.desc_i18n) {
                 hydrated.desc = undefined;
                hydrated.descPt = undefined;
                hydrated.descEn = undefined;
                hydrated.descEs = undefined;
                hydrated.descPl = undefined;
                 hydrated.desc_i18n = undefined;
             } else {
             } else {
                 container.classList.remove('weapon-active');
                 // Se subskill tem descrição, normaliza para desc_i18n
                container.setAttribute('aria-pressed', 'false');
                if (!hydrated.desc_i18n && (hydrated.descPt || hydrated.descEn || hydrated.descEs || hydrated.descPl)) {
                    hydrated.desc_i18n = {
                        pt: hydrated.descPt || '',
                        en: hydrated.descEn || '',
                        es: hydrated.descEs || '',
                        pl: hydrated.descPl || ''
                    };
                }
             }
             }


             // Atualiza idioma do texto
             return hydrated;
            const nameSpan = container.querySelector('.weapon-toggle-name');
            if (nameSpan) {
                nameSpan.setAttribute('data-lang', getCurrentLang());
            }
         }
         }


        // Observa quando o container de controles é criado para posicionar o toggle
         function inheritSubskillTree(subs, meta) {
         function observeCharacterHeader() {
             if (!Array.isArray(subs)) return [];
             const controlsContainer = document.querySelector('.character-header-controls');
             return subs.map(sub => {
            const characterHeader = document.querySelector('.character-header');
                 const hydrated = inheritSubskillFromMain(sub, meta);
            if (controlsContainer) {
                 if (Array.isArray(hydrated.subs)) {
                // Container existe - cria o toggle imediatamente
                     hydrated.subs = inheritSubskillTree(hydrated.subs, meta);
                createWeaponToggle();
                 }
             } else if (characterHeader) {
                return hydrated;
                // Header existe mas container não - cria o container e depois o toggle
             });
                 const newContainer = document.createElement('div');
                 newContainer.className = 'character-header-controls';
                characterHeader.appendChild(newContainer);
                // Aguarda um frame para garantir que o container foi adicionado
                requestAnimationFrame(() => {
                     createWeaponToggle();
                 });
             } else {
                // Nada existe ainda - tenta novamente após um delay
                setTimeout(observeCharacterHeader, 100);
            }
         }
         }


        // Observa mudanças no DOM para detectar quando o container de controles é criado
         function collectAssetsFromSubs(subs, iconsSet, videosSet, flagsSet) {
         function observeDOMForHeader() {
             if (!Array.isArray(subs)) return;
             const observer = new MutationObserver((mutations) => {
            subs.forEach(sub => {
                mutations.forEach((mutation) => {
                const iconURL = normalizeFileURL(sub.icon || 'Nada.png', '');
                    mutation.addedNodes.forEach((node) => {
                if (iconURL && iconURL !== '') iconsSet.add(iconURL);
                        if (node.nodeType === 1) {
                // Vídeo normal
                            if (node.classList && (node.classList.contains('character-header-controls') || node.classList.contains('character-header'))) {
                if (sub.video && sub.video.trim() !== '' && sub.video !== 'Nada.png' && !sub.video.toLowerCase().includes('nada.png')) {
                                setTimeout(() => createWeaponToggle(), 10);
                    const videoURL = normalizeFileURL(sub.video);
                            } else if (node.querySelector && (node.querySelector('.character-header-controls') || node.querySelector('.character-header'))) {
                    if (videoURL) videosSet.add(videoURL);
                                setTimeout(() => createWeaponToggle(), 10);
                }
                            }
                // Vídeo de weapon
                         }
                if (sub.weapon && typeof sub.weapon === 'object' && sub.weapon.video && sub.weapon.video.trim() !== '' && sub.weapon.video !== 'Nada.png' && !sub.weapon.video.toLowerCase().includes('nada.png')) {
                    const weaponVideoURL = normalizeFileURL(sub.weapon.video);
                    if (weaponVideoURL) videosSet.add(weaponVideoURL);
                }
                if (Array.isArray(sub.flags)) {
                    sub.flags.forEach(flagKey => {
                        const url = getFlagIconURL(flagKey);
                         if (url) flagsSet.add(url);
                     });
                     });
                 });
                 } if (Array.isArray(sub.subs)) {
                    collectAssetsFromSubs(sub.subs, iconsSet, videosSet, flagsSet);
                }
             });
             });
 
        } function buildAssetManifest() {
             observer.observe(document.body, { childList: true, subtree: true });
             if (window.__skillAssetManifest && window.__skillAssetManifest.ready) {
        }
                return window.__skillAssetManifest;
 
            } const iconsSet = new Set();
        const boot = () => {
             const videosSet = new Set();
             // Resolve o ícone do character antes de tudo
             const flagsSet = new Set();
             resolveCharacterWeaponIcon();
             iconItems.forEach(el => {
 
                 const img = el.querySelector('img');
             // Verificar se existe alguma skill ou subskill com arma
                 if (img && img.src) {
            function checkHasAnyWeapon() {
                    iconsSet.add(img.src);
                // PRIORIDADE 1: Verifica se há weaponicon global no character-box
                } else if (el.dataset.iconFile) {
                 const characterBox = document.querySelector('.character-box');
                     const iconURL = normalizeFileURL(el.dataset.iconFile);
                 if (characterBox && characterBox.dataset.weaponicon) {
                    if (iconURL) iconsSet.add(iconURL);
                     const weaponIcon = characterBox.dataset.weaponicon.trim();
                }
                    if (weaponIcon && weaponIcon !== '' && weaponIcon !== 'Nada.png') {
                // Vídeo normal da skill
                        return true;
                const videoRaw = (el.dataset.videoFile || el.dataset.video || '').trim();
                     }
                if (videoRaw && videoRaw !== 'Nada.png' && !videoRaw.toLowerCase().includes('nada.png')) {
                    const videoURL = normalizeFileURL(videoRaw);
                     if (videoURL) videosSet.add(videoURL);
                 }
                 }
 
                 // Vídeo de weapon da skill
                 // PRIORIDADE 2: Verifica skills principais
                 if (el.dataset.weapon) {
                 const mainSkills = document.querySelectorAll('.skill-icon[data-weapon]');
                    try {
                for (const el of mainSkills) {
                        const weaponData = JSON.parse(el.dataset.weapon);
                    const weapon = el.dataset.weapon;
                        if (weaponData && weaponData.video && weaponData.video.trim() !== '' && weaponData.video !== 'Nada.png' && !weaponData.video.toLowerCase().includes('nada.png')) {
                    if (weapon && weapon.trim() !== '' && weapon !== '{}') {
                             const weaponVideoURL = normalizeFileURL(weaponData.video);
                        try {
                             if (weaponVideoURL) videosSet.add(weaponVideoURL);
                             const weaponObj = JSON.parse(weapon);
                             if (weaponObj && typeof weaponObj === 'object' && Object.keys(weaponObj).length > 0) {
                                return true;
                            }
                        } catch (e) {
                            // Se não for JSON válido mas não está vazio, considera válido
                            return true;
                         }
                         }
                    } catch (e) {
                     }
                     }
                 }
                 }
 
                if (el.dataset.flags) {
                // PRIORIDADE 3: Verifica weaponicon em skills principais
                    try {
                const skillsWithWeaponIcon = document.querySelectorAll('.skill-icon[data-weaponicon]');
                        const parsedFlags = JSON.parse(el.dataset.flags);
                 for (const el of skillsWithWeaponIcon) {
                        (parsedFlags || []).forEach(flagKey => {
                     const weaponIcon = el.dataset.weaponicon;
                            const url = getFlagIconURL(flagKey);
                     if (weaponIcon && weaponIcon.trim() !== '' && weaponIcon !== 'Nada.png') {
                            if (url) flagsSet.add(url);
                        return true;
                        });
                    } catch (e) {
                    }
                 } if (el.dataset.subs) {
                     try {
                        const subs = JSON.parse(el.dataset.subs);
                        collectAssetsFromSubs(subs, iconsSet, videosSet, flagsSet);
                     } catch (e) {
                     }
                     }
                 }
                 }
            });
            Object.keys(FLAG_ICON_FILES).forEach(flagKey => {
                const url = getFlagIconURL(flagKey);
                if (url) flagsSet.add(url);
            });
            const manifest = {
                icons: iconsSet, videos: videosSet, flags: flagsSet, ready: true
            };
            window.__skillAssetManifest = manifest;
            return manifest;
        } const subskillVideosCache = new Map();
        window.__subskillVideosCache = subskillVideosCache;
        // Cache de vídeos que falharam (404) para evitar tentativas repetidas
        const failedVideosCache = new Set();
        const missingVideosReported = new Set(); // Para avisar apenas uma vez sobre vídeos faltantes
        // Cache de parsing JSON para evitar re-parsear os mesmos dados
        const jsonParseCache = new WeakMap();
        function getCachedJSON(el, key) {
            if (!el) return null;
            const cache = jsonParseCache.get(el) || {};
            if (cache[key] !== undefined) return cache[key];
            const raw = el.dataset[key] || el.getAttribute(`data-${key}`);
            if (!raw) {
                cache[key] = null;
                jsonParseCache.set(el, cache);
                return null;
            }
            try {
                const parsed = JSON.parse(raw);
                cache[key] = parsed;
                jsonParseCache.set(el, cache);
                return parsed;
            } catch (e) {
                cache[key] = null;
                jsonParseCache.set(el, cache);
                return null;
            }
        }


                // PRIORIDADE 4: Verifica subskills
        let assetManifest = null;
                const skillIcons = document.querySelectorAll('.skill-icon[data-subs]');
        const skillsTab = $('#skills');
                 for (const el of skillIcons) {
        const skinsTab = $('#skins');
                    try {
        ensureRemoved('.top-rail');
                        const subs = JSON.parse(el.getAttribute('data-subs') || '[]');
        // NÃO remove .content-card aqui - será gerenciado abaixo
                        if (Array.isArray(subs) && subs.some(s => s && s.weapon && typeof s.weapon === 'object' && Object.keys(s.weapon).length > 0)) {
        // ensureRemoved('.content-card'); // REMOVIDO - pode estar removendo skills-container
                            return true;
        ensureRemoved('.video-placeholder');
                        }
        Array.from(document.querySelectorAll('.card-skins-title, .card-skins .card-skins-title, .cardskins-title, .rail-title')).forEach(t => {
                     } catch (e) { }
            if ((t.textContent || '').trim().toLowerCase().includes('skins')) {
                 t.remove();
            }
        });
        if (skillsTab) {
            const iconBar = skillsTab.querySelector('.icon-bar');
            if (iconBar) {
                const rail = document.createElement('div');
                rail.className = 'top-rail skills';
                // Criar wrapper de scroll para permitir glow sem clipping
                if (!iconBar.parentElement || !iconBar.parentElement.classList.contains('icon-scroll-x')) {
                    const scrollWrapper = document.createElement('div');
                    scrollWrapper.className = 'icon-scroll-x';
                    scrollWrapper.appendChild(iconBar);
                    rail.appendChild(scrollWrapper);
                } else {
                     rail.appendChild(iconBar.parentElement);
                 }
                 }
                 return false;
                 skillsTab.prepend(rail);
             }
             }
            const hasAnyWeapon = checkHasAnyWeapon();


             if (!hasAnyWeapon) {
             // Busca skills-container criado pelo Lua
                // Limpar estado visual para chars sem arma (previne cache entre páginas)
            const skillsContainer = skillsTab.querySelector('.skills-container');
                const topRail = document.querySelector('.top-rail.skills');
 
                if (topRail) {
            // Busca skills-details e video-container (podem estar dentro de skills-container ou soltos)
                    topRail.classList.remove('weapon-mode-on');
            let details = skillsTab.querySelector('.skills-details');
                }
            if (!details && skillsContainer) {
                document.querySelectorAll('.skill-icon.has-weapon-available').forEach(el => {
                details = skillsContainer.querySelector('.skills-details');
                    el.classList.remove('has-weapon-available');
            }
                    el.classList.remove('weapon-equipped');
            if (!details) {
                    el.style.removeProperty('--weapon-badge-url');
                 details = document.createElement('div');
                    const ind = el.querySelector('.weapon-indicator');
                 details.className = 'skills-details';
                    if (ind) ind.remove();
                 });
                // Remover toggle se existir
                const toggleContainer = document.querySelector('.weapon-toggle-container');
                 if (toggleContainer) toggleContainer.remove();
                // Atualizar estado global para desligado
                if (typeof window.__setGlobalWeaponEnabled === 'function') {
                    window.__setGlobalWeaponEnabled(false);
                }
                return;
             }
             }


             ensureModal();
             // Busca ou cria desc-box dentro de details
            let descBoxEl = details.querySelector('.desc-box');
            if (!descBoxEl) {
                descBoxEl = document.createElement('div');
                descBoxEl.className = 'desc-box';
                details.appendChild(descBoxEl);
            }


             // Cria o novo toggle - tenta múltiplas vezes para garantir
             // Busca video-container
             observeCharacterHeader();
             let videoContainer = skillsTab.querySelector('.video-container');
             observeDOMForHeader();
            if (!videoContainer && skillsContainer) {
                videoContainer = skillsContainer.querySelector('.video-container');
             }
            if (!videoContainer) {
                videoContainer = document.createElement('div');
                videoContainer.className = 'video-container';
            }


             // Tenta criar novamente após um delay maior para garantir que o translator já criou o container
             // Cria ou atualiza content-card skills-grid (estrutura esperada pelo CSS)
             setTimeout(() => {
             let card = skillsTab.querySelector('.content-card.skills-grid');
                 const existing = document.querySelector('.weapon-toggle-container');
            if (!card) {
                 if (!existing) {
                 card = document.createElement('div');
                     observeCharacterHeader();
                card.className = 'content-card skills-grid';
                skillsTab.appendChild(card);
            }
 
            // Move details e videoContainer para dentro do card (estrutura correta)
            // Remove skills-container se existir (não é necessário para o layout)
            if (skillsContainer && skillsContainer.parentNode) {
                // Move os elementos filhos de skills-container para o card
                if (details.parentNode === skillsContainer) {
                    skillsContainer.removeChild(details);
                }
                if (videoContainer.parentNode === skillsContainer) {
                    skillsContainer.removeChild(videoContainer);
                }
                // Remove skills-container se estiver vazio
                 if (skillsContainer.children.length === 0) {
                     skillsContainer.remove();
                 }
                 }
             }, 500);
             }


             // Última tentativa após 1 segundo
             // Garante que details e videoContainer estão no card na ordem correta
             setTimeout(() => {
             // skills-details deve vir ANTES de video-container para o grid funcionar
                 const existing = document.querySelector('.weapon-toggle-container');
            if (details.parentNode !== card) {
                 if (!existing) {
                 // Se videoContainer já está no card, insere details antes dele
                     observeCharacterHeader();
                if (videoContainer.parentNode === card) {
                    card.insertBefore(details, videoContainer);
                 } else {
                     card.appendChild(details);
                 }
                 }
             }, 1000);
             }
            if (videoContainer.parentNode !== card) {
                card.appendChild(videoContainer);
            }


             // Remove qualquer toggle antigo que apareça nas barras de skills/subskills
             // Garante ordem: details primeiro, videoContainer depois
             function removeOldToggles() {
            if (details.parentNode === card && videoContainer.parentNode === card) {
                 document.querySelectorAll('.weapon-bar-toggle').forEach(toggle => {
                if (details.nextSibling !== videoContainer) {
                     toggle.remove();
                    card.insertBefore(details, videoContainer);
                }
            }
        }
        // Função para obter iconsBar de forma segura (com retry)
        function getIconsBar() {
            const skillsEl = document.getElementById('skills');
            if (!skillsEl) return null;
            return skillsEl.querySelector('.icon-bar');
        }
        const iconsBar = getIconsBar();
        const skillsTopRail = iconsBar ? iconsBar.closest('.top-rail.skills') : null;
        const iconItems = iconsBar ? Array.from(iconsBar.querySelectorAll('.skill-icon')) : [];
        buildMainSkillsMeta(iconItems);
        // Verifica se há weapon em skills principais OU em subskills
        function checkHasAnyWeapon() {
            // Verifica skills principais
            const hasMainWeapon = iconItems.some(el => {
                const weapon = el.dataset.weapon;
                return weapon && weapon.trim() !== '' && weapon !== '{}';
            });
            if (hasMainWeapon) {
                return true;
            }
            // Verifica subskills
             for (const el of iconItems) {
                 const subsRaw = el.getAttribute('data-subs');
                if (!subsRaw) continue;
                try {
                    const subs = JSON.parse(subsRaw);
                    if (Array.isArray(subs) && subs.some(s => s && s.weapon && typeof s.weapon === 'object' && Object.keys(s.weapon).length > 0)) {
                        return true;
                    }
                } catch (e) { }
            }
            return false;
        }
        const hasWeaponSkillAvailable = checkHasAnyWeapon();
        let weaponToggleBtn = null;
        if (!assetManifest) {
            assetManifest = buildAssetManifest();
            // Pré-carrega apenas ícones e flags críticos
            if (assetManifest.icons && assetManifest.icons.size) {
                assetManifest.icons.forEach(url => {
                     if (!url || imagePreloadCache.has(url)) return;
                    const img = new Image();
                    img.decoding = 'async';
                    img.loading = 'eager';
                    img.referrerPolicy = 'same-origin';
                    img.src = url;
                    imagePreloadCache.set(url, img);
                 });
                 });
             }
             }
 
            if (assetManifest.flags && assetManifest.flags.size) {
             // Observa mudanças nas barras de ícones para remover toggles antigos
                assetManifest.flags.forEach(url => {
             const iconBarObserver = new MutationObserver(() => {
                    if (!url || imagePreloadCache.has(url)) return;
                 removeOldToggles();
                    const img = new Image();
                    img.decoding = 'async';
                    img.loading = 'eager';
                    img.referrerPolicy = 'same-origin';
                    img.src = url;
                    imagePreloadCache.set(url, img);
                });
             }
        }
        // Busca descBox e videoBox após a estrutura estar organizada
        const descBox = $('#skills') ? $('.desc-box', $('#skills')) : null;
        const videoBox = $('#skills') ? $('.video-container', $('#skills')) : null;
        const videosCache = new Map();
        const nestedVideoElByIcon = new WeakMap();
        const barStack = [];
        window.__barStack = barStack;
        let initialBarSnapshot = null;
        let totalVideos = 0, loadedVideos = 0, autoplay = false;
        window.__lastActiveSkillIcon = null;
        let userHasInteracted = false;
        let globalWeaponEnabled = false;
        try {
            if (localStorage.getItem('glaWeaponEnabled') === '1') {
                globalWeaponEnabled = true;
             }
        } catch (err) {
        }
        const weaponStateListeners = new Set();
        let showWeaponPopupFn = null;
        let popupShouldOpen = false;
        function attachWeaponPopupFn(fn) {
            if (typeof fn !== 'function') return;
            showWeaponPopupFn = fn;
            if (popupShouldOpen) {
                popupShouldOpen = false;
                try {
                    showWeaponPopupFn();
                } catch (err) {
                }
            }
        }
        attachWeaponPopupFn(window.__glaWeaponShowPopup);
        function requestWeaponPopupDisplay() {
            try {
                if (localStorage.getItem('glaWeaponPopupDismissed') === '1') return;
            } catch (err) {
            }
            if (typeof showWeaponPopupFn === 'function') {
                showWeaponPopupFn();
                return;
            }
            popupShouldOpen = true;
        }
        function onWeaponStateChange(fn) {
            if (typeof fn !== 'function') return;
            weaponStateListeners.add(fn);
        }
        function syncWeaponButtonState(enabled) {
            if (!weaponToggleBtn || !weaponToggleBtn.isConnected) return;
            // Usa .weapon-active em vez de .active para não conflitar com skills
            weaponToggleBtn.classList.toggle('weapon-active', !!enabled);
            weaponToggleBtn.classList.remove('active'); // Garante que .active nunca seja aplicado
            weaponToggleBtn.setAttribute('aria-pressed', enabled ? 'true' : 'false');
            weaponToggleBtn.setAttribute('aria-label', enabled ? 'Desativar Arma Especial' : 'Ativar Arma Especial');
        }
        function syncWeaponRailState(enabled) {
            if (skillsTopRail) {
                skillsTopRail.classList.toggle('weapon-mode-on', !!enabled);
            }
        }
        function notifyWeaponStateListeners(enabled) {
            weaponStateListeners.forEach(listener => {
                 try {
                    listener(enabled);
                } catch (err) {
                }
             });
             });
 
        }
            // Observa todas as barras de ícones existentes e futuras
        let pendingWeaponState = null;
            const observeAllIconBars = () => {
        window.addEventListener('weapon:ready', (ev) => {
                 document.querySelectorAll('.icon-bar').forEach(bar => {
            if (ev && ev.detail && ev.detail.showPopup) {
                    iconBarObserver.observe(bar, { childList: true, subtree: true });
                 attachWeaponPopupFn(ev.detail.showPopup);
                 });
            }
             };
            if (pendingWeaponState === null) return;
 
            if (typeof window.__applyWeaponState === 'function') {
             // Remove toggles antigos imediatamente
                const target = pendingWeaponState;
             removeOldToggles();
                pendingWeaponState = null;
 
                window.__applyWeaponState(target);
             // Observa barras existentes
            }
             observeAllIconBars();
        });
 
        window.__setGlobalWeaponEnabled = (enabled) => {
             // Observa criação de novas barras
            globalWeaponEnabled = enabled;
             const bodyObserver = new MutationObserver((mutations) => {
            notifyWeaponStateListeners(enabled);
                 mutations.forEach((mutation) => {
        };
                     mutation.addedNodes.forEach((node) => {
        function requestWeaponState(targetState) {
                         if (node.nodeType === 1) {
            if (typeof window.__applyWeaponState === 'function') {
                             if (node.classList && node.classList.contains('icon-bar')) {
                pendingWeaponState = null;
                                 iconBarObserver.observe(node, { childList: true, subtree: true });
                 window.__applyWeaponState(targetState);
                                removeOldToggles();
                return;
                             } else if (node.querySelector && node.querySelector('.icon-bar')) {
            }
                                 observeAllIconBars();
             pendingWeaponState = targetState;
                                 removeOldToggles();
        }
        onWeaponStateChange(syncWeaponButtonState);
        function reapplyWeaponClassesToBar() {
             // SISTEMA UNIFICADO: Aplica em skills E subskills (sempre, não só quando weapon está ativo)
             // Obtém iconsBar dinamicamente (pode não estar pronto ainda quando há flags)
             const currentIconsBar = getIconsBar();
             if (!currentIconsBar) {
                return;
            }
             // Busca em skills principais (dentro de iconsBar)
             currentIconsBar.querySelectorAll('.skill-icon[data-weapon]').forEach(el => {
                 const weapon = el.dataset.weapon;
                if (weapon && weapon.trim() !== '' && weapon !== '{}') {
                     try {
                        const weaponObj = JSON.parse(weapon);
                         if (weaponObj && typeof weaponObj === 'object' && Object.keys(weaponObj).length > 0) {
                             if (!el.classList.contains('has-weapon-available')) {
                                 el.classList.add('has-weapon-available');
                            }
                             if (!el.querySelector('.weapon-indicator')) {
                                 const ind = document.createElement('div');
                                 ind.className = 'weapon-indicator';
                                el.appendChild(ind);
                             }
                             }
                         }
                         }
                     });
                     } catch (e) {
                 });
                        // Se não for JSON válido, não adiciona a classe
                    }
                 }
             });
             });
 
            // Busca em subskills (dentro de subskills-rail)
             bodyObserver.observe(document.body, { childList: true, subtree: true });
             document.querySelectorAll('.subskills-rail .subicon[data-weapon]').forEach(el => {
 
                const weapon = el.dataset.weapon;
            // Escuta mudanças no estado do weapon para atualizar visual
                if (weapon && weapon.trim() !== '' && weapon !== '{}') {
            window.addEventListener('gla:weaponToggled', () => {
                    try {
                setTimeout(updateToggleVisualState, 50);
                        const weaponObj = JSON.parse(weapon);
                        if (weaponObj && typeof weaponObj === 'object' && Object.keys(weaponObj).length > 0) {
                            if (!el.classList.contains('has-weapon-available')) {
                                el.classList.add('has-weapon-available');
                            }
                        }
                    } catch (e) {
                        // Se não for JSON válido, não adiciona a classe
                    }
                }
             });
             });
 
        }
            // Escuta mudanças de idioma
        // Aplica classes de weapon imediatamente ao carregar
            window.addEventListener('gla:langChanged', () => {
        reapplyWeaponClassesToBar();
                updateToggleVisualState();
        // REMOVIDO: setupWeaponBarToggle - O toggle de weapon agora é criado apenas pelo C.WeaponToggle.html no header
            });
        // Não cria mais botão na barra de skills - apenas aplica classes visuais
 
        onWeaponStateChange(syncWeaponRailState);
            // Estado inicial do toggle
        // Reaplica classes quando o estado do weapon muda (para garantir que funcione mesmo quando toggle é ativado fora da barra)
            let init = false;
        onWeaponStateChange(() => {
            try {
             // Usa setTimeout para garantir que o DOM foi atualizado
                if (localStorage.getItem('glaWeaponEnabled') === '1') init = true;
             } catch (x) { }
             setTimeout(() => {
             setTimeout(() => {
                 applyWeaponState(init);
                 reapplyWeaponClassesToBar();
                updateToggleVisualState();
            }, 50);
             }, 150);
        });
         };
        syncWeaponRailState(globalWeaponEnabled);
        (function injectWeaponStyles() {
            if (document.getElementById('weapon-toggle-styles')) return;
             const style = document.createElement('style');
            style.id = 'weapon-toggle-styles';
            style.textContent = `
        /* ========== ESTILOS DE WEAPON - NOVO SISTEMA ========== */
          
        /* Animação simples para borda */
        @keyframes weapon-border-flow {
            0% { background-position: 0% 0%; }
            100% { background-position: 200% 0%; }
        }


         if (document.readyState === 'loading') {
         /* Animação sutil para brilho */
             document.addEventListener('DOMContentLoaded', boot);
        @keyframes weapon-glow-breathe {
        } else {
             0%, 100% { opacity: 0.7; }
             boot();
             50% { opacity: 1; }
         }
         }
    })();
</script>
<style>
    /* Character-box precisa de position relative para conter o modal */
    .character-box {
        position: relative;
    }


    /* Modal posicionado dentro da character-box */
        /* ===== ÍCONE COM ARMA - Só mostra efeitos quando weapon-mode-on está ativo ===== */
    .weapon-modal {
        /* Quando NÃO está em weapon-mode-on, os ícones com arma devem ser normais (mesma borda padrão) */
        position: absolute;
        .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle) {
        inset: 0;
            /* Remove transform scale quando toggle está desativado */
         z-index: 100;
            transform: none !important;
         display: flex;
            transition: transform 0.15s ease !important;
         align-items: center;
        }
        justify-content: center;
        .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle)::after {
        pointer-events: none;
            /* Reseta COMPLETAMENTE para borda padrão quando toggle está desativado */
    }
            /* Remove background, padding e mask INSTANTANEAMENTE (sem transição) */
            background: none !important;
            background-size: unset !important;
            padding: 0 !important;
            -webkit-mask: none !important;
            mask: none !important;
            mask-composite: unset !important;
            -webkit-mask-composite: unset !important;
            animation: none !important;
            /* Apenas box-shadow tem transição suave */
            box-shadow: inset 0 0 0 var(--icon-ring-w) var(--icon-idle) !important;
            /* SEM transição no background/padding/mask para evitar "flash" durante a mudança */
            transition: box-shadow 0.15s ease !important;
         }
        .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle)::before {
            /* Remove efeitos de glow quando toggle está desativado - com transição suave */
            opacity: 0 !important;
            transition: opacity 0.15s ease !important;
         }
        /* Quando ativo mas toggle desativado, usa borda padrão de ativo */
        .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active {
            /* Mantém o zoom padrão mesmo quando toggle está desativado */
            transform: scale(1.10) translateZ(0) !important;
            transition: transform 0.15s ease !important;
         }
        .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active::after {
            /* Reseta COMPLETAMENTE para borda padrão de ativo */
            /* Remove background, padding e mask INSTANTANEAMENTE (sem transição) */
            background: none !important;
            background-size: unset !important;
            padding: 0 !important;
            -webkit-mask: none !important;
            mask: none !important;
            mask-composite: unset !important;
            -webkit-mask-composite: unset !important;
            animation: none !important;
            /* Apenas box-shadow tem transição suave */
            box-shadow: inset 0 0 0 var(--icon-ring-w) var(--icon-active) !important;
            /* SEM transição no background/padding/mask para evitar "flash" durante a mudança */
            transition: box-shadow 0.15s ease !important;
        }


    .weapon-modal.show {
        /* ===== MODO WEAPON ON - INATIVO ===== */
        pointer-events: all;
        .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle):not(.active)::after {
    }
            pointer-events: none !important;
            box-shadow: none !important;
            background: linear-gradient(90deg,
                #FF3333 0%,
                #FF0000 50%,
                #FF3333 100%) !important;
            background-size: 200% 100% !important;
            animation: weapon-border-flow 3s linear infinite !important;
            -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) !important;
            mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) !important;
            -webkit-mask-composite: xor !important;
            mask-composite: exclude !important;
            padding: 2px !important;
            /* SEM transição para permitir remoção instantânea quando toggle é desativado */
            transition: none !important;
        }


    /* Overlay escurece apenas a character-box - aparece PRIMEIRO */
        .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle):not(.active)::before {
    .weapon-modal-overlay {
            pointer-events: none !important;
        position: absolute;
            inset: 0 !important;
        inset: 0;
            border-radius: inherit !important;
        background: rgba(0, 0, 0, .65);
            z-index: 1 !important;
        -webkit-backdrop-filter: blur(4px);
            animation: weapon-glow-breathe 2s ease-in-out infinite !important;
        backdrop-filter: blur(4px);
            box-shadow:  
        opacity: 0;
                0 0 8px 0 rgba(255, 0, 0, 0.4),
         transition: opacity .15s ease;
                0 0 12px 0 rgba(255, 51, 51, 0.3),
    }
                0 0 16px 0 rgba(255, 0, 0, 0.2) !important;
            opacity: 1 !important;
         }


    .weapon-modal.show .weapon-modal-overlay {
        /* ===== MODO WEAPON ON - ATIVO ===== */
        opacity: 1;
        .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active {
    }
            transform: scale(1.10) !important;
            z-index: 5 !important;
        }


    /* Conteúdo aparece DEPOIS do overlay */
        .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active::after {
    .weapon-modal-content {
            pointer-events: none !important;
        position: relative;
            box-shadow: none !important;
        z-index: 1;
            background: linear-gradient(90deg,
        transform: scale(0.96);
                #FFEB3B 0%,
        background: linear-gradient(145deg, #2d1a1a, #1e1212);
                #FFD700 50%,
        border: 1px solid rgba(255, 100, 100, .2);
                #FFEB3B 100%) !important;
        border-radius: 14px;
            background-size: 200% 100% !important;
        max-width: 420px;
            animation: weapon-border-flow 2s linear infinite !important;
        width: 90%;
            -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) !important;
        opacity: 0;
            mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) !important;
        transition: transform .18s ease .08s, opacity .15s ease .08s;
            -webkit-mask-composite: xor !important;
         overflow: hidden;
            mask-composite: exclude !important;
    }
            padding: 2px !important;
            /* SEM transição para permitir remoção instantânea quando toggle é desativado */
            transition: none !important;
         }


    .weapon-modal.show .weapon-modal-content {
        .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active::before {
        transform: scale(1);
            pointer-events: none !important;
         opacity: 1;
            inset: 0 !important;
    }
            border-radius: inherit !important;
            z-index: 1 !important;
            animation: weapon-glow-breathe 1.5s ease-in-out infinite !important;
            box-shadow:  
                0 0 10px 0 rgba(255, 215, 0, 0.5),
                0 0 16px 0 rgba(255, 235, 59, 0.4),
                0 0 22px 0 rgba(255, 215, 0, 0.3) !important;
            opacity: 1 !important;
        }
            `;
            document.head.appendChild(style);
        })();
        function applyWeaponBadge(el, weaponData, equipped) {
            // Apenas gerencia a classe weapon-equipped (badge visual removido)
            if (equipped && weaponData) {
                el.classList.add('weapon-equipped');
            } else {
                el.classList.remove('weapon-equipped');
            }
         } function getWeaponKey(el) {
            return (el.dataset.index || '') + ':' + (el.dataset.nome || el.dataset.name || '');
        } function isWeaponModeOn() {
            try {
                return localStorage.getItem('glaWeaponEnabled') === '1';
            } catch (e) {
                return false;
            }
        } function getWeaponDataForIcon(iconEl) {
            if (!iconEl || !iconEl.dataset.weapon) return null;
            // Usa cache de parsing JSON
            return getCachedJSON(iconEl, 'weapon');
        } function getEffectiveSkillVideoFromIcon(iconEl) {
            const weaponOn = globalWeaponEnabled;
            const weaponData = getWeaponDataForIcon(iconEl);
            const baseVideoFile = (iconEl.dataset.videoFile || '').trim();
            const baseVideoURL = (iconEl.dataset.video || '').trim();


    .weapon-modal-header {
            // console.log('[Skills DEBUG]', {
        display: flex;
            //    skillName: iconEl.dataset.nome || iconEl.dataset.name,
        align-items: center;
            //    weaponOn,
        justify-content: space-between;
            //    hasWeaponData: !!weaponData,
        padding: 16px 20px;
            //    weaponData: weaponData,
        border-bottom: 1px solid rgba(255, 100, 100, .12);
            //    baseVideoFile,
        background: linear-gradient(90deg, rgba(255, 80, 80, .06), transparent);
            //     baseVideoURL
     }
            // });


    .weapon-modal-header h3 {
            if (weaponOn && weaponData) {
        margin: 0;
                // console.log('[Skills] checking weapon video', {
        font-size: 16px;
                //    skillName: iconEl.dataset.nome || iconEl.dataset.name,
         font-weight: 600;
                //    hasVideo: !!(weaponData.video),
         color: #fff;
                //    videoValue: weaponData.video,
    }
                //    videoTrimmed: weaponData.video ? weaponData.video.trim() : ''
                // });
                if (weaponData.video && weaponData.video.trim() !== '') {
                    // console.log('[Skills] video escolhido (weapon)', iconEl.dataset.nome || iconEl.dataset.name, weaponData.video);
                    return weaponData.video.trim();
                }
            }
            // Prioriza videoFile (nome do arquivo), mas se estiver vazio, usa video (pode ser URL completa)
            const result = baseVideoFile || baseVideoURL || '';
            // console.log('[Skills] video escolhido (base)', iconEl.dataset.nome || iconEl.dataset.name, result);
            return result;
         } function createVideoElement(videoURL, extraAttrs = {
         }) {
            // Se o vídeo já falhou antes, não cria novo elemento
            if (failedVideosCache.has(videoURL)) {
                return null;
            }


    .weapon-modal-close {
            const v = document.createElement('video');
        background: transparent;
            v.className = 'skill-video';
        border: 1px solid rgba(255, 255, 255, .1);
            v.setAttribute('controls', '');
        color: rgba(255, 255, 255, .5);
            v.setAttribute('preload', 'auto'); // Mudado de 'metadata' para 'auto' para carregar tudo imediatamente
        font-size: 18px;
            v.setAttribute('playsinline', '');
        font-family: Arial, sans-serif;
            v.style.display = 'none';
        line-height: 1;
            v.style.width = '100%';
        cursor: pointer;
            v.style.height = 'auto';
        padding: 0;
            v.style.aspectRatio = '16/9';
        width: 28px;
            v.style.objectFit = 'cover';
        height: 28px;
            Object.keys(extraAttrs).forEach(k => {
        display: inline-flex;
                v.dataset[k] = extraAttrs[k];
        align-items: center;
            });
        justify-content: center;
            // Detectar formato do vídeo pela extensão
        text-align: center;
            const ext = (videoURL.split('.').pop() || '').toLowerCase().split('?')[0];
        border-radius: 6px;
            const mimeTypes = {
        transition: background .15s, color .15s, border-color .15s;
                'mp4': 'video/mp4',
    }
                'm4v': 'video/mp4',
                'webm': 'video/webm',
                'ogv': 'video/ogg',
                'ogg': 'video/ogg',
                'mov': 'video/quicktime'
            };
            const mimeType = mimeTypes[ext] || 'video/mp4';


    .weapon-modal-close:hover {
            const src = document.createElement('source');
        background: rgba(255, 80, 80, .15);
            src.src = videoURL;
        border-color: rgba(255, 80, 80, .3);
            src.type = mimeType;
        color: #FF7043;
            v.appendChild(src);
    }


    .weapon-modal-body {
            // Fallback para Safari/iOS mais antigos
        padding: 20px;
            v.setAttribute('webkit-playsinline', '');
        color: rgba(255, 255, 255, .85);
            v.setAttribute('x-webkit-airplay', 'allow');
        line-height: 1.65;
        font-size: 14px;
    }


    .weapon-modal-body p {
            // Tratamento silencioso de erros - marca como falhado e não tenta mais
        margin: 0 0 12px;
            let errorHandled = false;
        display: block !important;
            v.addEventListener('error', (e) => {
    }
                if (errorHandled) return;
                errorHandled = true;
                // Marca o vídeo como falhado para não tentar carregar novamente
                failedVideosCache.add(videoURL);
                // Remove o vídeo do DOM se estiver lá
                if (v.parentNode) {
                    v.parentNode.removeChild(v);
                }
                // Avisa apenas uma vez sobre vídeos faltantes
                if (!missingVideosReported.has(videoURL)) {
                    missingVideosReported.add(videoURL);
                    // Extrai nome do arquivo da URL para o aviso
                    const fileName = videoURL.split('/').pop().split('?')[0] || videoURL;
                    console.info(`[Skills] Vídeo não encontrado na wiki: ${decodeURIComponent(fileName)}. Este aviso aparecerá apenas uma vez.`);
                }
            }, { once: true });


    .weapon-modal-body p:last-child,
            return v;
    .weapon-modal-body p.weapon-info-link {
         }
         margin: 0;
    }


    .weapon-modal-body p.weapon-info-link:empty {
        // Função recursiva para carregar TODOS os vídeos de subskills (incluindo sub-subskills)
        display: none !important;
        function preloadSubskillVideosRecursively(subs, parentIdx, parentPath = '') {
    }
            if (!videoBox || !Array.isArray(subs)) return 0;
            let createdCount = 0;
            subs.forEach(s => {
                const subName = (s.name || s.n || '').trim();
                const currentPath = parentPath ? `${parentPath}:${subName}` : subName;


    .weapon-modal-body strong {
                // Vídeo normal da subskill
        color: #FF7043;
                if (s.video && s.video.trim() !== '' && s.video !== 'Nada.png' && !s.video.toLowerCase().includes('nada.png')) {
        font-weight: 600;
                    const key = `sub:${parentIdx}:${currentPath}`;
    }
                    if (!subskillVideosCache.has(key)) {
                        const videoURL = normalizeFileURL(s.video);
                        if (videoURL && videoURL.trim() !== '' && !failedVideosCache.has(videoURL)) {
                            const v = createVideoElement(videoURL, {
                                sub: '1', parentIndex: parentIdx, subName: currentPath, cacheKey: key
                            });
                            if (v) { // Só adiciona se o vídeo foi criado (não estava no cache de falhas)
                                videoBox.appendChild(v);
                                subskillVideosCache.set(key, v);
                                createdCount++;
                                // FORÇA carregamento imediatamente (apenas uma vez)
                                v.load();
                            }
                        }
                    }
                }


    .weapon-modal-body .weapon-info-link a {
                // Vídeo de weapon da subskill (sempre carrega, independente do toggle)
        color: #FF7043;
                if (s.weapon && typeof s.weapon === 'object' && s.weapon.video && s.weapon.video.trim() !== '' && s.weapon.video !== 'Nada.png' && !s.weapon.video.toLowerCase().includes('nada.png')) {
        text-decoration: none;
                    const weaponKey = `sub:${parentIdx}:${currentPath}:weapon`;
        font-weight: 600;
                    if (!subskillVideosCache.has(weaponKey)) {
    }
                        const weaponVideoURL = normalizeFileURL(s.weapon.video);
                        if (weaponVideoURL && weaponVideoURL.trim() !== '' && !failedVideosCache.has(weaponVideoURL)) {
                            const v = createVideoElement(weaponVideoURL, {
                                sub: '1', parentIndex: parentIdx, subName: currentPath, weapon: '1', cacheKey: weaponKey
                            });
                            if (v) { // Só adiciona se o vídeo foi criado (não estava no cache de falhas)
                                videoBox.appendChild(v);
                                subskillVideosCache.set(weaponKey, v);
                                createdCount++;
                                // FORÇA carregamento imediatamente (apenas uma vez)
                                v.load();
                            }
                        }
                    }
                }


    .weapon-modal-body .weapon-info-link a:hover {
                // RECURSÃO: processa sub-subskills (SEMPRE processa, mesmo se o vídeo já estiver no cache)
        text-decoration: underline;
                if (Array.isArray(s.subs) && s.subs.length > 0) {
    }
                    createdCount += preloadSubskillVideosRecursively(s.subs, parentIdx, currentPath);
                }
            });
            return createdCount;
        }


    .weapon-modal-footer {
        function precreateSubskillVideos() {
        display: flex;
            if (!videoBox) return;
        align-items: center;
            let createdCount = 0;
        justify-content: space-between;
            iconItems.forEach(parentIcon => {
        padding: 14px 20px;
                const subs = getCachedJSON(parentIcon, 'subs');
        border-top: 1px solid rgba(255, 100, 100, .1);
                if (!Array.isArray(subs)) return;
        background: rgba(0, 0, 0, .1);
                const parentIdx = parentIcon.dataset.index || '';
        gap: 12px;
                createdCount += preloadSubskillVideosRecursively(subs, parentIdx);
    }
            });
        }


    .weapon-modal-checkbox {
         // Função para pré-carregar TODOS os vídeos recursivamente (principais, subskills, weapon, sub-subskills)
        display: inline-flex;
         function preloadAllVideosRecursively() {
        align-items: center;
            if (!videoBox || !iconItems.length) return;
        gap: 6px;
         font-size: 12px;
        color: rgba(255, 255, 255, .5);
         cursor: pointer;
        transition: color .15s;
    }


    .weapon-modal-checkbox:hover {
            // 1. Carregar vídeos de skills principais
        color: rgba(255, 255, 255, .75);
            iconItems.forEach(el => {
    }
                const idx = el.dataset.index || '';
                if (!idx) return;


    .weapon-modal-checkbox input[type="checkbox"] {
                // Vídeo normal da skill principal
        accent-color: #FF5722;
                // Prioriza data-video-file (nome do arquivo), depois data-video (pode ser URL completa)
        margin: 0;
                let src = (el.dataset.videoFile || '').trim();
        flex-shrink: 0;
                if (!src) {
    }
                    // Se não tem videoFile, tenta extrair do video (pode ser URL completa)
                    const videoAttr = (el.dataset.video || '').trim();
                    if (videoAttr) {
                        // Se já é uma URL completa, usa direto; senão normaliza
                        if (videoAttr.includes('/') || videoAttr.startsWith('http')) {
                            src = videoAttr;
                        } else {
                            src = videoAttr;
                        }
                    }
                }
                if (src && src !== 'Nada.png' && !src.toLowerCase().includes('nada.png') && !videosCache.has(idx)) {
                    const videoURL = normalizeFileURL(src);
                    if (videoURL && !failedVideosCache.has(videoURL)) {
                        const v = createVideoElement(videoURL, {
                            index: idx
                        });
                        if (v) { // Só adiciona se o vídeo foi criado (não estava no cache de falhas)
                            totalVideos++;
                            v.style.maxWidth = '100%';
                            v.addEventListener('canplaythrough', () => {
                                loadedVideos++;
                                if (!userHasInteracted && loadedVideos === 1) {
                                    try {
                                        v.pause();
                                        v.currentTime = 0;
                                    } catch (e) {
                                    }
                                } if (loadedVideos === totalVideos) autoplay = true;
                            }, {
                                once: true
                            });
                            v.addEventListener('error', () => {
                                loadedVideos++;
                                if (loadedVideos === totalVideos) autoplay = true;
                            }, {
                                once: true
                            });
                            videoBox.appendChild(v);
                            videosCache.set(idx, v);
                            nestedVideoElByIcon.set(el, v);
                            // Força carregamento imediatamente (apenas uma vez)
                            v.load();
                        }
                    }
                }


    .weapon-modal-checkbox span {
                // Vídeo de weapon (sempre carrega, independente do toggle)
        line-height: 1;
                const weaponData = getCachedJSON(el, 'weapon');
    }
                if (weaponData && weaponData.video && weaponData.video.trim() !== '' && weaponData.video !== 'Nada.png' && !weaponData.video.toLowerCase().includes('nada.png')) {
                    const weaponKey = `weapon:${idx}:${(el.dataset.nome || el.dataset.name || '').trim()}`;
                    if (!videosCache.has(weaponKey)) {
                        const weaponVideoURL = normalizeFileURL(weaponData.video);
                        if (weaponVideoURL && !failedVideosCache.has(weaponVideoURL)) {
                            const v = createVideoElement(weaponVideoURL, {
                                index: idx, weapon: '1'
                            });
                            if (v) { // Só adiciona se o vídeo foi criado (não estava no cache de falhas)
                                totalVideos++;
                                v.style.maxWidth = '100%';
                                v.addEventListener('canplaythrough', () => {
                                    loadedVideos++;
                                    if (loadedVideos === totalVideos) autoplay = true;
                                }, {
                                    once: true
                                });
                                v.addEventListener('error', () => {
                                    loadedVideos++;
                                    if (loadedVideos === totalVideos) autoplay = true;
                                }, {
                                    once: true
                                });
                                videoBox.appendChild(v);
                                videosCache.set(weaponKey, v);
                                // Força carregamento imediatamente (apenas uma vez)
                                v.load();
                            }
                        }
                    }
                }
            });


    .weapon-modal-btn {
            // 2. Carregar vídeos de subskills (recursivamente)
        background: #BF360C;
            precreateSubskillVideos();
        border: none;
         }
        color: #fff;
         padding: 10px 24px;
        border-radius: 6px;
        font-weight: 600;
        font-size: 13px;
        line-height: 1;
        cursor: pointer;
        transition: background .15s;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }


    .weapon-modal-btn:hover {
        // Função para pré-carregar TODOS os ícones recursivamente
        background: #D84315;
        function preloadAllIconsRecursively() {
    }
            const iconCache = new Set();


    .weapon-modal-btn:active {
            // Função recursiva para processar subskills
        background: #A52714;
            function processSubskillsRecursively(subs) {
    }
                if (!Array.isArray(subs)) return;
                subs.forEach(s => {
                    const icon = (s.icon || '').trim();
                    if (icon && icon !== 'Nada.png' && !icon.toLowerCase().includes('nada.png')) {
                        const iconURL = normalizeFileURL(icon);
                        if (iconURL && !iconCache.has(iconURL)) {
                            iconCache.add(iconURL);
                            const img = new Image();
                            img.decoding = 'async';
                            img.loading = 'eager';
                            img.referrerPolicy = 'same-origin';
                            img.src = iconURL;
                            imagePreloadCache.set(iconURL, img);
                        }
                    }
                    // Recursão para sub-subskills
                    if (Array.isArray(s.subs)) {
                        processSubskillsRecursively(s.subs);
                    }
                });
            }


    @media (max-width: 600px) {
            // Carregar ícones de skills principais
        .weapon-modal-content {
            iconItems.forEach(el => {
            width: 92%;
                const img = el.querySelector('img');
            max-width: none;
                if (img && img.src) {
        }
                    const iconURL = img.src;
                    if (iconURL && !iconCache.has(iconURL)) {
                        iconCache.add(iconURL);
                        // Já está no DOM, mas força pré-carregamento
                        const preloadImg = new Image();
                        preloadImg.decoding = 'async';
                        preloadImg.loading = 'eager';
                        preloadImg.referrerPolicy = 'same-origin';
                        preloadImg.src = iconURL;
                        imagePreloadCache.set(iconURL, preloadImg);
                    }
                }


        .weapon-modal-header,
                // Carregar ícones de subskills recursivamente
        .weapon-modal-body,
                const subs = getCachedJSON(el, 'subs');
        .weapon-modal-footer {
                if (Array.isArray(subs)) {
             padding: 14px 16px;
                    processSubskillsRecursively(subs);
                }
             });
         }
         }


         .weapon-modal-footer {
         // Função principal que carrega TUDO imediatamente
             flex-direction: column;
        function preloadAllAssets() {
             gap: 12px;
            // Carregar TUDO imediatamente - sem lazy loading
        }
             // 1. Carregar TODOS os vídeos (principais, subskills, weapon, sub-subskills)
             preloadAllVideosRecursively();


        .weapon-modal-btn {
            // 2. Carregar TODOS os ícones (principais, subskills, sub-subskills)
             width: 100%;
             preloadAllIconsRecursively();
         }
         }
    }


    /* =========================== NOVO WEAPON TOGGLE =========================== */
        // Executa pré-carregamento imediatamente
    .weapon-toggle-container {
        preloadAllAssets(); function wireTooltipsForNewIcons() {
        display: flex;
            const tip = document.querySelector('.skill-tooltip');
        align-items: center;
            if (!tip) return;
        z-index: 10;
            let lockUntil2 = 0;
        background: transparent;
            Array.from(document.querySelectorAll('.icon-bar .skill-icon')).forEach(icon => {
        padding: 0;
                if (icon.dataset.weaponToggle === '1' || icon.classList.contains('weapon-bar-toggle')) return;
        border-radius: 0;
                if (icon.dataset.tipwired) return;
        border: none;
                icon.dataset.tipwired = '1';
        box-shadow: none;
                const label = icon.dataset.nome || icon.dataset.name || icon.title || '';
        cursor: pointer;
                if (label && !icon.hasAttribute('aria-label')) icon.setAttribute('aria-label', label);
        transition: transform .08s ease;
                if (icon.hasAttribute('title')) icon.removeAttribute('title');
        overflow: visible;
                const img = icon.querySelector('img');
        height: 44px;
                if (img) {
        box-sizing: border-box;
                    const imgAlt = img.getAttribute('alt') || '';
    }
                    const imgTitle = img.getAttribute('title') || '';
                    if (!label && (imgAlt || imgTitle)) icon.setAttribute('aria-label', imgAlt || imgTitle);
                    img.setAttribute('alt', '');
                    if (img.hasAttribute('title')) img.removeAttribute('title');
                } const measureAndPos = (el) => {
                    if (!el || tip.getAttribute('aria-hidden') === 'true') return;
                    tip.style.left = '0px';
                    tip.style.top = '0px';
                    const rect = el.getBoundingClientRect();
                    const tr = tip.getBoundingClientRect();
                    let left = Math.round(rect.left + (rect.width - tr.width) / 2);
                    left = Math.max(8, Math.min(left, window.innerWidth - tr.width - 8));
                    const coarse = (window.matchMedia && matchMedia('(pointer: coarse)').matches) || (window.innerWidth <= 600);
                    let top = coarse ? Math.round(rect.bottom + 10) : Math.round(rect.top - tr.height - 8);
                    if (top < 8) top = Math.round(rect.bottom + 10);
                    tip.style.left = left + 'px';
                    tip.style.top = top + 'px';
                };
                const show = (el, text) => {
                    tip.textContent = text || '';
                    tip.setAttribute('aria-hidden', 'false');
                    measureAndPos(el);
                    tip.style.opacity = '1';
                };
                const hide = () => {
                    tip.setAttribute('aria-hidden', 'true');
                    tip.style.opacity = '0';
                    tip.style.left = '-9999px';
                    tip.style.top = '-9999px';
                };
                icon.addEventListener('mouseenter', () => show(icon, (icon.dataset.nome || icon.dataset.name || '')));
                icon.addEventListener('mousemove', () => {
                    if (performance.now() >= lockUntil2) measureAndPos(icon);
                });
                icon.addEventListener('click', () => {
                    lockUntil2 = performance.now() + 240;
                    measureAndPos(icon);
                });
                icon.addEventListener('mouseleave', hide);
            });
        } function showVideoForIcon(el) {
            userHasInteracted = true;
            if (!videoBox) return;
            const effectiveVideo = getEffectiveSkillVideoFromIcon(el);
            if (!effectiveVideo || effectiveVideo.trim() === '') {
                videoBox.style.display = 'none';
                return;
            }
            const videoURL = normalizeFileURL(effectiveVideo);
            if (!videoURL || videoURL.trim() === '') {
                videoBox.style.display = 'none';
                return;
            }
            Array.from(videoBox.querySelectorAll('video.skill-video')).forEach(v => {
                try {
                    v.pause();
                } catch (e) {
                }
                v.style.display = 'none';
            });
            if (window.__subskills) window.__subskills.hideAll?.(videoBox);
            const hasIdx = !!el.dataset.index;
            const weaponOn = globalWeaponEnabled;
            const weaponData = getWeaponDataForIcon(el);
            const isWeaponVideo = weaponOn && weaponData && weaponData.video && weaponData.video.trim() !== '';


     .weapon-toggle-container:hover {
            // console.log('[Skills] showVideoForIcon chamado', {
        transform: translateY(-1px);
            //     skillName: el.dataset.nome || el.dataset.name,
    }
            //    weaponOn,
            //    isWeaponVideo,
            //    effectiveVideo: getEffectiveSkillVideoFromIcon(el)
            // });
            const videoKey = isWeaponVideo ? `weapon:${getWeaponKey(el)}` : (el.dataset.index || '');
            const isSubskill = !hasIdx || el.dataset.nested === '1';
            const parentIdx = el.dataset.parentIndex || '';
            const subName = el.dataset.subName || el.dataset.nome || el.dataset.name || '';


    .weapon-toggle-sprite {
            if (hasIdx && !isWeaponVideo && videosCache.has(el.dataset.index)) {
        width: 44px;
                const v = videosCache.get(el.dataset.index);
        height: 44px;
                videoBox.style.display = 'block';
        flex-shrink: 0;
                v.style.display = 'block';
        border-radius: 50%;
                try {
        overflow: visible;
                    v.currentTime = 0;
        position: relative;
                } catch (e) {
        background: rgb(40, 40, 48);
                }
        border: 2px solid rgba(255, 255, 255, 0.15);
                const suppress = document.body.dataset.suppressSkillPlay === '1';
        display: flex;
                if (!suppress) {
        align-items: center;
                    v.play().catch(() => {
        justify-content: center;
                    });
        z-index: 2;
                } else {
        margin: 0;
                    try {
        padding: 0;
                        v.pause();
        box-sizing: border-box;
                    } catch (e) {
        box-shadow: 0 4px 12px rgba(0, 0, 0, .4);
                    }
        transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.15s cubic-bezier(0.4, 0, 0.2, 1);
                }
        will-change: background-color;
                return;
    }
            }
            // Para form_switch, permite criação dinâmica de vídeos (transições de forma)
            // Vídeos normais devem estar pré-carregados
            const isFormSwitch = el.dataset.formSwitch === 'true' || el.getAttribute('data-form-switch') === 'true';
            let v = null;
            if (isWeaponVideo) {
                const weaponKeyFull = `weapon:${getWeaponKey(el)}`;
                v = videosCache.get(weaponKeyFull);
                if (!v && isSubskill && parentIdx && subName) {
                    // Tenta buscar vídeo de weapon de subskill
                    // O cache usa o formato: sub:${parentIdx}:${path}:weapon onde path NÃO inclui o nome da skill principal
                    // O subName agora já está no formato correto (sem nome da skill principal)


    .weapon-toggle-sprite img {
                    // Tenta buscar diretamente com o subName
        width: 64px;
                    let subWeaponKey = `sub:${parentIdx}:${subName}:weapon`;
        height: 64px;
                    v = subskillVideosCache.get(subWeaponKey);
        display: block;
        /* Força redimensionamento pixelado (nearest neighbor) - ordem importante */
        -ms-interpolation-mode: nearest-neighbor;
        /* IE/Edge antigo - deve vir primeiro */
        image-rendering: -moz-crisp-edges;
        /* Firefox */
        image-rendering: -webkit-optimize-contrast;
        /* Safari/Chrome antigo */
        image-rendering: pixelated;
        /* Chrome/Edge moderno */
        image-rendering: crisp-edges !important;
        /* Fallback padrão - força sem suavização */
        /* Garante que não há suavização por transform ou filter */
        transform: translateZ(0);
        backface-visibility: hidden;
        /* Mantém proporção sem suavização */
        object-fit: contain;
        object-position: center;
        /* Força renderização sem suavização - importante para sprites pixelados */
        -webkit-font-smoothing: none;
        font-smoothing: none;
    }


    .weapon-toggle-bar {
                    // Se não encontrou, tenta buscar recursivamente
        background: rgb(40, 40, 48);
                    if (!v) {
        padding: 5px 14px 5px 28px;
                        const basePattern = `sub:${parentIdx}:`;
        border-radius: 0 7px 7px 0;
                        const weaponSuffix = ':weapon';
        border: 2px solid rgba(255, 255, 255, 0.15);
                        const searchName = subName.split(':').pop();
        border-left: none;
                        for (const [key, video] of subskillVideosCache.entries()) {
        display: flex;
                            if (key.startsWith(basePattern) && key.endsWith(weaponSuffix)) {
        align-items: center;
                                const pathInKey = key.substring(basePattern.length, key.length - weaponSuffix.length);
        width: 180px;
                                // Tenta match exato, ou se termina com o nome da skill
        position: relative;
                                if (pathInKey === subName ||
        overflow: hidden;
                                    pathInKey.endsWith(`:${searchName}`) ||
        margin: 0;
                                    pathInKey === searchName) {
        margin-left: -22px;
                                    v = video;
        height: 34px;
                                    break;
        box-sizing: border-box;
                                }
        box-shadow: 0 4px 12px rgba(0, 0, 0, .4);
                            }
        transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1), background-image 0.15s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
                        }
        will-change: background-color, background-image;
                    }
    }
                }
                if (!v) {
                    // Tenta buscar pelo padrão antigo também
                    v = videoBox.querySelector(`video[data-weapon-key="${videoKey}"]`);
                }
            } else {
                if (isSubskill && parentIdx && subName) {
                    // Busca vídeo de subskill no cache correto
                    // O cache usa o formato: sub:${parentIdx}:${path} onde path NÃO inclui o nome da skill principal
                    // O subName agora já está no formato correto (sem nome da skill principal)


    .weapon-toggle-name {
                    // Tenta buscar diretamente com o subName
        color: #fff;
                    let subKey = `sub:${parentIdx}:${subName}`;
        font-size: 14px;
                    v = subskillVideosCache.get(subKey);
        font-weight: 600;
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
        position: relative;
        z-index: 2;
        letter-spacing: 0.3px;
        display: inline-block;
    }


    /* Textos i18n - usando ::after para mostrar o texto baseado no data-lang e estado */
                    // Se não encontrou, tenta buscar recursivamente todas as chaves que começam com o padrão
    .weapon-toggle-name::after {
                    // Isso é útil caso haja alguma diferença no formato do caminho
        content: "Equipar Arma";
                    if (!v) {
        /* Default PT */
                        const basePattern = `sub:${parentIdx}:`;
    }
                        const searchName = subName.split(':').pop(); // Último segmento do caminho
                        // Tenta também buscar apenas pelo último segmento (útil para sub-subskills)
                        const lastSegmentKey = `sub:${parentIdx}:${searchName}`;
                        v = subskillVideosCache.get(lastSegmentKey);


    .weapon-toggle-name[data-lang="pt"]::after {
                        // Se ainda não encontrou, faz busca mais ampla
        content: "Equipar Arma";
                        if (!v) {
    }
                            for (const [key, video] of subskillVideosCache.entries()) {
                                if (key.startsWith(basePattern)) {
                                    const pathInKey = key.substring(basePattern.length);
                                    // Tenta match exato, ou se termina com o nome da skill, ou se contém o caminho completo
                                    if (pathInKey === subName ||
                                        pathInKey.endsWith(`:${searchName}`) ||
                                        pathInKey === searchName ||
                                        (subName.includes(':') && pathInKey.includes(subName)) ||
                                        (subName.includes(':') && pathInKey.endsWith(subName.split(':').slice(-2).join(':')))) {
                                        v = video;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                } else {
                    v = videosCache.get(el.dataset.index);
                    if (!v) {
                        v = nestedVideoElByIcon.get(el);
                    }
                }
            }


    .weapon-toggle-name[data-lang="en"]::after {
            // Se vídeo não foi encontrado no cache, verifica se falhou antes
        content: "Equip Weapon";
            if (!v) {
    }
                // Se o vídeo já foi marcado como falhado, não mostra aviso repetido
                if (failedVideosCache.has(videoURL)) {
                    videoBox.style.display = 'none';
                    return;
                }
                // Para form_switch, cria vídeo dinamicamente (transições de forma são dinâmicas)
                // Usa uma chave única que inclui o nome do arquivo do vídeo para garantir que cada vídeo diferente seja cacheado separadamente
                if (isFormSwitch && videoURL) {
                    const baseIndex = el.dataset.index || '';
                    const videoFileName = effectiveVideo || '';
                    // Chave única: index + nome do arquivo do vídeo
                    const videoKey = baseIndex + ':' + videoFileName;
                    v = videosCache.get(videoKey);
                    if (!v) {
                        v = createVideoElement(videoURL, { index: baseIndex });
                        if (v) {
                            videoBox.appendChild(v);
                            videosCache.set(videoKey, v);
                            v.load();
                        } else {
                            videoBox.style.display = 'none';
                            return;
                        }
                    }
                } else {
                    // Vídeos normais devem estar pré-carregados
                    videoBox.style.display = 'none';
                    return;
                }
            }
            videoBox.style.display = 'block';
            v.style.display = 'block';
            try {
                v.currentTime = 0;
            } catch (e) {
            }
            const suppress = document.body.dataset.suppressSkillPlay === '1';
            if (!suppress) {
                v.play().catch(() => {
                });
            } else {
                try {
                    v.pause();
                } catch (e) {
                }
            }
        } function activateSkill(el, options = {
        }) {
            const {
                openSubs = true
            } = options;
            const tip = document.querySelector('.skill-tooltip');
            if (tip) {
                tip.setAttribute('aria-hidden', 'true');
                tip.style.opacity = '0';
                tip.style.left = '-9999px';
                tip.style.top = '-9999px';
            } const skillsRoot = document.getElementById('skills');
            const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {
            };
            const L = i18nMap[getLangKey()] || i18nMap.pt || {
                cooldown: 'Recarga', energy_gain: 'Ganho de energia', energy_cost: 'Custo de energia', power: 'Poder', power_pvp: 'Poder PvP', level: 'Nível'
            };
            const name = el.dataset.nome || el.dataset.name || '';
            let weaponData = null;
            if (el.dataset.weapon) {
                try {
                    const parsed = JSON.parse(el.dataset.weapon);
                    // Só considera weapon válido se for um objeto não vazio
                    if (parsed && typeof parsed === 'object' && Object.keys(parsed).length > 0) {
                        weaponData = parsed;
                    }
                } catch (e) {
                    weaponData = null;
                }
            } const hasWeapon = !!weaponData;
            const weaponEquipped = hasWeapon && globalWeaponEnabled;
            // Level: usa o level da weapon se estiver ativa e tiver level, senão usa o level da skill base
            let level = (el.dataset.level || '').trim();
            if (weaponEquipped && weaponData) {
                // Verifica se weapon tem level definido (pode ser número ou string)
                const weaponLevel = weaponData.level;
                if (weaponLevel !== undefined && weaponLevel !== null && weaponLevel !== '') {
                    level = weaponLevel.toString().trim();
                }
            }
            const lang = getLangKey();
            const baseDescPack = {
                pt: el.dataset.descPt || '', en: el.dataset.descEn || '', es: el.dataset.descEs || '', pl: el.dataset.descPl || ''
            };
            const baseDesc = baseDescPack[lang] || baseDescPack.pt || baseDescPack.en || baseDescPack.es || baseDescPack.pl || el.dataset.desc || '';
            // Aceita tanto desc_i18n quanto desc para compatibilidade
            let weaponDescPack = {};
            if (weaponData) {
                if (weaponData.desc_i18n) {
                    weaponDescPack = weaponData.desc_i18n;
                } else if (weaponData.desc) {
                    weaponDescPack = weaponData.desc;
                } else {
                    weaponDescPack = {
                        pt: weaponData.descPt || '', en: weaponData.descEn || '', es: weaponData.descEs || '', pl: weaponData.descPl || ''
                    };
                }
            }
            const weaponDesc = weaponDescPack[lang] || weaponDescPack.pt || weaponDescPack.en || weaponDescPack.es || weaponDescPack.pl || '';
            const chosenDesc = (weaponEquipped && weaponDesc) ? weaponDesc : baseDesc;
            const descHtml = chosenDesc.replace(/'''(.*?)'''/g, '<b>$1</b>');
            let attrsHTML = '';
            if (weaponEquipped && weaponData) {
                // Faz merge: usa atributos da skill base e substitui apenas os que existem no weapon
                // Parse dos atributos da skill base (formato: "pve, pvp, energy, cooldown" ou "pve, pvp, energy, cooldown")
                const baseAttrsStr = el.dataset.atr || '';
                // Suporta tanto ", " quanto "," como separador
                const baseAttrs = baseAttrsStr.split(/\s*,\s*/).map(a => a.trim());
                const basePve = baseAttrs[0] && baseAttrs[0] !== '-' ? baseAttrs[0] : '';
                const basePvp = baseAttrs[1] && baseAttrs[1] !== '-' ? baseAttrs[1] : '';
                const baseEnergy = baseAttrs[2] && baseAttrs[2] !== '-' ? baseAttrs[2] : '';
                const baseCd = baseAttrs[3] && baseAttrs[3] !== '-' ? baseAttrs[3] : '';
 
                // Valores do weapon (substituem os da skill base se existirem)
                const wPve = (weaponData.powerpve !== undefined && weaponData.powerpve !== null && weaponData.powerpve !== '')
                    ? weaponData.powerpve.toString().trim()
                    : basePve;
                const wPvp = (weaponData.powerpvp !== undefined && weaponData.powerpvp !== null && weaponData.powerpvp !== '')
                    ? weaponData.powerpvp.toString().trim()
                    : basePvp;
                const wEnergy = (weaponData.energy !== undefined && weaponData.energy !== null && weaponData.energy !== '')
                    ? weaponData.energy.toString().trim()
                    : baseEnergy;
                const wCd = (weaponData.cooldown !== undefined && weaponData.cooldown !== null && weaponData.cooldown !== '')
                    ? weaponData.cooldown.toString().trim()
                    : baseCd;


    .weapon-toggle-name[data-lang="es"]::after {
                // Monta string de atributos mesclados
        content: "Equipar Arma";
                const mergedAttrs = [wPve, wPvp, wEnergy, wCd].join(',');
    }
                attrsHTML = renderAttributes(mergedAttrs);
            } else {
                attrsHTML = el.dataset.atr ? renderAttributes(el.dataset.atr) : (el.dataset.subattrs ? renderSubAttributesFromObj(JSON.parse(el.dataset.subattrs), L) : '');
            } let flagsHTML = '';
            // Debug: verifica se é uma skill do Urouge (verifica pela URL da página ou pelo contexto)
            const isUrougePage = window.location.href && window.location.href.toLowerCase().includes('urouge');
            if (el.dataset.flags) {
                try {
                    const flags = JSON.parse(el.dataset.flags);
                    if (flags && Array.isArray(flags) && flags.length > 0) {
                        flagsHTML = renderFlagsRow(flags);
                        // Debug para Urouge
                        if (isUrougePage) {
                            console.log('[Skills] Urouge - Flags processadas:', {
                                skill: name || el.dataset.nome,
                                flags: flags,
                                htmlLength: flagsHTML ? flagsHTML.length : 0,
                                hasHTML: !!flagsHTML
                            });
                        }
                    } else {
                        if (isUrougePage) {
                            console.warn('[Skills] Urouge - Flags inválidas:', {
                                skill: name || el.dataset.nome,
                                flags: flags,
                                rawData: el.dataset.flags
                            });
                        }
                    }
                } catch (e) {
                    console.warn('[Skills] Erro ao processar flags:', e, 'flags data:', el.dataset.flags, 'skill:', name || el.dataset.nome);
                    if (isUrougePage) {
                        console.error('[Skills] Urouge - Erro ao processar flags:', e, 'element:', el);
                    }
                }
            } else {
                // Debug: verifica se deveria ter flags mas não tem (apenas para Urouge)
                if (isUrougePage) {
                    console.warn('[Skills] Urouge - Skill sem data-flags:', {
                        skill: name || el.dataset.nome,
                        element: el,
                        allAttributes: Array.from(el.attributes).map(attr => attr.name + '=' + attr.value)
                    });
                }
            } if (descBox) {
                descBox.innerHTML = `<div class="skill-title"><h3>${name}</h3></div>${level ? `<div class="skill-level-line"><span class="attr-label">${L.level} ${level}</span></div>` : ''}${attrsHTML}<div class="desc">${descHtml}</div>`;
            } if (hasWeapon) {
                applyWeaponBadge(el, weaponData, weaponEquipped);
            } if (videoBox) {
                const oldFlags = videoBox.querySelector('.skill-flags');
                if (oldFlags) oldFlags.remove();
                if (flagsHTML) {
                    videoBox.insertAdjacentHTML('beforeend', flagsHTML);
                    applyFlagTooltips(videoBox);
                }
            } const currIcons = Array.from(iconsBar.querySelectorAll('.skill-icon'));
            currIcons.forEach(i => i.classList.remove('active'));
            const subsRaw = el.dataset.subs || el.getAttribute('data-subs');
            const isFormSwitch = el.dataset.formSwitch === 'true' || el.getAttribute('data-form-switch') === 'true';
            // Não marca como ativo se for form_switch (Change Form)
            if (!isFormSwitch) {
                el.classList.add('active');
                if (!autoplay && loadedVideos > 0) autoplay = true;
                window.__lastActiveSkillIcon = el;
                // Lógica de vídeo: usa função centralizada que já considera weapon
                showVideoForIcon(el);
            }
            const isBack = el.dataset.back === 'true' || el.getAttribute('data-back') === 'true' || el.dataset.back === 'yes' || el.getAttribute('data-back') === 'yes' || el.dataset.back === '1' || el.getAttribute('data-back') === '1';


    .weapon-toggle-name[data-lang="pl"]::after {
            // Se for form_switch, alterna forma (não processa como back)
        content: "Wyposaż Broń";
            if (isFormSwitch) {
    }
                // Atualiza o data-video-file do ícone com o vídeo correto da transição baseado na forma atual
                try {
                    const formsJSON = skillsRoot.dataset.forms || '{}';
                    if (formsJSON && formsJSON !== '{}') {
                        const tempFormsData = JSON.parse(formsJSON);
                        const formNames = Object.keys(tempFormsData);


    /* Estado ATIVO (arma equipada) - muda o texto */
                        // Busca vídeo de transição na skill Change Form
    .weapon-toggle-container.weapon-active .weapon-toggle-name::after {
                        const formVideosRaw = el.dataset.formVideos || el.getAttribute('data-form-videos');
        content: "Desequipar Arma";
                        if (formVideosRaw) {
        /* Default PT */
                            const videos = JSON.parse(formVideosRaw);
    }
                            // Se currentForm é null, detecta qual forma está atualmente visível no DOM
                            let formForVideo = currentForm;
                            if (!formForVideo) {
                                // Lê formsData se ainda não foi carregado
                                if (Object.keys(formsData).length === 0) {
                                    try {
                                        formsData = JSON.parse(formsJSON);
                                    } catch (e) {
                                        formsData = {};
                                    }
                                }
                                formForVideo = detectCurrentForm();
                                // Se ainda não conseguiu detectar, usa a primeira como fallback
                                if (!formForVideo && formNames.length > 0) {
                                    formForVideo = formNames[0];
                                }
                            }
                            const transitionVideo = formForVideo ? (videos[formForVideo] || '') : '';
                            if (transitionVideo && transitionVideo.trim() !== '') {
                                // Atualiza temporariamente o data-video-file (o sistema usa isso)
                                el.dataset.videoFile = transitionVideo;
                            }
                        }
                    }
                } catch (e) {
                    console.error('[Forms] Erro ao processar vídeo de transição:', e);
                }


    .weapon-toggle-container.weapon-active .weapon-toggle-name[data-lang="pt"]::after {
                // Usa o sistema normal de vídeo (mesmo que skills normais)
        content: "Desequipar Arma";
                showVideoForIcon(el);
    }
                switchForm();
                return;
            }


    .weapon-toggle-container.weapon-active .weapon-toggle-name[data-lang="en"]::after {
            if (isBack && !isFormSwitch && barStack.length) {
         content: "Unequip Weapon";
                const prev = barStack.pop();
    }
                // Restaura currentForm se estava salvo no snapshot
                if (prev.currentForm !== undefined) {
                    currentForm = prev.currentForm;
                }
                renderBarFromItems(prev);
                const btn = document.querySelector('.skills-back-wrapper');
                if (btn) btn.style.display = barStack.length ? 'block' : 'none';
                return;
            } if (openSubs && subsRaw && subsRaw.trim() !== '') {
                if (barStack.length && barStack[barStack.length - 1].parentIcon === el) return;
                try {
                    const subs = JSON.parse(subsRaw);
                    pushSubBarFrom(subs, el);
                } catch {
                }
            }
        } function wireClicksForCurrentBar() {
            const currIcons = Array.from(iconsBar.querySelectorAll('.skill-icon'));
            currIcons.forEach(el => {
                if (el.dataset.weaponToggle === '1' || el.classList.contains('weapon-bar-toggle')) return;
                if (el.dataset.wired) return;
                el.dataset.wired = '1';
                const label = el.dataset.nome || el.dataset.name || '';
                el.setAttribute('aria-label', label);
                if (el.hasAttribute('title')) el.removeAttribute('title');
                const img = el.querySelector('img');
                if (img) {
                    img.setAttribute('alt', '');
                    if (img.hasAttribute('title')) img.removeAttribute('title');
                } el.addEventListener('click', () => {
                    activateSkill(el, {
                        openSubs: true
                    });
                });
            });
            wireTooltipsForNewIcons();
        } function animateIconsBarEntrance() {
            Array.from(iconsBar.children).forEach((c, i) => {
                c.style.opacity = '0';
                c.style.transform = 'translateY(6px)';
                requestAnimationFrame(() => {
                    setTimeout(() => {
                        c.style.transition = 'opacity .18s ease, transform .18s ease';
                        c.style.opacity = '1';
                        c.style.transform = 'translateY(0)';
                    }, i * 24);
                });
            });
        } function snapshotCurrentBarItemsFromDOM() {
            const items = Array.from(iconsBar.querySelectorAll('.skill-icon')).filter(el => el.dataset.weaponToggle !== '1').map(el => {
                const img = el.querySelector('img');
                const iconURL = img ? img.src : '';
                const subsRaw = el.dataset.subs || el.getAttribute('data-subs') || '';
                let subs = null;
                try {
                    subs = subsRaw ? JSON.parse(subsRaw) : null;
                } catch {
                    subs = null;
                } const subattrsRaw = el.dataset.subattrs || '';
                let flags = null;
                if (el.dataset.flags) {
                    try {
                        flags = JSON.parse(el.dataset.flags);
                    } catch (e) {
                    }
                } let weapon = null;
                if (el.dataset.weapon) {
                    try {
                        weapon = JSON.parse(el.dataset.weapon);
                    } catch (e) {
                    }
                }
                // Preserva data-form-videos para poder restaurar depois
                const formVideos = el.dataset.formVideos || el.getAttribute('data-form-videos') || '';
                return {
                    name: el.dataset.nome || el.dataset.name || '', index: el.dataset.index || '', level: el.dataset.level || '', desc: el.dataset.desc || '', descPt: el.dataset.descPt || '', descEn: el.dataset.descEn || '', descEs: el.dataset.descEs || '', descPl: el.dataset.descPl || '', attrs: el.dataset.atr || el.dataset.attrs || '', video: el.dataset.video || '', iconURL, subs, subattrsStr: subattrsRaw, flags: flags, weapon: weapon, nested: el.dataset.nested || '', subName: el.dataset.subName || '', parentIndex: el.dataset.parentIndex || '', formSwitch: el.dataset.formSwitch || el.getAttribute('data-form-switch') || '', formVideos: formVideos
                };
            });
            // Retorna objeto com items e currentForm para poder restaurar depois
            return { items, currentForm: currentForm };
        } function ensureBackButton() {
            const rail = iconsBar.closest('.top-rail.skills');
            if (!rail) return null;
            let wrap = rail.parentElement;
            if (!wrap || !wrap.classList || !wrap.classList.contains('skills-rail-wrap')) {
                const parentNode = rail.parentNode;
                const newWrap = document.createElement('div');
                newWrap.className = 'skills-rail-wrap';
                parentNode.insertBefore(newWrap, rail);
                newWrap.appendChild(rail);
                wrap = newWrap;
            } let backWrap = wrap.querySelector('.skills-back-wrapper');
            if (!backWrap) {
                backWrap = document.createElement('div');
                backWrap.className = 'skills-back-wrapper';
                const btnInner = document.createElement('button');
                btnInner.className = 'skills-back';
                btnInner.type = 'button';
                btnInner.setAttribute('aria-label', 'Voltar');
                btnInner.innerHTML = '<svg class="back-chevron" width="100%" height="100%" viewBox="0 0 36 32" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" preserveAspectRatio="xMidYMid meet"><path d="M10 2L4 16L10 30" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M20 2L14 16L20 30" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M30 2L24 16L30 30" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/></svg>';
                backWrap.appendChild(btnInner);
                wrap.insertBefore(backWrap, rail);
                btnInner.addEventListener('click', () => {
                    if (!barStack.length) return;
                    const prev = barStack.pop();
                    renderBarFromItems(prev);
                    backWrap.style.display = barStack.length ? 'block' : 'none';
                    wrap.classList.toggle('has-sub-bar', barStack.length > 0);
                    if (!barStack.length) btnInner.classList.remove('peek');
                });
            } backWrap.style.display = barStack.length ? 'block' : 'none';
            wrap.classList.toggle('has-sub-bar', barStack.length > 0);
            const btnInner = backWrap.querySelector('.skills-back');
 
            // Calcula a posição do botão baseado na posição real do top-rail
            function updateBackButtonPosition() {
                if (!rail || !backWrap) return;
                const railRect = rail.getBoundingClientRect();
                const wrapRect = wrap.getBoundingClientRect();
                // Calcula a posição relativa do rail dentro do wrap
                const railLeft = railRect.left - wrapRect.left;
                // Posiciona o wrapper na borda esquerda do rail
                // O botão interno usa translateX(-97%) para ficar atrás da barra
                backWrap.style.left = railLeft + 'px';
            }
 
            // Atualiza a posição quando necessário
            if (backWrap.style.display !== 'none') {
                // Usa requestAnimationFrame para garantir que o DOM foi atualizado
                requestAnimationFrame(() => {
                    updateBackButtonPosition();
                });
 
                // Recalcula em resize e scroll
                if (!backWrap.dataset.positionWired) {
                    backWrap.dataset.positionWired = '1';
                    const updateOnResize = () => {
                        if (backWrap.style.display !== 'none') {
                            updateBackButtonPosition();
                        }
                    };
                    window.addEventListener('resize', updateOnResize);
                    const observer = new ResizeObserver(() => {
                        if (backWrap.style.display !== 'none') {
                            updateBackButtonPosition();
                        }
                    });
                    if (rail) observer.observe(rail);
                    observer.observe(wrap);
                }
            }
 
            return btnInner;
        } function renderBarFromItems(itemsOrSnapshot) {
            // Suporta tanto o formato antigo (array) quanto o novo (objeto com items e currentForm)
            let items, savedCurrentForm;
            if (Array.isArray(itemsOrSnapshot)) {
                items = itemsOrSnapshot;
                savedCurrentForm = null;
            } else if (itemsOrSnapshot && itemsOrSnapshot.items) {
                items = itemsOrSnapshot.items;
                savedCurrentForm = itemsOrSnapshot.currentForm;
            } else {
                items = [];
                savedCurrentForm = null;
            }
            // Restaura currentForm se estava salvo
            if (savedCurrentForm !== undefined && savedCurrentForm !== null) {
                currentForm = savedCurrentForm;
            }
            const tip = document.querySelector('.skill-tooltip');
            if (tip) {
                tip.setAttribute('aria-hidden', 'true');
                tip.style.opacity = '0';
                tip.style.left = '-9999px';
                tip.style.top = '-9999px';
            } iconsBar.innerHTML = '';
            items.forEach((it, idx) => {
                const node = document.createElement('div');
                node.className = 'skill-icon';
                node.dataset.nome = it.name || '';
                if (it.index) node.dataset.index = it.index;
                if (it.level) node.dataset.level = it.level;
                if (it.desc) node.dataset.desc = it.desc;
                if (it.descPt) node.dataset.descPt = it.descPt;
                if (it.descEn) node.dataset.descEn = it.descEn;
                if (it.descEs) node.dataset.descEs = it.descEs;
                if (it.descPl) node.dataset.descPl = it.descPl;
                if (it.attrs) node.dataset.atr = it.attrs;
                if (it.video) node.dataset.video = it.video;
                if (it.subs) node.dataset.subs = JSON.stringify(it.subs);
                if (it.subattrsStr) node.dataset.subattrs = it.subattrsStr;
                if (it.flags) node.dataset.flags = JSON.stringify(it.flags);
                if (it.weapon && typeof it.weapon === 'object' && Object.keys(it.weapon).length > 0) {
                    node.dataset.weapon = JSON.stringify(it.weapon);
                }
                // Restaura informações de subskill importantes para busca de vídeos
                if (it.nested) node.dataset.nested = it.nested;
                if (it.subName) node.dataset.subName = it.subName;
                if (it.parentIndex) node.dataset.parentIndex = it.parentIndex;
                if (!it.index && !it.nested) node.dataset.nested = '1';
                // Restaura formSwitch (Change Form)
                if (it.formSwitch) {
                    node.dataset.formSwitch = it.formSwitch;
                    node.setAttribute('data-form-switch', it.formSwitch);
                }
                // Restaura formVideos (vídeos de transição de forma)
                if (it.formVideos) {
                    node.dataset.formVideos = it.formVideos;
                    node.setAttribute('data-form-videos', it.formVideos);
                }
                const img = document.createElement('img');
                img.alt = '';
                img.src = it.iconURL || (it.icon ? filePathURL(it.icon) : '');
                img.decoding = 'async';
                img.loading = 'lazy';
                img.width = 50;
                img.height = 50;
                node.appendChild(img);
                iconsBar.appendChild(node);
            });
            animateIconsBarEntrance();
            wireClicksForCurrentBar();
            // Remove qualquer toggle antigo que possa aparecer
            const oldToggle = iconsBar.querySelector('.weapon-bar-toggle');
            if (oldToggle) oldToggle.remove();
            // Reaplica classes de weapon após renderizar barra
            reapplyWeaponClassesToBar();
            const b = ensureBackButton();
            if (b) b.classList.add('peek');
            // Atualiza a posição do botão back após a barra ser renderizada
            requestAnimationFrame(() => {
                const backWrap = document.querySelector('.skills-back-wrapper');
                if (backWrap && backWrap.style.display !== 'none') {
                    const rail = iconsBar.closest('.top-rail.skills');
                    const wrap = rail ? rail.parentElement : null;
                    if (rail && wrap && wrap.classList.contains('skills-rail-wrap')) {
                        const railRect = rail.getBoundingClientRect();
                        const wrapRect = wrap.getBoundingClientRect();
                        const railLeft = railRect.left - wrapRect.left;
                        // Posiciona na borda esquerda do rail (botão fica atrás com translateX)
                        backWrap.style.left = railLeft + 'px';
                    }
                }
            });
        } function pushSubBarFrom(subs, parentIconEl) {
            const tip = document.querySelector('.skill-tooltip');
            if (tip) {
                tip.setAttribute('aria-hidden', 'true');
                tip.style.opacity = '0';
                tip.style.left = '-9999px';
                tip.style.top = '-9999px';
            } const parentNameSnapshot = parentIconEl ? (parentIconEl.dataset.nome || parentIconEl.dataset.name || '') : '';
            // Para subskills, usa parentIndex; para skills principais, usa index
            const parentIndexSnapshot = parentIconEl ? (
                parentIconEl.dataset.nested === '1'
                    ? (parentIconEl.dataset.parentIndex || '')
                    : (parentIconEl.dataset.index || '')
            ) : '';
            const snapshot = snapshotCurrentBarItemsFromDOM();
            barStack.push({
                items: snapshot.items,
                currentForm: snapshot.currentForm,
                parentIcon: parentIconEl,
                parentName: parentNameSnapshot,
                parentIndex: parentIndexSnapshot
            });
            ensureBackButton();
            const langKey = getLangKey();
            let cacheKey = null;
            if (parentIconEl) {
                cacheKey = parentIconEl.dataset.subCacheKey || null;
                if (!cacheKey) {
                    if (parentIconEl.dataset.index) {
                        cacheKey = `idx:${parentIconEl.dataset.index}`;
                    } else {
                        const slug = slugify(parentIconEl.dataset.nome || parentIconEl.dataset.name || '');
                        if (slug) cacheKey = `slug:${slug}`;
                    } if (cacheKey) parentIconEl.dataset.subCacheKey = cacheKey;
                }
            } if (cacheKey) {
                const cached = subBarTemplateCache.get(cacheKey);
                if (cached && cached.lang === langKey) {
                    iconsBar.innerHTML = '';
                    const clone = cached.template.cloneNode(true);
                    iconsBar.appendChild(clone);
                    animateIconsBarEntrance();
                    wireClicksForCurrentBar();
                    // Remove qualquer toggle antigo que possa aparecer
                    const oldToggle2 = iconsBar.querySelector('.weapon-bar-toggle');
                    if (oldToggle2) oldToggle2.remove();
                    // Reaplica classes de weapon após renderizar do cache
                    reapplyWeaponClassesToBar();
                    const cachedBtn = ensureBackButton();
                    if (cachedBtn) cachedBtn.classList.add('peek');
                    return;
                }
            } const skillsRoot = document.getElementById('skills');
            const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {
            };
            const L = i18nMap[getLangKey()] || i18nMap.pt || {
                cooldown: 'Recarga', energy_gain: 'Ganho de energia', energy_cost: 'Custo de energia', power: 'Poder', power_pvp: 'Poder PvP', level: 'Nível'
            };
            const hydratedSubs = inheritSubskillTree(subs, mainSkillsMeta);
            const items = (hydratedSubs || []).filter(s => {
                // Filtra só se não tem nada útil
                const hasName = (s.name || s.n || '').trim() !== '';
                const hasIcon = (s.icon || '').trim() !== '' && s.icon !== 'Nada.png';
                const hasRef = (s.refS || s.refM || '').toString().trim() !== '';
                return hasName || hasIcon || hasRef;
            }).map(s => {
                const name = (s.name || s.n || '').trim();
                const desc = chooseDescFrom(s).replace(/'''(.*?)'''/g, '<b>$1</b>');
                const attrsHTML = renderSubAttributesFromObj(s, L);
                return {
                    name, level: (s.level || '').toString().trim(), desc, descPt: (s.descPt || (s.desc_i18n && s.desc_i18n.pt) || ''), descEn: (s.descEn || (s.desc_i18n && s.desc_i18n.en) || ''), descEs: (s.descEs || (s.desc_i18n && s.desc_i18n.es) || ''), descPl: (s.descPl || (s.desc_i18n && s.desc_i18n.pl) || ''), attrs: '', icon: (s.icon || ''), iconURL: (s.icon && s.icon !== 'Nada.png' && s.icon.toLowerCase() !== 'nada.png') ? filePathURL(s.icon) : '', video: s.video ? filePathURL(s.video) : '', subs: Array.isArray(s.subs) ? s.subs : null, subattrs: s, flags: Array.isArray(s.flags) ? s.flags : null, back: (s.back === true || s.back === 'true' || s.back === 'yes' || s.back === '1') ? 'true' : null, weapon: s.weapon || null
                };
            });
            const fragment = document.createDocumentFragment();
            items.forEach((it, iIdx) => {
                const node = document.createElement('div');
                node.className = 'skill-icon';
                node.dataset.nested = '1';
                node.dataset.nome = it.name || '';
                node.dataset.parentIndex = parentIndexSnapshot;
                // Constrói o caminho completo para sub-subskills
                // IMPORTANTE: O cache NÃO inclui o nome da skill principal no caminho
                // Formato do cache: "SubskillName" ou "SubskillName:SubSubskillName" (sem o nome da skill principal)
                let fullPath = it.name || '';
                if (parentIconEl) {
                    // Se o pai é uma subskill (tem nested), adiciona o nome do pai ao caminho
                    if (parentIconEl.dataset.nested === '1') {
                        // Se o pai tem subName, usa ele (já está no formato correto, sem nome da skill principal)
                        if (parentIconEl.dataset.subName && parentIconEl.dataset.subName.trim() !== '') {
                            fullPath = `${parentIconEl.dataset.subName}:${it.name || ''}`;
                        } else {
                            // Se o pai não tem subName, é a primeira subskill, então usa apenas o nome do pai
                            const parentName = (parentIconEl.dataset.nome || parentIconEl.dataset.name || '').trim();
                            fullPath = `${parentName}:${it.name || ''}`;
                        }
                    }
                    // Se o pai é uma skill principal (não é nested), o caminho é apenas o nome da subskill atual
                    // (já está definido como it.name acima)
                }
                node.dataset.subName = fullPath;
                const subSlug = slugify(it.name || '');
                if (subSlug) node.dataset.slug = subSlug;
                if (it.level) node.dataset.level = it.level;
                if (it.desc) node.dataset.desc = it.desc;
                if (it.descPt) node.dataset.descPt = it.descPt;
                if (it.descEn) node.dataset.descEn = it.descEn;
                if (it.descEs) node.dataset.descEs = it.descEs;
                if (it.descPl) node.dataset.descPl = it.descPl;
                if (it.video) node.dataset.video = it.video;
                if (it.subs) node.dataset.subs = JSON.stringify(it.subs);
                if (it.subattrs) node.dataset.subattrs = JSON.stringify(it.subattrs);
                if (it.flags) node.dataset.flags = JSON.stringify(it.flags);
                if (it.back) node.dataset.back = it.back;
                if (it.weapon && typeof it.weapon === 'object' && Object.keys(it.weapon).length > 0) {
                    try {
                        node.dataset.weapon = JSON.stringify(it.weapon);
                    } catch (e) {
                        console.error('[Skills] Erro ao serializar weapon de subskill', it.name, e);
                    }
                }
                const img = document.createElement('img');
                img.alt = '';
                img.src = it.iconURL;
                img.decoding = 'async';
                img.loading = 'lazy';
                img.width = 50;
                img.height = 50;
                node.appendChild(img);
                fragment.appendChild(node);
            });
            const templateClone = fragment.cloneNode(true);
            iconsBar.innerHTML = '';
            iconsBar.appendChild(fragment);
            animateIconsBarEntrance();
            wireClicksForCurrentBar();
            // Remove qualquer toggle antigo que possa aparecer
            const oldToggle3 = iconsBar.querySelector('.weapon-bar-toggle');
            if (oldToggle3) oldToggle3.remove();
            // Reaplica classes de weapon após renderizar subskills
            reapplyWeaponClassesToBar();
            const b2 = ensureBackButton();
            if (b2) b2.classList.add('peek');
            // Atualiza a posição do botão back após subskills serem renderizadas
            requestAnimationFrame(() => {
                const backWrap = document.querySelector('.skills-back-wrapper');
                if (backWrap && backWrap.style.display !== 'none') {
                    const rail = iconsBar.closest('.top-rail.skills');
                    const wrap = rail ? rail.parentElement : null;
                    if (rail && wrap && wrap.classList.contains('skills-rail-wrap')) {
                        const railRect = rail.getBoundingClientRect();
                        const wrapRect = wrap.getBoundingClientRect();
                        const railLeft = railRect.left - wrapRect.left;
                        // Posiciona na borda esquerda do rail (botão fica atrás com translateX)
                        backWrap.style.left = railLeft + 'px';
                    }
                }
            });
            if (cacheKey) {
                subBarTemplateCache.set(cacheKey, {
                    template: templateClone, lang: langKey
                });
            }
        } window.addEventListener('gla:langChanged', () => {
            subBarTemplateCache.clear();
            const skillsRoot = document.getElementById('skills');
            const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {
            };
            const lang = getLangKey();
            Array.from(iconsBar.querySelectorAll('.skill-icon')).forEach(icon => {
                const pack = {
                    pt: icon.dataset.descPt || '', en: icon.dataset.descEn || '', es: icon.dataset.descEs || '', pl: icon.dataset.descPl || ''
                };
                const chosen = (pack[lang] || pack.pt || pack.en || pack.es || pack.pl || icon.dataset.desc || '').trim();
                if (chosen) icon.dataset.desc = chosen;
            });
            barStack.forEach(frame => {
                (frame.items || []).forEach(it => {
                    const pack = {
                        pt: it.descPt, en: it.descEn, es: it.descEs, pl: it.descPl
                    };
                    const chosen = (pack[lang] || pack.pt || pack.en || pack.es || pack.pl || it.desc || '');
                    it.desc = chosen;
                });
            });
            if (descBox) {
                applyFlagTooltips(descBox);
            } const activeIcon = window.__lastActiveSkillIcon;
            if (activeIcon && activeIcon.dataset.weapon) {
                activateSkill(activeIcon, {
                    openSubs: false
                });
            }
        });
        wireClicksForCurrentBar();
         const b0 = ensureBackButton();
        if (b0) {
            b0.classList.add('peek');
            b0.style.alignSelf = 'stretch';
        }


    .weapon-toggle-container.weapon-active .weapon-toggle-name[data-lang="es"]::after {
        // Move inicialização de tooltip para requestIdleCallback (não crítico)
         content: "Desequipar Arma";
        if ('requestIdleCallback' in window) {
    }
            requestIdleCallback(() => {
                (function initSkillTooltip() {
                    if (document.querySelector('.skill-tooltip')) return;
                    const tip = document.createElement('div');
                    tip.className = 'skill-tooltip';
                    tip.setAttribute('role', 'tooltip');
                    tip.setAttribute('aria-hidden', 'true');
                    document.body.appendChild(tip);
                    const lockUntilRef = {
                        value: 0
                    };
                    function measureAndPos(el) {
                        if (!el || tip.getAttribute('aria-hidden') === 'true') return;
                        tip.style.left = '0px';
                        tip.style.top = '0px';
                        const rect = el.getBoundingClientRect();
                        const tr = tip.getBoundingClientRect();
                        let left = Math.round(rect.left + (rect.width - tr.width) / 2);
                        left = Math.max(8, Math.min(left, window.innerWidth - tr.width - 8));
                        const coarse = (window.matchMedia && matchMedia('(pointer: coarse)').matches) || (window.innerWidth <= 600);
                        let top = coarse ? Math.round(rect.bottom + 10) : Math.round(rect.top - tr.height - 8);
                        if (top < 8) top = Math.round(rect.bottom + 10);
                        tip.style.left = left + 'px';
                        tip.style.top = top + 'px';
                    } function show(el, text) {
                        tip.textContent = text || '';
                        tip.setAttribute('aria-hidden', 'false');
                        measureAndPos(el);
                        tip.style.opacity = '1';
                    } function hide() {
                        tip.setAttribute('aria-hidden', 'true');
                        tip.style.opacity = '0';
                        tip.style.left = '-9999px';
                        tip.style.top = '-9999px';
                    } window.__globalSkillTooltip = {
                        show, hide, measureAndPos, lockUntil: lockUntilRef
                    };
                    Array.from(document.querySelectorAll('.icon-bar .skill-icon')).forEach(icon => {
                        if (icon.dataset.weaponToggle === '1' || icon.classList.contains('weapon-bar-toggle')) return;
                        if (icon.dataset.tipwired) return;
                        icon.dataset.tipwired = '1';
                        const label = icon.dataset.nome || icon.dataset.name || icon.title || '';
                        if (label && !icon.hasAttribute('aria-label')) icon.setAttribute('aria-label', label);
                        if (icon.hasAttribute('title')) icon.removeAttribute('title');
                        const img = icon.querySelector('img');
                        if (img) {
                            const imgAlt = img.getAttribute('alt') || '';
                            const imgTitle = img.getAttribute('title') || '';
                            if (!label && (imgAlt || imgTitle)) icon.setAttribute('aria-label', imgAlt || imgTitle);
                            img.setAttribute('alt', '');
                            if (img.hasAttribute('title')) img.removeAttribute('title');
                        } icon.addEventListener('mouseenter', () => show(icon, label));
                        icon.addEventListener('mousemove', () => {
                            if (performance.now() >= lockUntilRef.value) measureAndPos(icon);
                        });
                        icon.addEventListener('click', () => {
                            lockUntilRef.value = performance.now() + 240;
                            measureAndPos(icon);
                        });
                        icon.addEventListener('mouseleave', hide);
                    });
                    Array.from(document.querySelectorAll('.subskills-rail .subicon')).forEach(sub => {
                        if (sub.dataset.tipwired) return;
                        sub.dataset.tipwired = '1';
                        const label = sub.getAttribute('title') || sub.getAttribute('aria-label') || '';
                        if (label && !sub.hasAttribute('aria-label')) sub.setAttribute('aria-label', label);
                        if (sub.hasAttribute('title')) sub.removeAttribute('title');
                        sub.addEventListener('mouseenter', () => show(sub, label));
                        sub.addEventListener('mousemove', () => {
                            if (performance.now() >= lockUntilRef.value) measureAndPos(sub);
                        });
                        sub.addEventListener('click', () => {
                            lockUntilRef.value = performance.now() + 240;
                            measureAndPos(sub);
                        });
                        sub.addEventListener('mouseleave', hide);
                    });
                    window.addEventListener('scroll', () => {
                        const visible = document.querySelector('.skill-tooltip[aria-hidden="false"]');
                        if (!visible) return;
                        const target = document.querySelector('.subskills-rail .subicon:hover') || document.querySelector('.subskills-rail .subicon.active') || document.querySelector('.icon-bar .skill-icon:hover') || document.querySelector('.icon-bar .skill-icon.active');
                        measureAndPos(target);
                    }, true);
                    window.addEventListener('resize', () => {
                        const target = document.querySelector('.subskills-rail .subicon:hover') || document.querySelector('.subskills-rail .subicon.active') || document.querySelector('.icon-bar .skill-icon:hover') || document.querySelector('.icon-bar .skill-icon.active');
                        measureAndPos(target);
                    });
                })();
            }, { timeout: 2000 });
         } else {
            // Fallback para navegadores sem requestIdleCallback
            setTimeout(() => {
                (function initSkillTooltip() {
                    if (document.querySelector('.skill-tooltip')) return;
                    const tip = document.createElement('div');
                    tip.className = 'skill-tooltip';
                    tip.setAttribute('role', 'tooltip');
                    tip.setAttribute('aria-hidden', 'true');
                    document.body.appendChild(tip);
                    window.__globalSkillTooltip = {
                        show: (el, text) => {
                            if (!el || !text) return;
                            tip.textContent = text;
                            tip.setAttribute('aria-hidden', 'false');
                            measureAndPos(el);
                        },
                        hide: () => {
                            tip.setAttribute('aria-hidden', 'true');
                            tip.style.left = '-9999px';
                            tip.style.top = '-9999px';
                        },
                        measureAndPos: (el) => {
                            if (!el || tip.getAttribute('aria-hidden') === 'true') return;
                            const rect = el.getBoundingClientRect();
                            const tipRect = tip.getBoundingClientRect();
                            let left = rect.left + (rect.width / 2) - (tipRect.width / 2);
                            let top = rect.top - tipRect.height - 8;
                            if (left < 8) left = 8;
                            if (left + tipRect.width > window.innerWidth - 8) left = window.innerWidth - tipRect.width - 8;
                            if (top < 8) top = rect.bottom + 8;
                            tip.style.left = left + 'px';
                            tip.style.top = top + 'px';
                        },
                        lockUntil: { value: 0 }
                    };
                    const { measureAndPos } = window.__globalSkillTooltip;
                    window.addEventListener('scroll', () => {
                        const visible = document.querySelector('.skill-tooltip[aria-hidden="false"]');
                        if (!visible) return;
                        const target = document.querySelector('.subskills-rail .subicon:hover') || document.querySelector('.subskills-rail .subicon.active') || document.querySelector('.icon-bar .skill-icon:hover') || document.querySelector('.icon-bar .skill-icon.active');
                        measureAndPos(target);
                    }, true);
                    window.addEventListener('resize', () => {
                        const target = document.querySelector('.subskills-rail .subicon:hover') || document.querySelector('.subskills-rail .subicon.active') || document.querySelector('.icon-bar .skill-icon:hover') || document.querySelector('.icon-bar .skill-icon.active');
                        measureAndPos(target);
                    });
                })();
            }, 100);
        }


    .weapon-toggle-container.weapon-active .weapon-toggle-name[data-lang="pl"]::after {
        (function initTabs() {
         content: "Zdjęć Broń";
            const tabs = Array.from(document.querySelectorAll('.tab-btn'));
    }
            if (!tabs.length) return;
            const contents = Array.from(document.querySelectorAll('.tab-content'));
            const characterBox = document.querySelector('.character-box');
            let wrapper = characterBox.querySelector('.tabs-height-wrapper');
            if (!wrapper) {
                wrapper = document.createElement('div');
                wrapper.className = 'tabs-height-wrapper';
                contents.forEach(c => {
                    wrapper.appendChild(c);
                });
                const tabsElement = characterBox.querySelector('.character-tabs');
                if (tabsElement && tabsElement.nextSibling) {
                    characterBox.insertBefore(wrapper, tabsElement.nextSibling);
                } else {
                    characterBox.appendChild(wrapper);
                }
            } async function smoothHeightTransition(fromTab, toTab) {
                if (!wrapper) return Promise.resolve();
                const scrollY = window.scrollY;
                const currentHeight = wrapper.getBoundingClientRect().height;
                await new Promise((resolve) => {
                    const videoContainers = toTab.querySelectorAll('.video-container');
                    const contentCard = toTab.querySelector('.content-card');
                    if (videoContainers.length === 0) {
                        requestAnimationFrame(() => {
                            requestAnimationFrame(() => {
                                requestAnimationFrame(() => resolve());
                            });
                        });
                        return;
                    } let lastHeight = 0;
                    let stableCount = 0;
                    const checksNeeded = 3;
                    let totalChecks = 0;
                    const maxChecks = 15;
                    function checkStability() {
                        totalChecks++;
                        const currentTabHeight = toTab.scrollHeight;
                        if (Math.abs(currentTabHeight - lastHeight) < 5) {
                            stableCount++;
                        } else {
                            stableCount = 0;
                        } lastHeight = currentTabHeight;
                        if (stableCount >= checksNeeded || totalChecks >= maxChecks) {
                            resolve();
                        } else {
                            setTimeout(checkStability, 50);
                        }
                    } setTimeout(checkStability, 50);
                });
                const nextHeight = toTab.getBoundingClientRect().height;
                const finalHeight = Math.max(nextHeight, 100);
                if (Math.abs(finalHeight - currentHeight) < 30) {
                    wrapper.style.height = '';
                    return Promise.resolve();
                } wrapper.style.overflow = 'hidden';
                wrapper.style.height = currentHeight + 'px';
                wrapper.offsetHeight;
                wrapper.style.transition = 'height 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
                requestAnimationFrame(() => {
                    wrapper.style.height = finalHeight + 'px';
                });
                return new Promise(resolve => {
                    setTimeout(() => {
                        wrapper.style.height = '';
                        wrapper.style.transition = '';
                        wrapper.style.overflow = '';
                        resolve();
                    }, 320);
                });
            } tabs.forEach(btn => {
                if (btn.dataset.wiredTab) return;
                btn.dataset.wiredTab = '1';
                btn.addEventListener('click', () => {
                    const target = btn.getAttribute('data-tab');
                    const currentActive = contents.find(c => c.classList.contains('active'));
                    const nextActive = contents.find(c => c.id === target);
                    if (currentActive === nextActive) return;
                    document.body.classList.add('transitioning-tabs');
                    if (currentActive) {
                        currentActive.style.opacity = '0';
                        currentActive.style.transform = 'translateY(-8px)';
                    } setTimeout(async () => {
                        contents.forEach(c => {
                            if (c !== nextActive) {
                                c.style.display = 'none';
                                c.classList.remove('active');
                            }
                        });
                        tabs.forEach(b => b.classList.toggle('active', b === btn));
                        if (nextActive) {
                            nextActive.classList.add('active');
                            nextActive.style.display = 'block';
                            nextActive.style.opacity = '0';
                            nextActive.style.visibility = 'hidden';
                            nextActive.offsetHeight;
                            try {
                                if (target === 'skills') {
                                    const tabEl = document.getElementById(target);
                                    if (tabEl) {
                                        const activeIcon = tabEl.querySelector('.icon-bar .skill-icon.active');
                                        const firstIcon = tabEl.querySelector('.icon-bar .skill-icon');
                                        const toClick = activeIcon || firstIcon;
                                        if (toClick) {
                                            const had = document.body.dataset.suppressSkillPlay;
                                            document.body.dataset.suppressSkillPlay = '1';
                                            toClick.click();
                                            if (had) document.body.dataset.suppressSkillPlay = had;
                                        }
                                    }
                                }
                            } catch (e) {
                            }
                        } if (currentActive && nextActive) {
                            await smoothHeightTransition(currentActive, nextActive);
                        } if (nextActive) {
                            nextActive.style.visibility = '';
                            nextActive.style.transform = 'translateY(12px)';
                            requestAnimationFrame(() => {
                                nextActive.style.opacity = '1';
                                nextActive.style.transform = 'translateY(0)';
                                setTimeout(() => {
                                    nextActive.style.opacity = '';
                                    nextActive.style.transform = '';
                                    document.body.classList.remove('transitioning-tabs');
                                    try {
                                        delete document.body.dataset.suppressSkillPlay;
                                    } catch {
                                    }
                                }, 300);
                            });
                        }
                    }, 120);
                    setTimeout(() => {
                        syncDescHeight();
                        if (target === 'skins') {
                            videosCache.forEach(v => {
                                try {
                                    v.pause();
                                } catch (e) {
                                } v.style.display = 'none';
                            });
                            if (videoBox) {
                                videoBox.querySelectorAll('video.skill-video').forEach(v => {
                                    try {
                                        v.pause();
                                    } catch (e) {
                                    } v.style.display = 'none';
                                });
                            } if (window.__subskills) window.__subskills.hideAll?.(videoBox);
                            const placeholder = videoBox?.querySelector('.video-placeholder');
                            if (videoBox && placeholder) {
                                placeholder.style.display = 'none';
                                placeholder.classList.add('fade-out');
                            }
                        } else {
                            const activeIcon = document.querySelector('.icon-bar .skill-icon.active');
                            if (activeIcon) activeIcon.click();
                        }
                    }, 450);
                });
            });
        })();
        (function initSkinsArrows() {
            const carousel = $('.skins-carousel');
            const wrapper = $('.skins-carousel-wrapper');
            const left = $('.skins-arrow.left');
            const right = $('.skins-arrow.right');
            if (!carousel || !left || !right || !wrapper) return;
            if (wrapper.dataset.wired) return;
            wrapper.dataset.wired = '1';
            const scrollAmt = () => Math.round(carousel.clientWidth * 0.6);
            function setState() {
                const max = carousel.scrollWidth - carousel.clientWidth;
                const x = carousel.scrollLeft;
                const hasLeft = x > 5, hasRight = x < max - 5;
                left.style.display = hasLeft ? 'inline-block' : 'none';
                right.style.display = hasRight ? 'inline-block' : 'none';
                wrapper.classList.toggle('has-left', hasLeft);
                wrapper.classList.toggle('has-right', hasRight);
                carousel.style.justifyContent = (!hasLeft && !hasRight) ? 'center' : '';
            } function go(dir) {
                const max = carousel.scrollWidth - carousel.clientWidth;
                const next = dir < 0 ? Math.max(0, carousel.scrollLeft - scrollAmt()) : Math.min(max, carousel.scrollLeft + scrollAmt());
                carousel.scrollTo({
                    left: next, behavior: 'smooth'
                });
            } left.addEventListener('click', () => go(-1));
            right.addEventListener('click', () => go(1));
            carousel.addEventListener('scroll', setState);
            new ResizeObserver(setState).observe(carousel);
            setState();
        })();
        function renderAttributes(str) {
            const skillsRoot = document.getElementById('skills');
            const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {
            };
            const langRaw = (document.documentElement.lang || skillsRoot?.dataset.i18nDefault || 'pt').toLowerCase();
            const langKey = i18nMap[langRaw] ? langRaw : (i18nMap[langRaw.split('-')[0]] ? langRaw.split('-')[0] : 'pt');
            const L = i18nMap[langKey] || i18nMap.pt || {
                cooldown: 'Recarga', energy_gain: 'Ganho de energia', energy_cost: 'Custo de energia', power: 'Poder', power_pvp: 'Poder PvP', level: 'Nível'
            };
            const vals = (str || '').split(',').map(v => v.trim());
            // Processa valores, tratando strings vazias e "-" como NaN
            // IMPORTANTE: ordem fixa é [powerpve, powerpvp, energy, cooldown]
            const parseValue = (val) => {
                if (!val || val === '' || val === '-') return NaN;
                const parsed = parseFloat(val);
                return isNaN(parsed) ? NaN : parsed;
            };
            const pve = parseValue(vals[0]);
            const pvp = parseValue(vals[1]);
            const ene = parseValue(vals[2]);
            const cd = parseValue(vals[3]);
            // Debug: log se houver problema na ordem
            if (str && str.includes(',') && !isNaN(cd) && !isNaN(pvp) && cd === pvp) {
                console.warn('[Skills] renderAttributes: possível problema na ordem dos atributos', { str, vals, pve, pvp, ene, cd });
            }
            const rows = [];
            // Ordem de exibição: cooldown, energy, power, power_pvp
            if (!isNaN(cd)) rows.push([L.cooldown, cd]);
            if (!isNaN(ene) && ene !== 0) {
                const label = ene > 0 ? L.energy_gain : L.energy_cost;
                rows.push([label, Math.abs(ene)]);
            }
            if (!isNaN(pve)) rows.push([L.power, pve]);
            if (!isNaN(pvp)) rows.push([L.power_pvp, pvp]);
            // Debug: log se houver valores suspeitos (desabilitado para performance)
            // if (str && str.includes(',')) {
            //    console.log('[Skills] renderAttributes processed', {
            //        str,
            //         vals: vals.slice(0, 4),
            //        parsed: { pve, pvp, ene, cd },
            //        rows: rows.map(r => r[0])
            //    });
            // }
            if (!rows.length) return '';
            const html = rows.map(([rowLabel, rowValue]) => `<div class="attr-row"><span class="attr-label">${rowLabel}</span><span class="attr-value">${rowValue}</span></div>`).join('');
            return `<div class="attr-list">${html}</div>`;
        } function syncDescHeight() {
        } window.addEventListener('resize', syncDescHeight);
        if (videoBox) new ResizeObserver(syncDescHeight).observe(videoBox);
        iconItems.forEach(el => {
            const wired = !!el.dataset._sync_wired;
            if (wired) return;
            el.dataset._sync_wired = '1';
            el.addEventListener('click', () => {
                Promise.resolve().then(syncDescHeight);
            });
        });
        if (iconsBar) {
            const scrollWrapper = iconsBar.closest('.icon-scroll-x') || iconsBar.parentElement;
            const scrollContainer = scrollWrapper && scrollWrapper.classList.contains('icon-scroll-x') ? scrollWrapper : iconsBar;
            addOnce(scrollContainer, 'wheel', (e) => {
                if (e.deltaY) {
                    e.preventDefault();
                    scrollContainer.scrollLeft += e.deltaY;
                }
            }, { passive: false }); // passive: false necessário porque usamos preventDefault()
        }
        wireClicksForCurrentBar();
        if (iconItems.length) {
            const first = iconItems[0];
            if (first) {
                activateSkill(first, {
                    openSubs: false
                });
            }
        }


    /* Estado ativo - destaque vermelho */
        // Aplica lazy loading em imagens fora do viewport inicial
    .weapon-toggle-container.weapon-active .weapon-toggle-sprite {
        (function applyLazyLoading() {
        background-color: rgb(200, 60, 40) !important;
            if ('IntersectionObserver' in window) {
        border: 2px solid rgba(255, 255, 255, 0.15);
                const imageObserver = new IntersectionObserver((entries, observer) => {
        box-shadow: 0 4px 12px rgba(0, 0, 0, .4);
                    entries.forEach(entry => {
    }
                        if (entry.isIntersecting) {
                            const img = entry.target;
                            if (img.tagName === 'IMG' && !img.hasAttribute('loading')) {
                                img.loading = 'lazy';
                            }
                            observer.unobserve(img);
                        }
                    });
                });


    .weapon-toggle-container.weapon-active .weapon-toggle-bar {
                // Observa imagens que não estão no viewport inicial
        background-color: rgb(200, 60, 40);
                document.querySelectorAll('img:not(.topbar-icon):not([loading])').forEach(img => {
        background-image: linear-gradient(135deg, rgb(200, 60, 40), rgb(160, 45, 30));
                    const rect = img.getBoundingClientRect();
        border-color: rgba(255, 87, 34, 0.3);
                    if (rect.bottom > window.innerHeight || rect.top < 0) {
        border-left: none;
                        imageObserver.observe(img);
         border-radius: 0 7px 7px 0;
                    }
    }
                });
            }
         })();


    .weapon-toggle-container.weapon-active .weapon-toggle-name {
        setTimeout(() => {
        color: #fff;
            Array.from(document.querySelectorAll('.skill-icon')).forEach(el => {
        text-shadow: 0 0 4px rgba(255, 87, 34, 0.5);
            });
     }
            videosCache.forEach((v, idx) => {
</style>
                const src = v.querySelector('source') ? v.querySelector('source').src : v.src;
                v.addEventListener('error', (ev) => {
                });
                v.addEventListener('loadedmetadata', () => {
                });
            });
        }, 600);
     })();
</script>

Edição atual tal como às 04h59min de 4 de janeiro de 2026

<script>

   (function () {
       const $ = (s, root = document) => root.querySelector(s);
       const $$ = (s, root = document) => Array.from(root.querySelectorAll(s));
       const ensureRemoved = sel => {
           Array.from(document.querySelectorAll(sel)).forEach(n => n.remove());
       };
       const onceFlag = (el, key) => {
           if (!el) return false;
           if (el.dataset[key]) return false;
           el.dataset[key] = '1';
           return true;
       };
       const addOnce = (el, ev, fn, options = {}) => {
           if (!el) return;
           const attr = `data-wired-${ev}`;
           if (el.hasAttribute(attr)) return;
           el.addEventListener(ev, fn, options);
           el.setAttribute(attr, '1');
       };
       const FLAG_ICON_FILES = {
           aggro: 'Enemyaggro-icon.png', bridge: 'Bridgemaker-icon.png', wall: 'Destroywall-icon.png', quickcast: 'Quickcast-icon.png', wallpass: 'Passthroughwall-icon.png'
       };
       const subBarTemplateCache = window.__skillSubBarTemplateCache || (window.__skillSubBarTemplateCache = new Map());
       const imagePreloadCache = window.__skillImagePreloadCache || (window.__skillImagePreloadCache = new Map());
       const videoPreloadCache = window.__skillVideoPreloadCache || (window.__skillVideoPreloadCache = new Set());
       const flagRowCache = window.__skillFlagRowCache || (window.__skillFlagRowCache = new Map());
       const flagIconURLCache = window.__skillFlagIconURLCache || (window.__skillFlagIconURLCache = new Map());
       // Sistema de múltiplas formas (genérico)
       let currentForm = null; // null = primeira forma, depois nome da forma atual
       let formsData = {};
       let fixedSkills = []; // Skills que sempre aparecem (Change Form, Guard Point, etc.)
       function showFormTransitionVideo(changeFormIconEl) {
           const skillsRoot = document.getElementById('skills');
           if (!skillsRoot) return;
           // Busca videoBox
           let videoBox = skillsRoot.querySelector('.video-container');
           if (!videoBox) {
               const skillsContainer = skillsRoot.querySelector('.skills-container');
               if (skillsContainer) {
                   videoBox = skillsContainer.querySelector('.video-container');
               }
           }
           if (!videoBox) return;
           try {
               // Lê dados de forms para determinar forma atual e próxima
               const formsJSON = skillsRoot.dataset.forms || '{}';
               if (formsJSON && formsJSON !== '{}') {
                   const tempFormsData = JSON.parse(formsJSON);
                   const formNames = Object.keys(tempFormsData);
                   // Determina forma atual e próxima
                   const currentIdx = currentForm ? formNames.indexOf(currentForm) : -1;
                   const nextIdx = (currentIdx + 1) % formNames.length;
                   const nextForm = formNames[nextIdx];
                   // Busca vídeo de transição na skill Change Form
                   // form_videos[forma_atual] = "video.mp4" (vídeo da transição atual → próxima)
                   const formVideosRaw = changeFormIconEl.dataset.formVideos || changeFormIconEl.getAttribute('data-form-videos');
                   if (formVideosRaw) {
                       try {
                           const videos = JSON.parse(formVideosRaw);
                           const transitionVideo = videos[currentForm] || ;
                           if (transitionVideo && transitionVideo.trim() !== ) {
                               const videoURL = filePathURL(transitionVideo);
                               if (videoURL) {
                                   // Busca ou cria elemento de vídeo para esta transição
                                   const videoKey = `form_transition:${currentForm}:${nextForm}`;
                                   let v = videosCache.get(videoKey);
                                   if (!v) {
                                       // Cria novo elemento de vídeo
                                       v = document.createElement('video');
                                       v.className = 'skill-video';
                                       v.src = videoURL;
                                       v.preload = 'auto';
                                       v.controls = false;
                                       v.muted = false;
                                       v.loop = false;
                                       v.playsInline = true;
                                       videoBox.appendChild(v);
                                       videosCache.set(videoKey, v);
                                   }
                                   // Mostra e reproduz o vídeo
                                   Array.from(videoBox.querySelectorAll('video.skill-video')).forEach(vid => {
                                       try {
                                           vid.pause();
                                       } catch (e) {
                                       }
                                       vid.style.display = 'none';
                                   });
                                   videoBox.style.display = 'block';
                                   v.style.display = 'block';
                                   try {
                                       v.currentTime = 0;
                                       v.play().catch(() => { });
                                   } catch (e) {
                                   }
                               }
                           }
                       } catch (e) {
                           console.error('[Forms] Erro ao parsear form_videos:', e);
                       }
                   }
               }
           } catch (e) {
               console.error('[Forms] Erro ao processar vídeo de transição:', e);
           }
       }
       // Detecta qual forma está atualmente visível no DOM
       function detectCurrentForm() {
           const iconBar = document.querySelector('.icon-bar');
           if (!iconBar || !formsData || Object.keys(formsData).length === 0) return null;
           // Coleta todas as skills de form que estão visíveis no DOM
           const allFormSkillNames = new Set();
           Object.values(formsData).forEach(form => {
               if (form.order && Array.isArray(form.order)) {
                   form.order.forEach(skillName => allFormSkillNames.add(skillName));
               }
           });
           const visibleFormSkillNames = new Set();
           Array.from(iconBar.querySelectorAll('.skill-icon[data-index]')).forEach(icon => {
               const name = (icon.dataset.nome || ).trim();
               if (name && allFormSkillNames.has(name)) {
                   visibleFormSkillNames.add(name);
               }
           });
           // Compara com cada forma para ver qual corresponde
           for (const [formName, formData] of Object.entries(formsData)) {
               if (formData.order && Array.isArray(formData.order)) {
                   const formSkillSet = new Set(formData.order);
                   // Verifica se todas as skills desta forma estão visíveis
                   let allMatch = true;
                   for (const skillName of formData.order) {
                       if (!visibleFormSkillNames.has(skillName)) {
                           allMatch = false;
                           break;
                       }
                   }
                   if (allMatch && formData.order.length === visibleFormSkillNames.size) {
                       return formName;
                   }
               }
           }
           return null;
       }
       function switchForm() {
           const skillsRoot = document.getElementById('skills');
           if (!skillsRoot) return;
           // Lê dados de forms do atributo data-forms
           try {
               const formsJSON = skillsRoot.dataset.forms || '{}';
               if (formsJSON && formsJSON !== '{}') {
                   formsData = JSON.parse(formsJSON);
               }
           } catch (e) {
               console.error('[Forms] Erro ao parsear forms:', e);
               return;
           }
           if (!formsData || Object.keys(formsData).length === 0) {
               return; // Não tem forms, não faz nada
           }
           // Identifica skills fixas (sempre presentes)
           const iconBar = document.querySelector('.icon-bar');
           if (!iconBar) return;
           // Busca a skill com form_switch dinamicamente (genérico)
           const changeFormIcon = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'))
               .find(icon => icon.dataset.formSwitch === 'true' || icon.getAttribute('data-form-switch') === 'true');
           if (changeFormIcon) {
               changeFormIcon.classList.add('active');
           }
           // Determina skills fixas dinamicamente: todas que não estão em nenhuma forms
           const allFormSkillNames = new Set();
           Object.values(formsData).forEach(form => {
               if (form.order && Array.isArray(form.order)) {
                   form.order.forEach(skillName => allFormSkillNames.add(skillName));
               }
           });
           // Skills fixas = todas as skills na barra que não estão em nenhuma forms
           fixedSkills = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'))
               .filter(icon => {
                   const name = (icon.dataset.nome || ).trim();
                   return name && !allFormSkillNames.has(name);
               })
               .map(icon => snapshotIconData(icon));
           // Obtém lista de formas disponíveis
           const formNames = Object.keys(formsData);
           if (formNames.length === 0) return;
           // Determina próxima forma
           // Se currentForm é null, detecta qual forma está atualmente visível no DOM
           if (currentForm === null) {
               currentForm = detectCurrentForm();
           }
           // Se ainda não conseguiu detectar, usa a primeira forma como fallback
           if (!currentForm && formNames.length > 0) {
               currentForm = formNames[0];
           }
           // Cria ordem circular fixa baseada na forma atual detectada
           // Se detectamos "Brain Point", ordem é: Brain → Kung Fu → Heavy → Brain
           // Se detectamos "Kung Fu Point", ordem é: Kung Fu → Heavy → Brain → Kung Fu
           // Se detectamos "Heavy Point", ordem é: Heavy → Brain → Kung Fu → Heavy
           let orderedFormNames = [];
           if (currentForm === "Brain Point" && formNames.length === 3) {
               // Ordem conhecida: Brain → Kung Fu → Heavy
               if (formNames.includes("Kung Fu Point") && formNames.includes("Heavy Point")) {
                   orderedFormNames = ["Brain Point", "Kung Fu Point", "Heavy Point"];
               }
           } else if (currentForm === "Kung Fu Point" && formNames.length === 3) {
               // Ordem conhecida: Kung Fu → Heavy → Brain
               if (formNames.includes("Heavy Point") && formNames.includes("Brain Point")) {
                   orderedFormNames = ["Kung Fu Point", "Heavy Point", "Brain Point"];
               }
           } else if (currentForm === "Heavy Point" && formNames.length === 3) {
               // Ordem conhecida: Heavy → Brain → Kung Fu
               if (formNames.includes("Brain Point") && formNames.includes("Kung Fu Point")) {
                   orderedFormNames = ["Heavy Point", "Brain Point", "Kung Fu Point"];
               }
           }
           // Se não conseguiu criar ordem conhecida, usa ordem alfabética como fallback
           if (orderedFormNames.length === 0) {
               orderedFormNames = [...formNames].sort();
               // Se sabemos a forma atual, reorganiza para começar por ela
               if (currentForm) {
                   const currentIdx = orderedFormNames.indexOf(currentForm);
                   if (currentIdx !== -1) {
                       orderedFormNames = [
                           ...orderedFormNames.slice(currentIdx),
                           ...orderedFormNames.slice(0, currentIdx)
                       ];
                   }
               }
           }
           const currentIdx = orderedFormNames.indexOf(currentForm);
           if (currentIdx === -1) return; // Forma não encontrada
           const nextIdx = (currentIdx + 1) % orderedFormNames.length;
           const nextForm = orderedFormNames[nextIdx];
           currentForm = nextForm;
           // Atualiza barra de skills (que vai remover o active depois da animação)
           updateSkillsBarForForm(nextForm, formsData[nextForm], changeFormIcon);
       }
       function snapshotIconData(icon) {
           const img = icon.querySelector('img');
           const iconURL = img ? img.src : ;
           const subsRaw = icon.dataset.subs || icon.getAttribute('data-subs') || ;
           let subs = null;
           try {
               subs = subsRaw ? JSON.parse(subsRaw) : null;
           } catch {
               subs = null;
           }
           let flags = null;
           if (icon.dataset.flags) {
               try {
                   flags = JSON.parse(icon.dataset.flags);
               } catch (e) {
               }
           }
           let weapon = null;
           if (icon.dataset.weapon) {
               try {
                   weapon = JSON.parse(icon.dataset.weapon);
               } catch (e) {
               }
           }
           return {
               name: icon.dataset.nome || icon.dataset.name || ,
               index: icon.dataset.index || ,
               level: icon.dataset.level || ,
               desc: icon.dataset.desc || ,
               descPt: icon.dataset.descPt || ,
               descEn: icon.dataset.descEn || ,
               descEs: icon.dataset.descEs || ,
               descPl: icon.dataset.descPl || ,
               attrs: icon.dataset.atr || icon.dataset.attrs || ,
               video: icon.dataset.video || ,
               iconURL,
               iconFile: icon.dataset.iconFile || ,
               subs,
               flags,
               weapon,
               formSwitch: icon.dataset.formSwitch || 
           };
       }
       function updateSkillsBarForForm(formName, formData, changeFormIconEl) {
           const iconBar = document.querySelector('.icon-bar');
           if (!iconBar || !formData || !formData.skills) return;
           // Determina skills fixas dinamicamente: todas que não estão em nenhuma forms
           const allFormSkillNames = new Set();
           Object.values(formsData).forEach(form => {
               if (form.order && Array.isArray(form.order)) {
                   form.order.forEach(skillName => allFormSkillNames.add(skillName));
               }
           });
           // Remove skills de forma antigas (que não são fixas) com animação de saída
           const existingIcons = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'));
           const iconsToRemove = [];
           existingIcons.forEach(icon => {
               const name = (icon.dataset.nome || ).trim();
               if (name && allFormSkillNames.has(name)) {
                   iconsToRemove.push(icon);
               }
           });
           // Anima saída das skills antigas
           iconsToRemove.forEach(icon => {
               icon.style.transition = 'opacity .15s ease, transform .15s ease';
               icon.style.opacity = '0';
               icon.style.transform = 'translateY(-6px)';
           });
           // Encontra a skill com form_switch dinamicamente (genérico)
           const changeFormIcon = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'))
               .find(icon => icon.dataset.formSwitch === 'true' || icon.getAttribute('data-form-switch') === 'true');
           // Encontra a próxima skill fixa depois do form_switch dinamicamente
           let nextFixedSkillIcon = null;
           if (changeFormIcon) {
               const allIcons = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]')).sort((a, b) => {
                   return parseInt(a.dataset.index || '0', 10) - parseInt(b.dataset.index || '0', 10);
               });
               const changeFormIndex = allIcons.indexOf(changeFormIcon);
               const allFormSkillNames = new Set();
               Object.values(formsData).forEach(form => {
                   if (form.order && Array.isArray(form.order)) {
                       form.order.forEach(skillName => allFormSkillNames.add(skillName));
                   }
               });
               // Procura a próxima skill fixa (que não está em forms)
               for (let i = changeFormIndex + 1; i < allIcons.length; i++) {
                   const icon = allIcons[i];
                   const name = (icon.dataset.nome || ).trim();
                   if (name && !allFormSkillNames.has(name)) {
                       nextFixedSkillIcon = icon;
                       break;
                   }
               }
           }
           if (!changeFormIcon || !nextFixedSkillIcon) {
               console.warn('[Forms] Skill com form_switch ou próxima skill fixa não encontrada');
               return;
           }
           const formSkills = formData.skills || [];
           const formOrder = formData.order || [];
           // Primeira skill da forma (vai ANTES do Change Form)
           const firstSkillName = formOrder[0];
           const firstSkillData = formSkills.find(s => s.name === firstSkillName);
           // Terceira skill da forma (vai DEPOIS do Change Form, ANTES do Guard Point)
           const thirdSkillName = formOrder[1]; // Segunda na ordem = terceira skill (índice 1)
           const thirdSkillData = formSkills.find(s => s.name === thirdSkillName);
           // Quinta skill da forma (vai DEPOIS do Guard Point)
           const fifthSkillName = formOrder[2]; // Terceira na ordem = quinta skill (índice 2)
           const fifthSkillData = formSkills.find(s => s.name === fifthSkillName);
           // Cria fragments para inserir
           const firstFragment = document.createDocumentFragment();
           const thirdFragment = document.createDocumentFragment();
           const fifthFragment = document.createDocumentFragment();
           if (firstSkillData) {
               const iconElement = createSkillIconElement(firstSkillData, 1);
               firstFragment.appendChild(iconElement);
           }
           if (thirdSkillData) {
               const changeFormIndex = parseInt(changeFormIcon.dataset.index || '2', 10);
               const iconElement = createSkillIconElement(thirdSkillData, changeFormIndex + 1);
               thirdFragment.appendChild(iconElement);
           }
           if (fifthSkillData) {
               const nextFixedSkillIndex = parseInt(nextFixedSkillIcon.dataset.index || '4', 10);
               const iconElement = createSkillIconElement(fifthSkillData, nextFixedSkillIndex + 1);
               fifthFragment.appendChild(iconElement);
           }
           // Remove os ícones antigos do DOM após animação
           setTimeout(() => {
               iconsToRemove.forEach(icon => {
                   if (icon.parentNode) {
                       icon.remove();
                   }
               });
               // Insere a primeira skill ANTES da skill com form_switch
               if (firstFragment.hasChildNodes()) {
                   iconBar.insertBefore(firstFragment, changeFormIcon);
               }
               // Insere a terceira skill DEPOIS da skill com form_switch, ANTES da próxima skill fixa
               if (thirdFragment.hasChildNodes()) {
                   iconBar.insertBefore(thirdFragment, nextFixedSkillIcon);
               }
               // Insere a quinta skill DEPOIS da próxima skill fixa
               if (fifthFragment.hasChildNodes()) {
                   if (nextFixedSkillIcon.nextSibling) {
                       iconBar.insertBefore(fifthFragment, nextFixedSkillIcon.nextSibling);
                   } else {
                       iconBar.appendChild(fifthFragment);
                   }
               }
               // Anima entrada das novas skills (similar a animateIconsBarEntrance)
               const newIconsInBar = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'))
                   .filter(icon => {
                       const name = (icon.dataset.nome || ).trim();
                       return name && allFormSkillNames.has(name);
                   });
               newIconsInBar.forEach((icon, idx) => {
                   icon.style.opacity = '0';
                   icon.style.transform = 'translateY(6px)';
                   requestAnimationFrame(() => {
                       setTimeout(() => {
                           icon.style.transition = 'opacity .18s ease, transform .18s ease';
                           icon.style.opacity = '1';
                           icon.style.transform = 'translateY(0)';
                       }, idx * 24);
                   });
               });
               // Remove slots de descrição das skills de forma antigas e cria novos
               const descBox = document.querySelector('.skills-details .desc-box');
               if (descBox) {
                   // Encontra os slots de descrição dos elementos fixos
                   const changeFormIndex = parseInt(changeFormIcon.dataset.index || '1', 10);
                   const nextFixedSkillIndex = parseInt(nextFixedSkillIcon.dataset.index || '1', 10);
                   const changeFormDescSlot = descBox.querySelector(`.skill-desc[data-index="${changeFormIndex}"]`);
                   const nextFixedSkillDescSlot = descBox.querySelector(`.skill-desc[data-index="${nextFixedSkillIndex}"]`);
                   // Cria slot para primeira skill (antes do Change Form)
                   if (firstSkillData && changeFormDescSlot) {
                       const descSlot = document.createElement('div');
                       descSlot.className = 'skill-desc';
                       descSlot.setAttribute('data-index', changeFormIndex);
                       descBox.insertBefore(descSlot, changeFormDescSlot);
                   }
                   // Cria slot para terceira skill (depois da skill com form_switch, antes da próxima skill fixa)
                   if (thirdSkillData && nextFixedSkillDescSlot) {
                       const descSlot = document.createElement('div');
                       descSlot.className = 'skill-desc';
                       descSlot.setAttribute('data-index', nextFixedSkillIndex);
                       descBox.insertBefore(descSlot, nextFixedSkillDescSlot);
                   }
                   // Cria slot para quinta skill (depois da próxima skill fixa)
                   if (fifthSkillData && nextFixedSkillDescSlot) {
                       const descSlot = document.createElement('div');
                       descSlot.className = 'skill-desc';
                       descSlot.setAttribute('data-index', nextFixedSkillIndex + 1);
                       if (nextFixedSkillDescSlot.nextSibling) {
                           descBox.insertBefore(descSlot, nextFixedSkillDescSlot.nextSibling);
                       } else {
                           descBox.appendChild(descSlot);
                       }
                   }
               }
               // Re-numera todas as skills na ordem do DOM
               const allIcons = Array.from(iconBar.querySelectorAll('.skill-icon[data-index]'));
               let currentIndex = 1;
               allIcons.forEach(icon => {
                   const oldIndex = icon.dataset.index;
                   icon.setAttribute('data-index', currentIndex);
                   // Atualiza slot de descrição
                   if (descBox && oldIndex) {
                       const descSlot = descBox.querySelector(`.skill-desc[data-index="${oldIndex}"]`);
                       if (descSlot) {
                           descSlot.setAttribute('data-index', currentIndex);
                       }
                   }
                   currentIndex++;
               });
               // Re-wire eventos
               wireClicksForCurrentBar();
               wireTooltipsForNewIcons();
               // Remove active do Change Form após animação completar
               setTimeout(() => {
                   if (changeFormIconEl) {
                       changeFormIconEl.classList.remove('active');
                   }
               }, (newIconsInBar.length * 24) + 180);
           }, 150);
       }
       function createSkillIconElement(skill, index) {
           const iconWrap = document.createElement('div');
           iconWrap.className = 'skill-icon';
           iconWrap.setAttribute('data-index', index);
           iconWrap.setAttribute('data-nome', skill.name || );
           iconWrap.setAttribute('data-desc', );
           iconWrap.setAttribute('data-atr', makeAttrString(skill.powerpve, skill.powerpvp, skill.energy, skill.cooldown));
           iconWrap.setAttribute('data-video', skill.video ? filePathURL(skill.video) : );
           iconWrap.setAttribute('data-video-preload', 'auto');
           iconWrap.setAttribute('data-icon-file', skill.icon || 'Nada.png');
           iconWrap.setAttribute('data-video-file', skill.video || );
           if (skill.level && skill.level !==  && skill.level.toUpperCase() !== 'NIVEL') {
               iconWrap.setAttribute('data-level', skill.level);
           }
           if (skill.desc_i18n) {
               if (skill.desc_i18n.pt) iconWrap.setAttribute('data-desc-pt', skill.desc_i18n.pt);
               if (skill.desc_i18n.en) iconWrap.setAttribute('data-desc-en', skill.desc_i18n.en);
               if (skill.desc_i18n.es) iconWrap.setAttribute('data-desc-es', skill.desc_i18n.es);
               if (skill.desc_i18n.pl) iconWrap.setAttribute('data-desc-pl', skill.desc_i18n.pl);
           }
           if (skill.subs && Array.isArray(skill.subs) && skill.subs.length > 0) {
               iconWrap.setAttribute('data-subs', JSON.stringify(skill.subs));
           }
           if (skill.suborder && Array.isArray(skill.suborder) && skill.suborder.length > 0) {
               iconWrap.setAttribute('data-suborder', JSON.stringify(skill.suborder));
           }
           if (skill.flags && Array.isArray(skill.flags) && skill.flags.length > 0) {
               iconWrap.setAttribute('data-flags', JSON.stringify(skill.flags));
           }
           if (skill.weapon && typeof skill.weapon === 'object' && Object.keys(skill.weapon).length > 0) {
               iconWrap.setAttribute('data-weapon', JSON.stringify(skill.weapon));
           }
           const img = document.createElement('img');
           img.className = 'skill-icon-img';
           img.src = filePathURL(skill.icon || 'Nada.png');
           img.alt = ;
           iconWrap.appendChild(img);
           return iconWrap;
       }
       function createSkillIcon(skill, index, container) {
           // Cria ícone similar ao que é gerado pelo servidor
           const iconWrap = document.createElement('div');
           iconWrap.className = 'skill-icon';
           iconWrap.setAttribute('data-index', index);
           iconWrap.setAttribute('data-nome', skill.name || );
           iconWrap.setAttribute('data-desc', );
           iconWrap.setAttribute('data-atr', makeAttrString(skill.powerpve, skill.powerpvp, skill.energy, skill.cooldown));
           iconWrap.setAttribute('data-video', skill.video ? filePathURL(skill.video) : );
           iconWrap.setAttribute('data-video-preload', 'auto');
           iconWrap.setAttribute('data-icon-file', skill.icon || 'Nada.png');
           iconWrap.setAttribute('data-video-file', skill.video || );
           if (skill.level && skill.level !==  && skill.level.toUpperCase() !== 'NIVEL') {
               iconWrap.setAttribute('data-level', skill.level);
           }
           if (skill.desc_i18n) {
               if (skill.desc_i18n.pt) iconWrap.setAttribute('data-desc-pt', skill.desc_i18n.pt);
               if (skill.desc_i18n.en) iconWrap.setAttribute('data-desc-en', skill.desc_i18n.en);
               if (skill.desc_i18n.es) iconWrap.setAttribute('data-desc-es', skill.desc_i18n.es);
               if (skill.desc_i18n.pl) iconWrap.setAttribute('data-desc-pl', skill.desc_i18n.pl);
           }
           if (skill.subs && Array.isArray(skill.subs) && skill.subs.length > 0) {
               iconWrap.setAttribute('data-subs', JSON.stringify(skill.subs));
           }
           if (skill.suborder && Array.isArray(skill.suborder) && skill.suborder.length > 0) {
               iconWrap.setAttribute('data-suborder', JSON.stringify(skill.suborder));
           }
           if (skill.flags && Array.isArray(skill.flags) && skill.flags.length > 0) {
               iconWrap.setAttribute('data-flags', JSON.stringify(skill.flags));
           }
           if (skill.weapon && typeof skill.weapon === 'object' && Object.keys(skill.weapon).length > 0) {
               iconWrap.setAttribute('data-weapon', JSON.stringify(skill.weapon));
           }
           const img = document.createElement('img');
           img.className = 'skill-icon-img';
           img.src = filePathURL(skill.icon || 'Nada.png');
           img.alt = ;
           iconWrap.appendChild(img);
           container.appendChild(iconWrap);
       }
       function makeAttrString(pve, pvp, energy, cd) {
           const parts = [
               (pve !== undefined && pve !== null && pve !== ) ? String(pve) : '-',
               (pvp !== undefined && pvp !== null && pvp !== ) ? String(pvp) : '-',
               (energy !== undefined && energy !== null && energy !== ) ? String(energy) : '-',
               (cd !== undefined && cd !== null && cd !== ) ? String(cd) : '-'
           ];
           return parts.join(', ');
       }
       function filePathURL(fileName) {
           // Evita requisições para Nada.png que não existe
           if (!fileName || fileName.trim() ===  || fileName === 'Nada.png' || fileName.toLowerCase() === 'nada.png') {
               return ;
           }
           const f = encodeURIComponent(fileName.replace(/^Arquivo:|^File:/, ));
           const base = (window.mw && mw.util && typeof mw.util.wikiScript === 'function') ? mw.util.wikiScript() : (window.mw && window.mw.config ? (mw.config.get('wgScript') || '/index.php') : '/index.php');
           // Garante HTTPS para evitar Mixed Content
           let url = `${base}?title=Especial:FilePath/${f}`;
           if (window.location.protocol === 'https:' && url.startsWith('http://')) {
               url = url.replace('http://', 'https://');
           }
           return url;
       } function slugify(s) {
           if (!s) return ;
           return String(s).toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, ).replace(/[^\w\s-]/g, ).replace(/[\s:/\-]+/g, '-').replace(/^-+|-+$/g, ).replace(/-+/g, '-');
       } window.__skillSlugify = slugify;
       function getLangKey() {
           const skillsRoot = document.getElementById('skills');
           const raw = (document.documentElement.lang || skillsRoot?.dataset.i18nDefault || 'pt').toLowerCase();
           return raw === 'pt-br' ? 'pt' : (raw.split('-')[0] || 'pt');
       } function chooseDescFrom(obj) {
           const lang = getLangKey();
           // Aceita tanto desc_i18n quanto desc para compatibilidade
           const pack = obj.desc_i18n || obj.desc || {
               pt: obj.descPt, en: obj.descEn, es: obj.descEs, pl: obj.descPl
           };
           return (pack && (pack[lang] || pack.pt || pack.en || pack.es || pack.pl)) || ;
       } function renderSubAttributesFromObj(s, L) {

const chip = (label, val) => (val ? `

${label}${val}

` : );

           const pve = (s.powerpve || ).toString().trim();
           const pvp = (s.powerpvp || ).toString().trim();
           const en = (s.energy || ).toString().trim();
           const cd = (s.cooldown || ).toString().trim();
           const rows = [cd ? chip(L.cooldown, cd) : , en ? chip((en.startsWith('-') ? L.energy_cost : L.energy_gain), en.startsWith('-') ? en.replace(/^-/, ) : en.replace(/^\+?/, )) : , pve ? chip(L.power, pve) : , pvp ? chip(L.power_pvp, pvp) : ,].filter(Boolean);

return rows.length ? `

${rows.join()}

` : ;

       } function getFlagIconURL(key) {
           if (!FLAG_ICON_FILES[key]) return ;
           if (!flagIconURLCache.has(key)) {
               flagIconURLCache.set(key, filePathURL(FLAG_ICON_FILES[key]));
           } return flagIconURLCache.get(key);
       } function renderFlagsRow(flags) {
           const arr = (flags || []).filter(Boolean);
           if (!arr.length) return ;
           const cacheKey = arr.join('|');
           if (flagRowCache.has(cacheKey)) {
               return flagRowCache.get(cacheKey);
           } const items = arr.map(k => {
               const url = getFlagIconURL(k);
               return url ? `<img class="skill-flag" data-flag="${k}" alt="" src="${url}">` : ;
           }).join();

const html = items ? `

${items}

` : ;

           if (html) flagRowCache.set(cacheKey, html);
           return html;
       } function applyFlagTooltips(container) {
           const skillsRoot = document.getElementById('skills');
           if (!skillsRoot) return;
           let pack = {
           };
           try {
               pack = JSON.parse(skillsRoot.dataset.i18nFlags || '{}');
           } catch (e) {
           } const lang = getLangKey();
           const dict = pack[lang] || pack.pt || {
           };
           const flags = container.querySelectorAll('.skill-flags .skill-flag[data-flag]');
           const tooltip = window.__globalSkillTooltip;
           if (!tooltip) return;
           flags.forEach(el => {
               const key = el.getAttribute('data-flag');
               const tip = (dict && dict[key]) || ;
               if (!tip) return;
               if (el.dataset.flagTipWired) return;
               el.dataset.flagTipWired = '1';
               el.setAttribute('aria-label', tip);
               if (el.hasAttribute('title')) el.removeAttribute('title');
               el.addEventListener('mouseenter', () => {
                   const tipEl = document.querySelector('.skill-tooltip');
                   if (tipEl) tipEl.classList.add('flag-tooltip');
                   tooltip.show(el, tip);
               });
               el.addEventListener('mousemove', () => {
                   if (performance.now() >= tooltip.lockUntil.value) {
                       tooltip.measureAndPos(el);
                   }
               });
               el.addEventListener('click', () => {
                   tooltip.lockUntil.value = performance.now() + 240;
                   tooltip.measureAndPos(el);
               });
               el.addEventListener('mouseleave', () => {
                   const tipEl = document.querySelector('.skill-tooltip');
                   if (tipEl) tipEl.classList.remove('flag-tooltip');
                   tooltip.hide();
               });
           });
       }
       // ====== Skill/Subskill inheritance helpers ======
       const mainSkillsMeta = {
           byIndex: new Map(),
           byName: new Map(),
           ready: false
       };
       function normalizeFileURL(raw, fallback = ) {
           if (!raw) return fallback;
           const val = String(raw).trim();
           if (!val) return fallback;
           if (/^(https?:)?\/\//i.test(val) || val.startsWith('data:') || val.includes('Especial:FilePath/')) {
               return val;
           } return filePathURL(val);
       }
       function extractFileNameFromURL(url) {
           if (!url) return ;
           const match = String(url).match(/(?:FilePath\/)([^&?]+)/i);
           return match ? decodeURIComponent(match[1]) : ;
       }
       function parseAttrString(raw) {
           const parts = (raw || ).split(',').map(v => v.trim());
           const safe = idx => {
               const val = parts[idx] || ;
               return (val && val !== '-') ? val : ;
           };
           return {
               powerpve: safe(0),
               powerpvp: safe(1),
               energy: safe(2),
               cooldown: safe(3)
           };
       }
       function hasText(value) {
           return typeof value === 'string' ? value.trim() !==  : value !== undefined && value !== null;
       }
       function pickFilled(current, fallback) {
           if (current === 0 || current === '0') return current;
           if (!hasText(current)) return fallback;
           return current;
       }
       function buildMainSkillsMeta(nodes) {
           if (mainSkillsMeta.ready) {
               return mainSkillsMeta;
           }
           (nodes || []).forEach(icon => {
               const index = (icon.dataset.index || ).trim();
               if (!index) return;
               const name = (icon.dataset.nome || icon.dataset.name || ).trim();
               const attrs = parseAttrString(icon.dataset.atr || );
               let iconFile = (icon.dataset.iconFile || ).trim();
               if (!iconFile) {
                   const imgSrc = icon.querySelector('img')?.src || ;
                   const iconMatch = imgSrc.match(/(?:FilePath|images)\/([^\/?]+)$/);
                   iconFile = iconMatch ? decodeURIComponent(iconMatch[1]) : ;
               }
               let videoFile = (icon.dataset.videoFile || ).trim();
               if (!videoFile) {
                   videoFile = extractFileNameFromURL(icon.dataset.video || );
               }
               const meta = {
                   index,
                   name,
                   icon: iconFile || 'Nada.png',
                   level: icon.dataset.level || ,
                   video: videoFile || ,
                   powerpve: attrs.powerpve || ,
                   powerpvp: attrs.powerpvp || ,
                   energy: attrs.energy || ,
                   cooldown: attrs.cooldown || ,
                   desc: icon.dataset.desc || ,
                   descPt: icon.dataset.descPt || ,
                   descEn: icon.dataset.descEn || ,
                   descEs: icon.dataset.descEs || ,
                   descPl: icon.dataset.descPl || 
               };
               mainSkillsMeta.byIndex.set(index, meta);
               mainSkillsMeta.byIndex.set(parseInt(index, 10), meta);
               if (name) {
                   mainSkillsMeta.byName.set(name, meta);
               }
           });
           mainSkillsMeta.ready = true;
           return mainSkillsMeta;
       }
       function inheritSubskillFromMain(sub, meta) {
           if (!sub || !meta) return sub;
           // Verifica se herança está desabilitada
           const shouldInherit = !(sub.inherit === false || sub.inherit === 'no' || sub.inherit === 'false');
           // Suporta refS (novo) e refM (legado)
           const refS = ((sub.refS || sub.S || sub.s || ) + ).trim();
           const refIndex = ((sub.refM || sub.M || sub.m || ) + ).trim();
           let name = (sub.name || sub.n || ).trim();
           let main = null;
           // Se herança está desabilitada, não busca a skill principal
           if (!shouldInherit) {
               return { ...sub };
           }
           // Primeiro tenta por refS
           if (refS) {
               main = meta.byIndex.get(refS) || meta.byIndex.get(parseInt(refS, 10));
           }
           // Depois por refM
           if (!main && refIndex) {
               main = meta.byIndex.get(refIndex) || meta.byIndex.get(parseInt(refIndex, 10));
           }
           // Por último pelo nome
           if (!main && name) {
               main = meta.byName.get(name);
           }
           if (!main) {
               return sub;
           }
           const hydrated = { ...sub };
           if (!name && main.name) {
               name = main.name;
           }
           hydrated.name = name || hydrated.name || main.name || ;
           hydrated.icon = pickFilled(hydrated.icon, main.icon || 'Nada.png');
           hydrated.level = pickFilled(hydrated.level, main.level || );
           // Vídeo NUNCA é herdado da skill principal
           const hasOwnVideo = Object.prototype.hasOwnProperty.call(sub, 'video');
           hydrated.video = hasOwnVideo ? (sub.video || ) : ;
           hydrated.powerpve = pickFilled(hydrated.powerpve, main.powerpve || );
           hydrated.powerpvp = pickFilled(hydrated.powerpvp, main.powerpvp || );
           hydrated.energy = pickFilled(hydrated.energy, main.energy || );
           hydrated.cooldown = pickFilled(hydrated.cooldown, main.cooldown || );
           // Descrição: sempre vem da subskill, nunca herda
           // PROTEÇÃO TOTAL: Remove qualquer descrição que possa ter sido copiada do main
           if (!sub.desc && !sub.descPt && !sub.descEn && !sub.descEs && !sub.descPl && !sub.desc_i18n) {
               hydrated.desc = undefined;
               hydrated.descPt = undefined;
               hydrated.descEn = undefined;
               hydrated.descEs = undefined;
               hydrated.descPl = undefined;
               hydrated.desc_i18n = undefined;
           } else {
               // Se subskill tem descrição, normaliza para desc_i18n
               if (!hydrated.desc_i18n && (hydrated.descPt || hydrated.descEn || hydrated.descEs || hydrated.descPl)) {
                   hydrated.desc_i18n = {
                       pt: hydrated.descPt || ,
                       en: hydrated.descEn || ,
                       es: hydrated.descEs || ,
                       pl: hydrated.descPl || 
                   };
               }
           }
           return hydrated;
       }
       function inheritSubskillTree(subs, meta) {
           if (!Array.isArray(subs)) return [];
           return subs.map(sub => {
               const hydrated = inheritSubskillFromMain(sub, meta);
               if (Array.isArray(hydrated.subs)) {
                   hydrated.subs = inheritSubskillTree(hydrated.subs, meta);
               }
               return hydrated;
           });
       }
       function collectAssetsFromSubs(subs, iconsSet, videosSet, flagsSet) {
           if (!Array.isArray(subs)) return;
           subs.forEach(sub => {
               const iconURL = normalizeFileURL(sub.icon || 'Nada.png', );
               if (iconURL && iconURL !== ) iconsSet.add(iconURL);
               // Vídeo normal
               if (sub.video && sub.video.trim() !==  && sub.video !== 'Nada.png' && !sub.video.toLowerCase().includes('nada.png')) {
                   const videoURL = normalizeFileURL(sub.video);
                   if (videoURL) videosSet.add(videoURL);
               }
               // Vídeo de weapon
               if (sub.weapon && typeof sub.weapon === 'object' && sub.weapon.video && sub.weapon.video.trim() !==  && sub.weapon.video !== 'Nada.png' && !sub.weapon.video.toLowerCase().includes('nada.png')) {
                   const weaponVideoURL = normalizeFileURL(sub.weapon.video);
                   if (weaponVideoURL) videosSet.add(weaponVideoURL);
               }
               if (Array.isArray(sub.flags)) {
                   sub.flags.forEach(flagKey => {
                       const url = getFlagIconURL(flagKey);
                       if (url) flagsSet.add(url);
                   });
               } if (Array.isArray(sub.subs)) {
                   collectAssetsFromSubs(sub.subs, iconsSet, videosSet, flagsSet);
               }
           });
       } function buildAssetManifest() {
           if (window.__skillAssetManifest && window.__skillAssetManifest.ready) {
               return window.__skillAssetManifest;
           } const iconsSet = new Set();
           const videosSet = new Set();
           const flagsSet = new Set();
           iconItems.forEach(el => {
               const img = el.querySelector('img');
               if (img && img.src) {
                   iconsSet.add(img.src);
               } else if (el.dataset.iconFile) {
                   const iconURL = normalizeFileURL(el.dataset.iconFile);
                   if (iconURL) iconsSet.add(iconURL);
               }
               // Vídeo normal da skill
               const videoRaw = (el.dataset.videoFile || el.dataset.video || ).trim();
               if (videoRaw && videoRaw !== 'Nada.png' && !videoRaw.toLowerCase().includes('nada.png')) {
                   const videoURL = normalizeFileURL(videoRaw);
                   if (videoURL) videosSet.add(videoURL);
               }
               // Vídeo de weapon da skill
               if (el.dataset.weapon) {
                   try {
                       const weaponData = JSON.parse(el.dataset.weapon);
                       if (weaponData && weaponData.video && weaponData.video.trim() !==  && weaponData.video !== 'Nada.png' && !weaponData.video.toLowerCase().includes('nada.png')) {
                           const weaponVideoURL = normalizeFileURL(weaponData.video);
                           if (weaponVideoURL) videosSet.add(weaponVideoURL);
                       }
                   } catch (e) {
                   }
               }
               if (el.dataset.flags) {
                   try {
                       const parsedFlags = JSON.parse(el.dataset.flags);
                       (parsedFlags || []).forEach(flagKey => {
                           const url = getFlagIconURL(flagKey);
                           if (url) flagsSet.add(url);
                       });
                   } catch (e) {
                   }
               } if (el.dataset.subs) {
                   try {
                       const subs = JSON.parse(el.dataset.subs);
                       collectAssetsFromSubs(subs, iconsSet, videosSet, flagsSet);
                   } catch (e) {
                   }
               }
           });
           Object.keys(FLAG_ICON_FILES).forEach(flagKey => {
               const url = getFlagIconURL(flagKey);
               if (url) flagsSet.add(url);
           });
           const manifest = {
               icons: iconsSet, videos: videosSet, flags: flagsSet, ready: true
           };
           window.__skillAssetManifest = manifest;
           return manifest;
       } const subskillVideosCache = new Map();
       window.__subskillVideosCache = subskillVideosCache;
       // Cache de vídeos que falharam (404) para evitar tentativas repetidas
       const failedVideosCache = new Set();
       const missingVideosReported = new Set(); // Para avisar apenas uma vez sobre vídeos faltantes
       // Cache de parsing JSON para evitar re-parsear os mesmos dados
       const jsonParseCache = new WeakMap();
       function getCachedJSON(el, key) {
           if (!el) return null;
           const cache = jsonParseCache.get(el) || {};
           if (cache[key] !== undefined) return cache[key];
           const raw = el.dataset[key] || el.getAttribute(`data-${key}`);
           if (!raw) {
               cache[key] = null;
               jsonParseCache.set(el, cache);
               return null;
           }
           try {
               const parsed = JSON.parse(raw);
               cache[key] = parsed;
               jsonParseCache.set(el, cache);
               return parsed;
           } catch (e) {
               cache[key] = null;
               jsonParseCache.set(el, cache);
               return null;
           }
       }
       let assetManifest = null;
       const skillsTab = $('#skills');
       const skinsTab = $('#skins');
       ensureRemoved('.top-rail');
       // NÃO remove .content-card aqui - será gerenciado abaixo
       // ensureRemoved('.content-card'); // REMOVIDO - pode estar removendo skills-container
       ensureRemoved('.video-placeholder');
       Array.from(document.querySelectorAll('.card-skins-title, .card-skins .card-skins-title, .cardskins-title, .rail-title')).forEach(t => {
           if ((t.textContent || ).trim().toLowerCase().includes('skins')) {
               t.remove();
           }
       });
       if (skillsTab) {
           const iconBar = skillsTab.querySelector('.icon-bar');
           if (iconBar) {
               const rail = document.createElement('div');
               rail.className = 'top-rail skills';
               // Criar wrapper de scroll para permitir glow sem clipping
               if (!iconBar.parentElement || !iconBar.parentElement.classList.contains('icon-scroll-x')) {
                   const scrollWrapper = document.createElement('div');
                   scrollWrapper.className = 'icon-scroll-x';
                   scrollWrapper.appendChild(iconBar);
                   rail.appendChild(scrollWrapper);
               } else {
                   rail.appendChild(iconBar.parentElement);
               }
               skillsTab.prepend(rail);
           }
           // Busca skills-container criado pelo Lua
           const skillsContainer = skillsTab.querySelector('.skills-container');
           // Busca skills-details e video-container (podem estar dentro de skills-container ou soltos)
           let details = skillsTab.querySelector('.skills-details');
           if (!details && skillsContainer) {
               details = skillsContainer.querySelector('.skills-details');
           }
           if (!details) {
               details = document.createElement('div');
               details.className = 'skills-details';
           }
           // Busca ou cria desc-box dentro de details
           let descBoxEl = details.querySelector('.desc-box');
           if (!descBoxEl) {
               descBoxEl = document.createElement('div');
               descBoxEl.className = 'desc-box';
               details.appendChild(descBoxEl);
           }
           // Busca video-container
           let videoContainer = skillsTab.querySelector('.video-container');
           if (!videoContainer && skillsContainer) {
               videoContainer = skillsContainer.querySelector('.video-container');
           }
           if (!videoContainer) {
               videoContainer = document.createElement('div');
               videoContainer.className = 'video-container';
           }
           // Cria ou atualiza content-card skills-grid (estrutura esperada pelo CSS)
           let card = skillsTab.querySelector('.content-card.skills-grid');
           if (!card) {
               card = document.createElement('div');
               card.className = 'content-card skills-grid';
               skillsTab.appendChild(card);
           }
           // Move details e videoContainer para dentro do card (estrutura correta)
           // Remove skills-container se existir (não é necessário para o layout)
           if (skillsContainer && skillsContainer.parentNode) {
               // Move os elementos filhos de skills-container para o card
               if (details.parentNode === skillsContainer) {
                   skillsContainer.removeChild(details);
               }
               if (videoContainer.parentNode === skillsContainer) {
                   skillsContainer.removeChild(videoContainer);
               }
               // Remove skills-container se estiver vazio
               if (skillsContainer.children.length === 0) {
                   skillsContainer.remove();
               }
           }
           // Garante que details e videoContainer estão no card na ordem correta
           // skills-details deve vir ANTES de video-container para o grid funcionar
           if (details.parentNode !== card) {
               // Se videoContainer já está no card, insere details antes dele
               if (videoContainer.parentNode === card) {
                   card.insertBefore(details, videoContainer);
               } else {
                   card.appendChild(details);
               }
           }
           if (videoContainer.parentNode !== card) {
               card.appendChild(videoContainer);
           }
           // Garante ordem: details primeiro, videoContainer depois
           if (details.parentNode === card && videoContainer.parentNode === card) {
               if (details.nextSibling !== videoContainer) {
                   card.insertBefore(details, videoContainer);
               }
           }
       }
       // Função para obter iconsBar de forma segura (com retry)
       function getIconsBar() {
           const skillsEl = document.getElementById('skills');
           if (!skillsEl) return null;
           return skillsEl.querySelector('.icon-bar');
       }
       const iconsBar = getIconsBar();
       const skillsTopRail = iconsBar ? iconsBar.closest('.top-rail.skills') : null;
       const iconItems = iconsBar ? Array.from(iconsBar.querySelectorAll('.skill-icon')) : [];
       buildMainSkillsMeta(iconItems);
       // Verifica se há weapon em skills principais OU em subskills
       function checkHasAnyWeapon() {
           // Verifica skills principais
           const hasMainWeapon = iconItems.some(el => {
               const weapon = el.dataset.weapon;
               return weapon && weapon.trim() !==  && weapon !== '{}';
           });
           if (hasMainWeapon) {
               return true;
           }
           // Verifica subskills
           for (const el of iconItems) {
               const subsRaw = el.getAttribute('data-subs');
               if (!subsRaw) continue;
               try {
                   const subs = JSON.parse(subsRaw);
                   if (Array.isArray(subs) && subs.some(s => s && s.weapon && typeof s.weapon === 'object' && Object.keys(s.weapon).length > 0)) {
                       return true;
                   }
               } catch (e) { }
           }
           return false;
       }
       const hasWeaponSkillAvailable = checkHasAnyWeapon();
       let weaponToggleBtn = null;
       if (!assetManifest) {
           assetManifest = buildAssetManifest();
           // Pré-carrega apenas ícones e flags críticos
           if (assetManifest.icons && assetManifest.icons.size) {
               assetManifest.icons.forEach(url => {
                   if (!url || imagePreloadCache.has(url)) return;
                   const img = new Image();
                   img.decoding = 'async';
                   img.loading = 'eager';
                   img.referrerPolicy = 'same-origin';
                   img.src = url;
                   imagePreloadCache.set(url, img);
               });
           }
           if (assetManifest.flags && assetManifest.flags.size) {
               assetManifest.flags.forEach(url => {
                   if (!url || imagePreloadCache.has(url)) return;
                   const img = new Image();
                   img.decoding = 'async';
                   img.loading = 'eager';
                   img.referrerPolicy = 'same-origin';
                   img.src = url;
                   imagePreloadCache.set(url, img);
               });
           }
       }
       // Busca descBox e videoBox após a estrutura estar organizada
       const descBox = $('#skills') ? $('.desc-box', $('#skills')) : null;
       const videoBox = $('#skills') ? $('.video-container', $('#skills')) : null;
       const videosCache = new Map();
       const nestedVideoElByIcon = new WeakMap();
       const barStack = [];
       window.__barStack = barStack;
       let initialBarSnapshot = null;
       let totalVideos = 0, loadedVideos = 0, autoplay = false;
       window.__lastActiveSkillIcon = null;
       let userHasInteracted = false;
       let globalWeaponEnabled = false;
       try {
           if (localStorage.getItem('glaWeaponEnabled') === '1') {
               globalWeaponEnabled = true;
           }
       } catch (err) {
       }
       const weaponStateListeners = new Set();
       let showWeaponPopupFn = null;
       let popupShouldOpen = false;
       function attachWeaponPopupFn(fn) {
           if (typeof fn !== 'function') return;
           showWeaponPopupFn = fn;
           if (popupShouldOpen) {
               popupShouldOpen = false;
               try {
                   showWeaponPopupFn();
               } catch (err) {
               }
           }
       }
       attachWeaponPopupFn(window.__glaWeaponShowPopup);
       function requestWeaponPopupDisplay() {
           try {
               if (localStorage.getItem('glaWeaponPopupDismissed') === '1') return;
           } catch (err) {
           }
           if (typeof showWeaponPopupFn === 'function') {
               showWeaponPopupFn();
               return;
           }
           popupShouldOpen = true;
       }
       function onWeaponStateChange(fn) {
           if (typeof fn !== 'function') return;
           weaponStateListeners.add(fn);
       }
       function syncWeaponButtonState(enabled) {
           if (!weaponToggleBtn || !weaponToggleBtn.isConnected) return;
           // Usa .weapon-active em vez de .active para não conflitar com skills
           weaponToggleBtn.classList.toggle('weapon-active', !!enabled);
           weaponToggleBtn.classList.remove('active'); // Garante que .active nunca seja aplicado
           weaponToggleBtn.setAttribute('aria-pressed', enabled ? 'true' : 'false');
           weaponToggleBtn.setAttribute('aria-label', enabled ? 'Desativar Arma Especial' : 'Ativar Arma Especial');
       }
       function syncWeaponRailState(enabled) {
           if (skillsTopRail) {
               skillsTopRail.classList.toggle('weapon-mode-on', !!enabled);
           }
       }
       function notifyWeaponStateListeners(enabled) {
           weaponStateListeners.forEach(listener => {
               try {
                   listener(enabled);
               } catch (err) {
               }
           });
       }
       let pendingWeaponState = null;
       window.addEventListener('weapon:ready', (ev) => {
           if (ev && ev.detail && ev.detail.showPopup) {
               attachWeaponPopupFn(ev.detail.showPopup);
           }
           if (pendingWeaponState === null) return;
           if (typeof window.__applyWeaponState === 'function') {
               const target = pendingWeaponState;
               pendingWeaponState = null;
               window.__applyWeaponState(target);
           }
       });
       window.__setGlobalWeaponEnabled = (enabled) => {
           globalWeaponEnabled = enabled;
           notifyWeaponStateListeners(enabled);
       };
       function requestWeaponState(targetState) {
           if (typeof window.__applyWeaponState === 'function') {
               pendingWeaponState = null;
               window.__applyWeaponState(targetState);
               return;
           }
           pendingWeaponState = targetState;
       }
       onWeaponStateChange(syncWeaponButtonState);
       function reapplyWeaponClassesToBar() {
           // SISTEMA UNIFICADO: Aplica em skills E subskills (sempre, não só quando weapon está ativo)
           // Obtém iconsBar dinamicamente (pode não estar pronto ainda quando há flags)
           const currentIconsBar = getIconsBar();
           if (!currentIconsBar) {
               return;
           }
           // Busca em skills principais (dentro de iconsBar)
           currentIconsBar.querySelectorAll('.skill-icon[data-weapon]').forEach(el => {
               const weapon = el.dataset.weapon;
               if (weapon && weapon.trim() !==  && weapon !== '{}') {
                   try {
                       const weaponObj = JSON.parse(weapon);
                       if (weaponObj && typeof weaponObj === 'object' && Object.keys(weaponObj).length > 0) {
                           if (!el.classList.contains('has-weapon-available')) {
                               el.classList.add('has-weapon-available');
                           }
                           if (!el.querySelector('.weapon-indicator')) {
                               const ind = document.createElement('div');
                               ind.className = 'weapon-indicator';
                               el.appendChild(ind);
                           }
                       }
                   } catch (e) {
                       // Se não for JSON válido, não adiciona a classe
                   }
               }
           });
           // Busca em subskills (dentro de subskills-rail)
           document.querySelectorAll('.subskills-rail .subicon[data-weapon]').forEach(el => {
               const weapon = el.dataset.weapon;
               if (weapon && weapon.trim() !==  && weapon !== '{}') {
                   try {
                       const weaponObj = JSON.parse(weapon);
                       if (weaponObj && typeof weaponObj === 'object' && Object.keys(weaponObj).length > 0) {
                           if (!el.classList.contains('has-weapon-available')) {
                               el.classList.add('has-weapon-available');
                           }
                       }
                   } catch (e) {
                       // Se não for JSON válido, não adiciona a classe
                   }
               }
           });
       }
       // Aplica classes de weapon imediatamente ao carregar
       reapplyWeaponClassesToBar();
       // REMOVIDO: setupWeaponBarToggle - O toggle de weapon agora é criado apenas pelo C.WeaponToggle.html no header
       // Não cria mais botão na barra de skills - apenas aplica classes visuais
       onWeaponStateChange(syncWeaponRailState);
       // Reaplica classes quando o estado do weapon muda (para garantir que funcione mesmo quando toggle é ativado fora da barra)
       onWeaponStateChange(() => {
           // Usa setTimeout para garantir que o DOM foi atualizado
           setTimeout(() => {
               reapplyWeaponClassesToBar();
           }, 50);
       });
       syncWeaponRailState(globalWeaponEnabled);
       (function injectWeaponStyles() {
           if (document.getElementById('weapon-toggle-styles')) return;
           const style = document.createElement('style');
           style.id = 'weapon-toggle-styles';
           style.textContent = `
       /* ========== ESTILOS DE WEAPON - NOVO SISTEMA ========== */
       
       /* Animação simples para borda */
       @keyframes weapon-border-flow {
           0% { background-position: 0% 0%; }
           100% { background-position: 200% 0%; }
       }
       /* Animação sutil para brilho */
       @keyframes weapon-glow-breathe {
           0%, 100% { opacity: 0.7; }
           50% { opacity: 1; }
       }
       /* ===== ÍCONE COM ARMA - Só mostra efeitos quando weapon-mode-on está ativo ===== */
       /* Quando NÃO está em weapon-mode-on, os ícones com arma devem ser normais (mesma borda padrão) */
       .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle) {
           /* Remove transform scale quando toggle está desativado */
           transform: none !important;
           transition: transform 0.15s ease !important;
       }
       .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle)::after {
           /* Reseta COMPLETAMENTE para borda padrão quando toggle está desativado */
           /* Remove background, padding e mask INSTANTANEAMENTE (sem transição) */
           background: none !important;
           background-size: unset !important;
           padding: 0 !important;
           -webkit-mask: none !important;
           mask: none !important;
           mask-composite: unset !important;
           -webkit-mask-composite: unset !important;
           animation: none !important;
           /* Apenas box-shadow tem transição suave */
           box-shadow: inset 0 0 0 var(--icon-ring-w) var(--icon-idle) !important;
           /* SEM transição no background/padding/mask para evitar "flash" durante a mudança */
           transition: box-shadow 0.15s ease !important;
       }
       .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle)::before {
           /* Remove efeitos de glow quando toggle está desativado - com transição suave */
           opacity: 0 !important;
           transition: opacity 0.15s ease !important;
       }
       /* Quando ativo mas toggle desativado, usa borda padrão de ativo */
       .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active {
           /* Mantém o zoom padrão mesmo quando toggle está desativado */
           transform: scale(1.10) translateZ(0) !important;
           transition: transform 0.15s ease !important;
       }
       .character-box .top-rail.skills:not(.weapon-mode-on) .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active::after {
           /* Reseta COMPLETAMENTE para borda padrão de ativo */
           /* Remove background, padding e mask INSTANTANEAMENTE (sem transição) */
           background: none !important;
           background-size: unset !important;
           padding: 0 !important;
           -webkit-mask: none !important;
           mask: none !important;
           mask-composite: unset !important;
           -webkit-mask-composite: unset !important;
           animation: none !important;
           /* Apenas box-shadow tem transição suave */
           box-shadow: inset 0 0 0 var(--icon-ring-w) var(--icon-active) !important;
           /* SEM transição no background/padding/mask para evitar "flash" durante a mudança */
           transition: box-shadow 0.15s ease !important;
       }
       /* ===== MODO WEAPON ON - INATIVO ===== */
       .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle):not(.active)::after {
           pointer-events: none !important;
           box-shadow: none !important;
           background: linear-gradient(90deg, 
               #FF3333 0%, 
               #FF0000 50%, 
               #FF3333 100%) !important;
           background-size: 200% 100% !important;
           animation: weapon-border-flow 3s linear infinite !important;
           -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) !important;
           mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) !important;
           -webkit-mask-composite: xor !important;
           mask-composite: exclude !important;
           padding: 2px !important;
           /* SEM transição para permitir remoção instantânea quando toggle é desativado */
           transition: none !important;
       }
       .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle):not(.active)::before {
           pointer-events: none !important;
           inset: 0 !important;
           border-radius: inherit !important;
           z-index: 1 !important;
           animation: weapon-glow-breathe 2s ease-in-out infinite !important;
           box-shadow: 
               0 0 8px 0 rgba(255, 0, 0, 0.4),
               0 0 12px 0 rgba(255, 51, 51, 0.3),
               0 0 16px 0 rgba(255, 0, 0, 0.2) !important;
           opacity: 1 !important;
       }
       /* ===== MODO WEAPON ON - ATIVO ===== */
       .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active {
           transform: scale(1.10) !important;
           z-index: 5 !important;
       }
       .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active::after {
           pointer-events: none !important;
           box-shadow: none !important;
           background: linear-gradient(90deg, 
               #FFEB3B 0%, 
               #FFD700 50%, 
               #FFEB3B 100%) !important;
           background-size: 200% 100% !important;
           animation: weapon-border-flow 2s linear infinite !important;
           -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) !important;
           mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) !important;
           -webkit-mask-composite: xor !important;
           mask-composite: exclude !important;
           padding: 2px !important;
           /* SEM transição para permitir remoção instantânea quando toggle é desativado */
           transition: none !important;
       }
       .character-box .top-rail.skills.weapon-mode-on .icon-bar .skill-icon.has-weapon-available:not(.weapon-bar-toggle).active::before {
           pointer-events: none !important;
           inset: 0 !important;
           border-radius: inherit !important;
           z-index: 1 !important;
           animation: weapon-glow-breathe 1.5s ease-in-out infinite !important;
           box-shadow: 
               0 0 10px 0 rgba(255, 215, 0, 0.5),
               0 0 16px 0 rgba(255, 235, 59, 0.4),
               0 0 22px 0 rgba(255, 215, 0, 0.3) !important;
           opacity: 1 !important;
       }
           `;
           document.head.appendChild(style);
       })();
       function applyWeaponBadge(el, weaponData, equipped) {
           // Apenas gerencia a classe weapon-equipped (badge visual removido)
           if (equipped && weaponData) {
               el.classList.add('weapon-equipped');
           } else {
               el.classList.remove('weapon-equipped');
           }
       } function getWeaponKey(el) {
           return (el.dataset.index || ) + ':' + (el.dataset.nome || el.dataset.name || );
       } function isWeaponModeOn() {
           try {
               return localStorage.getItem('glaWeaponEnabled') === '1';
           } catch (e) {
               return false;
           }
       } function getWeaponDataForIcon(iconEl) {
           if (!iconEl || !iconEl.dataset.weapon) return null;
           // Usa cache de parsing JSON
           return getCachedJSON(iconEl, 'weapon');
       } function getEffectiveSkillVideoFromIcon(iconEl) {
           const weaponOn = globalWeaponEnabled;
           const weaponData = getWeaponDataForIcon(iconEl);
           const baseVideoFile = (iconEl.dataset.videoFile || ).trim();
           const baseVideoURL = (iconEl.dataset.video || ).trim();
           // console.log('[Skills DEBUG]', {
           //     skillName: iconEl.dataset.nome || iconEl.dataset.name,
           //     weaponOn,
           //     hasWeaponData: !!weaponData,
           //     weaponData: weaponData,
           //     baseVideoFile,
           //     baseVideoURL
           // });
           if (weaponOn && weaponData) {
               // console.log('[Skills] checking weapon video', {
               //     skillName: iconEl.dataset.nome || iconEl.dataset.name,
               //     hasVideo: !!(weaponData.video),
               //     videoValue: weaponData.video,
               //     videoTrimmed: weaponData.video ? weaponData.video.trim() : 
               // });
               if (weaponData.video && weaponData.video.trim() !== ) {
                   // console.log('[Skills] video escolhido (weapon)', iconEl.dataset.nome || iconEl.dataset.name, weaponData.video);
                   return weaponData.video.trim();
               }
           }
           // Prioriza videoFile (nome do arquivo), mas se estiver vazio, usa video (pode ser URL completa)
           const result = baseVideoFile || baseVideoURL || ;
           // console.log('[Skills] video escolhido (base)', iconEl.dataset.nome || iconEl.dataset.name, result);
           return result;
       } function createVideoElement(videoURL, extraAttrs = {
       }) {
           // Se o vídeo já falhou antes, não cria novo elemento
           if (failedVideosCache.has(videoURL)) {
               return null;
           }
           const v = document.createElement('video');
           v.className = 'skill-video';
           v.setAttribute('controls', );
           v.setAttribute('preload', 'auto'); // Mudado de 'metadata' para 'auto' para carregar tudo imediatamente
           v.setAttribute('playsinline', );
           v.style.display = 'none';
           v.style.width = '100%';
           v.style.height = 'auto';
           v.style.aspectRatio = '16/9';
           v.style.objectFit = 'cover';
           Object.keys(extraAttrs).forEach(k => {
               v.dataset[k] = extraAttrs[k];
           });
           // Detectar formato do vídeo pela extensão
           const ext = (videoURL.split('.').pop() || ).toLowerCase().split('?')[0];
           const mimeTypes = {
               'mp4': 'video/mp4',
               'm4v': 'video/mp4',
               'webm': 'video/webm',
               'ogv': 'video/ogg',
               'ogg': 'video/ogg',
               'mov': 'video/quicktime'
           };
           const mimeType = mimeTypes[ext] || 'video/mp4';
           const src = document.createElement('source');
           src.src = videoURL;
           src.type = mimeType;
           v.appendChild(src);
           // Fallback para Safari/iOS mais antigos
           v.setAttribute('webkit-playsinline', );
           v.setAttribute('x-webkit-airplay', 'allow');
           // Tratamento silencioso de erros - marca como falhado e não tenta mais
           let errorHandled = false;
           v.addEventListener('error', (e) => {
               if (errorHandled) return;
               errorHandled = true;
               // Marca o vídeo como falhado para não tentar carregar novamente
               failedVideosCache.add(videoURL);
               // Remove o vídeo do DOM se estiver lá
               if (v.parentNode) {
                   v.parentNode.removeChild(v);
               }
               // Avisa apenas uma vez sobre vídeos faltantes
               if (!missingVideosReported.has(videoURL)) {
                   missingVideosReported.add(videoURL);
                   // Extrai nome do arquivo da URL para o aviso
                   const fileName = videoURL.split('/').pop().split('?')[0] || videoURL;
                   console.info(`[Skills] Vídeo não encontrado na wiki: ${decodeURIComponent(fileName)}. Este aviso aparecerá apenas uma vez.`);
               }
           }, { once: true });
           return v;
       }
       // Função recursiva para carregar TODOS os vídeos de subskills (incluindo sub-subskills)
       function preloadSubskillVideosRecursively(subs, parentIdx, parentPath = ) {
           if (!videoBox || !Array.isArray(subs)) return 0;
           let createdCount = 0;
           subs.forEach(s => {
               const subName = (s.name || s.n || ).trim();
               const currentPath = parentPath ? `${parentPath}:${subName}` : subName;
               // Vídeo normal da subskill
               if (s.video && s.video.trim() !==  && s.video !== 'Nada.png' && !s.video.toLowerCase().includes('nada.png')) {
                   const key = `sub:${parentIdx}:${currentPath}`;
                   if (!subskillVideosCache.has(key)) {
                       const videoURL = normalizeFileURL(s.video);
                       if (videoURL && videoURL.trim() !==  && !failedVideosCache.has(videoURL)) {
                           const v = createVideoElement(videoURL, {
                               sub: '1', parentIndex: parentIdx, subName: currentPath, cacheKey: key
                           });
                           if (v) { // Só adiciona se o vídeo foi criado (não estava no cache de falhas)
                               videoBox.appendChild(v);
                               subskillVideosCache.set(key, v);
                               createdCount++;
                               // FORÇA carregamento imediatamente (apenas uma vez)
                               v.load();
                           }
                       }
                   }
               }
               // Vídeo de weapon da subskill (sempre carrega, independente do toggle)
               if (s.weapon && typeof s.weapon === 'object' && s.weapon.video && s.weapon.video.trim() !==  && s.weapon.video !== 'Nada.png' && !s.weapon.video.toLowerCase().includes('nada.png')) {
                   const weaponKey = `sub:${parentIdx}:${currentPath}:weapon`;
                   if (!subskillVideosCache.has(weaponKey)) {
                       const weaponVideoURL = normalizeFileURL(s.weapon.video);
                       if (weaponVideoURL && weaponVideoURL.trim() !==  && !failedVideosCache.has(weaponVideoURL)) {
                           const v = createVideoElement(weaponVideoURL, {
                               sub: '1', parentIndex: parentIdx, subName: currentPath, weapon: '1', cacheKey: weaponKey
                           });
                           if (v) { // Só adiciona se o vídeo foi criado (não estava no cache de falhas)
                               videoBox.appendChild(v);
                               subskillVideosCache.set(weaponKey, v);
                               createdCount++;
                               // FORÇA carregamento imediatamente (apenas uma vez)
                               v.load();
                           }
                       }
                   }
               }
               // RECURSÃO: processa sub-subskills (SEMPRE processa, mesmo se o vídeo já estiver no cache)
               if (Array.isArray(s.subs) && s.subs.length > 0) {
                   createdCount += preloadSubskillVideosRecursively(s.subs, parentIdx, currentPath);
               }
           });
           return createdCount;
       }
       function precreateSubskillVideos() {
           if (!videoBox) return;
           let createdCount = 0;
           iconItems.forEach(parentIcon => {
               const subs = getCachedJSON(parentIcon, 'subs');
               if (!Array.isArray(subs)) return;
               const parentIdx = parentIcon.dataset.index || ;
               createdCount += preloadSubskillVideosRecursively(subs, parentIdx);
           });
       }
       // Função para pré-carregar TODOS os vídeos recursivamente (principais, subskills, weapon, sub-subskills)
       function preloadAllVideosRecursively() {
           if (!videoBox || !iconItems.length) return;
           // 1. Carregar vídeos de skills principais
           iconItems.forEach(el => {
               const idx = el.dataset.index || ;
               if (!idx) return;
               // Vídeo normal da skill principal
               // Prioriza data-video-file (nome do arquivo), depois data-video (pode ser URL completa)
               let src = (el.dataset.videoFile || ).trim();
               if (!src) {
                   // Se não tem videoFile, tenta extrair do video (pode ser URL completa)
                   const videoAttr = (el.dataset.video || ).trim();
                   if (videoAttr) {
                       // Se já é uma URL completa, usa direto; senão normaliza
                       if (videoAttr.includes('/') || videoAttr.startsWith('http')) {
                           src = videoAttr;
                       } else {
                           src = videoAttr;
                       }
                   }
               }
               if (src && src !== 'Nada.png' && !src.toLowerCase().includes('nada.png') && !videosCache.has(idx)) {
                   const videoURL = normalizeFileURL(src);
                   if (videoURL && !failedVideosCache.has(videoURL)) {
                       const v = createVideoElement(videoURL, {
                           index: idx
                       });
                       if (v) { // Só adiciona se o vídeo foi criado (não estava no cache de falhas)
                           totalVideos++;
                           v.style.maxWidth = '100%';
                           v.addEventListener('canplaythrough', () => {
                               loadedVideos++;
                               if (!userHasInteracted && loadedVideos === 1) {
                                   try {
                                       v.pause();
                                       v.currentTime = 0;
                                   } catch (e) {
                                   }
                               } if (loadedVideos === totalVideos) autoplay = true;
                           }, {
                               once: true
                           });
                           v.addEventListener('error', () => {
                               loadedVideos++;
                               if (loadedVideos === totalVideos) autoplay = true;
                           }, {
                               once: true
                           });
                           videoBox.appendChild(v);
                           videosCache.set(idx, v);
                           nestedVideoElByIcon.set(el, v);
                           // Força carregamento imediatamente (apenas uma vez)
                           v.load();
                       }
                   }
               }
               // Vídeo de weapon (sempre carrega, independente do toggle)
               const weaponData = getCachedJSON(el, 'weapon');
               if (weaponData && weaponData.video && weaponData.video.trim() !==  && weaponData.video !== 'Nada.png' && !weaponData.video.toLowerCase().includes('nada.png')) {
                   const weaponKey = `weapon:${idx}:${(el.dataset.nome || el.dataset.name || ).trim()}`;
                   if (!videosCache.has(weaponKey)) {
                       const weaponVideoURL = normalizeFileURL(weaponData.video);
                       if (weaponVideoURL && !failedVideosCache.has(weaponVideoURL)) {
                           const v = createVideoElement(weaponVideoURL, {
                               index: idx, weapon: '1'
                           });
                           if (v) { // Só adiciona se o vídeo foi criado (não estava no cache de falhas)
                               totalVideos++;
                               v.style.maxWidth = '100%';
                               v.addEventListener('canplaythrough', () => {
                                   loadedVideos++;
                                   if (loadedVideos === totalVideos) autoplay = true;
                               }, {
                                   once: true
                               });
                               v.addEventListener('error', () => {
                                   loadedVideos++;
                                   if (loadedVideos === totalVideos) autoplay = true;
                               }, {
                                   once: true
                               });
                               videoBox.appendChild(v);
                               videosCache.set(weaponKey, v);
                               // Força carregamento imediatamente (apenas uma vez)
                               v.load();
                           }
                       }
                   }
               }
           });
           // 2. Carregar vídeos de subskills (recursivamente)
           precreateSubskillVideos();
       }
       // Função para pré-carregar TODOS os ícones recursivamente
       function preloadAllIconsRecursively() {
           const iconCache = new Set();
           // Função recursiva para processar subskills
           function processSubskillsRecursively(subs) {
               if (!Array.isArray(subs)) return;
               subs.forEach(s => {
                   const icon = (s.icon || ).trim();
                   if (icon && icon !== 'Nada.png' && !icon.toLowerCase().includes('nada.png')) {
                       const iconURL = normalizeFileURL(icon);
                       if (iconURL && !iconCache.has(iconURL)) {
                           iconCache.add(iconURL);
                           const img = new Image();
                           img.decoding = 'async';
                           img.loading = 'eager';
                           img.referrerPolicy = 'same-origin';
                           img.src = iconURL;
                           imagePreloadCache.set(iconURL, img);
                       }
                   }
                   // Recursão para sub-subskills
                   if (Array.isArray(s.subs)) {
                       processSubskillsRecursively(s.subs);
                   }
               });
           }
           // Carregar ícones de skills principais
           iconItems.forEach(el => {
               const img = el.querySelector('img');
               if (img && img.src) {
                   const iconURL = img.src;
                   if (iconURL && !iconCache.has(iconURL)) {
                       iconCache.add(iconURL);
                       // Já está no DOM, mas força pré-carregamento
                       const preloadImg = new Image();
                       preloadImg.decoding = 'async';
                       preloadImg.loading = 'eager';
                       preloadImg.referrerPolicy = 'same-origin';
                       preloadImg.src = iconURL;
                       imagePreloadCache.set(iconURL, preloadImg);
                   }
               }
               // Carregar ícones de subskills recursivamente
               const subs = getCachedJSON(el, 'subs');
               if (Array.isArray(subs)) {
                   processSubskillsRecursively(subs);
               }
           });
       }
       // Função principal que carrega TUDO imediatamente
       function preloadAllAssets() {
           // Carregar TUDO imediatamente - sem lazy loading
           // 1. Carregar TODOS os vídeos (principais, subskills, weapon, sub-subskills)
           preloadAllVideosRecursively();
           // 2. Carregar TODOS os ícones (principais, subskills, sub-subskills)
           preloadAllIconsRecursively();
       }
       // Executa pré-carregamento imediatamente
       preloadAllAssets(); function wireTooltipsForNewIcons() {
           const tip = document.querySelector('.skill-tooltip');
           if (!tip) return;
           let lockUntil2 = 0;
           Array.from(document.querySelectorAll('.icon-bar .skill-icon')).forEach(icon => {
               if (icon.dataset.weaponToggle === '1' || icon.classList.contains('weapon-bar-toggle')) return;
               if (icon.dataset.tipwired) return;
               icon.dataset.tipwired = '1';
               const label = icon.dataset.nome || icon.dataset.name || icon.title || ;
               if (label && !icon.hasAttribute('aria-label')) icon.setAttribute('aria-label', label);
               if (icon.hasAttribute('title')) icon.removeAttribute('title');
               const img = icon.querySelector('img');
               if (img) {
                   const imgAlt = img.getAttribute('alt') || ;
                   const imgTitle = img.getAttribute('title') || ;
                   if (!label && (imgAlt || imgTitle)) icon.setAttribute('aria-label', imgAlt || imgTitle);
                   img.setAttribute('alt', );
                   if (img.hasAttribute('title')) img.removeAttribute('title');
               } const measureAndPos = (el) => {
                   if (!el || tip.getAttribute('aria-hidden') === 'true') return;
                   tip.style.left = '0px';
                   tip.style.top = '0px';
                   const rect = el.getBoundingClientRect();
                   const tr = tip.getBoundingClientRect();
                   let left = Math.round(rect.left + (rect.width - tr.width) / 2);
                   left = Math.max(8, Math.min(left, window.innerWidth - tr.width - 8));
                   const coarse = (window.matchMedia && matchMedia('(pointer: coarse)').matches) || (window.innerWidth <= 600);
                   let top = coarse ? Math.round(rect.bottom + 10) : Math.round(rect.top - tr.height - 8);
                   if (top < 8) top = Math.round(rect.bottom + 10);
                   tip.style.left = left + 'px';
                   tip.style.top = top + 'px';
               };
               const show = (el, text) => {
                   tip.textContent = text || ;
                   tip.setAttribute('aria-hidden', 'false');
                   measureAndPos(el);
                   tip.style.opacity = '1';
               };
               const hide = () => {
                   tip.setAttribute('aria-hidden', 'true');
                   tip.style.opacity = '0';
                   tip.style.left = '-9999px';
                   tip.style.top = '-9999px';
               };
               icon.addEventListener('mouseenter', () => show(icon, (icon.dataset.nome || icon.dataset.name || )));
               icon.addEventListener('mousemove', () => {
                   if (performance.now() >= lockUntil2) measureAndPos(icon);
               });
               icon.addEventListener('click', () => {
                   lockUntil2 = performance.now() + 240;
                   measureAndPos(icon);
               });
               icon.addEventListener('mouseleave', hide);
           });
       } function showVideoForIcon(el) {
           userHasInteracted = true;
           if (!videoBox) return;
           const effectiveVideo = getEffectiveSkillVideoFromIcon(el);
           if (!effectiveVideo || effectiveVideo.trim() === ) {
               videoBox.style.display = 'none';
               return;
           }
           const videoURL = normalizeFileURL(effectiveVideo);
           if (!videoURL || videoURL.trim() === ) {
               videoBox.style.display = 'none';
               return;
           }
           Array.from(videoBox.querySelectorAll('video.skill-video')).forEach(v => {
               try {
                   v.pause();
               } catch (e) {
               }
               v.style.display = 'none';
           });
           if (window.__subskills) window.__subskills.hideAll?.(videoBox);
           const hasIdx = !!el.dataset.index;
           const weaponOn = globalWeaponEnabled;
           const weaponData = getWeaponDataForIcon(el);
           const isWeaponVideo = weaponOn && weaponData && weaponData.video && weaponData.video.trim() !== ;
           // console.log('[Skills] showVideoForIcon chamado', {
           //     skillName: el.dataset.nome || el.dataset.name,
           //     weaponOn,
           //     isWeaponVideo,
           //     effectiveVideo: getEffectiveSkillVideoFromIcon(el)
           // });
           const videoKey = isWeaponVideo ? `weapon:${getWeaponKey(el)}` : (el.dataset.index || );
           const isSubskill = !hasIdx || el.dataset.nested === '1';
           const parentIdx = el.dataset.parentIndex || ;
           const subName = el.dataset.subName || el.dataset.nome || el.dataset.name || ;
           if (hasIdx && !isWeaponVideo && videosCache.has(el.dataset.index)) {
               const v = videosCache.get(el.dataset.index);
               videoBox.style.display = 'block';
               v.style.display = 'block';
               try {
                   v.currentTime = 0;
               } catch (e) {
               }
               const suppress = document.body.dataset.suppressSkillPlay === '1';
               if (!suppress) {
                   v.play().catch(() => {
                   });
               } else {
                   try {
                       v.pause();
                   } catch (e) {
                   }
               }
               return;
           }
           // Para form_switch, permite criação dinâmica de vídeos (transições de forma)
           // Vídeos normais devem estar pré-carregados
           const isFormSwitch = el.dataset.formSwitch === 'true' || el.getAttribute('data-form-switch') === 'true';
           let v = null;
           if (isWeaponVideo) {
               const weaponKeyFull = `weapon:${getWeaponKey(el)}`;
               v = videosCache.get(weaponKeyFull);
               if (!v && isSubskill && parentIdx && subName) {
                   // Tenta buscar vídeo de weapon de subskill
                   // O cache usa o formato: sub:${parentIdx}:${path}:weapon onde path NÃO inclui o nome da skill principal
                   // O subName agora já está no formato correto (sem nome da skill principal)
                   // Tenta buscar diretamente com o subName
                   let subWeaponKey = `sub:${parentIdx}:${subName}:weapon`;
                   v = subskillVideosCache.get(subWeaponKey);
                   // Se não encontrou, tenta buscar recursivamente
                   if (!v) {
                       const basePattern = `sub:${parentIdx}:`;
                       const weaponSuffix = ':weapon';
                       const searchName = subName.split(':').pop();
                       for (const [key, video] of subskillVideosCache.entries()) {
                           if (key.startsWith(basePattern) && key.endsWith(weaponSuffix)) {
                               const pathInKey = key.substring(basePattern.length, key.length - weaponSuffix.length);
                               // Tenta match exato, ou se termina com o nome da skill
                               if (pathInKey === subName ||
                                   pathInKey.endsWith(`:${searchName}`) ||
                                   pathInKey === searchName) {
                                   v = video;
                                   break;
                               }
                           }
                       }
                   }
               }
               if (!v) {
                   // Tenta buscar pelo padrão antigo também
                   v = videoBox.querySelector(`video[data-weapon-key="${videoKey}"]`);
               }
           } else {
               if (isSubskill && parentIdx && subName) {
                   // Busca vídeo de subskill no cache correto
                   // O cache usa o formato: sub:${parentIdx}:${path} onde path NÃO inclui o nome da skill principal
                   // O subName agora já está no formato correto (sem nome da skill principal)
                   // Tenta buscar diretamente com o subName
                   let subKey = `sub:${parentIdx}:${subName}`;
                   v = subskillVideosCache.get(subKey);
                   // Se não encontrou, tenta buscar recursivamente todas as chaves que começam com o padrão
                   // Isso é útil caso haja alguma diferença no formato do caminho
                   if (!v) {
                       const basePattern = `sub:${parentIdx}:`;
                       const searchName = subName.split(':').pop(); // Último segmento do caminho
                       // Tenta também buscar apenas pelo último segmento (útil para sub-subskills)
                       const lastSegmentKey = `sub:${parentIdx}:${searchName}`;
                       v = subskillVideosCache.get(lastSegmentKey);
                       // Se ainda não encontrou, faz busca mais ampla
                       if (!v) {
                           for (const [key, video] of subskillVideosCache.entries()) {
                               if (key.startsWith(basePattern)) {
                                   const pathInKey = key.substring(basePattern.length);
                                   // Tenta match exato, ou se termina com o nome da skill, ou se contém o caminho completo
                                   if (pathInKey === subName ||
                                       pathInKey.endsWith(`:${searchName}`) ||
                                       pathInKey === searchName ||
                                       (subName.includes(':') && pathInKey.includes(subName)) ||
                                       (subName.includes(':') && pathInKey.endsWith(subName.split(':').slice(-2).join(':')))) {
                                       v = video;
                                       break;
                                   }
                               }
                           }
                       }
                   }
               } else {
                   v = videosCache.get(el.dataset.index);
                   if (!v) {
                       v = nestedVideoElByIcon.get(el);
                   }
               }
           }
           // Se vídeo não foi encontrado no cache, verifica se falhou antes
           if (!v) {
               // Se o vídeo já foi marcado como falhado, não mostra aviso repetido
               if (failedVideosCache.has(videoURL)) {
                   videoBox.style.display = 'none';
                   return;
               }
               // Para form_switch, cria vídeo dinamicamente (transições de forma são dinâmicas)
               // Usa uma chave única que inclui o nome do arquivo do vídeo para garantir que cada vídeo diferente seja cacheado separadamente
               if (isFormSwitch && videoURL) {
                   const baseIndex = el.dataset.index || ;
                   const videoFileName = effectiveVideo || ;
                   // Chave única: index + nome do arquivo do vídeo
                   const videoKey = baseIndex + ':' + videoFileName;
                   v = videosCache.get(videoKey);
                   if (!v) {
                       v = createVideoElement(videoURL, { index: baseIndex });
                       if (v) {
                           videoBox.appendChild(v);
                           videosCache.set(videoKey, v);
                           v.load();
                       } else {
                           videoBox.style.display = 'none';
                           return;
                       }
                   }
               } else {
                   // Vídeos normais devem estar pré-carregados
                   videoBox.style.display = 'none';
                   return;
               }
           }
           videoBox.style.display = 'block';
           v.style.display = 'block';
           try {
               v.currentTime = 0;
           } catch (e) {
           }
           const suppress = document.body.dataset.suppressSkillPlay === '1';
           if (!suppress) {
               v.play().catch(() => {
               });
           } else {
               try {
                   v.pause();
               } catch (e) {
               }
           }
       } function activateSkill(el, options = {
       }) {
           const {
               openSubs = true
           } = options;
           const tip = document.querySelector('.skill-tooltip');
           if (tip) {
               tip.setAttribute('aria-hidden', 'true');
               tip.style.opacity = '0';
               tip.style.left = '-9999px';
               tip.style.top = '-9999px';
           } const skillsRoot = document.getElementById('skills');
           const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {
           };
           const L = i18nMap[getLangKey()] || i18nMap.pt || {
               cooldown: 'Recarga', energy_gain: 'Ganho de energia', energy_cost: 'Custo de energia', power: 'Poder', power_pvp: 'Poder PvP', level: 'Nível'
           };
           const name = el.dataset.nome || el.dataset.name || ;
           let weaponData = null;
           if (el.dataset.weapon) {
               try {
                   const parsed = JSON.parse(el.dataset.weapon);
                   // Só considera weapon válido se for um objeto não vazio
                   if (parsed && typeof parsed === 'object' && Object.keys(parsed).length > 0) {
                       weaponData = parsed;
                   }
               } catch (e) {
                   weaponData = null;
               }
           } const hasWeapon = !!weaponData;
           const weaponEquipped = hasWeapon && globalWeaponEnabled;
           // Level: usa o level da weapon se estiver ativa e tiver level, senão usa o level da skill base
           let level = (el.dataset.level || ).trim();
           if (weaponEquipped && weaponData) {
               // Verifica se weapon tem level definido (pode ser número ou string)
               const weaponLevel = weaponData.level;
               if (weaponLevel !== undefined && weaponLevel !== null && weaponLevel !== ) {
                   level = weaponLevel.toString().trim();
               }
           }
           const lang = getLangKey();
           const baseDescPack = {
               pt: el.dataset.descPt || , en: el.dataset.descEn || , es: el.dataset.descEs || , pl: el.dataset.descPl || 
           };
           const baseDesc = baseDescPack[lang] || baseDescPack.pt || baseDescPack.en || baseDescPack.es || baseDescPack.pl || el.dataset.desc || ;
           // Aceita tanto desc_i18n quanto desc para compatibilidade
           let weaponDescPack = {};
           if (weaponData) {
               if (weaponData.desc_i18n) {
                   weaponDescPack = weaponData.desc_i18n;
               } else if (weaponData.desc) {
                   weaponDescPack = weaponData.desc;
               } else {
                   weaponDescPack = {
                       pt: weaponData.descPt || , en: weaponData.descEn || , es: weaponData.descEs || , pl: weaponData.descPl || 
                   };
               }
           }
           const weaponDesc = weaponDescPack[lang] || weaponDescPack.pt || weaponDescPack.en || weaponDescPack.es || weaponDescPack.pl || ;
           const chosenDesc = (weaponEquipped && weaponDesc) ? weaponDesc : baseDesc;
           const descHtml = chosenDesc.replace(/(.*?)/g, '$1');
           let attrsHTML = ;
           if (weaponEquipped && weaponData) {
               // Faz merge: usa atributos da skill base e substitui apenas os que existem no weapon
               // Parse dos atributos da skill base (formato: "pve, pvp, energy, cooldown" ou "pve, pvp, energy, cooldown")
               const baseAttrsStr = el.dataset.atr || ;
               // Suporta tanto ", " quanto "," como separador
               const baseAttrs = baseAttrsStr.split(/\s*,\s*/).map(a => a.trim());
               const basePve = baseAttrs[0] && baseAttrs[0] !== '-' ? baseAttrs[0] : ;
               const basePvp = baseAttrs[1] && baseAttrs[1] !== '-' ? baseAttrs[1] : ;
               const baseEnergy = baseAttrs[2] && baseAttrs[2] !== '-' ? baseAttrs[2] : ;
               const baseCd = baseAttrs[3] && baseAttrs[3] !== '-' ? baseAttrs[3] : ;
               // Valores do weapon (substituem os da skill base se existirem)
               const wPve = (weaponData.powerpve !== undefined && weaponData.powerpve !== null && weaponData.powerpve !== )
                   ? weaponData.powerpve.toString().trim()
                   : basePve;
               const wPvp = (weaponData.powerpvp !== undefined && weaponData.powerpvp !== null && weaponData.powerpvp !== )
                   ? weaponData.powerpvp.toString().trim()
                   : basePvp;
               const wEnergy = (weaponData.energy !== undefined && weaponData.energy !== null && weaponData.energy !== )
                   ? weaponData.energy.toString().trim()
                   : baseEnergy;
               const wCd = (weaponData.cooldown !== undefined && weaponData.cooldown !== null && weaponData.cooldown !== )
                   ? weaponData.cooldown.toString().trim()
                   : baseCd;
               // Monta string de atributos mesclados
               const mergedAttrs = [wPve, wPvp, wEnergy, wCd].join(',');
               attrsHTML = renderAttributes(mergedAttrs);
           } else {
               attrsHTML = el.dataset.atr ? renderAttributes(el.dataset.atr) : (el.dataset.subattrs ? renderSubAttributesFromObj(JSON.parse(el.dataset.subattrs), L) : );
           } let flagsHTML = ;
           // Debug: verifica se é uma skill do Urouge (verifica pela URL da página ou pelo contexto)
           const isUrougePage = window.location.href && window.location.href.toLowerCase().includes('urouge');
           if (el.dataset.flags) {
               try {
                   const flags = JSON.parse(el.dataset.flags);
                   if (flags && Array.isArray(flags) && flags.length > 0) {
                       flagsHTML = renderFlagsRow(flags);
                       // Debug para Urouge
                       if (isUrougePage) {
                           console.log('[Skills] Urouge - Flags processadas:', {
                               skill: name || el.dataset.nome,
                               flags: flags,
                               htmlLength: flagsHTML ? flagsHTML.length : 0,
                               hasHTML: !!flagsHTML
                           });
                       }
                   } else {
                       if (isUrougePage) {
                           console.warn('[Skills] Urouge - Flags inválidas:', {
                               skill: name || el.dataset.nome,
                               flags: flags,
                               rawData: el.dataset.flags
                           });
                       }
                   }
               } catch (e) {
                   console.warn('[Skills] Erro ao processar flags:', e, 'flags data:', el.dataset.flags, 'skill:', name || el.dataset.nome);
                   if (isUrougePage) {
                       console.error('[Skills] Urouge - Erro ao processar flags:', e, 'element:', el);
                   }
               }
           } else {
               // Debug: verifica se deveria ter flags mas não tem (apenas para Urouge)
               if (isUrougePage) {
                   console.warn('[Skills] Urouge - Skill sem data-flags:', {
                       skill: name || el.dataset.nome,
                       element: el,
                       allAttributes: Array.from(el.attributes).map(attr => attr.name + '=' + attr.value)
                   });
               }
           } if (descBox) {

descBox.innerHTML = `

${name}

${level ? `

${L.level} ${level}

` : }${attrsHTML}

${descHtml}

`;

           } if (hasWeapon) {
               applyWeaponBadge(el, weaponData, weaponEquipped);
           } if (videoBox) {
               const oldFlags = videoBox.querySelector('.skill-flags');
               if (oldFlags) oldFlags.remove();
               if (flagsHTML) {
                   videoBox.insertAdjacentHTML('beforeend', flagsHTML);
                   applyFlagTooltips(videoBox);
               }
           } const currIcons = Array.from(iconsBar.querySelectorAll('.skill-icon'));
           currIcons.forEach(i => i.classList.remove('active'));
           const subsRaw = el.dataset.subs || el.getAttribute('data-subs');
           const isFormSwitch = el.dataset.formSwitch === 'true' || el.getAttribute('data-form-switch') === 'true';
           // Não marca como ativo se for form_switch (Change Form)
           if (!isFormSwitch) {
               el.classList.add('active');
               if (!autoplay && loadedVideos > 0) autoplay = true;
               window.__lastActiveSkillIcon = el;
               // Lógica de vídeo: usa função centralizada que já considera weapon
               showVideoForIcon(el);
           }
           const isBack = el.dataset.back === 'true' || el.getAttribute('data-back') === 'true' || el.dataset.back === 'yes' || el.getAttribute('data-back') === 'yes' || el.dataset.back === '1' || el.getAttribute('data-back') === '1';
           // Se for form_switch, alterna forma (não processa como back)
           if (isFormSwitch) {
               // Atualiza o data-video-file do ícone com o vídeo correto da transição baseado na forma atual
               try {
                   const formsJSON = skillsRoot.dataset.forms || '{}';
                   if (formsJSON && formsJSON !== '{}') {
                       const tempFormsData = JSON.parse(formsJSON);
                       const formNames = Object.keys(tempFormsData);
                       // Busca vídeo de transição na skill Change Form
                       const formVideosRaw = el.dataset.formVideos || el.getAttribute('data-form-videos');
                       if (formVideosRaw) {
                           const videos = JSON.parse(formVideosRaw);
                           // Se currentForm é null, detecta qual forma está atualmente visível no DOM
                           let formForVideo = currentForm;
                           if (!formForVideo) {
                               // Lê formsData se ainda não foi carregado
                               if (Object.keys(formsData).length === 0) {
                                   try {
                                       formsData = JSON.parse(formsJSON);
                                   } catch (e) {
                                       formsData = {};
                                   }
                               }
                               formForVideo = detectCurrentForm();
                               // Se ainda não conseguiu detectar, usa a primeira como fallback
                               if (!formForVideo && formNames.length > 0) {
                                   formForVideo = formNames[0];
                               }
                           }
                           const transitionVideo = formForVideo ? (videos[formForVideo] || ) : ;
                           if (transitionVideo && transitionVideo.trim() !== ) {
                               // Atualiza temporariamente o data-video-file (o sistema usa isso)
                               el.dataset.videoFile = transitionVideo;
                           }
                       }
                   }
               } catch (e) {
                   console.error('[Forms] Erro ao processar vídeo de transição:', e);
               }
               // Usa o sistema normal de vídeo (mesmo que skills normais)
               showVideoForIcon(el);
               switchForm();
               return;
           }
           if (isBack && !isFormSwitch && barStack.length) {
               const prev = barStack.pop();
               // Restaura currentForm se estava salvo no snapshot
               if (prev.currentForm !== undefined) {
                   currentForm = prev.currentForm;
               }
               renderBarFromItems(prev);
               const btn = document.querySelector('.skills-back-wrapper');
               if (btn) btn.style.display = barStack.length ? 'block' : 'none';
               return;
           } if (openSubs && subsRaw && subsRaw.trim() !== ) {
               if (barStack.length && barStack[barStack.length - 1].parentIcon === el) return;
               try {
                   const subs = JSON.parse(subsRaw);
                   pushSubBarFrom(subs, el);
               } catch {
               }
           }
       } function wireClicksForCurrentBar() {
           const currIcons = Array.from(iconsBar.querySelectorAll('.skill-icon'));
           currIcons.forEach(el => {
               if (el.dataset.weaponToggle === '1' || el.classList.contains('weapon-bar-toggle')) return;
               if (el.dataset.wired) return;
               el.dataset.wired = '1';
               const label = el.dataset.nome || el.dataset.name || ;
               el.setAttribute('aria-label', label);
               if (el.hasAttribute('title')) el.removeAttribute('title');
               const img = el.querySelector('img');
               if (img) {
                   img.setAttribute('alt', );
                   if (img.hasAttribute('title')) img.removeAttribute('title');
               } el.addEventListener('click', () => {
                   activateSkill(el, {
                       openSubs: true
                   });
               });
           });
           wireTooltipsForNewIcons();
       } function animateIconsBarEntrance() {
           Array.from(iconsBar.children).forEach((c, i) => {
               c.style.opacity = '0';
               c.style.transform = 'translateY(6px)';
               requestAnimationFrame(() => {
                   setTimeout(() => {
                       c.style.transition = 'opacity .18s ease, transform .18s ease';
                       c.style.opacity = '1';
                       c.style.transform = 'translateY(0)';
                   }, i * 24);
               });
           });
       } function snapshotCurrentBarItemsFromDOM() {
           const items = Array.from(iconsBar.querySelectorAll('.skill-icon')).filter(el => el.dataset.weaponToggle !== '1').map(el => {
               const img = el.querySelector('img');
               const iconURL = img ? img.src : ;
               const subsRaw = el.dataset.subs || el.getAttribute('data-subs') || ;
               let subs = null;
               try {
                   subs = subsRaw ? JSON.parse(subsRaw) : null;
               } catch {
                   subs = null;
               } const subattrsRaw = el.dataset.subattrs || ;
               let flags = null;
               if (el.dataset.flags) {
                   try {
                       flags = JSON.parse(el.dataset.flags);
                   } catch (e) {
                   }
               } let weapon = null;
               if (el.dataset.weapon) {
                   try {
                       weapon = JSON.parse(el.dataset.weapon);
                   } catch (e) {
                   }
               }
               // Preserva data-form-videos para poder restaurar depois
               const formVideos = el.dataset.formVideos || el.getAttribute('data-form-videos') || ;
               return {
                   name: el.dataset.nome || el.dataset.name || , index: el.dataset.index || , level: el.dataset.level || , desc: el.dataset.desc || , descPt: el.dataset.descPt || , descEn: el.dataset.descEn || , descEs: el.dataset.descEs || , descPl: el.dataset.descPl || , attrs: el.dataset.atr || el.dataset.attrs || , video: el.dataset.video || , iconURL, subs, subattrsStr: subattrsRaw, flags: flags, weapon: weapon, nested: el.dataset.nested || , subName: el.dataset.subName || , parentIndex: el.dataset.parentIndex || , formSwitch: el.dataset.formSwitch || el.getAttribute('data-form-switch') || , formVideos: formVideos
               };
           });
           // Retorna objeto com items e currentForm para poder restaurar depois
           return { items, currentForm: currentForm };
       } function ensureBackButton() {
           const rail = iconsBar.closest('.top-rail.skills');
           if (!rail) return null;
           let wrap = rail.parentElement;
           if (!wrap || !wrap.classList || !wrap.classList.contains('skills-rail-wrap')) {
               const parentNode = rail.parentNode;
               const newWrap = document.createElement('div');
               newWrap.className = 'skills-rail-wrap';
               parentNode.insertBefore(newWrap, rail);
               newWrap.appendChild(rail);
               wrap = newWrap;
           } let backWrap = wrap.querySelector('.skills-back-wrapper');
           if (!backWrap) {
               backWrap = document.createElement('div');
               backWrap.className = 'skills-back-wrapper';
               const btnInner = document.createElement('button');
               btnInner.className = 'skills-back';
               btnInner.type = 'button';
               btnInner.setAttribute('aria-label', 'Voltar');
               btnInner.innerHTML = '<svg class="back-chevron" width="100%" height="100%" viewBox="0 0 36 32" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" preserveAspectRatio="xMidYMid meet"><path d="M10 2L4 16L10 30" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M20 2L14 16L20 30" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M30 2L24 16L30 30" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/></svg>';
               backWrap.appendChild(btnInner);
               wrap.insertBefore(backWrap, rail);
               btnInner.addEventListener('click', () => {
                   if (!barStack.length) return;
                   const prev = barStack.pop();
                   renderBarFromItems(prev);
                   backWrap.style.display = barStack.length ? 'block' : 'none';
                   wrap.classList.toggle('has-sub-bar', barStack.length > 0);
                   if (!barStack.length) btnInner.classList.remove('peek');
               });
           } backWrap.style.display = barStack.length ? 'block' : 'none';
           wrap.classList.toggle('has-sub-bar', barStack.length > 0);
           const btnInner = backWrap.querySelector('.skills-back');
           // Calcula a posição do botão baseado na posição real do top-rail
           function updateBackButtonPosition() {
               if (!rail || !backWrap) return;
               const railRect = rail.getBoundingClientRect();
               const wrapRect = wrap.getBoundingClientRect();
               // Calcula a posição relativa do rail dentro do wrap
               const railLeft = railRect.left - wrapRect.left;
               // Posiciona o wrapper na borda esquerda do rail
               // O botão interno usa translateX(-97%) para ficar atrás da barra
               backWrap.style.left = railLeft + 'px';
           }
           // Atualiza a posição quando necessário
           if (backWrap.style.display !== 'none') {
               // Usa requestAnimationFrame para garantir que o DOM foi atualizado
               requestAnimationFrame(() => {
                   updateBackButtonPosition();
               });
               // Recalcula em resize e scroll
               if (!backWrap.dataset.positionWired) {
                   backWrap.dataset.positionWired = '1';
                   const updateOnResize = () => {
                       if (backWrap.style.display !== 'none') {
                           updateBackButtonPosition();
                       }
                   };
                   window.addEventListener('resize', updateOnResize);
                   const observer = new ResizeObserver(() => {
                       if (backWrap.style.display !== 'none') {
                           updateBackButtonPosition();
                       }
                   });
                   if (rail) observer.observe(rail);
                   observer.observe(wrap);
               }
           }
           return btnInner;
       } function renderBarFromItems(itemsOrSnapshot) {
           // Suporta tanto o formato antigo (array) quanto o novo (objeto com items e currentForm)
           let items, savedCurrentForm;
           if (Array.isArray(itemsOrSnapshot)) {
               items = itemsOrSnapshot;
               savedCurrentForm = null;
           } else if (itemsOrSnapshot && itemsOrSnapshot.items) {
               items = itemsOrSnapshot.items;
               savedCurrentForm = itemsOrSnapshot.currentForm;
           } else {
               items = [];
               savedCurrentForm = null;
           }
           // Restaura currentForm se estava salvo
           if (savedCurrentForm !== undefined && savedCurrentForm !== null) {
               currentForm = savedCurrentForm;
           }
           const tip = document.querySelector('.skill-tooltip');
           if (tip) {
               tip.setAttribute('aria-hidden', 'true');
               tip.style.opacity = '0';
               tip.style.left = '-9999px';
               tip.style.top = '-9999px';
           } iconsBar.innerHTML = ;
           items.forEach((it, idx) => {
               const node = document.createElement('div');
               node.className = 'skill-icon';
               node.dataset.nome = it.name || ;
               if (it.index) node.dataset.index = it.index;
               if (it.level) node.dataset.level = it.level;
               if (it.desc) node.dataset.desc = it.desc;
               if (it.descPt) node.dataset.descPt = it.descPt;
               if (it.descEn) node.dataset.descEn = it.descEn;
               if (it.descEs) node.dataset.descEs = it.descEs;
               if (it.descPl) node.dataset.descPl = it.descPl;
               if (it.attrs) node.dataset.atr = it.attrs;
               if (it.video) node.dataset.video = it.video;
               if (it.subs) node.dataset.subs = JSON.stringify(it.subs);
               if (it.subattrsStr) node.dataset.subattrs = it.subattrsStr;
               if (it.flags) node.dataset.flags = JSON.stringify(it.flags);
               if (it.weapon && typeof it.weapon === 'object' && Object.keys(it.weapon).length > 0) {
                   node.dataset.weapon = JSON.stringify(it.weapon);
               }
               // Restaura informações de subskill importantes para busca de vídeos
               if (it.nested) node.dataset.nested = it.nested;
               if (it.subName) node.dataset.subName = it.subName;
               if (it.parentIndex) node.dataset.parentIndex = it.parentIndex;
               if (!it.index && !it.nested) node.dataset.nested = '1';
               // Restaura formSwitch (Change Form)
               if (it.formSwitch) {
                   node.dataset.formSwitch = it.formSwitch;
                   node.setAttribute('data-form-switch', it.formSwitch);
               }
               // Restaura formVideos (vídeos de transição de forma)
               if (it.formVideos) {
                   node.dataset.formVideos = it.formVideos;
                   node.setAttribute('data-form-videos', it.formVideos);
               }
               const img = document.createElement('img');
               img.alt = ;
               img.src = it.iconURL || (it.icon ? filePathURL(it.icon) : );
               img.decoding = 'async';
               img.loading = 'lazy';
               img.width = 50;
               img.height = 50;
               node.appendChild(img);
               iconsBar.appendChild(node);
           });
           animateIconsBarEntrance();
           wireClicksForCurrentBar();
           // Remove qualquer toggle antigo que possa aparecer
           const oldToggle = iconsBar.querySelector('.weapon-bar-toggle');
           if (oldToggle) oldToggle.remove();
           // Reaplica classes de weapon após renderizar barra
           reapplyWeaponClassesToBar();
           const b = ensureBackButton();
           if (b) b.classList.add('peek');
           // Atualiza a posição do botão back após a barra ser renderizada
           requestAnimationFrame(() => {
               const backWrap = document.querySelector('.skills-back-wrapper');
               if (backWrap && backWrap.style.display !== 'none') {
                   const rail = iconsBar.closest('.top-rail.skills');
                   const wrap = rail ? rail.parentElement : null;
                   if (rail && wrap && wrap.classList.contains('skills-rail-wrap')) {
                       const railRect = rail.getBoundingClientRect();
                       const wrapRect = wrap.getBoundingClientRect();
                       const railLeft = railRect.left - wrapRect.left;
                       // Posiciona na borda esquerda do rail (botão fica atrás com translateX)
                       backWrap.style.left = railLeft + 'px';
                   }
               }
           });
       } function pushSubBarFrom(subs, parentIconEl) {
           const tip = document.querySelector('.skill-tooltip');
           if (tip) {
               tip.setAttribute('aria-hidden', 'true');
               tip.style.opacity = '0';
               tip.style.left = '-9999px';
               tip.style.top = '-9999px';
           } const parentNameSnapshot = parentIconEl ? (parentIconEl.dataset.nome || parentIconEl.dataset.name || ) : ;
           // Para subskills, usa parentIndex; para skills principais, usa index
           const parentIndexSnapshot = parentIconEl ? (
               parentIconEl.dataset.nested === '1'
                   ? (parentIconEl.dataset.parentIndex || )
                   : (parentIconEl.dataset.index || )
           ) : ;
           const snapshot = snapshotCurrentBarItemsFromDOM();
           barStack.push({
               items: snapshot.items,
               currentForm: snapshot.currentForm,
               parentIcon: parentIconEl,
               parentName: parentNameSnapshot,
               parentIndex: parentIndexSnapshot
           });
           ensureBackButton();
           const langKey = getLangKey();
           let cacheKey = null;
           if (parentIconEl) {
               cacheKey = parentIconEl.dataset.subCacheKey || null;
               if (!cacheKey) {
                   if (parentIconEl.dataset.index) {
                       cacheKey = `idx:${parentIconEl.dataset.index}`;
                   } else {
                       const slug = slugify(parentIconEl.dataset.nome || parentIconEl.dataset.name || );
                       if (slug) cacheKey = `slug:${slug}`;
                   } if (cacheKey) parentIconEl.dataset.subCacheKey = cacheKey;
               }
           } if (cacheKey) {
               const cached = subBarTemplateCache.get(cacheKey);
               if (cached && cached.lang === langKey) {
                   iconsBar.innerHTML = ;
                   const clone = cached.template.cloneNode(true);
                   iconsBar.appendChild(clone);
                   animateIconsBarEntrance();
                   wireClicksForCurrentBar();
                   // Remove qualquer toggle antigo que possa aparecer
                   const oldToggle2 = iconsBar.querySelector('.weapon-bar-toggle');
                   if (oldToggle2) oldToggle2.remove();
                   // Reaplica classes de weapon após renderizar do cache
                   reapplyWeaponClassesToBar();
                   const cachedBtn = ensureBackButton();
                   if (cachedBtn) cachedBtn.classList.add('peek');
                   return;
               }
           } const skillsRoot = document.getElementById('skills');
           const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {
           };
           const L = i18nMap[getLangKey()] || i18nMap.pt || {
               cooldown: 'Recarga', energy_gain: 'Ganho de energia', energy_cost: 'Custo de energia', power: 'Poder', power_pvp: 'Poder PvP', level: 'Nível'
           };
           const hydratedSubs = inheritSubskillTree(subs, mainSkillsMeta);
           const items = (hydratedSubs || []).filter(s => {
               // Filtra só se não tem nada útil
               const hasName = (s.name || s.n || ).trim() !== ;
               const hasIcon = (s.icon || ).trim() !==  && s.icon !== 'Nada.png';
               const hasRef = (s.refS || s.refM || ).toString().trim() !== ;
               return hasName || hasIcon || hasRef;
           }).map(s => {
               const name = (s.name || s.n || ).trim();
               const desc = chooseDescFrom(s).replace(/(.*?)/g, '$1');
               const attrsHTML = renderSubAttributesFromObj(s, L);
               return {
                   name, level: (s.level || ).toString().trim(), desc, descPt: (s.descPt || (s.desc_i18n && s.desc_i18n.pt) || ), descEn: (s.descEn || (s.desc_i18n && s.desc_i18n.en) || ), descEs: (s.descEs || (s.desc_i18n && s.desc_i18n.es) || ), descPl: (s.descPl || (s.desc_i18n && s.desc_i18n.pl) || ), attrs: , icon: (s.icon || ), iconURL: (s.icon && s.icon !== 'Nada.png' && s.icon.toLowerCase() !== 'nada.png') ? filePathURL(s.icon) : , video: s.video ? filePathURL(s.video) : , subs: Array.isArray(s.subs) ? s.subs : null, subattrs: s, flags: Array.isArray(s.flags) ? s.flags : null, back: (s.back === true || s.back === 'true' || s.back === 'yes' || s.back === '1') ? 'true' : null, weapon: s.weapon || null
               };
           });
           const fragment = document.createDocumentFragment();
           items.forEach((it, iIdx) => {
               const node = document.createElement('div');
               node.className = 'skill-icon';
               node.dataset.nested = '1';
               node.dataset.nome = it.name || ;
               node.dataset.parentIndex = parentIndexSnapshot;
               // Constrói o caminho completo para sub-subskills
               // IMPORTANTE: O cache NÃO inclui o nome da skill principal no caminho
               // Formato do cache: "SubskillName" ou "SubskillName:SubSubskillName" (sem o nome da skill principal)
               let fullPath = it.name || ;
               if (parentIconEl) {
                   // Se o pai é uma subskill (tem nested), adiciona o nome do pai ao caminho
                   if (parentIconEl.dataset.nested === '1') {
                       // Se o pai tem subName, usa ele (já está no formato correto, sem nome da skill principal)
                       if (parentIconEl.dataset.subName && parentIconEl.dataset.subName.trim() !== ) {
                           fullPath = `${parentIconEl.dataset.subName}:${it.name || }`;
                       } else {
                           // Se o pai não tem subName, é a primeira subskill, então usa apenas o nome do pai
                           const parentName = (parentIconEl.dataset.nome || parentIconEl.dataset.name || ).trim();
                           fullPath = `${parentName}:${it.name || }`;
                       }
                   }
                   // Se o pai é uma skill principal (não é nested), o caminho é apenas o nome da subskill atual
                   // (já está definido como it.name acima)
               }
               node.dataset.subName = fullPath;
               const subSlug = slugify(it.name || );
               if (subSlug) node.dataset.slug = subSlug;
               if (it.level) node.dataset.level = it.level;
               if (it.desc) node.dataset.desc = it.desc;
               if (it.descPt) node.dataset.descPt = it.descPt;
               if (it.descEn) node.dataset.descEn = it.descEn;
               if (it.descEs) node.dataset.descEs = it.descEs;
               if (it.descPl) node.dataset.descPl = it.descPl;
               if (it.video) node.dataset.video = it.video;
               if (it.subs) node.dataset.subs = JSON.stringify(it.subs);
               if (it.subattrs) node.dataset.subattrs = JSON.stringify(it.subattrs);
               if (it.flags) node.dataset.flags = JSON.stringify(it.flags);
               if (it.back) node.dataset.back = it.back;
               if (it.weapon && typeof it.weapon === 'object' && Object.keys(it.weapon).length > 0) {
                   try {
                       node.dataset.weapon = JSON.stringify(it.weapon);
                   } catch (e) {
                       console.error('[Skills] Erro ao serializar weapon de subskill', it.name, e);
                   }
               }
               const img = document.createElement('img');
               img.alt = ;
               img.src = it.iconURL;
               img.decoding = 'async';
               img.loading = 'lazy';
               img.width = 50;
               img.height = 50;
               node.appendChild(img);
               fragment.appendChild(node);
           });
           const templateClone = fragment.cloneNode(true);
           iconsBar.innerHTML = ;
           iconsBar.appendChild(fragment);
           animateIconsBarEntrance();
           wireClicksForCurrentBar();
           // Remove qualquer toggle antigo que possa aparecer
           const oldToggle3 = iconsBar.querySelector('.weapon-bar-toggle');
           if (oldToggle3) oldToggle3.remove();
           // Reaplica classes de weapon após renderizar subskills
           reapplyWeaponClassesToBar();
           const b2 = ensureBackButton();
           if (b2) b2.classList.add('peek');
           // Atualiza a posição do botão back após subskills serem renderizadas
           requestAnimationFrame(() => {
               const backWrap = document.querySelector('.skills-back-wrapper');
               if (backWrap && backWrap.style.display !== 'none') {
                   const rail = iconsBar.closest('.top-rail.skills');
                   const wrap = rail ? rail.parentElement : null;
                   if (rail && wrap && wrap.classList.contains('skills-rail-wrap')) {
                       const railRect = rail.getBoundingClientRect();
                       const wrapRect = wrap.getBoundingClientRect();
                       const railLeft = railRect.left - wrapRect.left;
                       // Posiciona na borda esquerda do rail (botão fica atrás com translateX)
                       backWrap.style.left = railLeft + 'px';
                   }
               }
           });
           if (cacheKey) {
               subBarTemplateCache.set(cacheKey, {
                   template: templateClone, lang: langKey
               });
           }
       } window.addEventListener('gla:langChanged', () => {
           subBarTemplateCache.clear();
           const skillsRoot = document.getElementById('skills');
           const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {
           };
           const lang = getLangKey();
           Array.from(iconsBar.querySelectorAll('.skill-icon')).forEach(icon => {
               const pack = {
                   pt: icon.dataset.descPt || , en: icon.dataset.descEn || , es: icon.dataset.descEs || , pl: icon.dataset.descPl || 
               };
               const chosen = (pack[lang] || pack.pt || pack.en || pack.es || pack.pl || icon.dataset.desc || ).trim();
               if (chosen) icon.dataset.desc = chosen;
           });
           barStack.forEach(frame => {
               (frame.items || []).forEach(it => {
                   const pack = {
                       pt: it.descPt, en: it.descEn, es: it.descEs, pl: it.descPl
                   };
                   const chosen = (pack[lang] || pack.pt || pack.en || pack.es || pack.pl || it.desc || );
                   it.desc = chosen;
               });
           });
           if (descBox) {
               applyFlagTooltips(descBox);
           } const activeIcon = window.__lastActiveSkillIcon;
           if (activeIcon && activeIcon.dataset.weapon) {
               activateSkill(activeIcon, {
                   openSubs: false
               });
           }
       });
       wireClicksForCurrentBar();
       const b0 = ensureBackButton();
       if (b0) {
           b0.classList.add('peek');
           b0.style.alignSelf = 'stretch';
       }
       // Move inicialização de tooltip para requestIdleCallback (não crítico)
       if ('requestIdleCallback' in window) {
           requestIdleCallback(() => {
               (function initSkillTooltip() {
                   if (document.querySelector('.skill-tooltip')) return;
                   const tip = document.createElement('div');
                   tip.className = 'skill-tooltip';
                   tip.setAttribute('role', 'tooltip');
                   tip.setAttribute('aria-hidden', 'true');
                   document.body.appendChild(tip);
                   const lockUntilRef = {
                       value: 0
                   };
                   function measureAndPos(el) {
                       if (!el || tip.getAttribute('aria-hidden') === 'true') return;
                       tip.style.left = '0px';
                       tip.style.top = '0px';
                       const rect = el.getBoundingClientRect();
                       const tr = tip.getBoundingClientRect();
                       let left = Math.round(rect.left + (rect.width - tr.width) / 2);
                       left = Math.max(8, Math.min(left, window.innerWidth - tr.width - 8));
                       const coarse = (window.matchMedia && matchMedia('(pointer: coarse)').matches) || (window.innerWidth <= 600);
                       let top = coarse ? Math.round(rect.bottom + 10) : Math.round(rect.top - tr.height - 8);
                       if (top < 8) top = Math.round(rect.bottom + 10);
                       tip.style.left = left + 'px';
                       tip.style.top = top + 'px';
                   } function show(el, text) {
                       tip.textContent = text || ;
                       tip.setAttribute('aria-hidden', 'false');
                       measureAndPos(el);
                       tip.style.opacity = '1';
                   } function hide() {
                       tip.setAttribute('aria-hidden', 'true');
                       tip.style.opacity = '0';
                       tip.style.left = '-9999px';
                       tip.style.top = '-9999px';
                   } window.__globalSkillTooltip = {
                       show, hide, measureAndPos, lockUntil: lockUntilRef
                   };
                   Array.from(document.querySelectorAll('.icon-bar .skill-icon')).forEach(icon => {
                       if (icon.dataset.weaponToggle === '1' || icon.classList.contains('weapon-bar-toggle')) return;
                       if (icon.dataset.tipwired) return;
                       icon.dataset.tipwired = '1';
                       const label = icon.dataset.nome || icon.dataset.name || icon.title || ;
                       if (label && !icon.hasAttribute('aria-label')) icon.setAttribute('aria-label', label);
                       if (icon.hasAttribute('title')) icon.removeAttribute('title');
                       const img = icon.querySelector('img');
                       if (img) {
                           const imgAlt = img.getAttribute('alt') || ;
                           const imgTitle = img.getAttribute('title') || ;
                           if (!label && (imgAlt || imgTitle)) icon.setAttribute('aria-label', imgAlt || imgTitle);
                           img.setAttribute('alt', );
                           if (img.hasAttribute('title')) img.removeAttribute('title');
                       } icon.addEventListener('mouseenter', () => show(icon, label));
                       icon.addEventListener('mousemove', () => {
                           if (performance.now() >= lockUntilRef.value) measureAndPos(icon);
                       });
                       icon.addEventListener('click', () => {
                           lockUntilRef.value = performance.now() + 240;
                           measureAndPos(icon);
                       });
                       icon.addEventListener('mouseleave', hide);
                   });
                   Array.from(document.querySelectorAll('.subskills-rail .subicon')).forEach(sub => {
                       if (sub.dataset.tipwired) return;
                       sub.dataset.tipwired = '1';
                       const label = sub.getAttribute('title') || sub.getAttribute('aria-label') || ;
                       if (label && !sub.hasAttribute('aria-label')) sub.setAttribute('aria-label', label);
                       if (sub.hasAttribute('title')) sub.removeAttribute('title');
                       sub.addEventListener('mouseenter', () => show(sub, label));
                       sub.addEventListener('mousemove', () => {
                           if (performance.now() >= lockUntilRef.value) measureAndPos(sub);
                       });
                       sub.addEventListener('click', () => {
                           lockUntilRef.value = performance.now() + 240;
                           measureAndPos(sub);
                       });
                       sub.addEventListener('mouseleave', hide);
                   });
                   window.addEventListener('scroll', () => {
                       const visible = document.querySelector('.skill-tooltip[aria-hidden="false"]');
                       if (!visible) return;
                       const target = document.querySelector('.subskills-rail .subicon:hover') || document.querySelector('.subskills-rail .subicon.active') || document.querySelector('.icon-bar .skill-icon:hover') || document.querySelector('.icon-bar .skill-icon.active');
                       measureAndPos(target);
                   }, true);
                   window.addEventListener('resize', () => {
                       const target = document.querySelector('.subskills-rail .subicon:hover') || document.querySelector('.subskills-rail .subicon.active') || document.querySelector('.icon-bar .skill-icon:hover') || document.querySelector('.icon-bar .skill-icon.active');
                       measureAndPos(target);
                   });
               })();
           }, { timeout: 2000 });
       } else {
           // Fallback para navegadores sem requestIdleCallback
           setTimeout(() => {
               (function initSkillTooltip() {
                   if (document.querySelector('.skill-tooltip')) return;
                   const tip = document.createElement('div');
                   tip.className = 'skill-tooltip';
                   tip.setAttribute('role', 'tooltip');
                   tip.setAttribute('aria-hidden', 'true');
                   document.body.appendChild(tip);
                   window.__globalSkillTooltip = {
                       show: (el, text) => {
                           if (!el || !text) return;
                           tip.textContent = text;
                           tip.setAttribute('aria-hidden', 'false');
                           measureAndPos(el);
                       },
                       hide: () => {
                           tip.setAttribute('aria-hidden', 'true');
                           tip.style.left = '-9999px';
                           tip.style.top = '-9999px';
                       },
                       measureAndPos: (el) => {
                           if (!el || tip.getAttribute('aria-hidden') === 'true') return;
                           const rect = el.getBoundingClientRect();
                           const tipRect = tip.getBoundingClientRect();
                           let left = rect.left + (rect.width / 2) - (tipRect.width / 2);
                           let top = rect.top - tipRect.height - 8;
                           if (left < 8) left = 8;
                           if (left + tipRect.width > window.innerWidth - 8) left = window.innerWidth - tipRect.width - 8;
                           if (top < 8) top = rect.bottom + 8;
                           tip.style.left = left + 'px';
                           tip.style.top = top + 'px';
                       },
                       lockUntil: { value: 0 }
                   };
                   const { measureAndPos } = window.__globalSkillTooltip;
                   window.addEventListener('scroll', () => {
                       const visible = document.querySelector('.skill-tooltip[aria-hidden="false"]');
                       if (!visible) return;
                       const target = document.querySelector('.subskills-rail .subicon:hover') || document.querySelector('.subskills-rail .subicon.active') || document.querySelector('.icon-bar .skill-icon:hover') || document.querySelector('.icon-bar .skill-icon.active');
                       measureAndPos(target);
                   }, true);
                   window.addEventListener('resize', () => {
                       const target = document.querySelector('.subskills-rail .subicon:hover') || document.querySelector('.subskills-rail .subicon.active') || document.querySelector('.icon-bar .skill-icon:hover') || document.querySelector('.icon-bar .skill-icon.active');
                       measureAndPos(target);
                   });
               })();
           }, 100);
       }
       (function initTabs() {
           const tabs = Array.from(document.querySelectorAll('.tab-btn'));
           if (!tabs.length) return;
           const contents = Array.from(document.querySelectorAll('.tab-content'));
           const characterBox = document.querySelector('.character-box');
           let wrapper = characterBox.querySelector('.tabs-height-wrapper');
           if (!wrapper) {
               wrapper = document.createElement('div');
               wrapper.className = 'tabs-height-wrapper';
               contents.forEach(c => {
                   wrapper.appendChild(c);
               });
               const tabsElement = characterBox.querySelector('.character-tabs');
               if (tabsElement && tabsElement.nextSibling) {
                   characterBox.insertBefore(wrapper, tabsElement.nextSibling);
               } else {
                   characterBox.appendChild(wrapper);
               }
           } async function smoothHeightTransition(fromTab, toTab) {
               if (!wrapper) return Promise.resolve();
               const scrollY = window.scrollY;
               const currentHeight = wrapper.getBoundingClientRect().height;
               await new Promise((resolve) => {
                   const videoContainers = toTab.querySelectorAll('.video-container');
                   const contentCard = toTab.querySelector('.content-card');
                   if (videoContainers.length === 0) {
                       requestAnimationFrame(() => {
                           requestAnimationFrame(() => {
                               requestAnimationFrame(() => resolve());
                           });
                       });
                       return;
                   } let lastHeight = 0;
                   let stableCount = 0;
                   const checksNeeded = 3;
                   let totalChecks = 0;
                   const maxChecks = 15;
                   function checkStability() {
                       totalChecks++;
                       const currentTabHeight = toTab.scrollHeight;
                       if (Math.abs(currentTabHeight - lastHeight) < 5) {
                           stableCount++;
                       } else {
                           stableCount = 0;
                       } lastHeight = currentTabHeight;
                       if (stableCount >= checksNeeded || totalChecks >= maxChecks) {
                           resolve();
                       } else {
                           setTimeout(checkStability, 50);
                       }
                   } setTimeout(checkStability, 50);
               });
               const nextHeight = toTab.getBoundingClientRect().height;
               const finalHeight = Math.max(nextHeight, 100);
               if (Math.abs(finalHeight - currentHeight) < 30) {
                   wrapper.style.height = ;
                   return Promise.resolve();
               } wrapper.style.overflow = 'hidden';
               wrapper.style.height = currentHeight + 'px';
               wrapper.offsetHeight;
               wrapper.style.transition = 'height 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
               requestAnimationFrame(() => {
                   wrapper.style.height = finalHeight + 'px';
               });
               return new Promise(resolve => {
                   setTimeout(() => {
                       wrapper.style.height = ;
                       wrapper.style.transition = ;
                       wrapper.style.overflow = ;
                       resolve();
                   }, 320);
               });
           } tabs.forEach(btn => {
               if (btn.dataset.wiredTab) return;
               btn.dataset.wiredTab = '1';
               btn.addEventListener('click', () => {
                   const target = btn.getAttribute('data-tab');
                   const currentActive = contents.find(c => c.classList.contains('active'));
                   const nextActive = contents.find(c => c.id === target);
                   if (currentActive === nextActive) return;
                   document.body.classList.add('transitioning-tabs');
                   if (currentActive) {
                       currentActive.style.opacity = '0';
                       currentActive.style.transform = 'translateY(-8px)';
                   } setTimeout(async () => {
                       contents.forEach(c => {
                           if (c !== nextActive) {
                               c.style.display = 'none';
                               c.classList.remove('active');
                           }
                       });
                       tabs.forEach(b => b.classList.toggle('active', b === btn));
                       if (nextActive) {
                           nextActive.classList.add('active');
                           nextActive.style.display = 'block';
                           nextActive.style.opacity = '0';
                           nextActive.style.visibility = 'hidden';
                           nextActive.offsetHeight;
                           try {
                               if (target === 'skills') {
                                   const tabEl = document.getElementById(target);
                                   if (tabEl) {
                                       const activeIcon = tabEl.querySelector('.icon-bar .skill-icon.active');
                                       const firstIcon = tabEl.querySelector('.icon-bar .skill-icon');
                                       const toClick = activeIcon || firstIcon;
                                       if (toClick) {
                                           const had = document.body.dataset.suppressSkillPlay;
                                           document.body.dataset.suppressSkillPlay = '1';
                                           toClick.click();
                                           if (had) document.body.dataset.suppressSkillPlay = had;
                                       }
                                   }
                               }
                           } catch (e) {
                           }
                       } if (currentActive && nextActive) {
                           await smoothHeightTransition(currentActive, nextActive);
                       } if (nextActive) {
                           nextActive.style.visibility = ;
                           nextActive.style.transform = 'translateY(12px)';
                           requestAnimationFrame(() => {
                               nextActive.style.opacity = '1';
                               nextActive.style.transform = 'translateY(0)';
                               setTimeout(() => {
                                   nextActive.style.opacity = ;
                                   nextActive.style.transform = ;
                                   document.body.classList.remove('transitioning-tabs');
                                   try {
                                       delete document.body.dataset.suppressSkillPlay;
                                   } catch {
                                   }
                               }, 300);
                           });
                       }
                   }, 120);
                   setTimeout(() => {
                       syncDescHeight();
                       if (target === 'skins') {
                           videosCache.forEach(v => {
                               try {
                                   v.pause();
                               } catch (e) {
                               } v.style.display = 'none';
                           });
                           if (videoBox) {
                               videoBox.querySelectorAll('video.skill-video').forEach(v => {
                                   try {
                                       v.pause();
                                   } catch (e) {
                                   } v.style.display = 'none';
                               });
                           } if (window.__subskills) window.__subskills.hideAll?.(videoBox);
                           const placeholder = videoBox?.querySelector('.video-placeholder');
                           if (videoBox && placeholder) {
                               placeholder.style.display = 'none';
                               placeholder.classList.add('fade-out');
                           }
                       } else {
                           const activeIcon = document.querySelector('.icon-bar .skill-icon.active');
                           if (activeIcon) activeIcon.click();
                       }
                   }, 450);
               });
           });
       })();
       (function initSkinsArrows() {
           const carousel = $('.skins-carousel');
           const wrapper = $('.skins-carousel-wrapper');
           const left = $('.skins-arrow.left');
           const right = $('.skins-arrow.right');
           if (!carousel || !left || !right || !wrapper) return;
           if (wrapper.dataset.wired) return;
           wrapper.dataset.wired = '1';
           const scrollAmt = () => Math.round(carousel.clientWidth * 0.6);
           function setState() {
               const max = carousel.scrollWidth - carousel.clientWidth;
               const x = carousel.scrollLeft;
               const hasLeft = x > 5, hasRight = x < max - 5;
               left.style.display = hasLeft ? 'inline-block' : 'none';
               right.style.display = hasRight ? 'inline-block' : 'none';
               wrapper.classList.toggle('has-left', hasLeft);
               wrapper.classList.toggle('has-right', hasRight);
               carousel.style.justifyContent = (!hasLeft && !hasRight) ? 'center' : ;
           } function go(dir) {
               const max = carousel.scrollWidth - carousel.clientWidth;
               const next = dir < 0 ? Math.max(0, carousel.scrollLeft - scrollAmt()) : Math.min(max, carousel.scrollLeft + scrollAmt());
               carousel.scrollTo({
                   left: next, behavior: 'smooth'
               });
           } left.addEventListener('click', () => go(-1));
           right.addEventListener('click', () => go(1));
           carousel.addEventListener('scroll', setState);
           new ResizeObserver(setState).observe(carousel);
           setState();
       })();
       function renderAttributes(str) {
           const skillsRoot = document.getElementById('skills');
           const i18nMap = skillsRoot ? JSON.parse(skillsRoot.dataset.i18nAttrs || '{}') : {
           };
           const langRaw = (document.documentElement.lang || skillsRoot?.dataset.i18nDefault || 'pt').toLowerCase();
           const langKey = i18nMap[langRaw] ? langRaw : (i18nMap[langRaw.split('-')[0]] ? langRaw.split('-')[0] : 'pt');
           const L = i18nMap[langKey] || i18nMap.pt || {
               cooldown: 'Recarga', energy_gain: 'Ganho de energia', energy_cost: 'Custo de energia', power: 'Poder', power_pvp: 'Poder PvP', level: 'Nível'
           };
           const vals = (str || ).split(',').map(v => v.trim());
           // Processa valores, tratando strings vazias e "-" como NaN
           // IMPORTANTE: ordem fixa é [powerpve, powerpvp, energy, cooldown]
           const parseValue = (val) => {
               if (!val || val ===  || val === '-') return NaN;
               const parsed = parseFloat(val);
               return isNaN(parsed) ? NaN : parsed;
           };
           const pve = parseValue(vals[0]);
           const pvp = parseValue(vals[1]);
           const ene = parseValue(vals[2]);
           const cd = parseValue(vals[3]);
           // Debug: log se houver problema na ordem
           if (str && str.includes(',') && !isNaN(cd) && !isNaN(pvp) && cd === pvp) {
               console.warn('[Skills] renderAttributes: possível problema na ordem dos atributos', { str, vals, pve, pvp, ene, cd });
           }
           const rows = [];
           // Ordem de exibição: cooldown, energy, power, power_pvp
           if (!isNaN(cd)) rows.push([L.cooldown, cd]);
           if (!isNaN(ene) && ene !== 0) {
               const label = ene > 0 ? L.energy_gain : L.energy_cost;
               rows.push([label, Math.abs(ene)]);
           }
           if (!isNaN(pve)) rows.push([L.power, pve]);
           if (!isNaN(pvp)) rows.push([L.power_pvp, pvp]);
           // Debug: log se houver valores suspeitos (desabilitado para performance)
           // if (str && str.includes(',')) {
           //     console.log('[Skills] renderAttributes processed', {
           //         str,
           //         vals: vals.slice(0, 4),
           //         parsed: { pve, pvp, ene, cd },
           //         rows: rows.map(r => r[0])
           //     });
           // }
           if (!rows.length) return ;

const html = rows.map(([rowLabel, rowValue]) => `

${rowLabel}${rowValue}

`).join(); return `

${html}

`;

       } function syncDescHeight() {
       } window.addEventListener('resize', syncDescHeight);
       if (videoBox) new ResizeObserver(syncDescHeight).observe(videoBox);
       iconItems.forEach(el => {
           const wired = !!el.dataset._sync_wired;
           if (wired) return;
           el.dataset._sync_wired = '1';
           el.addEventListener('click', () => {
               Promise.resolve().then(syncDescHeight);
           });
       });
       if (iconsBar) {
           const scrollWrapper = iconsBar.closest('.icon-scroll-x') || iconsBar.parentElement;
           const scrollContainer = scrollWrapper && scrollWrapper.classList.contains('icon-scroll-x') ? scrollWrapper : iconsBar;
           addOnce(scrollContainer, 'wheel', (e) => {
               if (e.deltaY) {
                   e.preventDefault();
                   scrollContainer.scrollLeft += e.deltaY;
               }
           }, { passive: false }); // passive: false necessário porque usamos preventDefault()
       }
       wireClicksForCurrentBar();
       if (iconItems.length) {
           const first = iconItems[0];
           if (first) {
               activateSkill(first, {
                   openSubs: false
               });
           }
       }
       // Aplica lazy loading em imagens fora do viewport inicial
       (function applyLazyLoading() {
           if ('IntersectionObserver' in window) {
               const imageObserver = new IntersectionObserver((entries, observer) => {
                   entries.forEach(entry => {
                       if (entry.isIntersecting) {
                           const img = entry.target;
                           if (img.tagName === 'IMG' && !img.hasAttribute('loading')) {
                               img.loading = 'lazy';
                           }
                           observer.unobserve(img);
                       }
                   });
               });
               // Observa imagens que não estão no viewport inicial
               document.querySelectorAll('img:not(.topbar-icon):not([loading])').forEach(img => {
                   const rect = img.getBoundingClientRect();
                   if (rect.bottom > window.innerHeight || rect.top < 0) {
                       imageObserver.observe(img);
                   }
               });
           }
       })();
       setTimeout(() => {
           Array.from(document.querySelectorAll('.skill-icon')).forEach(el => {
           });
           videosCache.forEach((v, idx) => {
               const src = v.querySelector('source') ? v.querySelector('source').src : v.src;
               v.addEventListener('error', (ev) => {
               });
               v.addEventListener('loadedmetadata', () => {
               });
           });
       }, 600);
   })();

</script>