=== CATEGORIAS ===
306-        <div class="nav navFocus">🎬 Movies</div>
307-        <div class="nav navFocus">▤ TV Shows</div>
308-        <div class="nav navFocus">⚙ Settings</div>
309-    </aside>
310-
311:    <section class="cats">
312-        <h1>All playlists</h1>
313:        <a class="cat navFocus <?=$cat===''?'active':''?>" href="tv_clean.php">All channels</a>
314-        <?php foreach($cats as $c): ?>
315:        <a class="cat navFocus <?=((string)$cat===(string)$c["category_id"])?'active':''?>" href="tv_clean.php?cat=<?=urlencode($c["category_id"])?><?=$keepEpg?>">
316-            <?=htmlspecialchars($c["category_name"] ?? "Sin nombre")?>
317-        </a>
318-        <?php endforeach; ?>
319-    </section>
320-

=== NAVFOCUS ===
304:        <div class="nav active navFocus">▣ TV EN VIVO</div>
305:        <div class="nav navFocus">⌂ Inicio</div>
306:        <div class="nav navFocus">🎬 Movies</div>
307:        <div class="nav navFocus">▤ TV Shows</div>
308:        <div class="nav navFocus">⚙ Settings</div>
313:        <a class="cat navFocus <?=$cat===''?'active':''?>" href="tv_clean.php">All channels</a>
315:        <a class="cat navFocus <?=((string)$cat===(string)$c["category_id"])?'active':''?>" href="tv_clean.php?cat=<?=urlencode($c["category_id"])?><?=$keepEpg?>">
323:            <div class="videoBox navFocus" tabindex="0">
325:                <video id="mainVideo" class="navFocus" tabindex="0" autoplay playsinline src="<?=htmlspecialchars($playUrl)?>"></video>
328:            <div class="info"><a class="refreshEpg navFocus" href="<?=htmlspecialchars($_SERVER["PHP_SELF"])?>?<?=htmlspecialchars(http_build_query(array_merge($_GET, ["epg_refresh"=>time()])))?>">↻ Actualizar EPG</a>
395:    <a class="row row36 navFocus <?=$is?'active':''?>"
433:        Array.from(document.querySelectorAll('.side .navFocus')),

