AnimeWorld Better Player

Il player migliore di sempre — riscritto da zero.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         AnimeWorld Better Player
// @namespace    aw-better-player
// @version      2.3.1
// @match        *://www.animeworld.ac/play/*
// @run-at       document-start
// @description  Il player migliore di sempre — riscritto da zero.
// @description:it Il player migliore di sempre — riscritto da zero.
// @license      MIT
// @grant        unsafeWindow
// ==/UserScript==

(() => {
    'use strict';

    const pageWin=(typeof unsafeWindow!=='undefined')?unsafeWindow:window;

    const HIDE_DELAY_MS=3000,SKIP_SECONDS=85,SAVE_INTERVAL_MS=5000,RESUME_MIN_POS=5,RESUME_END_GAP=10,RESUME_MAX_AGE=30*24*60*60*1000,PRELOAD_THRESHOLD=0.75;
    const KEY_VOL='aw-np-vol',KEY_MUTE='aw-np-muted',KEY_GLOBAL='aw-np-global',KEY_RESUME_ENABLE='aw-np-resume-enabled',KEY_RESUME_PFX='aw-np-resume:',KEY_SEEK_SECS='aw-np-seek-secs',KEY_AUTOEP_ENABLE='aw-np-autoep-enabled',KEY_AUTOEP_PFX='aw-np-autoep:',KEY_AUTOPLAY_ENABLE='aw-np-autoplay-enabled',KEY_COLOR='aw-np-color',KEY_COLOR_GLOBAL='aw-np-color-global',KEY_ICON_COLOR='aw-np-icon-color',KEY_TOP_COLOR='aw-np-top-color',KEY_FLASH_ENABLE='aw-np-flash-enabled',KEY_CLOCK='aw-np-clock-enabled',KEY_SPEED_POPUP='aw-np-speed-popup-enabled',KEY_CONN_MONITOR='aw-np-conn-monitor-enabled',KEY_SPEED='aw-np-speed';
    const SEEK_DEFAULT=5,SEEK_MIN=5,SEEK_MAX=30,SEEK_STEP=5,SPEED_DEFAULT=1,SPEED_MIN=0.25,SPEED_MAX=3,SPEED_STEP=0.25;
    const PALETTE=[{name:'Bianco',hex:'#ffffff'},{name:'Rosso',hex:'#f44336'},{name:'Arancio',hex:'#ff9800'},{name:'Giallo',hex:'#ffeb3b'},{name:'Verde',hex:'#4caf50'},{name:'Ciano',hex:'#00bcd4'},{name:'Azzurro',hex:'#42a5f5'},{name:'Blu',hex:'#1565c0'},{name:'Viola',hex:'#9c27b0'},{name:'Rosa',hex:'#e91e8c'}];

    // ── Blocca playerServersAndDownloads.js ───────────────────────────────────
    const _srcDesc=Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype,'src');
    Object.defineProperty(HTMLScriptElement.prototype,'src',{configurable:true,enumerable:true,get(){return _srcDesc.get.call(this);},set(val){if(typeof val==='string'&&val.includes('playerServersAndDownloads'))return;_srcDesc.set.call(this,val);}});

    // ── Storage helpers ───────────────────────────────────────────────────────
    const lsGet=k=>{try{return localStorage.getItem(k);}catch{return null;}};
    const lsSet=(k,v)=>{try{localStorage.setItem(k,v);}catch{}};
    const lsDel=k=>{try{localStorage.removeItem(k);}catch{}};

    // ── Impostazioni ──────────────────────────────────────────────────────────
    let _cachedAnimeId='';
    const animeId=()=>{if(!_cachedAnimeId){const el=document.querySelector('#player');if(el)_cachedAnimeId=el.dataset.animeId||'';}return _cachedAnimeId;};
    const isGlobalOn=()=>lsGet(KEY_GLOBAL)!=='0';
    const pKey=k=>isGlobalOn()?k:k+':'+(animeId()||'unknown');
    const isResumeOn=()=>lsGet(pKey(KEY_RESUME_ENABLE))!=='0';
    const isAutoEpOn=()=>lsGet(pKey(KEY_AUTOEP_ENABLE))==='1';
    const isAutoPlayOn=()=>lsGet(pKey(KEY_AUTOPLAY_ENABLE))==='1';
    const isColorGlobalOn=()=>lsGet(KEY_COLOR_GLOBAL)!=='0';
    const isIconColorOn=()=>lsGet(KEY_ICON_COLOR)==='1';
    const isTopColorOn=()=>lsGet(KEY_TOP_COLOR)==='1';
    const isFlashOn=()=>lsGet(KEY_FLASH_ENABLE)!=='0';
    const isConnMonitorOn=()=>lsGet(KEY_CONN_MONITOR)!=='0';
    const isClockOn=()=>lsGet(KEY_CLOCK)!=='0';
    const isSpeedPopupOn=()=>lsGet(KEY_SPEED_POPUP)!=='0';
    const colorKey=()=>isColorGlobalOn()?KEY_COLOR:KEY_COLOR+':'+(animeId()||'unknown');
    const loadColor=()=>lsGet(colorKey())||'#ffffff';
    const loadSeekSecs=()=>{const v=parseInt(lsGet(pKey(KEY_SEEK_SECS))??String(SEEK_DEFAULT),10);return isNaN(v)?SEEK_DEFAULT:Math.max(SEEK_MIN,Math.min(SEEK_MAX,v));};
    const loadSpeed=()=>{const v=parseFloat(lsGet(pKey(KEY_SPEED))??String(SPEED_DEFAULT));return isNaN(v)?SPEED_DEFAULT:Math.max(SPEED_MIN,Math.min(SPEED_MAX,v));};
    const fmtSpeed=v=>v.toFixed(2)+'x';

    // ── Colore ────────────────────────────────────────────────────────────────
    function applyColor(hex,wrap,dotEl){
        if(wrap){
            wrap.style.setProperty('--np-accent',hex);
            wrap.style.setProperty('--np-accent-bg',`color-mix(in srgb, ${hex} 30%, #282828)`);
            wrap.style.setProperty('--np-accent-bg-fg',`color-mix(in srgb, #ffffff 78%, ${hex})`);
            wrap.style.setProperty('--np-accent-state-1',`color-mix(in srgb, ${hex} 20%, transparent)`);
            wrap.style.setProperty('--np-accent-state-2',`color-mix(in srgb, ${hex} 35%, transparent)`);
            wrap.style.setProperty('--np-accent-dim',`color-mix(in srgb, #ffffff 60%, ${hex})`);
        }
        if(dotEl)dotEl.style.background=hex;
    }

    // ── Episodio automatico ───────────────────────────────────────────────────
    const saveLastEpisode=t=>{const a=animeId();if(a)lsSet(KEY_AUTOEP_PFX+a,t);};
    const loadLastEpisode=()=>{const a=animeId();return a?lsGet(KEY_AUTOEP_PFX+a):null;};

    // ── Volume ────────────────────────────────────────────────────────────────
    function loadVol(){const v=parseFloat(lsGet(KEY_VOL)??'1');return{vol:isNaN(v)?1:Math.max(0,Math.min(1,v)),muted:lsGet(KEY_MUTE)==='true'};}
    const saveVol=(vol,muted)=>{lsSet(KEY_VOL,String(vol));lsSet(KEY_MUTE,String(muted));};

    // ── Resume ────────────────────────────────────────────────────────────────
    let _activeToken='',_stopSavingFn=null;
    const resumeKey=()=>KEY_RESUME_PFX+(_activeToken||location.pathname);
    const resumeTs=()=>resumeKey()+':ts';
    function saveResumePos(t){if(!isResumeOn()||!isFinite(t)||t<=RESUME_MIN_POS)return;lsSet(resumeKey(),String(t));lsSet(resumeTs(),String(Date.now()));}
    function cleanupResumeStorage(){try{const now=Date.now();Array.from({length:localStorage.length},(_,i)=>localStorage.key(i)).forEach(k=>{if(!k?.startsWith(KEY_RESUME_PFX)||k.endsWith(':ts'))return;const ts=parseFloat(lsGet(k+':ts')??'');if(isNaN(ts)||now-ts>RESUME_MAX_AGE){lsDel(k);lsDel(k+':ts');}});}catch{}}

    // ── Utilities ─────────────────────────────────────────────────────────────
    function fmt(s){const t=Math.floor(s||0),h=Math.floor(t/3600),m=Math.floor((t%3600)/60),sec=t%60;return h>0?`${h}:${String(m).padStart(2,'0')}:${String(sec).padStart(2,'0')}`:`${String(m).padStart(2,'0')}:${String(sec).padStart(2,'0')}`;}
    function mk(tag,id){const e=document.createElement(tag);if(id)e.id=id;return e;}
    function mkBtn(id,html,tip){const b=mk('button');b.className='np-btn';b.id=id;b.innerHTML=html;b.tabIndex=-1;if(tip){const t=document.createElement('span');t.className='np-tip';t.textContent=tip;b.appendChild(t);}return b;}
    function mkIcon(btn,html){const s=document.createElement('span');s.className='np-icon';s.innerHTML=html;btn.prepend(s);return s;}
    function setIcon(el,html){if(el)el.innerHTML=html;}
    function setTip(btn,text){const t=btn.querySelector('.np-tip');if(t)t.textContent=text;}
    function mkRowTip(text){const t=document.createElement('span');t.className='np-row-tip';t.textContent=text;return t;}
    function mkSwitch(checked){const label=document.createElement('label');label.className='np-switch';const input=document.createElement('input');input.type='checkbox';input.checked=checked;const track=document.createElement('span');track.className='np-switch-track';const thumb=document.createElement('span');thumb.className='np-switch-thumb';label.append(input,track,thumb);return{label,input};}
    function getAdjacentEpisode(dir){const all=Array.from(document.querySelectorAll('.episode a'));const idx=all.findIndex(a=>a.classList.contains('active'));if(idx===-1)return null;return dir==='next'?(all[idx+1]??null):(all[idx-1]??null);}
    function getUrlForToken(token){return fetchWithRetry(`/api/episode/serverPlayerAnimeWorld?alt=1&id=${token}`,{credentials:'same-origin'}).then(r=>r.text()).then(html=>{const m=html.match(/["']?file["']?\s*:\s*["']([^"']+)["']/i);return m?m[1].replace(/\\\//g,'/'):null;}).catch(()=>null);}


    // ── Fetch con retry ───────────────────────────────────────────────────────
    function fetchWithRetry(url,opts,retries=3,delay=1000){
        return fetch(url,opts).then(r=>{if(!r.ok)throw new Error(r.status);return r;}).catch(err=>{
            if(retries<=0)throw err;
            return new Promise(res=>setTimeout(res,delay)).then(()=>fetchWithRetry(url,opts,retries-1,delay*2));
        });
    }

    // ── Fullscreen helpers ────────────────────────────────────────────────────
    const fsElement=()=>document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||null;
    const fsExit=()=>(document.exitFullscreen||document.mozCancelFullScreen||document.webkitExitFullscreen)?.call(document).catch(()=>{});
    const fsRequest=el=>(el.requestFullscreen||el.mozRequestFullScreen||el.webkitRequestFullscreen)?.call(el).catch(()=>{});
    const fsChange=cb=>{['fullscreenchange','mozfullscreenchange','webkitfullscreenchange'].forEach(e=>document.addEventListener(e,cb));return()=>['fullscreenchange','mozfullscreenchange','webkitfullscreenchange'].forEach(e=>document.removeEventListener(e,cb));};

    // ── PiP helpers ───────────────────────────────────────────────────────────
    const pipElement=()=>document.pictureInPictureElement||null;
    const pipExit=()=>document.exitPictureInPicture?.().catch(()=>{});
    const pipRequest=el=>{if(el.readyState>=1)return el.requestPictureInPicture?.().catch(()=>{});};

    const isMobile=/Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);

    // ── Shared panel builder: mkSwitchRow ─────────────────────────────────────
    function mkSwitchRow(label,tip,isOn,onChange,extraStyle='',stopProp=false){
        const row=document.createElement('div');
        row.style.cssText=`position:relative;display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer;${extraStyle}`;
        row.dataset.tip='1';
        const lbl=document.createElement('span');lbl.textContent=label;
        const{label:sw,input:toggle}=mkSwitch(typeof isOn==='function'?isOn():isOn);
        toggle.addEventListener('change',e=>{if(stopProp)e.stopPropagation();onChange(toggle.checked);});
        row.addEventListener('click',()=>{toggle.checked=!toggle.checked;toggle.dispatchEvent(new Event('change'));});
        sw.addEventListener('click',e=>e.stopPropagation());
        row.append(lbl,sw,mkRowTip(tip));
        return{row,toggle};
    }

    // ── Shared panel builder: mkStepRow ──────────────────────────────────────
    function mkStepRow(label,tipText,val,setVal,step,fmtFn,BTN_CTRL_STYLE){
        const row=document.createElement('div');row.style.cssText='position:relative;display:flex;align-items:center;justify-content:space-between;gap:12px;user-select:none;';row.dataset.tip='1';
        const valEl=document.createElement('span');valEl.style.cssText='min-width:40px;text-align:center;font-weight:500;';
        const upd=()=>valEl.textContent=fmtFn(val());
        const bM=document.createElement('button');bM.textContent='−';bM.style.cssText=BTN_CTRL_STYLE;bM.tabIndex=-1;
        const bP=document.createElement('button');bP.textContent='+';bP.style.cssText=BTN_CTRL_STYLE;bP.tabIndex=-1;
        bM.addEventListener('click',e=>{e.stopPropagation();setVal(-step);upd();});
        bP.addEventListener('click',e=>{e.stopPropagation();setVal(+step);upd();});
        const ctrl=document.createElement('div');ctrl.style.cssText='display:flex;align-items:center;gap:6px;';ctrl.append(bM,valEl,bP);
        const lbl=document.createElement('span');lbl.textContent=label;
        row.append(lbl,ctrl,mkRowTip(tipText));
        upd();return{row,update:upd};
    }

    // ── Shared: buildTopBar ───────────────────────────────────────────────────
    function buildTopBar(wrap,colorPanel){
        const topBar=mk('div','aw-np-top');topBar.classList.add('np-ui-layer');
        const topLeft=mk('div','aw-np-top-left'),topRight=mk('div','aw-np-top-right');
        const titleEl=mk('div','aw-np-title'),epInfoEl=mk('div','aw-np-epinfo'),dotEl=mk('div','aw-np-dot'),kbdBtn=mk('div','aw-np-kbd-btn');
        kbdBtn.textContent='A';kbdBtn.setAttribute('aria-label','Mostra hotkey');
        const brandEl=mk('div','aw-np-brand');brandEl.textContent='AW Better Player';
        const allEps=Array.from(document.querySelectorAll('.episode a'));
        const epIdx=allEps.findIndex(a=>a.classList.contains('active'));
        const activeEp=epIdx!==-1?allEps[epIdx]:null;
        const epNum=activeEp?(activeEp.textContent.trim()||String(epIdx+1)):'?';
        const epMaxNum=allEps.reduce((m,a)=>{const n=parseFloat(a.textContent.trim());return isNaN(n)?m:Math.max(m,n);},0);
        titleEl.textContent=document.querySelector('h1.title, .title-1')?.textContent?.trim()||document.title.split(' Episodio')[0]||'';
        epInfoEl.textContent=`Episodio ${epNum}/${epMaxNum>0?String(epMaxNum):(allEps.length||'?')}`;
        topLeft.append(titleEl,epInfoEl);
        topRight.append(brandEl,dotEl,kbdBtn);
        topBar.append(topLeft,topRight);
        return{topBar,dotEl,kbdBtn,titleEl,epInfoEl};
    }

    // ── Shared: connection monitor ───────────────────────────────────────────
    const CONN_SVG_SLOW='<path d="M12 2L1 21h22L12 2zm0 3.5L21 20H3L12 5.5zM11 10v4h2v-4zm0 6v2h2v-2z" fill="#fff"/>';
    const CONN_SVG_GOOD='<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" fill="#fff"/>';
    const CONN_MSG_SLOW='<span>Connessione lenta, video</span><span>potenzialmente instabile</span>';
    const CONN_MSG_GOOD='<span>Connessione buona, video</span><span>potenzialmente stabile</span>';
    function _buildConnToast(wrap){
        let toast=wrap.querySelector('#aw-np-conn-toast');
        if(toast)return toast;
        toast=mk('div','aw-np-conn-toast');
        const icon=document.createElementNS('http://www.w3.org/2000/svg','svg');
        icon.setAttribute('viewBox','0 0 24 24');icon.setAttribute('width','13');icon.setAttribute('height','13');icon.style.flexShrink='0';
        const msg=mk('div');msg.className='conn-msg';
        toast.append(icon,msg);
        wrap.appendChild(toast);
        return toast;
    }
    function _showConnToast(wrap,slow,hideTimerRef){
        const toast=_buildConnToast(wrap);
        const icon=toast.querySelector('svg'),msg=toast.querySelector('.conn-msg');
        icon.innerHTML=slow?CONN_SVG_SLOW:CONN_SVG_GOOD;
        msg.innerHTML=slow?CONN_MSG_SLOW:CONN_MSG_GOOD;
        toast.classList.remove('slow','good');
        toast.classList.add(slow?'slow':'good');
        toast.style.opacity='1';
        clearTimeout(hideTimerRef.id);
        hideTimerRef.id=setTimeout(()=>{toast.style.opacity='0';},3000);
    }
    function buildConnectionMonitor(video,wrap){
        // Soglie con isteresi: zona morta 1.3-1.8 previene flickering
        const SLOW_TH=1.3,GOOD_TH=1.8,WIN=6,SLOW_COUNT=4,GOOD_COUNT=6,MIN_SAMPLE_INTERVAL=950;
        const samples=new Float32Array(WIN);
        let sIdx=0,sCount=0,sSum=0;
        let lastBufEnd=null,lastTs=null,connState=null,slowN=0,goodN=0,initialShown=false;
        const hideRef={id:null};
        const getBufEnd=()=>{const n=video.buffered.length;if(!n)return null;const ct=video.currentTime;for(let i=n-1;i>=0;i--){if(video.buffered.start(i)<=ct+0.5)return video.buffered.end(i);}return null;};
        const pushSample=v=>{
            if(sCount<WIN){samples[sIdx]=v;sSum+=v;sCount++;}
            else{sSum+=v-samples[sIdx];samples[sIdx]=v;}
            sIdx=(sIdx+1)%WIN;
        };
        const onProgress=()=>{
            if(!isConnMonitorOn()){
                const t=wrap.querySelector('#aw-np-conn-toast');
                if(t)t.style.opacity='0';
                return;
            }
            if(video.networkState!==2)return;
            const now=Date.now();
            if(lastTs!==null&&now-lastTs<MIN_SAMPLE_INTERVAL)return;
            const bufEnd=getBufEnd();
            if(bufEnd===null){lastBufEnd=null;lastTs=null;return;}
            if(lastBufEnd!==null&&lastTs!==null){
                const dt=(now-lastTs)/1000,db=bufEnd-lastBufEnd;
                if(dt>0.1&&db>=0){
                    pushSample(db/dt);
                    if(sCount>=WIN){
                        const avg=sSum/WIN;
                        const isSlow=avg<SLOW_TH,isGood=avg>=GOOD_TH;
                        if(isSlow){slowN++;goodN=0;}else if(isGood){goodN++;slowN=0;}
                        if(!initialShown){
                            if(slowN>=SLOW_COUNT||goodN>=GOOD_COUNT){
                                initialShown=true;connState=slowN>=SLOW_COUNT?'slow':'good';
                                _showConnToast(wrap,connState==='slow',hideRef);
                            }
                        }else{
                            if(slowN>=SLOW_COUNT&&connState!=='slow'){connState='slow';_showConnToast(wrap,true,hideRef);}
                            else if(goodN>=GOOD_COUNT&&connState!=='good'){connState='good';_showConnToast(wrap,false,hideRef);}
                        }
                    }
                }
            }
            lastBufEnd=bufEnd;lastTs=now;
        };
        const onSeeking=()=>{lastBufEnd=null;lastTs=null;sCount=0;sIdx=0;sSum=0;slowN=0;goodN=0;};
        video.addEventListener('progress',onProgress);
        video.addEventListener('seeking',onSeeking);
        return{clearMonitor:()=>{video.removeEventListener('progress',onProgress);video.removeEventListener('seeking',onSeeking);clearTimeout(hideRef.id);}};
    }
    // ── Shared: buildHotkeyPanel (tastiera) ───────────────────────────────────
    function buildHotkeyPanel(){
        const mc=(tag,cls)=>{const e=document.createElement(tag);if(cls)e.className=cls;return e;};
        const arrow=d=>`<svg viewBox="0 0 24 24"><path d="${d}" fill="currentColor"/></svg>`;
        const A_UP=arrow('M12 7 L17.5 16.5 L6.5 16.5 Z');
        const A_DN=arrow('M12 17 L17.5 7.5 L6.5 7.5 Z');
        const A_LF=arrow('M7 12 L16.5 6.5 L16.5 17.5 Z');
        const A_RT=arrow('M17 12 L7.5 6.5 L7.5 17.5 Z');
        const overlay=mk('div','aw-np-hotkey-overlay');
        const inner=mk('div','aw-np-hotkey-inner');
        const hint=mc('div','aw-np-hotkey-hint');hint.textContent='(TOCCA UN PUNTO QUALSIASI PER CHIUDERE LA LEGENDA, OPPURE A)';
        const kbd=mc('div','aw-np-kbd');
        const fnStrip=mc('div','aw-np-kbd-fn');
        const fnName=mc('span','aw-np-kbd-fn-name'),fnDesc=mc('span','aw-np-kbd-fn-desc');
        fnStrip.append(fnName,fnDesc);
        const showFn=s=>{fnName.textContent=s.f;fnDesc.textContent=s.d;fnStrip.classList.add('show');};
        const clearFn=()=>{fnStrip.classList.remove('show');};
        // Funzioni: nome MAIUSCOLO, descrizioni concise
        const FN={
            M:{ic:IC.mute,f:'TOGGLE VOLUME',d:'Attiva/disattiva l\'audio'},
            F:{ic:IC.fsOn,f:'FULL SCREEN',d:'Entra/esce dal full screen'},
            O:{ic:IC.skip,f:'SKIP OP/ED',d:'Salto in avanti di 1:25 min.'},
            B:{ic:IC.undo,f:'ANNULLA SKIP',d:'Torna indietro di 1:25 min.'},
            P:{ic:IC.prev,f:'PRECEDENTE',d:'Episodio precedente'},
            N:{ic:IC.next,f:'SUCCESSIVO',d:'Episodio successivo'},
            R:{ic:IC.restart,f:'RESTART',d:'Riparte da inizio episodio'},
            S:{ic:IC.unlock,f:'SBLOCCA VIDEO',d:'Forza un refresh del video'},
            A:{ic:'<span class="aw-np-key-a-badge">A</span>',f:'LEGENDA HOTKEY',d:'Apre/chiude questa legenda'},
        };
        const mkKey=(label,spec,extraCls)=>{
            const key=mc('div','aw-np-key'+(extraCls?' '+extraCls:''));
            if(spec){
                key.classList.add('on');
                const ico=mc('span','aw-np-key-ico');ico.innerHTML=spec.ic;
                const lt=mc('span','aw-np-key-letter');lt.textContent=label;
                key.append(ico,lt);
                key.addEventListener('mouseenter',()=>{key.classList.add('hovered');showFn(spec);});
                key.addEventListener('mouseleave',()=>{key.classList.remove('hovered');clearFn();});
            } else {
                key.classList.add('off');key.textContent=label;
            }
            return key;
        };
        const mkFiller=(label,wide,pad)=>{
            const k=mc('div','aw-np-key off');
            if(wide||pad){
                k.classList.add('aw-np-key-fill-wide');
                if(wide)k.style.setProperty('--wmult',wide);
                if(pad)k.style.setProperty('--padmult',pad);
                const g=mc('span','aw-np-glyph');g.textContent=label;k.appendChild(g);
            } else {
                k.textContent=label;
            }
            return k;
        };
        // === Layout 1:1 con specifica ===
        // RIGA 1: 0.5(\) + 10×1 + 1.5(⌫)
        const r1=mc('div','aw-np-krow');
        const bs=mc('div','aw-np-key off aw-np-key-half');bs.textContent='\\';
        r1.appendChild(bs);
        for(let i=0;i<10;i++){
            const ch=String((i+1)%10);
            const pct=((i+1)%10)*10;
            const spec={ic:IC.seekFwd,f:'AVANZAMENTO RAPIDO',d:`${pct}% della durata totale`};
            const key=mc('div','aw-np-key on aw-np-key-num');
            const pctEl=mc('span','aw-np-key-ico aw-np-key-pct');pctEl.textContent=`${pct}%`;
            const numEl=mc('span','aw-np-key-letter');numEl.textContent=ch;
            key.append(pctEl,numEl);
            key.addEventListener('mouseenter',()=>{key.classList.add('hovered');showFn(spec);});
            key.addEventListener('mouseleave',()=>{key.classList.remove('hovered');clearFn();});
            r1.appendChild(key);
        }
        r1.appendChild(mkFiller('🠔',1.5));
        kbd.appendChild(r1);
        // RIGA 2: 1(Tab) + 10×1 QWERTYUIOP + 1(+)
        const r2=mc('div','aw-np-krow');
        r2.appendChild(mkFiller('⮀'));
        for(const ch of 'QWERTYUIOP'){
            r2.appendChild(FN[ch]?mkKey(ch,FN[ch]):mkKey(ch,null));
        }
        r2.appendChild(mkFiller('+'));
        kbd.appendChild(r2);
        // RIGA 3: 1.5(Caps) + 9×1 ASDFGHJKL + (0.5+P+1)=Enter composto 1.5U+P
        const r3=mc('div','aw-np-krow');
        r3.appendChild(mkFiller('⇪',1.5));
        for(const ch of 'ASDFGHJKL'){
            r3.appendChild(FN[ch]?mkKey(ch,FN[ch]):mkKey(ch,null));
        }
        // Enter come singolo tasto largo 1.5U+P (cioè wmult=1.5 con formula 1.5U + 0.5P? no: 1.5U+1P)
        // formula attuale fill-wide: width = ku*wmult + kg*(wmult-1). Per 1.5U+1P serve ku*1.5 + kg*1 → wmult tale che (wmult-1)=1 → wmult=2 dà 2U+1P. Non funziona.
        // Aggiungo classe specifica per Enter
        const enterKey=mc('div','aw-np-key off aw-np-key-enter-flat');
        enterKey.innerHTML='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" style="width:60%;height:60%;display:block"><path fill="currentColor" d="M20.94,7 C20.27,7 19.61,7 18.95,7 C18.95,8.33 18.95,9.66 18.95,11 C15.25,11 11.55,11 7.85,11 C7.85,9.66 7.85,8.33 7.85,7 C6.25,8.66 4.66,10.31 3.07,11.97 C4.66,13.65 6.25,15.32 7.85,17 C7.85,15.66 7.85,14.33 7.85,12.99 C12.21,12.99 16.57,12.99 20.94,12.99 C20.94,10.99 20.94,9 20.94,7 Z"/></svg>';
        r3.appendChild(enterKey);
        kbd.appendChild(r3);
        // RIGA 4: (1+P+1)=Shift sx 2U+1P + 7 ZXCVBNM + 1(Shift dx) + 1(▲) + 1(-)
        const r4=mc('div','aw-np-krow');
        r4.appendChild(mkFiller('⇧',2,1));
        for(const ch of 'ZXCVBNM'){
            r4.appendChild(FN[ch]?mkKey(ch,FN[ch]):mkKey(ch,null));
        }
        r4.appendChild(mkFiller('⇧'));
        r4.appendChild(mkKey('▲',{ic:IC.vol,f:'VOLUME +',d:'Alza il volume'}));
        r4.appendChild(mkFiller('-'));
        kbd.appendChild(r4);
        // RIGA 5: 1(Ctrl) + 1(AW) + 1(Alt) + (1+P+1+P+1+P+1+P+1)=Space 5U+4P + 1(AltGr) + 1(◀) + 1(▼) + 1(▶)
        const r5=mc('div','aw-np-krow aw-np-krow-bottom');
        const mkMod=(l,wide)=>{const k=mc('div','aw-np-key off aw-np-key-mod');if(wide){k.classList.add('aw-np-key-fill-wide');k.style.setProperty('--wmult',wide);}k.textContent=l;return k;};
        const space=mkKey('',{ic:IC.play,f:'PLAY/PAUSA',d:'play/pausa del video'},'aw-np-key-space');
        r5.append(
            mkMod('CTRL'),mkMod('AW'),mkMod('ALT'),
            space,
            mkMod('ALT GR'),
            mkKey('◀',{ic:IC.seekBwd,f:'SEEK INDIETRO',d:'Breve riavvolgimento di 5-30 s'}),
            mkKey('▼',{ic:IC.volDown,f:'VOLUME −',d:'Abbassa il volume'}),
            mkKey('▶',{ic:IC.seekFwd,f:'SEEK AVANTI',d:'Breve avanzamento di 5-30 s'}));
        kbd.appendChild(r5);
        inner.append(hint,kbd,fnStrip);
        overlay.append(inner);
        const isOpen=()=>overlay.classList.contains('open');
        const open=()=>{overlay.classList.add('open');};
        const closeFn=()=>{overlay.classList.remove('open');};
        overlay.addEventListener('click',closeFn);
        return{overlay,open,close:closeFn,isOpen};
    }

    // ── Shared: buildColorPanel ───────────────────────────────────────────────
    function buildColorPanel(wrap,dotEl,SEP){
        const colorPanel=mk('div','aw-np-color-panel');
        const swatchWrap=mk('div','aw-np-color-swatches');
        let currentColor=loadColor();
        const getDot=()=>dotEl||wrap.querySelector('#aw-np-dot');
        const customInput=document.createElement('input'),customPreview=document.createElement('div');
        const syncCustomInput=hex=>{customInput.value=hex;customPreview.style.background=hex;};
        const updateSwatches=c=>swatchWrap.querySelectorAll('.np-swatch').forEach(s=>s.classList.toggle('active',s.dataset.hex===c));
        const applyCustomColor=()=>{
            let val=customInput.value.trim();
            if(!val.startsWith('#'))val='#'+val;
            if(!/^#[0-9a-fA-F]{6}$/i.test(val)){syncCustomInput(currentColor);return;}
            val=val.toLowerCase();currentColor=val;lsSet(colorKey(),val);
            applyColor(val,wrap,getDot());syncCustomInput(val);updateSwatches(val);
        };
        syncCustomInput(currentColor);
        PALETTE.forEach(({name,hex})=>{
            const sw=document.createElement('div');
            sw.className='np-swatch'+(hex===currentColor?' active':'');
            sw.style.background=hex;sw.dataset.hex=hex;sw.title=name;
            sw.addEventListener('click',e=>{e.stopPropagation();currentColor=hex;lsSet(colorKey(),hex);applyColor(hex,wrap,getDot());syncCustomInput(hex);updateSwatches(hex);});
            swatchWrap.appendChild(sw);
        });
        const customRow=document.createElement('div');customRow.style.cssText='position:relative;display:flex;align-items:center;justify-content:space-between;gap:8px;';customRow.addEventListener('click',e=>e.stopPropagation());
        const customLabel=document.createElement('span');customLabel.textContent='Custom';customLabel.style.cssText='font-size:var(--np-fs-body);color:var(--np-accent-bg-fg,rgba(255,255,255,.9));flex-shrink:0;';
        customPreview.style.cssText='width:14px;height:14px;border-radius:50%;flex-shrink:0;border:1px solid var(--np-accent-state-2,rgba(255,255,255,.3));';
        customInput.type='text';customInput.maxLength=7;customInput.placeholder='#ffffff';customInput.spellcheck=false;
        customInput.style.cssText='background:var(--np-accent-state-1,rgba(255,255,255,.1));border:1px solid var(--np-accent-state-2,rgba(255,255,255,.2));color:var(--np-accent-bg-fg,#fff);font-size:12px;padding:3px 6px;border-radius:4px;width:76px;outline:none;font-family:monospace;user-select:text;';
        customInput.addEventListener('input',()=>{let v=customInput.value.trim();if(!v.startsWith('#'))v='#'+v;if(/^#[0-9a-fA-F]{6}$/i.test(v))customPreview.style.background=v;});
        let _applyingCustom=false;
        customInput.addEventListener('blur',()=>{if(!_applyingCustom)applyCustomColor();});
        customInput.addEventListener('keydown',e=>{e.stopPropagation();if(e.key==='Enter'){_applyingCustom=true;applyCustomColor();customInput.blur();_applyingCustom=false;}if(e.key==='Escape'){syncCustomInput(currentColor);customInput.blur();}});
        customInput.addEventListener('click',e=>e.stopPropagation());
        customInput.addEventListener('focus',()=>customInput.select());
        customRow.append(customLabel,customPreview,customInput);
        const{row:topColorRow,toggle:topColorToggle}=mkSwitchRow('Top bar colorata','Colora la barra superiore.',isTopColorOn,v=>{lsSet(KEY_TOP_COLOR,v?'1':'0');wrap.classList.toggle('accent-top',v);},SEP,true);
        const{row:iconColorRow,toggle:iconColorToggle}=mkSwitchRow('Icone colorate','Colora le icone del player.',isIconColorOn,v=>{lsSet(KEY_ICON_COLOR,v?'1':'0');wrap.classList.toggle('accent-icons',v);},'',true);
        const{row:flashRow,toggle:flashToggle}=mkSwitchRow('Flash centrali','Animazioni al centro del player.',isFlashOn,v=>{lsSet(KEY_FLASH_ENABLE,v?'1':'0');},'',true);
        const{row:clockRow,toggle:clockToggle}=mkSwitchRow('Orologio','Pop-up orologio (in alto a destra).',isClockOn,v=>{lsSet(KEY_CLOCK,v?'1':'0');wrap.classList.toggle('clock-hidden',!v);},'',true);
        const{row:speedPopupRow,toggle:speedPopupToggle}=mkSwitchRow('Popup velocità','Pop-up velocità alterata (in alto a sinistra).',isSpeedPopupOn,v=>{lsSet(KEY_SPEED_POPUP,v?'1':'0');wrap.classList.toggle('speed-popup-hidden',!v);},'',true);
        const{row:colorGlobalRow,toggle:colorGlobalToggle}=mkSwitchRow('Globale','Applica a tutte le serie.',isColorGlobalOn,v=>{
            lsSet(KEY_COLOR_GLOBAL,v?'1':'0');currentColor=loadColor();applyColor(currentColor,wrap,getDot());
            syncCustomInput(currentColor);updateSwatches(currentColor);
        },SEP,true);
        colorGlobalRow.id='aw-np-color-global';
        colorPanel.append(swatchWrap,customRow,topColorRow,iconColorRow,flashRow,clockRow,speedPopupRow,colorGlobalRow);
        if(isIconColorOn())wrap.classList.add('accent-icons');
        if(isTopColorOn())wrap.classList.add('accent-top');
        if(!isClockOn())wrap.classList.add('clock-hidden');
        if(!isSpeedPopupOn())wrap.classList.add('speed-popup-hidden');
        return{colorPanel,swatchWrap,currentColor:()=>currentColor,setCurrentColor:c=>{currentColor=c;},syncCustomInput,updateSwatches,topColorToggle,iconColorToggle,flashToggle,clockToggle,speedPopupToggle,colorGlobalToggle};
    }

    // ── Shared: buildSettingsPanel ────────────────────────────────────────────
    function buildSettingsPanel(video,SEP,seekTip,onSpeedChange=null){
        const settingsPanel=mk('div','aw-np-settings-panel');
        const BTN_CTRL_STYLE='background:var(--np-accent-state-1,rgba(255,255,255,.15));border:none;color:var(--np-accent-bg-fg,#fff);width:22px;height:22px;border-radius:4px;cursor:pointer;font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center;';
        const{row:resumeRow,toggle:resumeToggle}=mkSwitchRow('Ripresa automatica','Riprende dall\'ultima interruzione.',isResumeOn(),v=>lsSet(pKey(KEY_RESUME_ENABLE),v?'1':'0'));
        const{row:autoEpRow,toggle:autoEpToggle}=mkSwitchRow('Episodio automatico','Riapre l\'ultimo episodio visto.',isAutoEpOn(),v=>lsSet(pKey(KEY_AUTOEP_ENABLE),v?'1':'0'));
        const{row:autoPlayRow,toggle:autoPlayToggle}=mkSwitchRow('Autoplay','In fullscreen, parte il video in automatico.',isAutoPlayOn(),v=>lsSet(pKey(KEY_AUTOPLAY_ENABLE),v?'1':'0'));
        const{row:connMonitorRow,toggle:connMonitorToggle}=mkSwitchRow('Monitor connessione','Notifiche sulla qualità di connessione.',isConnMonitorOn(),v=>lsSet(KEY_CONN_MONITOR,v?'1':'0'));
        let seekSecs=loadSeekSecs();
        const{row:seekRow,update:updateSeekVal}=mkStepRow('Seek',seekTip||'Secondi saltati.',()=>seekSecs,(d)=>{if(seekSecs+d<SEEK_MIN||seekSecs+d>SEEK_MAX)return;seekSecs+=d;lsSet(pKey(KEY_SEEK_SECS),String(seekSecs));},SEEK_STEP,v=>String(v).padStart(2,'0')+' s',BTN_CTRL_STYLE);
        let speedVal=loadSpeed();
        const{row:speedRow,update:updateSpeedVal}=mkStepRow('Velocità','Velocità di riproduzione.',()=>speedVal,(d)=>{const nv=Math.round((speedVal+d)*100)/100;if(nv<SPEED_MIN||nv>SPEED_MAX)return;speedVal=nv;lsSet(pKey(KEY_SPEED),String(speedVal));if(video.readyState>0)video.playbackRate=speedVal;if(onSpeedChange)onSpeedChange(speedVal);},SPEED_STEP,fmtSpeed,BTN_CTRL_STYLE);
        const globalRow=document.createElement('div');globalRow.style.cssText=`position:relative;display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer;${SEP}margin-top:2px;`;globalRow.dataset.tip='1';
        const globalLabel=document.createElement('span');globalLabel.textContent='Globale';
        const{label:globalSw,input:globalToggle}=mkSwitch(isGlobalOn());
        globalToggle.addEventListener('change',()=>{
            lsSet(KEY_GLOBAL,globalToggle.checked?'1':'0');
            resumeToggle.checked=isResumeOn();autoEpToggle.checked=isAutoEpOn();autoPlayToggle.checked=isAutoPlayOn();
            seekSecs=loadSeekSecs();updateSeekVal();speedVal=loadSpeed();updateSpeedVal();
        });
        globalRow.addEventListener('click',()=>{globalToggle.checked=!globalToggle.checked;globalToggle.dispatchEvent(new Event('change'));});
        globalSw.addEventListener('click',e=>e.stopPropagation());
        globalRow.append(globalLabel,globalSw,mkRowTip('Applica a tutte le serie.'));
        settingsPanel.append(resumeRow,autoEpRow,autoPlayRow,connMonitorRow,seekRow,speedRow,globalRow);
        return{settingsPanel,resumeToggle,autoEpToggle,autoPlayToggle,connMonitorToggle,globalToggle,seekSecs:()=>seekSecs,speedVal:()=>speedVal,updateSeekVal,updateSpeedVal};
    }

    // ── Shared: buildResumeLogic ──────────────────────────────────────────────
    function buildResumeLogic(video,wrap,speedValFn){
        const expectedToken=_activeToken;
        const myResumeKey=()=>KEY_RESUME_PFX+(expectedToken||location.pathname);
        const myResumeTs=()=>myResumeKey()+':ts';
        function showResumeToast(seconds){wrap.querySelector('#aw-np-toast')?.remove();const toast=mk('div','aw-np-toast');toast.textContent=`▶ Ripreso da ${fmt(seconds)}`;wrap.appendChild(toast);setTimeout(()=>{toast.style.opacity='0';setTimeout(()=>toast.remove(),500);},4000);}
        function attemptResume(){if(!isResumeOn()||!isFinite(video.duration))return;const saved=parseFloat(lsGet(myResumeKey())??'');if(!saved||saved<RESUME_MIN_POS)return;if(video.duration-saved<RESUME_END_GAP){lsDel(myResumeKey());lsDel(myResumeTs());return;}video.currentTime=saved;showResumeToast(saved);}
        video.addEventListener('loadedmetadata',()=>{if(video.playbackRate!==speedValFn())video.playbackRate=speedValFn();attemptResume();},{once:true});
        let saveTimer=null,episodeEnded=false;
        const saveNow=()=>{if(!isResumeOn()||!isFinite(video.currentTime)||video.currentTime<=RESUME_MIN_POS)return;if(isFinite(video.duration)&&video.duration-video.currentTime<RESUME_END_GAP)return;lsSet(myResumeKey(),String(video.currentTime));lsSet(myResumeTs(),String(Date.now()));};
        const startSaving=()=>{if(saveTimer)return;saveTimer=setInterval(saveNow,SAVE_INTERVAL_MS);};
        const stopSaving=()=>{clearInterval(saveTimer);saveTimer=null;};
        _stopSavingFn=stopSaving;
        video.addEventListener('play',startSaving);
        video.addEventListener('pause',()=>{stopSaving();saveNow();});
        video.addEventListener('seeked',()=>{if(isFinite(video.duration)&&video.duration-video.currentTime>=RESUME_END_GAP){episodeEnded=false;saveNow();}});
        video.addEventListener('ended',()=>{stopSaving();lsDel(myResumeKey());lsDel(myResumeTs());episodeEnded=true;});
        return{showResumeToast,stopSaving,episodeEnded:()=>episodeEnded};
    }

    // ── Shared: buildSeekBar ──────────────────────────────────────────────────
    function buildSeekBar(video,withTip=false,onTimeUpdate=null){
        const seekWrap=mk('div','aw-np-seek-wrap'),seekTrack=mk('div','aw-np-seek-track'),seekBuf=mk('div','aw-np-seek-buf'),seekFill=mk('div','aw-np-seek-fill'),seekThumb=mk('div','aw-np-seek-thumb');
        let seekTip=null;
        if(withTip){seekTip=mk('div','aw-np-seek-tip');seekTrack.appendChild(seekTip);}
        seekTrack.append(seekBuf,seekFill,seekThumb);seekWrap.append(seekTrack);
        let seeking=false;
        const applySeek=e=>{const r=seekTrack.getBoundingClientRect();const p=Math.max(0,Math.min(1,(e.clientX-r.left)/r.width));if(video.duration)video.currentTime=p*video.duration;const pct=p*100+'%';seekFill.style.width=pct;seekThumb.style.left=pct;};
        seekWrap.addEventListener('pointerdown',e=>{seeking=true;seekWrap.classList.add('seeking');seekWrap.setPointerCapture(e.pointerId);applySeek(e);e.preventDefault();});
        seekWrap.addEventListener('pointermove',e=>{
            if(seeking)applySeek(e);
            if(seekTip){const r=seekTrack.getBoundingClientRect();const p=Math.max(0,Math.min(1,(e.clientX-r.left)/r.width));seekTip.textContent=fmt(p*(video.duration||0));seekTip.style.left=(p*100)+'%';seekTip.style.visibility='visible';}
        });
        if(seekTip)seekWrap.addEventListener('pointerleave',()=>{seekTip.style.visibility='hidden';});
        seekWrap.addEventListener('pointerup',()=>{seeking=false;seekWrap.classList.remove('seeking');});
        seekWrap.addEventListener('pointercancel',()=>{seeking=false;seekWrap.classList.remove('seeking');});
        let malSyncTriggered=false;
        video.addEventListener('loadedmetadata',()=>{malSyncTriggered=false;});
        video.addEventListener('timeupdate',()=>{
            if(seeking||!video.duration)return;
            const p=video.currentTime/video.duration*100;
            seekFill.style.width=p+'%';seekThumb.style.left=p+'%';
            if(onTimeUpdate)onTimeUpdate();
            if(!malSyncTriggered&&p>=90){malSyncTriggered=true;history.pushState({},'',location.href);}
            if(!_preloadedToken&&p>=PRELOAD_THRESHOLD*100){const nxt=getAdjacentEpisode('next');if(nxt){_preloadedToken=nxt.dataset.id;const _pTok=_preloadedToken;getUrlForToken(_pTok).then(url=>{if(!url||!cleanup||_preloadedToken!==_pTok)return;document.querySelectorAll('video[data-aw-preload]').forEach(v=>{try{v.pause();v.src='';v.remove();}catch(e){}});_preloadedUrl=url;const pv=document.createElement('video');pv.preload='auto';pv.muted=true;pv.dataset.awPreload='1';pv.style.cssText='position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;pointer-events:none';pv.src=url;document.body.appendChild(pv);pv.load();_preloadedVideo=pv;});}}
        });
        video.addEventListener('progress',()=>{if(!video.duration||!video.buffered.length)return;seekBuf.style.width=(video.buffered.end(video.buffered.length-1)/video.duration*100)+'%';});
        return{seekWrap,seekFill,seekThumb,seekBuf,isSeeking:()=>seeking};
    }

    // ── Shared: initVideo ─────────────────────────────────────────────────────
    function initVideo(videoUrl){
        const{vol,muted}=loadVol();
        const video=mk('video','aw-np-video');
        video.autoplay=false;video.preload='auto';video.src=videoUrl;video.volume=vol;video.muted=muted;video.playbackRate=loadSpeed();
        let _userInteracted=false;
        const _play=()=>{_userInteracted=true;return video.play().catch(()=>{});};
        const _enforceInitialPause=()=>{try{if(_userInteracted)return;if(video.paused)return;if(isAutoPlayOn()&&fsElement())return;video.pause();}catch(e){}};
        video.addEventListener('play',_enforceInitialPause,{capture:true});
        return{video,vol,muted,_play};
    }

    // ── Shared: addRipple ─────────────────────────────────────────────────────
    function addRipple(btn){btn.addEventListener('pointerdown',e=>{const r=btn.getBoundingClientRect(),size=Math.max(r.width,r.height);const ripple=document.createElement('span');ripple.className='np-ripple';ripple.style.cssText=`width:${size}px;height:${size}px;left:${e.clientX-r.left-size/2}px;top:${e.clientY-r.top-size/2}px;`;btn.appendChild(ripple);ripple.addEventListener('animationend',()=>ripple.remove());});}

    // ── Icone SVG ─────────────────────────────────────────────────────────────
    const svg=p=>`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">${p}</svg>`;
    const IC={
        play:    svg('<path d="M8 5v14l11-7z"/>'),
        pause:   svg('<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>'),
        mute:    svg('<path d="M16.5 12A4.5 4.5 0 0 0 14 7.97v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3 3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06A8.99 8.99 0 0 0 17.73 18l1.98 2L21 18.73 4.27 3zM12 4 9.91 6.09 12 8.18V4z"/>'),
        vol:     svg('<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3A4.5 4.5 0 0 0 14 7.97v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>'),
        volDown: svg('<path d="M18.5 12A4.5 4.5 0 0 0 16 7.97v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"/>'),
        fsOn:    svg('<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>'),
        fsOff:   svg('<path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/>'),
        pip:     svg('<path d="M19 11h-8v6h8v-6zm4 8V4.98C23 3.88 22.1 3 21 3H3C1.9 3 1 3.88 1 4.98V19c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2zm-2 .02H3V4.97h18v14.05z"/>'),
        settings:svg('<path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>'),
        restart: svg('<path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/>'),
        skip:    svg('<path d="M13 3a9 9 0 1 0 9 9h-2a7 7 0 1 1-7-7V3z"/><path d="M13 1v6l4-3z"/><line x1="13" y1="8" x2="13" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none"/><line x1="13" y1="14" x2="16" y2="16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none"/>'),
        undo:    svg('<g transform="scale(-1,1) translate(-24,0)"><path d="M13 3a9 9 0 1 0 9 9h-2a7 7 0 1 1-7-7V3z"/><path d="M13 1v6l4-3z"/><line x1="13" y1="8" x2="13" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none"/><line x1="13" y1="14" x2="16" y2="16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none"/></g>'),
        prev:    svg('<rect x="5" y="5" width="2.5" height="14"/><polygon points="19,5 9,12 19,19"/>'),
        next:    svg('<polygon points="5,5 15,12 5,19"/><rect x="16.5" y="5" width="2.5" height="14"/>'),
        seekFwd: svg('<path d="M6 5l6 7-6 7M13 5l6 7-6 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>'),
        seekBwd: svg('<path d="M18 5l-6 7 6 7M11 5l-6 7 6 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>'),
        menu:    svg('<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>'),
        unlock:  svg('<path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm0 12H6V10h12v10zm-6-3c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/>'),
    };

    // ── Stili desktop ─────────────────────────────────────────────────────────
    function injectStyleDesktop(){
        if(document.getElementById('aw-np-style'))return;
        const s=document.createElement('style');s.id='aw-np-style';
        s.textContent=`
            #player{background:#000}*,*::before,*::after{box-sizing:border-box}*:focus{outline:none!important}button{-webkit-tap-highlight-color:transparent}
            #aw-np,#aw-np *{-webkit-touch-callout:none!important;-webkit-user-drag:none;user-select:none!important;-webkit-user-select:none!important}
            #aw-np{--np-bar-h:clamp(40px,5.2cqh,56px);--np-btn-size:clamp(36px,4.8cqh,52px);--np-svg-size:clamp(20px,2.7cqh,32px);--np-seek-h:44px;--np-top-h:clamp(56px,8.3cqh,90px);--np-fs-title:clamp(14px,2.4cqh,26px);--np-fs-subtitle:clamp(13px,2cqh,22px);--np-fs-body:clamp(13px,1.7cqh,17px);--np-fs-small:clamp(12px,1.5cqh,15px);--np-fs-micro:clamp(10px,1.2cqh,13px);--np-fs-brand:clamp(11px,1.6cqh,17px);--np-spinner-size:clamp(40px,6.5cqh,80px);container-type:size;position:relative;isolation:isolate;width:100%;height:100%;background:#000;display:flex;flex-direction:column;overflow:hidden;font-family:'Google Sans',Roboto,'Helvetica Neue',sans-serif;user-select:none;touch-action:pan-x pan-y}
            #aw-np-video{flex:1;width:100%;min-height:0;display:block;background:#000;cursor:none}
            #aw-np.ui #aw-np-video{cursor:pointer}
            #aw-np-bar,#aw-np-top,#aw-np-toast,#aw-np-error-toast,#aw-np-conn-toast,#aw-np-settings-panel,#aw-np-color-panel,#aw-np-menu-panel,.np-tip,.np-row-tip,.np-btn,.np-swatch,.np-switch-track,.np-switch-thumb,#aw-np-seek-fill,#aw-np-seek-buf,#aw-np-seek-thumb,#aw-np-seek-tip,#aw-np-title,#aw-np-epinfo,#aw-np-brand,#aw-np-clock,#aw-np-clock svg circle,#aw-np-clock .hand-h,#aw-np-clock .hand-m,#aw-np-clock .pin,#aw-np-spinner,#aw-np-vol-popup,#aw-np-time,#aw-np-speed-ind,#aw-np-speed-popup,#aw-np-buf-pct,#aw-np-dot{transition-property:color,background,background-color,fill,stroke,border-color,box-shadow;transition-duration:.4s;transition-timing-function:cubic-bezier(.4,0,.2,1)}
            .np-grad{position:absolute;left:0;right:0;height:160px;pointer-events:none;opacity:0;transition:opacity .35s cubic-bezier(.4,0,.2,1)}
            #aw-np.ui .np-grad{opacity:1}
            #aw-np-gradient{bottom:0;background:linear-gradient(to top,rgba(0,0,0,.9) 0%,rgba(0,0,0,.4) 60%,transparent 100%)}
            #aw-np-gradient-top{top:0;background:linear-gradient(to bottom,rgba(0,0,0,.9) 0%,rgba(0,0,0,.4) 60%,transparent 100%)}
            .np-ui-layer{opacity:0;transition:opacity .35s cubic-bezier(.4,0,.2,1),transform .35s cubic-bezier(.4,0,.2,1);pointer-events:none}
            #aw-np-top.np-ui-layer{transform:translateY(-12px)}
            #aw-np-controls.np-ui-layer{transform:translateY(8px)}
            #aw-np.ui #aw-np-top.np-ui-layer,#aw-np.ui #aw-np-controls.np-ui-layer{transform:translateY(0)}
            #aw-np.ui .np-ui-layer{opacity:1;pointer-events:all}
            #aw-np-top{position:absolute;top:0;left:0;right:0;height:var(--np-top-h);display:flex;align-items:flex-start;justify-content:space-between;padding:clamp(12px,1.7cqh,18px) 16px}
            #aw-np-top-left{display:flex;flex-direction:column;gap:2px;overflow:hidden}
            #aw-np-title{font-size:var(--np-fs-title);font-weight:500;letter-spacing:.01em;color:var(--np-accent-bg-fg,#fff);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:clamp(120px,35vw,400px);text-shadow:0 1px 3px rgba(0,0,0,.8),0 0 12px rgba(0,0,0,.6)}
            #aw-np-epinfo{font-size:var(--np-fs-subtitle);font-weight:400;letter-spacing:.02em;color:var(--np-accent-bg-fg,rgba(255,255,255,.7));opacity:.8;text-shadow:0 1px 3px rgba(0,0,0,.8)}
            #aw-np-top-right{display:flex;align-items:center;gap:14px;flex-shrink:0}
            #aw-np-brand{font-size:var(--np-fs-brand);font-weight:500;letter-spacing:.04em;color:var(--np-accent-bg-fg,rgba(255,255,255,.5));opacity:.6;white-space:nowrap;line-height:1;text-shadow:0 1px 3px rgba(0,0,0,.8);text-transform:uppercase}
            #aw-np-dot{width:10px;height:10px;border-radius:50%;background:var(--np-accent,#fff);cursor:pointer;flex-shrink:0;transition:transform .2s cubic-bezier(.4,0,.2,1),box-shadow .2s;position:relative;top:-1px;box-shadow:0 0 0 0 var(--np-accent-dim,rgba(255,255,255,.3))}
            #aw-np-kbd-btn{width:14px;height:14px;border-radius:3px;background:var(--np-accent-bg,#223A56);color:var(--np-accent-bg-fg,#CCDDF1);font-size:9px;font-weight:400;font-family:Arial,'Segoe UI','Roboto',sans-serif;display:flex;align-items:center;justify-content:center;cursor:pointer;flex-shrink:0;line-height:1;transition:transform .2s cubic-bezier(.4,0,.2,1),background-color .2s;user-select:none;position:relative;top:-1px}
            #aw-np-kbd-btn:hover{transform:scale(1.15)}
            #aw-np-kbd-btn:active{transform:scale(1.05)}
            #aw-np-hotkey-overlay{position:absolute;inset:0;background:rgba(0,0,0,.82);z-index:30;opacity:0;pointer-events:none;transition:opacity .2s cubic-bezier(.4,0,.2,1);font-family:Arial,'Segoe UI','Roboto',sans-serif;container-type:size;cursor:pointer}
            #aw-np-hotkey-overlay.open{opacity:1;pointer-events:auto}
            #aw-np-hotkey-inner{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:clamp(16px,4cqh,40px);padding:4cqh 4cqw;box-sizing:border-box;overflow:hidden;--ku:clamp(34px,7cqh,60px);--kg:clamp(5px,1.2cqh,12px);--kstep:calc((var(--ku) + var(--kg)) / 2)}
            .aw-np-hotkey-hint{text-align:center;font-size:clamp(9px,1.5cqh,12px);font-weight:400;letter-spacing:.08em;color:var(--np-accent-bg-fg,#CCDDF1);opacity:.55;font-family:Arial,sans-serif;line-height:1}
            .aw-np-kbd{display:flex;flex-direction:column;gap:var(--kg)}
            .aw-np-krow{display:flex;gap:var(--kg);opacity:0;transform:translateY(18px) scale(.98);transition:opacity .3s cubic-bezier(.4,0,.2,1),transform .42s cubic-bezier(.34,1.56,.64,1)}
            #aw-np-hotkey-overlay.open .aw-np-krow{opacity:1;transform:translateY(0) scale(1)}
            #aw-np-hotkey-overlay.open .aw-np-krow:nth-child(1){transition-delay:.05s}
            #aw-np-hotkey-overlay.open .aw-np-krow:nth-child(2){transition-delay:.14s}
            #aw-np-hotkey-overlay.open .aw-np-krow:nth-child(3){transition-delay:.23s}
            #aw-np-hotkey-overlay.open .aw-np-krow:nth-child(4){transition-delay:.32s}
            #aw-np-hotkey-overlay.open .aw-np-krow:nth-child(5){transition-delay:.41s}
            .aw-np-krow-bottom{margin-left:0 !important}
            .aw-np-key-enter-flat{width:calc(var(--ku) * 1.5 + var(--kg)) !important}
            .aw-np-key{width:var(--ku);height:var(--ku);border-radius:6px;background:var(--np-accent-bg,#223A56);display:flex;align-items:center;justify-content:center;color:var(--np-accent-bg-fg,#CCDDF1);font-size:calc(var(--ku) * .48);font-weight:500;flex-shrink:0;position:relative;line-height:1;box-sizing:border-box;transition:background-color .15s,color .15s}
            .aw-np-key-fill-wide{width:calc(var(--ku) * var(--wmult, 1.5) + var(--kg) * var(--padmult, 0)) !important}
            .aw-np-key-fill-wide{justify-content:flex-start}
            .aw-np-key-fill-wide>.aw-np-glyph{display:inline-flex;align-items:center;justify-content:center;width:var(--ku);height:var(--ku)}
            .aw-np-key-half{width:calc(var(--ku) * .5) !important}
            .aw-np-key.off{opacity:.5}
            .aw-np-key.on{cursor:pointer}
            .aw-np-key.on.hovered{background:var(--np-accent-state-1,color-mix(in srgb,var(--np-accent,#1565C0) 22%,var(--np-accent-bg,#223A56)));color:#fff}
            .aw-np-key-ico,.aw-np-key-letter{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;transition:opacity .15s}
            .aw-np-key-ico svg{width:56%;height:56%}
            .aw-np-key-ico svg path:not([fill="none"]),.aw-np-key-ico svg polygon,.aw-np-key-ico svg rect{fill:var(--np-accent-bg-fg,#CCDDF1)}
            .aw-np-key-ico svg path[fill="none"]{stroke:var(--np-accent-bg-fg,#CCDDF1)}
            .aw-np-key-ico svg line{stroke:var(--np-accent-bg-fg,#CCDDF1)}
            .aw-np-key.hovered .aw-np-key-ico svg path:not([fill="none"]),.aw-np-key.hovered .aw-np-key-ico svg polygon,.aw-np-key.hovered .aw-np-key-ico svg rect{fill:#fff}
            .aw-np-key.hovered .aw-np-key-ico svg path[fill="none"]{stroke:#fff}
            .aw-np-key-pct{font-size:calc(var(--ku) * .26);font-weight:600}
            .aw-np-key-a-badge{display:flex;align-items:center;justify-content:center;width:calc(var(--ku) * .55);height:calc(var(--ku) * .55);border-radius:3px;background:var(--np-accent-bg-fg,#CCDDF1);color:var(--np-accent-bg,#223A56);font-size:calc(var(--ku) * .32);font-weight:500;font-family:Arial,'Segoe UI','Roboto',sans-serif;line-height:1}
            .aw-np-key-letter{opacity:0;font-size:calc(var(--ku) * .48);font-weight:500}
            .aw-np-key.hovered .aw-np-key-ico{opacity:0}
            .aw-np-key.hovered .aw-np-key-letter{opacity:1}
            .aw-np-key-mod{font-size:calc(var(--ku) * .19);font-weight:600;opacity:.5;letter-spacing:.04em}
            .aw-np-key-space{width:calc(var(--ku) * 5 + var(--kg) * 4)}
            .aw-np-kbd-fn{height:clamp(20px,3cqh,30px);display:flex;align-items:center;justify-content:center;gap:clamp(10px,1.6cqw,18px);opacity:0;transform:translateY(4px);transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1)}
            .aw-np-kbd-fn.show{opacity:1;transform:translateY(0)}
            .aw-np-kbd-fn-name{font-size:clamp(10px,1.7cqh,14px);font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--np-accent-dim,#9db8e0);font-family:Arial,sans-serif;line-height:1;padding-right:clamp(10px,1.6cqw,18px);border-right:1px solid color-mix(in srgb,var(--np-accent-bg-fg,#CCDDF1) 22%,transparent)}
            .aw-np-kbd-fn-desc{font-size:clamp(12px,2cqh,18px);font-weight:400;color:var(--np-accent-bg-fg,rgba(255,255,255,.92));font-family:Arial,sans-serif;line-height:1}
            #aw-np-dot:hover{transform:scale(1.4);box-shadow:0 0 0 4px var(--np-accent-dim,rgba(255,255,255,.15))}
            #aw-np-dot:hover .np-tip{opacity:1;transition-delay:.3s}
            #aw-np-dot .np-tip{bottom:auto;top:calc(100% + 10px);left:auto;right:0;transform:none}
            #aw-np-dot .np-tip::after{top:auto;bottom:100%;left:auto;right:5px;transform:none;border-top-color:transparent;border-bottom-color:rgba(30,30,30,.97)}
            #aw-np-color-panel{position:absolute;top:var(--np-top-h);right:12px;background:var(--np-accent-bg,#000);border:1px solid color-mix(in srgb,var(--np-accent,#fff) 20%,transparent);border-radius:12px;padding:14px;display:flex;flex-direction:column;gap:12px;font-size:var(--np-fs-body);color:var(--np-accent-bg-fg,rgba(255,255,255,.9));z-index:11;opacity:0;transform:scale(.9) translateY(-8px);transform-origin:top right;pointer-events:none;transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);box-shadow:0 8px 24px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.3)}
            #aw-np-color-panel.open{opacity:1;transform:scale(1) translateY(0);pointer-events:all}
            #aw-np-color-swatches{display:flex;flex-wrap:wrap;gap:8px;width:162px}
            .np-swatch{width:26px;height:26px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:transform .2s cubic-bezier(.4,0,.2,1),border-color .15s,box-shadow .2s;flex-shrink:0}
            .np-swatch:hover{transform:scale(1.12);box-shadow:0 3px 10px rgba(0,0,0,.45)}
            .np-swatch.active{border-color:var(--np-accent,#fff);box-shadow:0 0 0 3px color-mix(in srgb,var(--np-accent,#fff) 35%,transparent),0 2px 6px rgba(0,0,0,.4);transform:scale(1.08)}
            #aw-np-controls{position:absolute;bottom:0;left:0;right:0;display:flex;flex-direction:column;padding:0 6px 6px}
            #aw-np-seek-wrap{height:var(--np-seek-h);display:flex;align-items:center;cursor:pointer;padding:0 4px;touch-action:none}
            #aw-np-seek-track{position:relative;width:100%;height:4px;border-radius:2px;background:rgba(255,255,255,.2);transition:height .15s cubic-bezier(.4,0,.2,1)}
            #aw-np-seek-wrap:hover #aw-np-seek-track{height:6px}
            #aw-np-seek-buf{position:absolute;inset:0;border-radius:inherit;background:var(--np-accent-dim,rgba(255,255,255,.5));width:0;opacity:.6}
            #aw-np-seek-fill{position:absolute;inset:0;border-radius:inherit;background:var(--np-accent,#fff);width:0;transition:background .2s}
            #aw-np-seek-thumb{position:absolute;top:50%;left:0;width:14px;height:14px;background:var(--np-accent,#fff);border-radius:50%;transform:translate(-50%,-50%) scale(0);transition:transform .15s cubic-bezier(.4,0,.2,1),box-shadow .15s;box-shadow:0 2px 6px rgba(0,0,0,.4)}
            #aw-np-seek-wrap:hover #aw-np-seek-thumb{transform:translate(-50%,-50%) scale(1)}
            #aw-np-seek-wrap.seeking #aw-np-seek-thumb{transform:translate(-50%,-50%) scale(1.2)}
            #aw-np-seek-tip{position:absolute;bottom:calc(100% + 10px);left:0;transform:translateX(-50%);background:var(--np-accent-bg,#282828);color:var(--np-accent-bg-fg,#fff);font-size:var(--np-fs-small);font-weight:500;padding:4px 8px;border-radius:6px;pointer-events:none;white-space:nowrap;visibility:hidden;box-shadow:0 2px 8px rgba(0,0,0,.4);letter-spacing:.02em}
            #aw-np-bar{display:flex;align-items:center;height:var(--np-bar-h);gap:0}
            .np-icon{display:contents}
            .np-btn{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;width:var(--np-btn-size);height:var(--np-btn-size);background:none;border:none;cursor:pointer;color:var(--np-accent-bg-fg,rgba(255,255,255,.75));padding:0;flex-shrink:0;border-radius:50%;transition:color .2s cubic-bezier(.4,0,.2,1),background .2s}
            .np-btn:hover{color:var(--np-accent-bg-fg,#fff);background:var(--np-accent-state-1,rgba(255,255,255,.1))}
            .np-btn:active{background:var(--np-accent-state-2,rgba(255,255,255,.18))}
            .np-btn svg{display:block;fill:currentColor;flex-shrink:0;width:var(--np-svg-size);height:var(--np-svg-size);transition:transform .2s cubic-bezier(.2,0,0,1)}
            .np-btn:active svg{transition-duration:.1s;transform:scale(.88)}
            .np-btn svg line{stroke:currentColor}
            .accent-icons .np-btn{color:var(--np-accent,#fff)}
            .accent-icons .np-btn svg{fill:var(--np-accent,#fff)}
            .accent-icons .np-btn svg line{stroke:var(--np-accent,#fff)}
            .accent-top #aw-np-title{color:var(--np-accent,#fff)}
            .accent-top #aw-np-epinfo{color:var(--np-accent,#fff);opacity:.75}
            .accent-top #aw-np-brand{color:var(--np-accent,#fff);opacity:.5}
            .np-ripple{position:absolute;border-radius:50%;background:var(--np-accent-state-2,rgba(255,255,255,.35));transform:scale(0);opacity:1;animation:np-ripple .55s cubic-bezier(.2,0,.2,1);pointer-events:none}
            @keyframes np-ripple{0%{transform:scale(0);opacity:1}60%{opacity:.6}100%{transform:scale(2.8);opacity:0}}
            #aw-np-time{font-size:var(--np-fs-small);font-weight:400;color:var(--np-accent-bg-fg,rgba(255,255,255,.85));letter-spacing:.04em;white-space:nowrap;padding:0 6px;font-variant-numeric:tabular-nums;text-shadow:0 1px 3px rgba(0,0,0,.8)}
            #aw-np-spacer{flex:1}
            #aw-np-vol-group{position:relative;display:flex;align-items:center}
            #aw-np-vol-group::after{content:'';position:absolute;bottom:100%;left:-8px;right:-8px;height:calc(var(--np-seek-h) + 20px);pointer-events:none}
            #aw-np-vol-group:hover::after{pointer-events:all}
            #aw-np-vol-popup{position:absolute;bottom:calc(var(--np-bar-h) + var(--np-seek-h) + 8px);left:50%;transform:translateX(-50%);width:44px;height:0;overflow:hidden;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:6px;transition:height .25s cubic-bezier(.4,0,.2,1),padding .25s cubic-bezier(.4,0,.2,1);padding:0}
            #aw-np-vol-group:hover #aw-np-vol-popup,#aw-np-vol-group:focus-within #aw-np-vol-popup{height:148px;padding:10px 0 12px;background:var(--np-accent-bg,#1c1c1c);border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,.4)}
            #aw-np-vol-pct{font-size:var(--np-fs-small);font-weight:500;color:var(--np-accent-bg-fg,rgba(255,255,255,.85));width:32px;text-align:center;font-variant-numeric:tabular-nums;flex-shrink:0;display:block;letter-spacing:.02em;text-shadow:0 1px 3px rgba(0,0,0,.8)}
            #aw-np-vol{-webkit-appearance:none;appearance:none;width:4px;height:108px;border-radius:2px;background:rgba(255,255,255,.2);cursor:pointer;outline:none;writing-mode:vertical-lr;direction:rtl;transition:background .15s}
            #aw-np-vol::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--np-accent,#fff);border-radius:50%;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,.4);transition:transform .15s cubic-bezier(.4,0,.2,1)}
            #aw-np-vol:hover::-webkit-slider-thumb{transform:scale(1.2)}
            #aw-np-vol::-moz-range-thumb{width:14px;height:14px;background:var(--np-accent,#fff);border:none;border-radius:50%;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,.4)}
            #aw-np-settings-panel{position:absolute;bottom:calc(var(--np-bar-h) + var(--np-seek-h) + 8px);right:12px;background:var(--np-accent-bg,#000);border:1px solid color-mix(in srgb,var(--np-accent,#fff) 20%,transparent);border-radius:12px;padding:14px 18px;min-width:230px;display:flex;flex-direction:column;gap:10px;font-size:var(--np-fs-body);color:var(--np-accent-bg-fg,rgba(255,255,255,.9));z-index:10;opacity:0;transform:scale(.9) translateY(8px);transform-origin:bottom right;pointer-events:none;transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);box-shadow:0 8px 24px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.3)}
            #aw-np-settings-panel.open{opacity:1;transform:scale(1) translateY(0);pointer-events:all}
            .np-switch{position:relative;width:36px;height:20px;flex-shrink:0;cursor:pointer}
            .np-switch input{opacity:0;width:0;height:0;position:absolute}
            .np-switch-track{position:absolute;inset:0;border-radius:10px;background:rgba(255,255,255,.2);transition:background .2s cubic-bezier(.4,0,.2,1)}
            .np-switch input:checked~.np-switch-track{background:var(--np-accent,#fff)}
            .np-switch-thumb{position:absolute;top:3px;left:3px;width:14px;height:14px;background:#fff;border-radius:50%;transition:transform .2s cubic-bezier(.4,0,.2,1);box-shadow:0 1px 4px rgba(0,0,0,.3)}
            .np-switch input:checked~.np-switch-thumb{transform:translateX(16px)}
            .np-switch input:not(:checked)~.np-switch-thumb{background:rgba(255,255,255,.8)}
            .np-tip{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);background:rgba(30,30,30,.97);color:rgba(255,255,255,.92);font-size:var(--np-fs-small);font-weight:500;padding:5px 10px;border-radius:6px;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .15s cubic-bezier(.4,0,.2,1);z-index:20;box-shadow:0 2px 8px rgba(0,0,0,.4)}
            .np-tip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:rgba(30,30,30,.97)}
            .np-btn:hover .np-tip{opacity:1;transition-delay:.4s}
            .np-row-tip{position:absolute;top:50%;right:calc(100% + 14px);transform:translateY(-50%);background:var(--np-accent-bg,#000);color:var(--np-accent-bg-fg,rgba(255,255,255,.9));font-size:var(--np-fs-small);line-height:1.5;padding:6px 10px;border-radius:8px;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .15s cubic-bezier(.4,0,.2,1);transition-delay:0s;z-index:20;box-shadow:0 4px 12px rgba(0,0,0,.4)}
            .np-row-tip::after{content:'';position:absolute;top:50%;left:100%;transform:translateY(-50%);border:5px solid transparent;border-left-color:var(--np-accent-bg,#000)}
            [data-tip]{margin:0 -8px;padding:6px 8px;border-radius:8px;transition:background .15s cubic-bezier(.4,0,.2,1)}[data-tip]:hover{background:var(--np-accent-state-1,rgba(255,255,255,.06))}[data-tip]:hover .np-row-tip{opacity:1;transition-delay:.5s}
            #aw-np-toast{position:absolute;bottom:calc(var(--np-bar-h) + var(--np-seek-h) + 16px);left:50%;transform:translateX(-50%);background:color-mix(in srgb,var(--np-accent-bg,#282828) 80%,transparent);color:var(--np-accent-bg-fg,rgba(255,255,255,.92));font-size:var(--np-fs-body);font-weight:500;letter-spacing:.02em;padding:7px 16px;border-radius:24px;pointer-events:none;white-space:nowrap;opacity:1;transition:opacity .4s cubic-bezier(.4,0,.2,1);z-index:20;box-shadow:0 4px 12px rgba(0,0,0,.4)}

            #aw-np-speed-ind{font-size:var(--np-fs-micro);font-weight:400;color:var(--np-accent-bg-fg,rgba(255,255,255,.55));letter-spacing:.03em;white-space:nowrap;padding:0 0 0 6px;font-variant-numeric:tabular-nums}
            #aw-np-speed-popup{position:absolute;top:10px;left:10px;background:transparent;color:rgba(255,255,255,.6);font-size:var(--np-fs-title);font-weight:500;padding:2px 4px;border-radius:4px;pointer-events:none;opacity:0;transition:opacity .3s cubic-bezier(.4,0,.2,1);z-index:20;letter-spacing:.02em;text-shadow:0 1px 6px rgba(0,0,0,.95)}
            #aw-np-speed-popup.on{opacity:1}
            #aw-np.ui #aw-np-speed-popup{opacity:0!important}
            #aw-np-clock{position:absolute!important;inset:clamp(8px,1.2cqh,16px) clamp(10px,1.4cqh,18px) auto auto!important;display:flex;align-items:center;gap:6px;color:rgba(255,255,255,.6);font-size:clamp(18px,3.1cqh,34px);font-weight:500;padding:2px 4px;pointer-events:none;z-index:20;letter-spacing:.03em;text-shadow:0 1px 6px rgba(0,0,0,.95);font-variant-numeric:tabular-nums;transition:opacity .3s cubic-bezier(.4,0,.2,1);flex:none;transform:none}
            #aw-np-clock svg{width:1em;height:1em;flex-shrink:0;display:block;filter:drop-shadow(0 0 1px rgba(0,0,0,.95)) drop-shadow(0 1px 3px rgba(0,0,0,.7))}
            #aw-np-clock .hand-h{fill:var(--np-accent,#fff);fill-opacity:1;stroke:var(--np-accent,#fff)}#aw-np-clock .pin{fill:var(--np-accent,#fff);fill-opacity:1;stroke:var(--np-accent,#fff)}#aw-np-clock .hand-m{fill:currentColor}
            #aw-np.ui #aw-np-clock{opacity:0!important;visibility:hidden}
            #aw-np.clock-hidden #aw-np-clock{display:none!important}
            #aw-np.speed-popup-hidden #aw-np-speed-popup{display:none!important}
            #aw-np-conn-toast{position:absolute;top:clamp(12px,1.7cqh,18px);left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:8px;padding:6px 12px;border-radius:12px;font-size:calc(var(--np-fs-body) * .82);font-weight:500;color:rgba(255,255,255,.95);z-index:22;box-shadow:0 4px 14px rgba(0,0,0,.45),0 1px 3px rgba(0,0,0,.3);pointer-events:all;white-space:nowrap;opacity:0;transition:opacity .35s cubic-bezier(.4,0,.2,1);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.08)}
            #aw-np-conn-toast.slow{background:rgba(210,100,15,.78)}
            #aw-np-conn-toast.good{background:rgba(30,155,65,.78)}
            #aw-np-conn-toast .conn-msg{display:flex;flex-direction:column;gap:2px;line-height:1.3;text-align:center;letter-spacing:.025em;flex:1}
            #aw-np-buf-pct{position:absolute;inset:0;display:none;align-items:center;justify-content:center;font-size:var(--np-fs-title);font-weight:600;color:var(--np-accent-bg-fg,rgba(255,255,255,.85));pointer-events:none;font-variant-numeric:tabular-nums;text-shadow:0 1px 4px rgba(0,0,0,.9)}
            #aw-np-buf-pct.on{display:flex}
            #aw-np-error-toast{position:absolute;bottom:calc(var(--np-bar-h) + var(--np-seek-h) + 16px);left:50%;transform:translateX(-50%);background:rgba(180,30,30,.92);color:#fff;font-size:var(--np-fs-body);font-weight:500;letter-spacing:.02em;padding:7px 18px;border-radius:24px;pointer-events:all;white-space:nowrap;z-index:21;box-shadow:0 4px 12px rgba(0,0,0,.5);cursor:pointer}
            #aw-np-spinner{position:absolute;inset:0;margin:auto;width:var(--np-spinner-size);height:var(--np-spinner-size);border:3px solid rgba(255,255,255,.12);border-top-color:var(--np-accent,#fff);border-radius:50%;animation:np-spin .65s linear infinite;pointer-events:none;display:none}
            #aw-np-spinner.on{display:block}
            @keyframes np-spin{to{transform:rotate(360deg)}}
            .np-flash-circle{position:absolute;top:50%;left:50%;width:72px;height:72px;border-radius:50%;display:flex;align-items:center;justify-content:center;pointer-events:none;opacity:0;z-index:12;color:var(--np-accent-bg-fg,rgba(255,255,255,.9))}
            .np-flash-circle::before{content:'';position:absolute;inset:0;border-radius:50%;background:var(--np-accent-bg,#1a1a2e);opacity:.8;pointer-events:none}
            .np-flash-circle.on{opacity:1}
            .np-flash-circle svg{fill:var(--np-accent-bg-fg,rgba(255,255,255,.9));opacity:1;width:34px;height:34px;position:relative;z-index:1}
            #aw-np-center{margin:-36px 0 0 -36px;transform:scale(.7);transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.34,1.56,.64,1)}
            #aw-np-center.on{transform:scale(1)}
            #aw-np-vol-flash{transform:translate(-50%,-50%);transition:opacity .2s cubic-bezier(.4,0,.2,1)}
            #aw-np-vol-flash svg{display:block}
        `;
        document.head.appendChild(s);
    }

    // ── Shared: buildClock ───────────────────────────────────────────────────
    function buildClock(wrap){
        const clockEl=mk('div','aw-np-clock');
        const fmt2=n=>String(n).padStart(2,'0');
        const _ico='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round"><circle cx="12" cy="12" r="9.1" fill="rgba(255,255,255,.3)"/><circle cx="12" cy="12" r="10" stroke-width="1.2"/><rect class="hand-m" x="10.8" y="4.4" width="2.4" height="8.0" rx="1.2"/><rect class="hand-h" x="10.8" y="6.6" width="2.4" height="5.8" rx="1.2"/><circle class="pin" cx="12" cy="12" r="1.0"/></svg>';
        const timeEl=document.createElement('span');
        clockEl.innerHTML=_ico;
        clockEl.appendChild(timeEl);
        const handH=clockEl.querySelector('.hand-h');
        const handM=clockEl.querySelector('.hand-m');
        const tick=()=>{
            const d=new Date(),h=d.getHours(),m=d.getMinutes();
            timeEl.textContent=fmt2(h)+':'+fmt2(m);
            handH.setAttribute('transform',`rotate(${(h%12)*30+m*0.5} 12 12)`);
            handM.setAttribute('transform',`rotate(${m*6} 12 12)`);
        };
        tick();
        let timer;
        const sync=()=>{tick();timer=setInterval(tick,60000);};
        const initTimer=setTimeout(()=>sync(),(60-new Date().getSeconds())*1000);
        wrap.appendChild(clockEl);
        return{clockEl,clearTimer:()=>{clearTimeout(initTimer);clearInterval(timer);}};
    }

    // ── Shared: buildSpeedIndicator ───────────────────────────────────────────
    function buildSpeedIndicator(initSpeed){
        const speedIndEl=mk('span','aw-np-speed-ind');
        const speedPopup=mk('div','aw-np-speed-popup');
        const updateSpeedInd=v=>{speedIndEl.textContent='('+fmtSpeed(v)+')';};
        const showSpeedPopup=v=>{speedPopup.textContent=fmtSpeed(v);speedPopup.classList.toggle('on',Math.abs(v-1)>0.001);};
        updateSpeedInd(initSpeed);showSpeedPopup(initSpeed);
        return{speedIndEl,speedPopup,updateSpeedInd,showSpeedPopup,clearTimer:()=>{}};
    }

    // ── Shared: buildBufferingIndicator ───────────────────────────────────────
    function buildBufferingIndicator(video,spinner){
        const bufPctEl=mk('div','aw-np-buf-pct');
        const TARGET_AHEAD=1;
        let bufStartCt=null;
        const updateBufPct=()=>{
            if(bufStartCt===null||!video.buffered.length){bufPctEl.textContent='0%';return;}
            for(let i=0;i<video.buffered.length;i++){
                if(video.buffered.start(i)<=bufStartCt+0.1&&bufStartCt<=video.buffered.end(i)+0.1){
                    const ahead=Math.max(0,video.buffered.end(i)-bufStartCt);
                    const pct=Math.min(100,Math.round(ahead/TARGET_AHEAD*100));
                    bufPctEl.textContent=pct+'%';
                    return;
                }
            }
            bufPctEl.textContent='0%';
        };
        let bufTimer=null;
        const startBufTimer=()=>{if(bufTimer)return;updateBufPct();bufTimer=setInterval(updateBufPct,250);};
        const stopBufTimer=()=>{clearInterval(bufTimer);bufTimer=null;bufStartCt=null;};
        video.addEventListener('progress',updateBufPct);
        video.addEventListener('waiting',()=>{bufStartCt=video.currentTime;bufPctEl.classList.add('on');spinner.classList.add('on');startBufTimer();});
        video.addEventListener('playing',()=>{bufPctEl.classList.remove('on');spinner.classList.remove('on');stopBufTimer();});
        video.addEventListener('canplay',()=>{bufPctEl.classList.remove('on');spinner.classList.remove('on');stopBufTimer();});
        return{bufPctEl};
    }



    // ── Shared: buildErrorHandler ─────────────────────────────────────────────
    function buildErrorHandler(video,wrap,_play,errorMsg){
        const hideErrorToast=()=>wrap.querySelector('#aw-np-error-toast')?.remove();
        const reloadVideo=(silent=false)=>{hideErrorToast();const t=video.currentTime;const wasPlaying=!video.paused;const s=video.src;if(silent)video.dataset.silentReload='1';video.src='';video.src=s;video.addEventListener('loadedmetadata',()=>{if(t>0)video.currentTime=t;if(wasPlaying)_play();setTimeout(()=>{delete video.dataset.silentReload;},100);},{once:true});};
        const showErrorToast=msg=>{hideErrorToast();const t=mk('div','aw-np-error-toast');t.id='aw-np-error-toast';t.textContent=msg;t.addEventListener('click',()=>reloadVideo());wrap.appendChild(t);};
        video.addEventListener('error',()=>{if(video.networkState!==0)showErrorToast(errorMsg);});
        let _lastTime=-1,_freezeTimer=null;
        const _checkFreeze=()=>{if(video.paused||video.ended)return;if(video.currentTime===_lastTime&&video.readyState<3)showErrorToast(errorMsg);_lastTime=video.currentTime;};
        video.addEventListener('play',()=>{hideErrorToast();_lastTime=video.currentTime;clearInterval(_freezeTimer);_freezeTimer=setInterval(_checkFreeze,5000);});
        video.addEventListener('playing',()=>{hideErrorToast();_lastTime=video.currentTime;});
        video.addEventListener('canplaythrough',()=>hideErrorToast());
        video.addEventListener('pause',()=>clearInterval(_freezeTimer));
        video.addEventListener('ended',()=>clearInterval(_freezeTimer));
        video.addEventListener('seeking',()=>{_lastTime=-1;});
        return{reloadVideo,clearTimer:()=>clearInterval(_freezeTimer)};
    }

    // ── Shared: buildEpisodeActions ───────────────────────────────────────────
    function buildEpisodeActions({video,_play,flash}){
        return{
            restart:()=>{video.currentTime=0;_play();flash(IC.restart);},
            undo:()=>{video.currentTime=Math.max(0,video.currentTime-SKIP_SECONDS);flash(IC.undo);},
            skip:()=>{video.currentTime=Math.min(video.duration||0,video.currentTime+SKIP_SECONDS);flash(IC.skip);},
            prev:()=>{const t=getAdjacentEpisode('prev');if(t){flash(IC.prev);loadEpisode(t.dataset.id);}},
            next:()=>{const t=getAdjacentEpisode('next');if(t){flash(IC.next);loadEpisode(t.dataset.id);}}
        };
    }

    // ── Shared: buildVolFlash ─────────────────────────────────────────────────
    function buildVolFlash(video){
        const volFlash=mk('div','aw-np-vol-flash');volFlash.classList.add('np-flash-circle');
        const volFlashIco=mk('div','aw-np-vol-flash-icon');volFlash.appendChild(volFlashIco);
        let volFlashTimer=null;
        const showVolFlash=dir=>{if(!isFlashOn())return;const m=video.muted||video.volume===0;volFlashIco.innerHTML=m?IC.mute:(dir==='down'?IC.volDown:IC.vol);volFlash.classList.add('on');clearTimeout(volFlashTimer);volFlashTimer=setTimeout(()=>volFlash.classList.remove('on'),400);};
        return{volFlash,showVolFlash,clearTimer:()=>clearTimeout(volFlashTimer)};
    }

    // ── Shared: buildCenterFlash ──────────────────────────────────────────────
    function buildCenterFlash(center){
        let cTimer=null,skipFlash=false;
        const flashAt=(html,dur)=>{if(!isFlashOn())return;center.innerHTML=html;center.classList.add('on');clearTimeout(cTimer);cTimer=setTimeout(()=>center.classList.remove('on'),dur);};
        return{
            flash:html=>flashAt(html,700),
            flashBrief:html=>flashAt(html,400),
            playPauseFlash:html=>{if(!skipFlash)flashAt(html,700);},
            setSkipFlash:v=>{skipFlash=v;},
            clearTimer:()=>clearTimeout(cTimer)
        };
    }

    // ── Shared: buildPipHandler ───────────────────────────────────────────────
    function buildPipHandler({video,btnPip,wrap,onEnter,onLeave}){
        btnPip.addEventListener('click',()=>pipElement()?pipExit():pipRequest(video));
        video.addEventListener('enterpictureinpicture',()=>{wrap.style.visibility='hidden';onEnter?.();});
        video.addEventListener('leavepictureinpicture',()=>{wrap.style.visibility='';onLeave?.();});
    }

    // ── Shared: wirePlayPauseEvents ───────────────────────────────────────────
    function wirePlayPauseEvents({video,onUpdate,playPauseFlash}){
        video.addEventListener('play',()=>{if(video.dataset.silentReload)return;onUpdate(true);playPauseFlash?.(IC.pause);});
        video.addEventListener('pause',()=>{if(video.dataset.silentReload)return;onUpdate(false);playPauseFlash?.(IC.play);});
        video.addEventListener('ended',()=>onUpdate(false));
    }

    // ── Shared: buildShellElements ────────────────────────────────────────────
    function buildShellElements(){
        const wrap=mk('div','aw-np');
        const grad=mk('div','aw-np-gradient');grad.classList.add('np-grad');
        const gradTop=mk('div','aw-np-gradient-top');gradTop.classList.add('np-grad');
        const spinner=mk('div','aw-np-spinner');
        const center=mk('div','aw-np-center');center.classList.add('np-flash-circle');center.innerHTML=IC.play;
        const ctrls=mk('div','aw-np-controls');ctrls.classList.add('np-ui-layer');
        const timeEl=mk('div','aw-np-time');timeEl.textContent='00:00 / 00:00';
        const SEP='border-top:1px solid var(--np-accent-state-1,rgba(255,255,255,.12));padding-top:10px;';
        return{wrap,grad,gradTop,spinner,center,ctrls,timeEl,SEP};
    }

    // ── Shared: bindPanelToggle ───────────────────────────────────────────────
    function bindPanelToggle(trigger,target,others,afterClose){
        trigger.addEventListener('click',e=>{
            e.stopPropagation();
            others.forEach(o=>o.classList.remove('open'));
            const willOpen=!target.classList.contains('open');
            target.classList.toggle('open',willOpen);
            if(!willOpen&&afterClose)afterClose();
        });
        target.addEventListener('click',e=>e.stopPropagation());
    }

    // ── Build player desktop ──────────────────────────────────────────────────
    let cleanup=null,_preloadedToken=null,_preloadedUrl=null,_preloadedVideo=null;
    function buildPlayerDesktop(videoUrl){
        const{video,vol,muted,_play}=initVideo(videoUrl);
        const{wrap,grad,gradTop,spinner,center,ctrls,timeEl,SEP}=buildShellElements();
        const{speedIndEl,speedPopup,updateSpeedInd,showSpeedPopup,clearTimer:clearSpeedTimer}=buildSpeedIndicator(loadSpeed());
        const{bufPctEl}=buildBufferingIndicator(video,spinner);
        const{seekWrap,isSeeking}=buildSeekBar(video,true,()=>{timeEl.textContent=fmt(video.currentTime)+' / '+fmt(video.duration);});
        const{settingsPanel,resumeToggle,autoEpToggle,autoPlayToggle,connMonitorToggle,globalToggle,seekSecs:getSeekSecs,updateSeekVal,updateSpeedVal}=buildSettingsPanel(video,SEP,'Secondi saltati con le freccette.',v=>{updateSpeedInd(v);showSpeedPopup(v);});
        let seekSecs=getSeekSecs(),speedVal=loadSpeed();
        const{colorPanel,syncCustomInput,updateSwatches,topColorToggle,iconColorToggle,flashToggle,clockToggle,speedPopupToggle,colorGlobalToggle}=buildColorPanel(wrap,null,SEP);
        let currentColor=loadColor();
        const{topBar,dotEl,kbdBtn}=buildTopBar(wrap,colorPanel);
        const{overlay:hotkeyOverlay,open:openHotkey,close:closeHotkey,isOpen:isHotkeyOpen}=buildHotkeyPanel();
        wrap.appendChild(hotkeyOverlay);
        kbdBtn.addEventListener('click',e=>{e.stopPropagation();[settingsPanel,colorPanel].forEach(p=>p.classList.remove('open'));openHotkey();});
        const btnPlay=mkBtn('aw-btn-play','','Riproduci'),btnRestart=mkBtn('aw-btn-restart',IC.restart,'Ricomincia (R)');
        const btnMute=mkBtn('aw-btn-mute','',muted?'Audio (M)':'Muto (M)');
        const btnUndo=mkBtn('aw-btn-undo',IC.undo,'Annulla skip (B)'),btnSkip=mkBtn('aw-btn-skip',IC.skip,'Skip OP/ED (O)');
        const btnPrev=mkBtn('aw-btn-prev',IC.prev,'Precedente (P)'),btnNext=mkBtn('aw-btn-next',IC.next,'Successivo (N)');
        const btnSettings=mkBtn('aw-btn-settings',IC.settings,'Impostazioni'),btnPip=mkBtn('aw-btn-pip',IC.pip,'Picture in Picture');
        const btnFs=mkBtn('aw-btn-fs','','Fullscreen (F)');
        const icoPlay=mkIcon(btnPlay,IC.play),icoMute=mkIcon(btnMute,muted?IC.mute:IC.vol),icoFs=mkIcon(btnFs,IC.fsOn);
        const volGroup=mk('div','aw-np-vol-group'),volPopup=mk('div','aw-np-vol-popup'),volPctEl=mk('div','aw-np-vol-pct'),volEl=mk('input','aw-np-vol');
        volEl.type='range';volEl.min=0;volEl.max=100;volEl.value=muted?0:Math.round(vol*100);volEl.tabIndex=-1;
        volPctEl.textContent=(muted?0:Math.round(vol*100))+'%';
        volPopup.append(volPctEl,volEl);volGroup.append(volPopup,btnMute);
        let lastNonZeroVol=muted?(vol||1):vol;
        const updateMuteState=()=>{const m=video.muted||video.volume===0;setIcon(icoMute,m?IC.mute:IC.vol);setTip(btnMute,m?'Audio (M)':'Muto (M)');};
        const updateVolUi=()=>{const pct=(video.muted||video.volume===0)?0:Math.round(video.volume*100);volPctEl.textContent=pct+'%';volEl.style.background=`linear-gradient(to top, var(--np-accent,#fff) ${pct}%, rgba(255,255,255,.25) ${pct}%)`;};
        updateVolUi();
        const{volFlash,showVolFlash,clearTimer:clearVolFlashTimer}=buildVolFlash(video);
        volEl.addEventListener('input',()=>{const v=Number(volEl.value)/100;video.volume=v;video.muted=v===0;if(v>0)lastNonZeroVol=v;updateMuteState();updateVolUi();saveVol(v===0?lastNonZeroVol:v,video.muted);});
        volEl.addEventListener('pointerup',()=>volEl.blur());
        btnMute.addEventListener('click',()=>{if(video.muted||video.volume===0){video.muted=false;video.volume=lastNonZeroVol;volEl.value=Math.round(video.volume*100);}else{if(video.volume>0)lastNonZeroVol=video.volume;video.muted=true;volEl.value=0;}updateMuteState();updateVolUi();saveVol(video.muted?lastNonZeroVol:video.volume,video.muted);showVolFlash(video.muted?'down':'up');});
        const bar=mk('div','aw-np-bar');
        bar.append(btnPlay,btnRestart,volGroup,timeEl,speedIndEl,mk('div','aw-np-spacer'),btnUndo,btnSkip,btnPrev,btnNext,btnSettings,btnPip,btnFs);
        ctrls.append(seekWrap,bar);
        bindPanelToggle(btnSettings,settingsPanel,[colorPanel]);
        bindPanelToggle(dotEl,colorPanel,[settingsPanel]);
        wrap.addEventListener('click',()=>{settingsPanel.classList.remove('open');colorPanel.classList.remove('open');});
        wrap.append(video,grad,gradTop,topBar,colorPanel,spinner,bufPctEl,speedPopup,center,settingsPanel,ctrls,volFlash);
        const{clearMonitor}=buildConnectionMonitor(video,wrap);
        applyColor(currentColor,wrap,dotEl);
        const{clearTimer:clearClockTimer}=buildClock(wrap);
        const{reloadVideo,clearTimer:clearFreezeTimer}=buildErrorHandler(video,wrap,_play,'Sblocca video (S)');
        let hideTimer=null;
        const showUi=()=>{wrap.classList.add('ui');clearTimeout(hideTimer);if(!video.paused)hideTimer=setTimeout(()=>{if(settingsPanel.classList.contains('open')||colorPanel.classList.contains('open'))return;wrap.classList.remove('ui');},HIDE_DELAY_MS);};
        wrap.addEventListener('pointermove',showUi);wrap.addEventListener('pointerleave',()=>{if(!video.paused)wrap.classList.remove('ui');});
        video.addEventListener('pause',()=>{if(video.dataset.silentReload)return;wrap.classList.add('ui');clearTimeout(hideTimer);});video.addEventListener('play',()=>{if(video.dataset.silentReload)return;showUi();});
        const{flash,flashBrief,playPauseFlash,setSkipFlash,clearTimer:clearCenterTimer}=buildCenterFlash(center);
        [btnPlay,btnRestart,btnMute,btnUndo,btnSkip,btnPrev,btnNext,btnSettings,btnPip,btnFs].forEach(addRipple);
        const toggle=()=>video.paused?_play():video.pause();
        video.addEventListener('click',toggle);video.addEventListener('dblclick',()=>btnFs.click());btnPlay.addEventListener('click',toggle);
        wirePlayPauseEvents({video,onUpdate:p=>{setIcon(icoPlay,p?IC.pause:IC.play);setTip(btnPlay,p?'Pausa':'Riproduci');},playPauseFlash});
        const ep=buildEpisodeActions({video,_play,flash});
        btnRestart.addEventListener('click',ep.restart);
        btnSkip.addEventListener('click',ep.skip);
        btnUndo.addEventListener('click',ep.undo);
        btnPrev.addEventListener('click',ep.prev);
        btnNext.addEventListener('click',ep.next);
        buildPipHandler({video,btnPip,wrap,onEnter:()=>setTip(btnPip,'Chiudi PiP'),onLeave:()=>setTip(btnPip,'Picture in Picture')});
        btnFs.addEventListener('click',()=>fsElement()?fsExit():fsRequest(wrap));
        const{showResumeToast,stopSaving,episodeEnded}=buildResumeLogic(video,wrap,()=>speedVal);
        const onFs=()=>{const isFs=!!fsElement();if(isFs&&isAutoPlayOn()&&video.paused&&!episodeEnded())_play();setTimeout(()=>{setIcon(icoFs,isFs?IC.fsOff:IC.fsOn);setTip(btnFs,isFs?'Esci (F)':'Fullscreen (F)');},0);};
        const onKey=e=>{if(pipElement())return;if(e.ctrlKey||e.metaKey||e.altKey)return;const tag=document.activeElement?.tagName??'',editable=document.activeElement?.isContentEditable;if(/INPUT|TEXTAREA/.test(tag)||editable)return;if(isHotkeyOpen()){if(e.key==='Escape'||e.key==='a'||e.key==='A'){e.preventDefault();closeHotkey();}return;}if(e.key==='a'||e.key==='A'){e.preventDefault();openHotkey();return;}if(e.key===' '){e.preventDefault();toggle();}if(e.key==='ArrowRight'){e.preventDefault();video.currentTime=Math.min(video.duration||0,video.currentTime+seekSecs);flashBrief(IC.seekFwd);}if(e.key==='ArrowLeft'){e.preventDefault();video.currentTime=Math.max(0,video.currentTime-seekSecs);flashBrief(IC.seekBwd);}if(e.key==='ArrowUp'){e.preventDefault();video.volume=Math.min(1,video.volume+.1);video.muted=false;lastNonZeroVol=video.volume;volEl.value=Math.round(video.volume*100);saveVol(video.volume,false);updateMuteState();updateVolUi();showVolFlash('up');}if(e.key==='ArrowDown'){e.preventDefault();video.volume=Math.max(0,video.volume-.1);video.muted=video.volume===0;if(video.volume>0)lastNonZeroVol=video.volume;volEl.value=Math.round(video.volume*100);saveVol(video.muted?lastNonZeroVol:video.volume,video.muted);updateMuteState();updateVolUi();showVolFlash('down');}if(e.key>='0'&&e.key<='9'&&video.duration){e.preventDefault();const t=video.duration*(parseInt(e.key,10)/10);flashBrief(t>video.currentTime?IC.seekFwd:IC.seekBwd);video.currentTime=t;}if(e.key==='f'||e.key==='F')btnFs.click();if(e.key==='m'||e.key==='M')btnMute.click();if(e.key==='r'||e.key==='R')btnRestart.click();if(e.key==='o'||e.key==='O')btnSkip.click();if(e.key==='b'||e.key==='B')btnUndo.click();if(e.key==='p'||e.key==='P')btnPrev.click();if(e.key==='n'||e.key==='N')btnNext.click();if(e.key==='s'||e.key==='S')reloadVideo();};
        const onStorage=e=>{if(!e.key?.startsWith('aw-np-'))return;resumeToggle.checked=isResumeOn();autoEpToggle.checked=isAutoEpOn();autoPlayToggle.checked=isAutoPlayOn();connMonitorToggle.checked=isConnMonitorOn();globalToggle.checked=isGlobalOn();seekSecs=getSeekSecs();updateSeekVal();speedVal=loadSpeed();updateSpeedVal();updateSpeedInd(speedVal);showSpeedPopup(speedVal);const newColor=loadColor();if(newColor!==currentColor){currentColor=newColor;applyColor(currentColor,wrap,dotEl);syncCustomInput(currentColor);updateSwatches(currentColor);}const iconOn=isIconColorOn();wrap.classList.toggle('accent-icons',iconOn);iconColorToggle.checked=iconOn;const topOn=isTopColorOn();wrap.classList.toggle('accent-top',topOn);topColorToggle.checked=topOn;flashToggle.checked=isFlashOn();const clockOn=isClockOn();wrap.classList.toggle('clock-hidden',!clockOn);clockToggle.checked=clockOn;const spOn=isSpeedPopupOn();wrap.classList.toggle('speed-popup-hidden',!spOn);speedPopupToggle.checked=spOn;colorGlobalToggle.checked=isColorGlobalOn();};
        const onUnload=()=>{if(!episodeEnded())saveResumePos(video.currentTime);};
        const removeFs=fsChange(onFs);
        document.addEventListener('keydown',onKey);window.addEventListener('beforeunload',onUnload);window.addEventListener('storage',onStorage);
        cleanup=()=>{removeFs();document.removeEventListener('keydown',onKey);window.removeEventListener('beforeunload',onUnload);window.removeEventListener('storage',onStorage);stopSaving();_stopSavingFn=null;clearTimeout(hideTimer);clearCenterTimer();clearVolFlashTimer();clearSpeedTimer();clearFreezeTimer();clearClockTimer();clearMonitor();setSkipFlash(true);video.pause();video.src='';if(_preloadedVideo){_preloadedVideo.pause();_preloadedVideo.src='';_preloadedVideo.remove();_preloadedVideo=null;}_preloadedToken=null;_preloadedUrl=null;cleanup=null;};
        wrap._play=()=>_play();wrap._showResumeTst=s=>showResumeToast(s);wrap._setSkipFlash=setSkipFlash;
        return wrap;
    }

    // ── Mount (windowed) ──────────────────────────────────────────────────────
    function mountPlayer(url){
        if(!url)return;const container=document.querySelector('#player');if(!container)return;
        const existing=container.querySelector('#aw-np-video');
        if(existing&&existing.getAttribute('src')===url)return;
        if(cleanup)cleanup();injectStyle();container.innerHTML='';container.appendChild(buildPlayer(url));
    }

    // ── Dispatch desktop/mobile ───────────────────────────────────────────────
    function injectStyle(){isMobile?injectStyleMobile():injectStyleDesktop();}
    function buildPlayer(url){return isMobile?buildPlayerMobile(url):buildPlayerDesktop(url);}

    // ── Stili mobile ──────────────────────────────────────────────────────────
    function injectStyleMobile(){
        if(document.getElementById('aw-np-style'))return;
        const s=document.createElement('style');s.id='aw-np-style';
        s.textContent=`
            #player{background:#000}*,*::before,*::after{box-sizing:border-box}*:focus{outline:none!important}button{-webkit-tap-highlight-color:transparent}
            #aw-np,#aw-np *{-webkit-touch-callout:none!important;-webkit-user-drag:none;user-select:none!important;-webkit-user-select:none!important}
            #aw-np{--np-bar-h:clamp(40px,5.2cqh,56px);--np-btn-size:clamp(36px,4.8cqh,52px);--np-svg-size:clamp(20px,2.7cqh,32px);--np-seek-h:30px;--np-top-h:52px;--np-fs-title:clamp(14px,2.4cqh,26px);--np-fs-subtitle:clamp(13px,2cqh,22px);--np-fs-body:clamp(13px,1.7cqh,17px);--np-fs-small:clamp(12px,1.5cqh,15px);--np-fs-micro:clamp(10px,1.2cqh,13px);--np-fs-brand:clamp(11px,1.6cqh,17px);--np-spinner-size:clamp(40px,6.5cqh,80px);container-type:size;position:relative;isolation:isolate;width:100%;height:100%;background:#000;display:flex;flex-direction:column;overflow:hidden;font-family:'Google Sans',Roboto,'Helvetica Neue',sans-serif;user-select:none;touch-action:pan-y}
            #aw-np-video{flex:1;width:100%;min-height:0;display:block;background:#000}
            #aw-np-bar,#aw-np-top,#aw-np-toast,#aw-np-error-toast,#aw-np-conn-toast,#aw-np-settings-panel,#aw-np-color-panel,#aw-np-menu-panel,.np-row-tip,.np-btn,.np-swatch,.np-switch-track,.np-switch-thumb,#aw-np-seek-fill,#aw-np-seek-buf,#aw-np-seek-thumb,#aw-np-title,#aw-np-epinfo,#aw-np-brand,#aw-np-clock,#aw-np-clock svg circle,#aw-np-clock .hand-h,#aw-np-clock .hand-m,#aw-np-clock .pin,#aw-np-spinner,#aw-np-time,#aw-np-speed-ind,#aw-np-speed-popup,#aw-np-buf-pct,#aw-np-dot,#aw-np-play-center{transition-property:color,background,background-color,fill,stroke,border-color,box-shadow;transition-duration:.4s;transition-timing-function:cubic-bezier(.4,0,.2,1)}
            .np-grad{position:absolute;left:0;right:0;height:140px;pointer-events:none;opacity:0;transition:opacity .3s cubic-bezier(.4,0,.2,1)}
            #aw-np.ui .np-grad{opacity:1}
            #aw-np-gradient{bottom:0;background:linear-gradient(to top,rgba(0,0,0,.9) 0%,rgba(0,0,0,.4) 60%,transparent 100%)}
            #aw-np-gradient-top{top:0;background:linear-gradient(to bottom,rgba(0,0,0,.9) 0%,rgba(0,0,0,.4) 60%,transparent 100%)}
            .np-ui-layer{opacity:0;transition:opacity .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1);pointer-events:none}
            #aw-np-top.np-ui-layer{transform:translateY(-12px)}
            #aw-np-controls.np-ui-layer{transform:translateY(8px)}
            #aw-np.ui #aw-np-top.np-ui-layer,#aw-np.ui #aw-np-controls.np-ui-layer{transform:translateY(0)}
            #aw-np.ui .np-ui-layer{opacity:1;pointer-events:all}
            #aw-np-top{position:absolute;top:0;left:0;right:0;height:var(--np-top-h);display:flex;align-items:center;justify-content:space-between;padding:0 14px}
            #aw-np-top-left{display:flex;flex-direction:column;gap:1px;overflow:hidden;flex:1}
            #aw-np-title{font-size:var(--np-fs-title);font-weight:600;color:var(--np-accent-bg-fg,#fff);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-shadow:0 1px 3px rgba(0,0,0,.8)}
            #aw-np-epinfo{font-size:var(--np-fs-subtitle);font-weight:400;color:var(--np-accent-bg-fg,rgba(255,255,255,.7));opacity:.8;text-shadow:0 1px 3px rgba(0,0,0,.8)}
            #aw-np-top-right{display:flex;align-items:center;gap:10px;flex-shrink:0}
            #aw-np-dot{width:10px;height:10px;border-radius:50%;background:var(--np-accent,#fff);cursor:pointer;flex-shrink:0;transition:transform .2s cubic-bezier(.4,0,.2,1);position:relative}
            #aw-np-kbd-btn{display:none!important}
            #aw-np-color-panel{position:absolute;top:var(--np-top-h);right:12px;background:var(--np-accent-bg,#000);border:1px solid color-mix(in srgb,var(--np-accent,#fff) 20%,transparent);border-radius:12px;padding:clamp(10px,2cqw,14px);display:flex;flex-direction:column;gap:clamp(8px,1.5cqw,12px);font-size:var(--np-fs-body);color:var(--np-accent-bg-fg,rgba(255,255,255,.9));z-index:25;opacity:0;transform:scale(.9) translateY(-8px);transform-origin:top right;pointer-events:none;transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);box-shadow:0 8px 24px rgba(0,0,0,.5);max-height:calc(100% - 148px);overflow-y:auto}
            #aw-np-color-panel.open{opacity:1;transform:scale(1) translateY(0);pointer-events:all}
            #aw-np-color-swatches{display:flex;flex-wrap:wrap;gap:clamp(6px,1.2vw,8px);width:clamp(150px,30vw,184px)}
            .np-swatch{width:clamp(24px,4.5vw,30px);height:clamp(24px,4.5vw,30px);border-radius:50%;cursor:pointer;border:2px solid transparent;transition:transform .2s cubic-bezier(.4,0,.2,1),border-color .15s,box-shadow .2s;flex-shrink:0}
            .np-swatch.active{border-color:var(--np-accent,#fff);box-shadow:0 0 0 3px color-mix(in srgb,var(--np-accent,#fff) 35%,transparent),0 2px 6px rgba(0,0,0,.4);transform:scale(1.08)}
            .np-swatch:hover{transform:scale(1.12);box-shadow:0 3px 10px rgba(0,0,0,.45)}
            #aw-np-controls{position:absolute;bottom:0;left:0;right:0;display:flex;flex-direction:column;padding:0 6px 6px}
            #aw-np-seek-wrap{height:var(--np-seek-h);display:flex;align-items:center;cursor:pointer;padding:0 4px;touch-action:none}
            #aw-np-seek-track{position:relative;width:100%;height:4px;border-radius:2px;background:rgba(255,255,255,.2)}
            #aw-np-seek-buf{position:absolute;inset:0;border-radius:inherit;background:var(--np-accent-dim,rgba(255,255,255,.5));width:0;opacity:.6}
            #aw-np-seek-fill{position:absolute;inset:0;border-radius:inherit;background:var(--np-accent,#fff);width:0}
            #aw-np-seek-thumb{position:absolute;top:50%;left:0;width:16px;height:16px;background:var(--np-accent,#fff);border-radius:50%;transform:translate(-50%,-50%) scale(0);transition:transform .15s cubic-bezier(.4,0,.2,1);box-shadow:0 2px 6px rgba(0,0,0,.4)}
            #aw-np-seek-wrap:active #aw-np-seek-thumb,#aw-np-seek-wrap.seeking #aw-np-seek-thumb{transform:translate(-50%,-50%) scale(1.2)}
            #aw-np-bar{display:flex;align-items:center;height:var(--np-bar-h);gap:0}
            #aw-np-spacer{flex:1}
            .np-icon{display:contents}
            .np-btn{position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;width:var(--np-btn-size);height:var(--np-btn-size);min-width:unset;background:none;border:none;cursor:pointer;color:var(--np-accent-bg-fg,rgba(255,255,255,.85));padding:0;flex-shrink:0;border-radius:50%}
            .np-btn:active{background:var(--np-accent-state-2,rgba(255,255,255,.18))}
            .np-btn svg{display:block;fill:currentColor;flex-shrink:0;width:var(--np-svg-size);height:var(--np-svg-size);transition:transform .2s cubic-bezier(.2,0,0,1)}
            .np-btn:active svg{transition-duration:.1s;transform:scale(.88)}
            .np-btn svg line{stroke:currentColor}
            .accent-icons .np-btn{color:var(--np-accent,#fff)}
            .accent-icons .np-btn svg{fill:var(--np-accent,#fff)}
            .accent-icons .np-btn svg line{stroke:var(--np-accent,#fff)}
            .accent-top #aw-np-title{color:var(--np-accent,#fff)}
            .accent-top #aw-np-epinfo{color:var(--np-accent,#fff);opacity:.75}
            #aw-np-brand{font-size:var(--np-fs-brand);font-weight:500;letter-spacing:.04em;color:var(--np-accent-bg-fg,rgba(255,255,255,.5));opacity:.6;white-space:nowrap;line-height:1;text-transform:uppercase}
            .accent-top #aw-np-brand{color:var(--np-accent,#fff);opacity:.5}
            .np-ripple{position:absolute;border-radius:50%;background:var(--np-accent-state-2,rgba(255,255,255,.35));transform:scale(0);opacity:1;animation:np-ripple .55s cubic-bezier(.2,0,.2,1);pointer-events:none}
            @keyframes np-ripple{0%{transform:scale(0);opacity:1}60%{opacity:.6}100%{transform:scale(2.8);opacity:0}}
            #aw-np-time{font-size:var(--np-fs-small);font-weight:400;color:var(--np-accent-bg-fg,rgba(255,255,255,.85));letter-spacing:.03em;white-space:nowrap;padding:0 4px;font-variant-numeric:tabular-nums}
            #aw-np-menu-panel{position:absolute;bottom:calc(var(--np-bar-h) + var(--np-seek-h) + 8px);right:8px;background:var(--np-accent-bg,#282828);border:1px solid color-mix(in srgb,var(--np-accent,#fff) 20%,transparent);border-radius:12px;padding:8px;display:flex;flex-direction:column;gap:2px;z-index:25;opacity:0;transform:scale(.9) translateY(8px);transform-origin:bottom right;pointer-events:none;transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);box-shadow:0 8px 24px rgba(0,0,0,.5);max-height:calc(100% - 120px);overflow-y:auto}
            #aw-np-menu-panel.open{opacity:1;transform:scale(1) translateY(0);pointer-events:all}
            .np-menu-btn{display:flex;align-items:center;gap:12px;padding:10px 14px;border-radius:8px;border:none;background:none;color:var(--np-accent-bg-fg,rgba(255,255,255,.9));font-size:var(--np-fs-body);cursor:pointer;width:100%;text-align:left}
            .np-menu-btn:active{background:var(--np-accent-state-2,rgba(255,255,255,.18))}
            .np-menu-btn svg{fill:var(--np-accent-bg-fg,rgba(255,255,255,.9));width:22px;height:22px;flex-shrink:0}
            .np-menu-btn span{display:block}
            @media (orientation:portrait){#aw-np-menu-panel{flex-direction:row;padding:4px}.np-menu-btn{padding:8px;width:auto;gap:0}.np-menu-btn span{display:none}}
            #aw-np-settings-panel{position:absolute;bottom:calc(var(--np-bar-h) + var(--np-seek-h) + 8px);right:8px;background:var(--np-accent-bg,#000);border:1px solid color-mix(in srgb,var(--np-accent,#fff) 20%,transparent);border-radius:12px;padding:clamp(10px,2cqw,14px) clamp(12px,2.5cqw,18px);min-width:clamp(190px,40cqw,230px);display:flex;flex-direction:column;gap:clamp(7px,1.5cqw,10px);font-size:var(--np-fs-body);color:var(--np-accent-bg-fg,rgba(255,255,255,.9));z-index:25;opacity:0;transform:scale(.9) translateY(8px);transform-origin:bottom right;pointer-events:none;transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);box-shadow:0 8px 24px rgba(0,0,0,.5);max-height:calc(100% - 120px);overflow-y:auto}
            #aw-np-settings-panel.open{opacity:1;transform:scale(1) translateY(0);pointer-events:all}
            .np-switch{position:relative;width:36px;height:20px;flex-shrink:0;cursor:pointer}
            .np-switch input{opacity:0;width:0;height:0;position:absolute}
            .np-switch-track{position:absolute;inset:0;border-radius:10px;background:rgba(255,255,255,.2);transition:background .2s cubic-bezier(.4,0,.2,1)}
            .np-switch input:checked~.np-switch-track{background:var(--np-accent,#fff)}
            .np-switch-thumb{position:absolute;top:3px;left:3px;width:14px;height:14px;background:#fff;border-radius:50%;transition:transform .2s cubic-bezier(.4,0,.2,1);box-shadow:0 1px 4px rgba(0,0,0,.3)}
            .np-switch input:checked~.np-switch-thumb{transform:translateX(16px)}
            .np-switch input:not(:checked)~.np-switch-thumb{background:rgba(255,255,255,.8)}
            .np-row-tip{position:absolute;top:50%;right:calc(100% + 14px);transform:translateY(-50%);background:var(--np-accent-bg,#000);color:var(--np-accent-bg-fg,rgba(255,255,255,.9));font-size:var(--np-fs-small);line-height:1.5;padding:6px 10px;border-radius:8px;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .15s;z-index:20;box-shadow:0 4px 12px rgba(0,0,0,.4)}
            .np-row-tip::after{content:'';position:absolute;top:50%;left:100%;transform:translateY(-50%);border:5px solid transparent;border-left-color:var(--np-accent-bg,#000)}
            [data-tip]{margin:0 -8px;padding:6px 8px;border-radius:8px;transition:background .15s cubic-bezier(.4,0,.2,1)}[data-tip]:hover{background:var(--np-accent-state-1,rgba(255,255,255,.06))}[data-tip]:hover .np-row-tip{opacity:1;transition-delay:.5s}
            #aw-np-toast{position:absolute;bottom:calc(var(--np-bar-h) + var(--np-seek-h) + 16px);left:50%;transform:translateX(-50%);background:color-mix(in srgb,var(--np-accent-bg,#282828) 80%,transparent);color:var(--np-accent-bg-fg,rgba(255,255,255,.92));font-size:var(--np-fs-body);font-weight:500;padding:7px 16px;border-radius:24px;pointer-events:none;white-space:nowrap;opacity:1;transition:opacity .4s cubic-bezier(.4,0,.2,1);z-index:20;box-shadow:0 4px 12px rgba(0,0,0,.4)}

            #aw-np-speed-ind{font-size:var(--np-fs-micro);font-weight:400;color:var(--np-accent-bg-fg,rgba(255,255,255,.55));letter-spacing:.03em;white-space:nowrap;padding:0 0 0 4px;font-variant-numeric:tabular-nums;display:none}
            @media (orientation:landscape){#aw-np-speed-ind{display:inline}}
            #aw-np-speed-popup{position:absolute;top:10px;left:10px;background:transparent;color:rgba(255,255,255,.6);font-size:var(--np-fs-title);font-weight:500;padding:2px 4px;border-radius:4px;pointer-events:none;opacity:0;transition:opacity .3s cubic-bezier(.4,0,.2,1);z-index:20;letter-spacing:.02em;text-shadow:0 1px 6px rgba(0,0,0,.95)}
            #aw-np-speed-popup.on{opacity:1}
            #aw-np.ui #aw-np-speed-popup{opacity:0!important}
            #aw-np-clock{position:absolute!important;inset:10px 12px auto auto!important;display:flex;align-items:center;gap:5px;color:rgba(255,255,255,.6);font-size:clamp(18px,3.1cqh,34px);font-weight:500;padding:2px 4px;pointer-events:none;z-index:20;letter-spacing:.03em;text-shadow:0 1px 6px rgba(0,0,0,.95);font-variant-numeric:tabular-nums;transition:opacity .3s cubic-bezier(.4,0,.2,1);flex:none;transform:none;margin:0}
            #aw-np-clock svg{width:1em;height:1em;flex-shrink:0;display:block;filter:drop-shadow(0 0 1px rgba(0,0,0,.95)) drop-shadow(0 1px 3px rgba(0,0,0,.7))}
            #aw-np-clock .hand-h{fill:var(--np-accent,#fff);fill-opacity:1;stroke:var(--np-accent,#fff)}#aw-np-clock .pin{fill:var(--np-accent,#fff);fill-opacity:1;stroke:var(--np-accent,#fff)}#aw-np-clock .hand-m{fill:currentColor}
            #aw-np.ui #aw-np-clock{opacity:0!important;visibility:hidden}
            #aw-np.clock-hidden #aw-np-clock{display:none!important}
            #aw-np.speed-popup-hidden #aw-np-speed-popup{display:none!important}
            #aw-np-conn-toast{position:absolute;top:clamp(12px,1.7cqh,18px);left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:8px;padding:6px 12px;border-radius:12px;font-size:calc(var(--np-fs-body) * .82);font-weight:500;color:rgba(255,255,255,.95);z-index:22;box-shadow:0 4px 14px rgba(0,0,0,.45),0 1px 3px rgba(0,0,0,.3);pointer-events:all;white-space:nowrap;opacity:0;transition:opacity .35s cubic-bezier(.4,0,.2,1);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.08)}
            #aw-np-conn-toast.slow{background:rgba(210,100,15,.78)}
            #aw-np-conn-toast.good{background:rgba(30,155,65,.78)}
            #aw-np-conn-toast .conn-msg{display:flex;flex-direction:column;gap:2px;line-height:1.3;text-align:center;letter-spacing:.025em;flex:1}
            #aw-np-buf-pct{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:var(--np-fs-title);font-weight:600;color:var(--np-accent-bg-fg,rgba(255,255,255,.85));pointer-events:none;display:none;font-variant-numeric:tabular-nums;text-shadow:0 1px 4px rgba(0,0,0,.9)}
            #aw-np-buf-pct.on{display:block}
            #aw-np-error-toast{position:absolute;bottom:calc(var(--np-bar-h) + var(--np-seek-h) + 16px);left:50%;transform:translateX(-50%);background:rgba(180,30,30,.92);color:#fff;font-size:var(--np-fs-body);font-weight:500;letter-spacing:.02em;padding:7px 18px;border-radius:24px;pointer-events:all;white-space:nowrap;z-index:21;box-shadow:0 4px 12px rgba(0,0,0,.5);cursor:pointer}
            #aw-np-spinner{position:absolute;inset:0;margin:auto;width:var(--np-spinner-size);height:var(--np-spinner-size);border:3px solid rgba(255,255,255,.12);border-top-color:var(--np-accent,#fff);border-radius:50%;animation:np-spin .65s linear infinite;pointer-events:none;display:none}
            #aw-np-spinner.on{display:block}
            @keyframes np-spin{to{transform:rotate(360deg)}}
            .np-flash-circle{position:absolute;top:50%;left:50%;width:72px;height:72px;border-radius:50%;display:flex;align-items:center;justify-content:center;pointer-events:none;opacity:0;z-index:12;color:var(--np-accent-bg-fg,rgba(255,255,255,.9))}
            .np-flash-circle::before{content:'';position:absolute;inset:0;border-radius:50%;background:var(--np-accent-bg,#1a1a2e);opacity:.8;pointer-events:none}
            .np-flash-circle.on{opacity:1}
            .np-flash-circle svg{fill:var(--np-accent-bg-fg,rgba(255,255,255,.9));opacity:1;width:34px;height:34px;position:relative;z-index:1}
            #aw-np-center{margin:-36px 0 0 -36px;transform:scale(.7);transition:opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.34,1.56,.64,1)}
            #aw-np-center.on{transform:scale(1)}
            #aw-np-vol-flash{transform:translate(-50%,-50%);transition:opacity .2s cubic-bezier(.4,0,.2,1)}
            #aw-np-vol-flash svg{display:block}

            #aw-np-play-center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:64px;height:64px;border-radius:50%;display:flex;align-items:center;justify-content:center;pointer-events:all;z-index:5;color:var(--np-accent-bg-fg,rgba(255,255,255,.9))}
            #aw-np-play-center::before{content:'';position:absolute;inset:0;border-radius:50%;background:var(--np-accent-bg,#1a1a2e);opacity:.85;pointer-events:none}
            #aw-np-play-center svg{fill:var(--np-accent-bg-fg,rgba(255,255,255,.9));width:30px;height:30px;position:relative;z-index:1}
            .np-seek-flash{position:absolute;top:0;bottom:0;width:25%;display:flex;align-items:center;justify-content:center;pointer-events:none;opacity:0;transition:opacity .2s}
            .np-seek-flash.on{opacity:1}
            #aw-np-seek-flash-left{left:0}
            #aw-np-seek-flash-right{right:0}
            .np-seek-flash svg{fill:rgba(255,255,255,.7);width:40px;height:40px}
            .np-vol-bar{position:absolute;top:0;bottom:0;width:25%;display:flex;align-items:center;justify-content:center;pointer-events:none;opacity:0;transition:opacity .3s}
            .np-vol-bar.on{opacity:1}
            #aw-np-vol-bar-left{left:0}
            #aw-np-vol-bar-right{right:0}
            @media (orientation:landscape){.np-portrait-only{display:none!important}}
            @media (orientation:portrait){.np-landscape-only{display:none!important}}
        `;
        document.head.appendChild(s);
    }

    // ── Build player mobile ───────────────────────────────────────────────────
    function buildPlayerMobile(videoUrl){
        const{video,vol,muted,_play}=initVideo(videoUrl);
        const{wrap,grad,gradTop,spinner,center,ctrls,timeEl,SEP}=buildShellElements();

        const{flash,flashBrief,setSkipFlash,clearTimer:clearCenterTimer}=buildCenterFlash(center);
        const ep=buildEpisodeActions({video,_play,flash});

        const{speedIndEl,speedPopup,updateSpeedInd,showSpeedPopup,clearTimer:clearSpeedTimer}=buildSpeedIndicator(loadSpeed());
        const{bufPctEl}=buildBufferingIndicator(video,spinner);
        const{seekWrap,isSeeking}=buildSeekBar(video,false,()=>{timeEl.textContent=fmt(video.currentTime)+' / '+fmt(video.duration);});

        const mkMBtn=(id,html)=>{const b=mk('button');b.className='np-btn';b.id=id;b.innerHTML=html;b.tabIndex=-1;return b;};
        const btnPlay=mkMBtn('aw-btn-play',IC.play),btnMute=mkMBtn('aw-btn-mute',muted?IC.mute:IC.vol);
        const btnPip=mkMBtn('aw-btn-pip',IC.pip),btnSettings=mkMBtn('aw-btn-settings',IC.settings);
        const btnMenu=mkMBtn('aw-btn-menu',IC.menu),btnFs=mkMBtn('aw-btn-fs',IC.fsOn);
        const btnRestart=mkMBtn('aw-btn-restart',IC.restart),btnUndo=mkMBtn('aw-btn-undo',IC.undo);
        const btnSkip=mkMBtn('aw-btn-skip',IC.skip),btnPrev=mkMBtn('aw-btn-prev',IC.prev),btnNext=mkMBtn('aw-btn-next',IC.next);
        const spacer=mk('div','aw-np-spacer');
        const bar=mk('div','aw-np-bar');
        [btnRestart,btnUndo,btnSkip,btnPrev,btnNext].forEach(b=>b.classList.add('np-landscape-only'));
        btnMenu.classList.add('np-portrait-only');
        bar.append(btnPlay,btnRestart,btnMute,timeEl,speedIndEl,spacer,btnUndo,btnSkip,btnPrev,btnNext,btnMenu,btnSettings,btnPip,btnFs);
        ctrls.append(seekWrap,bar);

        const menuPanel=mk('div','aw-np-menu-panel');
        const mkMenuBtn=(html,label,onClick)=>{const b=document.createElement('button');b.className='np-menu-btn';b.innerHTML=html+`<span>${label}</span>`;b.addEventListener('click',()=>{menuPanel.classList.remove('open');onClick();});return b;};
        menuPanel.append(
            mkMenuBtn(IC.restart,'Ricomincia',ep.restart),
            mkMenuBtn(IC.undo,'Annulla skip',ep.undo),
            mkMenuBtn(IC.skip,'Skip OP/ED',ep.skip),
            mkMenuBtn(IC.prev,'Episodio prec.',ep.prev),
            mkMenuBtn(IC.next,'Episodio succ.',ep.next)
        );

        const{settingsPanel,resumeToggle,autoEpToggle,autoPlayToggle,connMonitorToggle,seekSecs:getSeekSecs,speedVal:getSpeedVal,updateSeekVal,updateSpeedVal}=buildSettingsPanel(video,SEP,'Secondi saltati col doppio tap.',v=>{updateSpeedInd(v);showSpeedPopup(v);});
        let seekSecs=getSeekSecs(),speedVal=getSpeedVal();

        const{colorPanel,syncCustomInput,updateSwatches,topColorToggle,iconColorToggle,flashToggle,clockToggle,speedPopupToggle,colorGlobalToggle}=buildColorPanel(wrap,null,SEP);
        let currentColor=loadColor();

        const{topBar,dotEl}=buildTopBar(wrap,colorPanel);

        const playCenter=mk('div','aw-np-play-center');playCenter.classList.add('np-ui-layer');playCenter.innerHTML=IC.play;
        const seekFlashLeft=document.createElement('div');seekFlashLeft.className='np-seek-flash';seekFlashLeft.id='aw-np-seek-flash-left';seekFlashLeft.innerHTML=IC.seekBwd;
        const seekFlashRight=document.createElement('div');seekFlashRight.className='np-seek-flash';seekFlashRight.id='aw-np-seek-flash-right';seekFlashRight.innerHTML=IC.seekFwd;

        const volBarLeft=document.createElement('div');volBarLeft.id='aw-np-vol-bar-left';
        const volBarRight=document.createElement('div');volBarRight.id='aw-np-vol-bar-right';
        const BAR_S='position:absolute;top:0;bottom:0;width:25%;display:flex;align-items:center;justify-content:center;pointer-events:none;opacity:0;transition:opacity .3s cubic-bezier(.4,0,.2,1);z-index:50;';
        volBarLeft.style.cssText=BAR_S+'left:0;';volBarRight.style.cssText=BAR_S+'right:0;';
        const mkVolBarInner=()=>{
            const inner=document.createElement('div');
            inner.style.cssText='display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:6px;background:var(--np-accent-bg,#1c1c1c);border-radius:12px;padding:10px 0 12px;width:44px;height:48%;box-shadow:0 4px 16px rgba(0,0,0,.4);';
            const pct=document.createElement('div');pct.style.cssText='font-size:var(--np-fs-small);font-weight:500;color:var(--np-accent-bg-fg,rgba(255,255,255,.85));width:32px;text-align:center;font-variant-numeric:tabular-nums;letter-spacing:.02em;';
            const track=document.createElement('div');track.style.cssText='position:relative;width:4px;flex:1;border-radius:2px;background:rgba(255,255,255,.2);flex-shrink:0;';
            const fill=document.createElement('div');fill.style.cssText='position:absolute;bottom:0;left:0;right:0;border-radius:2px;background:var(--np-accent,#fff);';
            track.appendChild(fill);inner.append(pct,track);return{inner,pct,fill};
        };
        const{inner:volInnerL,pct:volPctL,fill:volBarFillL}=mkVolBarInner();
        const{inner:volInnerR,pct:volPctR,fill:volBarFillR}=mkVolBarInner();
        volBarLeft.appendChild(volInnerL);volBarRight.appendChild(volInnerR);

        let lastNonZeroVol=muted?(vol||1):vol;
        const{volFlash,showVolFlash,clearTimer:clearVolFlashTimer}=buildVolFlash(video);

        wrap.append(video,grad,gradTop,topBar,colorPanel,menuPanel,settingsPanel,spinner,bufPctEl,speedPopup,center,playCenter,seekFlashLeft,seekFlashRight,volBarLeft,volBarRight,volFlash,ctrls);
        const{clearMonitor}=buildConnectionMonitor(video,wrap);
        applyColor(currentColor,wrap,dotEl);
        const{clearTimer:clearClockTimer}=buildClock(wrap);
        const{reloadVideo,clearTimer:clearFreezeTimer}=buildErrorHandler(video,wrap,_play,'Sblocca video');

        let hideTimer=null;
        const toggle=()=>video.paused?_play():video.pause();
        const closepanels=()=>{settingsPanel.classList.remove('open');colorPanel.classList.remove('open');menuPanel.classList.remove('open');};
        const startHideTimer=()=>{clearTimeout(hideTimer);if(!video.paused)hideTimer=setTimeout(()=>{if(!wrap.querySelector('.open'))wrap.classList.remove('ui');},HIDE_DELAY_MS);};
        const showUi=()=>{closepanels();wrap.classList.add('ui');startHideTimer();};
        const hideUi=()=>{wrap.classList.remove('ui');clearTimeout(hideTimer);};
        const isOnControls=e=>{const t=e.target;return t&&(t.closest('#aw-np-controls')||t.closest('#aw-np-top')||t.closest('#aw-np-settings-panel')||t.closest('#aw-np-color-panel')||t.closest('#aw-np-menu-panel'));};
        video.addEventListener('pause',()=>{if(video.dataset.silentReload)return;wrap.classList.add('ui');clearTimeout(hideTimer);});
        video.addEventListener('play',()=>{if(video.dataset.silentReload)return;showUi();});

        [btnPlay,btnMute,btnPip,btnSettings,btnMenu,btnFs].forEach(addRipple);
        btnPlay.addEventListener('click',toggle);
        playCenter.addEventListener('click',e=>{e.stopPropagation();toggle();});
        wirePlayPauseEvents({video,onUpdate:p=>{const html=p?IC.pause:IC.play;btnPlay.innerHTML=html;playCenter.innerHTML=html;}});
        btnRestart.addEventListener('click',ep.restart);
        btnUndo.addEventListener('click',ep.undo);
        btnSkip.addEventListener('click',ep.skip);
        btnPrev.addEventListener('click',ep.prev);
        btnNext.addEventListener('click',ep.next);
        btnMute.addEventListener('click',()=>{if(video.muted||video.volume===0){video.muted=false;video.volume=lastNonZeroVol;}else{if(video.volume>0)lastNonZeroVol=video.volume;video.muted=true;}const m=(video.muted||video.volume===0);btnMute.innerHTML=m?IC.mute:IC.vol;saveVol(video.muted?lastNonZeroVol:video.volume,video.muted);showVolFlash(video.muted?'down':'up');});
        buildPipHandler({video,btnPip,wrap});
        let mobileFs=false;
        const setMobileFs=state=>{mobileFs=state;btnFs.innerHTML=state?IC.fsOff:IC.fsOn;};
        btnFs.addEventListener('click',()=>{if(mobileFs){document.exitFullscreen?.()?.catch?.(()=>{});}else{wrap.requestFullscreen?.()?.catch?.(()=>{});}});
        const removeFsM=fsChange(()=>{const fs=!!document.fullscreenElement;if(fs&&isAutoPlayOn()&&video.paused&&!episodeEnded())_play();setTimeout(()=>setMobileFs(fs),0);});
        bindPanelToggle(btnSettings,settingsPanel,[menuPanel,colorPanel],startHideTimer);
        bindPanelToggle(btnMenu,menuPanel,[settingsPanel,colorPanel],startHideTimer);
        bindPanelToggle(dotEl,colorPanel,[settingsPanel,menuPanel],startHideTimer);
        wrap.addEventListener('click',e=>{if(isOnControls(e))return;closepanels();startHideTimer();});
        let volBarTimer=null;
        const updateVolBars=()=>{const pct=(video.muted?0:video.volume)*100;const ps=Math.round(pct)+'%';volBarFillL.style.height=pct+'%';volBarFillR.style.height=pct+'%';volPctL.textContent=ps;volPctR.textContent=ps;};

        let volSliding=false,volSlideStartY=0,volSlideStartX=0,volSlideStartVol=0,volSlideEndTime=0;
        const isFullscreenLandscape=()=>window.innerWidth>window.innerHeight&&(!!document.fullscreenElement||window.innerHeight===screen.height||window.innerWidth===screen.width);

        // ── Volume popup posizione bande nere (portrait) ──────────────────────
        const updateVolBarPosition=()=>{
            if(window.innerWidth<window.innerHeight){
                const vRect=video.getBoundingClientRect();
                const wRect=wrap.getBoundingClientRect();
                const bandH=vRect.top-wRect.top;
                const topPct=bandH>20?((bandH/2-30)/wRect.height*100)+'%':'10%';
                volBarLeft.style.alignItems='flex-start';volBarRight.style.alignItems='flex-start';
                volBarLeft.style.paddingTop=topPct;volBarRight.style.paddingTop=topPct;
            } else {
                volBarLeft.style.alignItems='center';volBarRight.style.alignItems='center';
                volBarLeft.style.paddingTop='0';volBarRight.style.paddingTop='0';
            }
        };

        video.addEventListener('contextmenu',e=>e.preventDefault());

        // ── Volume slide (solo fullscreen landscape) ──────────────────────────
        wrap.addEventListener('touchstart',e=>{
            if(isOnControls(e))return;
            if(!isFullscreenLandscape())return;
            const touch=e.touches[0];
            if(touch.clientX<8||touch.clientX>window.innerWidth-8||touch.clientY<20)return;
            const rect=wrap.getBoundingClientRect(),x=touch.clientX-rect.left,quarter=rect.width/5;
            if(x<quarter||x>rect.width-quarter){volSliding=false;volSlideStartY=touch.clientY;volSlideStartX=touch.clientX;volSlideStartVol=video.muted?0:video.volume;}
        },{passive:true});
        wrap.addEventListener('touchmove',e=>{
            if(isOnControls(e))return;
            if(!isFullscreenLandscape())return;
            const touch=e.touches[0],rect=wrap.getBoundingClientRect(),x=touch.clientX-rect.left,quarter=rect.width/5;
            if(x>=quarter&&x<=rect.width-quarter)return;
            const dy=volSlideStartY-touch.clientY,dx=touch.clientX-volSlideStartX;
            if(!volSliding&&Math.abs(dx)>Math.abs(dy))return;
            if(!volSliding&&Math.abs(dy)<10)return;
            volSliding=true;
            const newVol=Math.max(0,Math.min(1,volSlideStartVol+dy/rect.height));
            video.volume=newVol;video.muted=newVol===0;
            const m=(video.muted||video.volume===0);btnMute.innerHTML=m?IC.mute:IC.vol;
            if(newVol>0)lastNonZeroVol=newVol;saveVol(newVol===0?lastNonZeroVol:newVol,newVol===0);
            updateVolBars();updateVolBarPosition();
            const slidingLeft=x<quarter;
            if(slidingLeft){volBarRight.style.opacity='1';volBarLeft.style.opacity='0';}
            else{volBarLeft.style.opacity='1';volBarRight.style.opacity='0';}
            clearTimeout(volBarTimer);
            volBarTimer=setTimeout(()=>{volBarLeft.style.opacity='0';volBarRight.style.opacity='0';},1500);
        },{passive:true});
        wrap.addEventListener('touchend',()=>{if(volSliding)volSlideEndTime=Date.now();volSliding=false;});
        wrap.addEventListener('touchcancel',()=>{if(volSliding)volSlideEndTime=Date.now();volSliding=false;});

        let tapTimer=null,lastTap=0,seekFlashLTimer=null,seekFlashRTimer=null;
        wrap.addEventListener('click',e=>{
            if(isOnControls(e))return;
            if(isSeeking())return;
            if(Date.now()-volSlideEndTime<300)return;
            const now=Date.now(),rect=wrap.getBoundingClientRect(),x=e.clientX-rect.left,quarter=rect.width/5;
            const inCenter=x>=quarter&&x<=rect.width-quarter;
            if(now-lastTap<300){
                clearTimeout(tapTimer);
                if(x<quarter){video.currentTime=Math.max(0,video.currentTime-seekSecs);flashBrief(IC.seekBwd);seekFlashLeft.classList.add('on');clearTimeout(seekFlashLTimer);seekFlashLTimer=setTimeout(()=>seekFlashLeft.classList.remove('on'),400);}
                else if(x>rect.width-quarter){video.currentTime=Math.min(video.duration||0,video.currentTime+seekSecs);flashBrief(IC.seekFwd);seekFlashRight.classList.add('on');clearTimeout(seekFlashRTimer);seekFlashRTimer=setTimeout(()=>seekFlashRight.classList.remove('on'),400);}
                else if(inCenter)toggle();
                lastTap=0;
            }else{tapTimer=setTimeout(()=>{if(wrap.classList.contains('ui'))hideUi();else showUi();},200);lastTap=now;}
        });

        const{showResumeToast,stopSaving,episodeEnded}=buildResumeLogic(video,wrap,getSpeedVal);
        const onStorage=e=>{
            if(!e.key?.startsWith('aw-np-'))return;
            resumeToggle.checked=isResumeOn();autoEpToggle.checked=isAutoEpOn();autoPlayToggle.checked=isAutoPlayOn();connMonitorToggle.checked=isConnMonitorOn();
            seekSecs=getSeekSecs();updateSeekVal();speedVal=getSpeedVal();updateSpeedVal();updateSpeedInd(speedVal);showSpeedPopup(speedVal);
            const newColor=loadColor();
            if(newColor!==currentColor){currentColor=newColor;applyColor(currentColor,wrap,dotEl);syncCustomInput(currentColor);updateSwatches(currentColor);}
            const iconOn=isIconColorOn();wrap.classList.toggle('accent-icons',iconOn);iconColorToggle.checked=iconOn;
            const topOn=isTopColorOn();wrap.classList.toggle('accent-top',topOn);topColorToggle.checked=topOn;
            flashToggle.checked=isFlashOn();const clockOn=isClockOn();wrap.classList.toggle('clock-hidden',!clockOn);clockToggle.checked=clockOn;const spOn=isSpeedPopupOn();wrap.classList.toggle('speed-popup-hidden',!spOn);speedPopupToggle.checked=spOn;colorGlobalToggle.checked=isColorGlobalOn();
        };
        const onUnload=()=>{if(!episodeEnded())saveResumePos(video.currentTime);};
        window.addEventListener('beforeunload',onUnload);
        window.addEventListener('storage',onStorage);
        cleanup=()=>{removeFsM();window.removeEventListener('beforeunload',onUnload);window.removeEventListener('storage',onStorage);stopSaving();_stopSavingFn=null;clearTimeout(hideTimer);clearCenterTimer();clearVolFlashTimer();clearTimeout(volBarTimer);clearTimeout(seekFlashLTimer);clearTimeout(seekFlashRTimer);clearTimeout(tapTimer);clearSpeedTimer();clearFreezeTimer();clearClockTimer();clearMonitor();setSkipFlash(true);video.pause();video.src='';if(_preloadedVideo){_preloadedVideo.pause();_preloadedVideo.src='';_preloadedVideo.remove();_preloadedVideo=null;}_preloadedToken=null;_preloadedUrl=null;cleanup=null;};
        wrap._play=()=>_play();wrap._showResumeTst=s=>showResumeToast(s);wrap._setSkipFlash=setSkipFlash;
        return wrap;
    }

    // ── Swap src (fullscreen) ─────────────────────────────────────────────────
    function swapVideoSrc(url){
        const video=document.querySelector('#aw-np-video');
        if(!video){mountPlayer(url);return;}
        if(video.getAttribute('src')===url)return;
        const wrap=document.querySelector('#aw-np');
        const swapToken=_activeToken;
        const swapKey=KEY_RESUME_PFX+(swapToken||location.pathname);
        wrap?._setSkipFlash(true);video.pause();video.src=url;
        video.addEventListener('loadedmetadata',()=>{
            const spd=loadSpeed();if(video.playbackRate!==spd)video.playbackRate=spd;
            if(isResumeOn()){const saved=parseFloat(lsGet(swapKey)??'');if(saved>=RESUME_MIN_POS&&isFinite(video.duration)&&video.duration-saved>=RESUME_END_GAP){video.currentTime=saved;wrap?._showResumeTst(saved);}}
            if(isAutoPlayOn()&&!!fsElement()){wrap?._play();video.addEventListener('playing',()=>wrap?._setSkipFlash(false),{once:true});}else{wrap?._setSkipFlash(false);}
        },{once:true});
        ['#aw-np-seek-fill','#aw-np-seek-thumb','#aw-np-seek-buf'].forEach((sel,i)=>{const el=document.querySelector(sel);if(el)el.style[i===1?'left':'width']='0%';});
        const timeEl=document.querySelector('#aw-np-time');if(timeEl)timeEl.textContent='00:00 / 00:00';
    }

    // ── Navigazione ───────────────────────────────────────────────────────────
    function setActiveEpisode(token){
        const all=Array.from(document.querySelectorAll('.episode a'));
        const idx=all.findIndex(a=>a.dataset.id===token);
        all.forEach((a,i)=>a.classList.toggle('active',i===idx));
        const prevBtn=document.querySelector('.prevnext.prev');if(prevBtn)prevBtn.style.display=idx>0?'':'none';
        const nextBtn=document.querySelector('.prevnext.next');if(nextBtn)nextBtn.style.display=idx<all.length-1?'':'none';
        const epInfoEl=document.querySelector('#aw-np-epinfo');
        if(epInfoEl&&idx!==-1){const num=all[idx].textContent.trim()||String(idx+1);const maxNum=all.reduce((m,a)=>{const n=parseFloat(a.textContent.trim());return isNaN(n)?m:Math.max(m,n);},0);epInfoEl.textContent=`Episodio ${num}/${maxNum>0?maxNum:all.length}`;}
        if(idx===-1)return;
        const epData=all[idx].dataset;
        const episodeId=epData.episodeId,epNum=epData.num||epData.episodeNum;
        const player=document.querySelector('#player');
        if(player){player.dataset.id=token;if(episodeId)player.dataset.episodeId=episodeId;if(epNum)player.dataset.num=epNum;}
        document.querySelectorAll('.episodeNum').forEach(el=>el.textContent=epNum||'');
        const _animeId=document.querySelector("#player")?.dataset.animeId||"";
        const _csrf=document.querySelector('meta[name="csrf-token"]')?.content||"";
        const _updatePageMeta=(eId,num)=>{
            fetchWithRetry(`/api/episode/download?id=${eId}`,{credentials:"same-origin"})
                .then(r=>r.json()).then(data=>{const dl=document.querySelector("#downloadLink");if(dl&&data?.url)dl.href=data.url;}).catch(()=>{});
            if(!_animeId)return;
            fetchWithRetry(`/api/comments/anime/get/${_animeId}/${eId}`,{
                method:"POST",credentials:"same-origin",
                headers:{"CSRF-Token":_csrf,"Content-Type":"application/x-www-form-urlencoded"}
            }).then(r=>r.text()).then(html=>{
                const el=document.querySelector("#comments-scrollover-wrapper");
                if(el)el.innerHTML=html;
                document.querySelector("#episode-comment")?.classList.add("active");
                const sp=document.querySelector("#episode-comment span");if(sp)sp.textContent=num;
                document.querySelectorAll("#anime-comment,#rules").forEach(e=>e.classList.remove("active"));
                pageWin.loadSideFeatures?.();
            }).catch(()=>{});
        };
        if(episodeId)_updatePageMeta(episodeId,epNum);
    }

    // ── loadEpisode ───────────────────────────────────────────────────────────
    function loadEpisode(token){
        if(!token)return;
        if(_stopSavingFn){_stopSavingFn();_stopSavingFn=null;}
        const vid=document.querySelector('#aw-np-video');if(vid&&_activeToken)saveResumePos(vid.currentTime);
        _activeToken=token;saveLastEpisode(token);setActiveEpisode(token);
        const wasFullscreen=!!fsElement();
        const _preUrl=(token===_preloadedToken&&_preloadedUrl)?_preloadedUrl:null;
        const _preVid=_preloadedVideo;
        const _preVidUsed=token===_preloadedToken&&!!_preVid;
        _preloadedToken=null;_preloadedUrl=null;_preloadedVideo=null;
        if(_preVid&&!_preVidUsed){_preVid.pause();_preVid.src='';_preVid.remove();}
        const _doLoad=url=>{if(!url)return;const epLink=document.querySelector(`.episode a[data-id="${token}"]`);if(epLink?.href)history.pushState({},'',epLink.href);if(wasFullscreen&&!!fsElement())swapVideoSrc(url);else mountPlayer(url);if(_preVid&&_preVidUsed)setTimeout(()=>{_preVid.pause();_preVid.src='';_preVid.remove();},4000);};
        if(_preUrl)_doLoad(_preUrl);else getUrlForToken(token).then(_doLoad);
    }

    // ── Wire navigazione ──────────────────────────────────────────────────────
    function wireControls(){
        document.querySelectorAll('.episode a').forEach(a=>{if(a.dataset.npWired)return;a.dataset.npWired='1';a.addEventListener('click',e=>{e.preventDefault();e.stopPropagation();loadEpisode(a.dataset.id);});});
        document.querySelectorAll('.prevnext').forEach(btn=>{if(btn.dataset.npWired)return;btn.dataset.npWired='1';btn.addEventListener('click',e=>{e.preventDefault();e.stopPropagation();const t=getAdjacentEpisode(btn.dataset.value);if(t)loadEpisode(t.dataset.id);});});
    }

    // ── Label "Better Player" ─────────────────────────────────────────────────
    function setupPlayerLabel(){
        let labelDone=false;
        const hide=()=>{
            ['.control[data-value="original"]','.control[data-value="alternative"]'].forEach(sel=>document.querySelectorAll(sel).forEach(el=>{if(el.dataset.npBlocked)return;el.dataset.npBlocked='1';el.style.setProperty('display','none','important');el.addEventListener('click',e=>{e.preventDefault();e.stopPropagation();},true);}));
            if(!document.getElementById('aw-bp-label')){const ref=document.querySelector('.control[data-value="original"]')||document.querySelector('.control[data-value="alternative"]');if(!ref)return;const label=document.createElement('div');label.id='aw-bp-label';label.className='control active';label.style.pointerEvents='none';label.innerHTML='<i style="color:#ec4f4f;" class="icon icon-random"></i> <span>Better Player</span>';ref.insertAdjacentElement('beforebegin',label);}
            labelDone=true;
        };
        hide();
        if(labelDone)return;
        const obs=new MutationObserver(()=>{hide();if(labelDone)obs.disconnect();});
        obs.observe(document.body,{childList:true,subtree:true});
    }

    // ── Init ──────────────────────────────────────────────────────────────────
    function init(){
        cleanupResumeStorage();injectStyle();
        const currentToken=document.querySelector('#player')?.dataset?.id;
        if(currentToken)_activeToken=currentToken;
        const lastToken=isAutoEpOn()?loadLastEpisode():null;
        if(lastToken&&lastToken!==currentToken){loadEpisode(lastToken);}
        else if(currentToken){saveLastEpisode(currentToken);getUrlForToken(currentToken).then(url=>{if(url)mountPlayer(url);});}
        else{const link=document.querySelector('#downloadLink');const href=link?.getAttribute('href')||'';const m=href.match(/[?&]id=(.+)/);const url=m?decodeURIComponent(m[1]):(href.startsWith('http')?href:null);if(url)mountPlayer(url);}
        wireControls();setupPlayerLabel();
    }

    if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',()=>setTimeout(init,200));}else{setTimeout(init,200);}
})();