=== FOCUS CSS ===
185-.info h2{margin:0 0 12px;font-size:34px}
186-.info p{margin:5px 0;font-size:17px;color:#ddd}
187-.timebar{display:grid;grid-template-columns:300px repeat(4,1fr);background:#223039;border-top:1px solid #334;border-bottom:1px solid #334}
188-.timebar div{padding:17px 18px;font-size:18px;font-weight:900;border-right:1px solid #394852}
189-.grid{height:778px;overflow-y:auto;background:#142026;scroll-behavior:smooth}
190-.row{display:grid;grid-template-columns:300px repeat(4,1fr);height:66px;color:white;text-decoration:none;border-bottom:1px solid #25343b;align-items:stretch}
191-.row.active{background:#087ec0}
192-.ch{display:flex;align-items:center;gap:14px;padding:8px 18px;font-size:17px;font-weight:900;min-height:66px}
193-.ch img{width:54px;height:42px;object-fit:contain;display:block;flex:0 0 54px}
194-.epg{padding:0 14px;color:#9caeb8;font-size:15px;border-left:1px solid #25343b;display:flex;align-items:center;justify-content:center;text-align:center;line-height:1.2;overflow:hidden}
195:.focus{outline:5px solid #00d9ff!important;box-shadow:0 0 25px #00d9ff!important;z-index:9}
196-.refreshEpg{outline:none;
197-position:absolute;top:22px;right:26px;
198-padding:10px 18px;border:1px solid #00d9ff;
199-border-radius:14px;background:rgba(0,217,255,.10);
200-color:white;text-decoration:none;font-weight:900;
201-box-shadow:0 0 18px #00d9ff55;
202-}
203-.refreshEpg:hover{background:rgba(0,217,255,.22)}
204-.toast{
205-position:absolute;top:78px;right:30px;
206-background:rgba(0,217,255,.18);
207-border:1px solid #00d9ff;color:white;
208-padding:12px 18px;border-radius:14px;
209-font-weight:900;box-shadow:0 0 18px #00d9ff77;
210-animation:fadeToast 2.2s forwards;
211-}
212-@keyframes fadeToast{0%{opacity:1}75%{opacity:1}100%{opacity:0}}
213-
214-.timelineWrap{
215-display:flex;
--
249-}
250-
251-.epgText{
252-font-size:14px;
253-font-weight:700;
254-line-height:1.2;
255-}
256-
257-
258-/* PLAYER_FOCUS_INVISIBLE */
259:.videoBox.focus{
260-    outline:none!important;
261-    box-shadow:none!important;
262-    border:0!important;
263-}
264-
265-
266-.epgDetail{margin-top:6px;color:white;max-width:640px}
267-.epgDate{font-size:12px;font-weight:800;color:#d9f6ff;margin-bottom:7px;letter-spacing:.3px}
268-.epgLabelNow{font-size:12px;font-weight:900;color:#ffd900;margin-top:3px}
269-.epgProgramNow{font-size:16px;font-weight:900;color:white;margin:2px 0 5px 0;line-height:1.08;max-width:620px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
270-.epgTimeSimple{font-size:12px;font-weight:700;color:#d9f6ff;margin-bottom:4px}
271-.epgBarLine{display:flex;align-items:center;gap:10px;margin:3px 0 8px 0}
272-.epgBarMini{width:300px;height:7px;border-radius:20px;background:rgba(220,230,235,.38);overflow:hidden}
273-.epgBarFill{height:100%;border-radius:20px;background:#ffd900}
274-.epgBarLine span{font-size:12px;font-weight:800;color:white;white-space:nowrap}
275-.epgLabelNext{font-size:12px;font-weight:900;color:#00d2ff;margin-top:3px}
276-.epgProgramNext{font-size:14px;font-weight:800;color:white;margin:2px 0;line-height:1.08;max-width:620px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
277-.epgNextTime{font-size:12px;font-weight:700;color:#cdefff}
278-
279-
280-.timebar36{display:flex;height:46px;background:#0878c8;color:white;font-weight:900;overflow:hidden}
281-.timeDate{width:330px;min-width:330px;padding:13px 16px;font-size:16px}
282-.timeScroll{display:flex;min-width:8640px}
283-.hourCell{width:240px;min-width:240px;padding:13px 0;font-size:15px;border-left:1px solid rgba(255,255,255,.18)}
284-.grid36Wrap{overflow:hidden;background:rgba(0,35,75,.55)}
285-.row36{display:flex;height:64px;color:white;text-decoration:none;border-bottom:1px solid rgba(255,255,255,.11)}
286:.row36.active,.row36.focus,.row36:hover{background:rgba(0,210,255,.35);outline:none}
287-.ch36{width:330px;min-width:330px;height:64px;display:flex;align-items:center;gap:12px;padding:0 14px;background:rgba(0,38,85,.82);font-size:15px;font-weight:900}
288-.ch36 img{width:52px;height:40px;object-fit:contain}
289-.track36{position:relative;height:64px;min-width:8640px;background:rgba(0,62,130,.42)}
290-.prog36{position:absolute;top:5px;height:54px;border-radius:7px;background:rgba(0,95,165,.74);border:1px solid rgba(0,210,255,.18);padding:7px 10px;overflow:hidden}
291-.prog36 b{display:block;font-size:14px;line-height:1.05;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
292-.prog36 small{display:block;font-size:10px;color:#cdefff;margin-top:4px}
293-.prog36.nowProg{background:rgba(0,190,230,.72);border:2px solid #ffd900}
294-.prog36.noinfo{text-align:center;color:#bdefff;font-weight:800;padding-top:18px}
295-
296-</style>
297-</head>
298-<body>
299-
300-
301-<div class="app">
302-    <aside class="side">
303-        <div class="logo"><span>puntoz</span> TV</div>
304-        <div class="nav active navFocus">▣ TV EN VIVO</div>
305-        <div class="nav navFocus">⌂ Inicio</div>
306-        <div class="nav navFocus">🎬 Movies</div>
--
444-
445-    if(!g[zone] || !g[zone].length) return;
446-
447-    idx[zone] = Math.max(0, Math.min(idx[zone], g[zone].length - 1));
448-
449-    const el = g[zone][idx[zone]];
450-    if(!el) return;
451-
452-    el.classList.add('focus');
453-    el.setAttribute('tabindex','0');
454:    el.focus({preventScroll:true});
455-    el.scrollIntoView({block:'nearest', inline:'nearest'});
456-}
457-
458-function enterItem(){
459-    const g = groups();
460-    const el = g[zone] && g[zone][idx[zone]];
461-    if(!el) return;
462-
463-    if(zone === 3){
464-        const v=document.getElementById('mainVideo');
465-        if(v){
466-            v.muted=false;
467-            v.volume=1.0;
468-            if(v.requestFullscreen) v.requestFullscreen();
469-            else if(v.webkitRequestFullscreen) v.webkitRequestFullscreen();
470-        }
471-        return;
472-    }
473-
474-    if(el.classList.contains('row') && typeof quickPlay === 'function'){
--
560-
561-    if(!url) return false;
562-
563-    document.querySelectorAll('.row').forEach(r=>r.classList.remove('active'));
564-    row.classList.add('active');
565-
566-    if(title) title.textContent=name;
567-
568-/* FOCO_PLAYER_AUTOMATICO_FINAL */
569-setTimeout(function(){
570:    document.querySelectorAll('.focus').forEach(function(x){x.classList.remove('focus');});
571-    var box=document.querySelector('.videoBox');
572-    if(box){
573-        box.classList.add('focus');
574-        box.setAttribute('tabindex','0');
575:        box.focus();
576-    }
577-},250);
578-
579-    video.muted = false;
580-    video.volume = 1.0;
581-    if(video.src !== url){
582-        video.src = url;
583-    }
584-    video.play().catch(()=>{});
585-
586-    return true;
587-}
588-
589-document.addEventListener('click',function(e){
590-    const row=e.target.closest('.row');
591-    if(row){
592-        e.preventDefault();
593-        quickPlay(row);
594-    }
595-},true);
--
608-    }
609-});
610-</script>
611-
612-<script>
613-let lastRow = null;
614-let lastTime = 0;
615-
616-function abrirFullscreenActual(){
617-    const v=document.getElementById('mainVideo');
618:    const focused=document.querySelector('.focus.row');
619-    const active=document.querySelector('.row.active');
620-
621-    let url = "";
622-
623-    if(focused && focused.getAttribute('data-play')) url = focused.getAttribute('data-play');
624-    else if(active && active.getAttribute('data-play')) url = active.getAttribute('data-play');
625-    else if(v && v.currentSrc) url = v.currentSrc;
626-    else if(v && v.src) url = v.src;
627-
628-    if(!url) return;
629-
630-    if(window.PuntozAndroid && PuntozAndroid.abrirFullscreen){
631-        PuntozAndroid.abrirFullscreen(url);
632-        return;
633-    }
634-
635-    if(v.requestFullscreen) v.requestFullscreen();
636-    else if(v.webkitRequestFullscreen) v.webkitRequestFullscreen();
637-}
638-
639-document.addEventListener('keydown',function(e){
640-    if(e.key !== 'Enter') return;
641-
642:    const el=document.querySelector('.focus');
643-
644-    if(el && el.classList.contains('videoBox')){
645-        e.preventDefault();
646-        abrirFullscreenActual();
647-        return;
648-    }
649-
650-    if(el && el.classList.contains('row')){
651-        const now=Date.now();
652-
653-        if(lastRow === el && (now-lastTime) < 700){
654-            e.preventDefault();
655-            if(typeof quickPlay === 'function') quickPlay(el);
656-            setTimeout(abrirFullscreenActual,250);
657-            return;
658-        }
659-
660-        lastRow = el;
661-        lastTime = now;
662-    }
