Tighten bottom UI, fix ch-bug/ticker/hamburger, reduce gradients

Layout:
- Move NOW PLAYING ticker into #np-strip above scrubber; #bb is controls-only at 46px
- --bot-h: 76px → 46px; #tc repositioned to clear new ticker strip
- #np-strip added to idle slide-out animation

Bug fixes:
- Channel bug (#ch-bug) now hides during title card display, restores after
- Reset A.npTitle/A.npArtist in loadCh() so ticker always updates on channel change
- Hamburger (☰) and C key always open to MY LIST tab

Visual:
- .gt gradient 140px → 72px, .gb gradient 220px → 140px (less intrusive)

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
Aaron
2026-05-23 12:41:29 -04:00
parent e5780b2c17
commit 90642b22ec
+30 -28
View File
@@ -17,7 +17,7 @@
--accent:#ff2200;--accent2:#00d4ff;--text:#f0f0ff;--dim:#6668a0;
--font-d:'Bebas Neue',Impact,'Arial Black',sans-serif;
--font-b:'Rajdhani',sans-serif;
--top-h:52px;--bot-h:76px;
--top-h:52px;--bot-h:46px;
}
html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-family:var(--font-b);color:var(--text);user-select:none;-webkit-tap-highlight-color:transparent}
@@ -61,8 +61,8 @@ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-famil
#pw iframe{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);border:none;pointer-events:none}
/* Overlays */
.gt{position:absolute;top:0;left:0;right:0;height:140px;background:linear-gradient(180deg,rgba(6,6,15,.92) 0%,transparent 100%);z-index:2;pointer-events:none}
.gb{position:absolute;bottom:0;left:0;right:0;height:220px;background:linear-gradient(0deg,rgba(6,6,15,1) 0%,rgba(6,6,15,.92) 35%,rgba(6,6,15,.55) 65%,transparent 100%);z-index:2;pointer-events:none}
.gt{position:absolute;top:0;left:0;right:0;height:72px;background:linear-gradient(180deg,rgba(6,6,15,.92) 0%,transparent 100%);z-index:2;pointer-events:none}
.gb{position:absolute;bottom:0;left:0;right:0;height:140px;background:linear-gradient(0deg,rgba(6,6,15,1) 0%,rgba(6,6,15,.85) 30%,rgba(6,6,15,.4) 65%,transparent 100%);z-index:2;pointer-events:none}
.gr{position:absolute;top:0;right:0;bottom:0;width:220px;background:linear-gradient(270deg,rgba(6,6,15,.85) 0%,rgba(6,6,15,.4) 50%,transparent 100%);z-index:2;pointer-events:none}
.gl{position:absolute;top:0;left:0;bottom:0;width:180px;background:linear-gradient(90deg,rgba(6,6,15,.85) 0%,rgba(6,6,15,.4) 50%,transparent 100%);z-index:2;pointer-events:none}
#scanlines{position:absolute;inset:0;z-index:3;pointer-events:none;background:repeating-linear-gradient(0deg,transparent,transparent 3px,rgba(0,0,0,.055) 3px,rgba(0,0,0,.055) 4px);opacity:.5}
@@ -119,9 +119,8 @@ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-famil
#pb-thumb{position:absolute;right:-5px;top:-3px;width:10px;height:10px;background:#fff;border-radius:50%;opacity:0;transition:opacity .15s;pointer-events:none}
/* Bottom bar */
#bb{position:absolute;bottom:0;left:0;right:0;height:var(--bot-h);z-index:5;display:flex;flex-direction:column;justify-content:center;align-items:stretch;padding:5px 14px;gap:2px}
.bb-top{display:flex;align-items:center;gap:8px;}
.bb-bot{display:flex;justify-content:center;align-items:center}
#np-strip{position:absolute;bottom:calc(var(--bot-h) + 3px);left:0;right:0;height:26px;z-index:5;display:flex;align-items:center;padding:0 14px;gap:8px}
#bb{position:absolute;bottom:0;left:0;right:0;height:var(--bot-h);z-index:5;display:flex;align-items:center;justify-content:center;padding:0 14px}
.np-lbl{font-family:var(--font-d);font-size:12px;letter-spacing:2.5px;color:var(--accent);flex-shrink:0;display:flex;align-items:center;gap:5px;white-space:nowrap}
.np-lbl-dot{width:5px;height:5px;background:var(--accent);border-radius:50%;animation:dot-p 1s ease-in-out infinite}
.np-wrap{flex:1;overflow:hidden;height:26px;position:relative}
@@ -231,23 +230,23 @@ html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-famil
}
@media(max-width:420px){
.c-btn{width:30px;height:30px;font-size:13px}
#bb{gap:7px;padding:0 10px}
#np-strip{padding:0 10px}
.np-lbl{display:none}
}
/* ── Title card (lower-third) ── */
#tc{position:absolute;bottom:calc(var(--bot-h) + 16px);left:0;z-index:7;padding:0 24px 0 20px;pointer-events:none;opacity:0;transform:translateY(14px);transition:opacity .45s ease,transform .45s ease;max-width:75vw}
#tc{position:absolute;bottom:calc(var(--bot-h) + 45px);left:0;z-index:7;padding:0 24px 0 20px;pointer-events:none;opacity:0;transform:translateY(14px);transition:opacity .45s ease,transform .45s ease;max-width:75vw}
#tc.show{opacity:1;transform:translateY(0)}
#tc.hide{opacity:0;transform:translateY(6px);transition:opacity .6s ease,transform .6s ease}
.tc-bar{position:absolute;left:0;top:4px;bottom:4px;width:4px;background:var(--accent)}
.tc-artist{font-family:var(--font-d);font-size:clamp(13px,1.8vw,18px);letter-spacing:3px;color:var(--accent2);text-transform:uppercase;line-height:1.2;margin-bottom:3px;text-shadow:0 1px 12px rgba(0,0,0,.9)}
.tc-title{font-family:var(--font-d);font-size:clamp(26px,4.5vw,52px);letter-spacing:1px;color:#fff;line-height:1.05;text-shadow:0 2px 24px rgba(0,0,0,.95)}
@media(max-width:600px){
#tc{max-width:90vw;bottom:calc(var(--bot-h) + 10px)}
#tc{max-width:90vw;bottom:calc(var(--bot-h) + 39px)}
}
/* ── Idle / broadcast mode ── */
#tb,#bb,#pb-wrap{
#tb,#bb,#pb-wrap,#np-strip{
will-change:transform,opacity;
transition:transform .5s cubic-bezier(.4,0,.15,1), opacity .5s ease;
}
@@ -257,6 +256,7 @@ body.idle{cursor:none}
body.idle #tb{transform:translateY(-120%) scaleY(0.5);transform-origin:top center;opacity:0}
body.idle #bb{transform:translateY(120%) scaleY(0.5);transform-origin:bottom center;opacity:0}
body.idle #pb-wrap{opacity:0}
body.idle #np-strip{transform:translateY(120%) scaleY(0.5);transform-origin:bottom center;opacity:0}
body.idle #scanlines{opacity:.68}
body.idle #ch-bug{opacity:1}
body.idle #tc{bottom:20px}
@@ -370,23 +370,22 @@ body.idle .gt,body.idle .gb,body.idle .gr,body.idle .gl{opacity:0;transition:opa
<div id="pb"><div id="pb-thumb"></div></div>
</div>
<div id="bb">
<div class="bb-top">
<div class="np-lbl"><span class="np-lbl-dot"></span><span>NOW PLAYING</span></div>
<div class="np-wrap">
<div id="np-ticker">
<span class="np-art" id="npa"></span><span id="npt">Select a channel above to begin</span>
</div>
<div id="np-strip">
<div class="np-lbl"><span class="np-lbl-dot"></span><span>NOW PLAYING</span></div>
<div class="np-wrap">
<div id="np-ticker">
<span class="np-art" id="npa"></span><span id="npt">Select a channel above to begin</span>
</div>
</div>
<div class="bb-bot">
<div class="ctrls">
<button class="c-btn" id="b-prev" title="Previous (&#8592;)">&#9194;</button>
<button class="c-btn" id="b-play" title="Play / Pause (Space)">&#9654;</button>
<button class="c-btn" id="b-next" title="Next (&#8594;)">&#9193;</button>
<button class="c-btn" id="b-shuf" title="Shuffle (S)">&#8652;</button>
<button class="c-btn" id="b-sb" title="Channels (C)">&#9776;</button>
</div>
</div>
<div id="bb">
<div class="ctrls">
<button class="c-btn" id="b-prev" title="Previous (&#8592;)">&#9194;</button>
<button class="c-btn" id="b-play" title="Play / Pause (Space)">&#9654;</button>
<button class="c-btn" id="b-next" title="Next (&#8594;)">&#9193;</button>
<button class="c-btn" id="b-shuf" title="Shuffle (S)">&#8652;</button>
<button class="c-btn" id="b-sb" title="Channels (C)">&#9776;</button>
</div>
</div>
@@ -531,6 +530,7 @@ function loadCh(i){
A.player.stopVideo();
const startIdx=A.shuffled?Math.floor(Math.random()*30):0;
A.player.loadPlaylist({list:ch.pid,listType:'playlist',index:startIdx});
A.npTitle=''; A.npArtist='';
setTicker('',ch.title);
setTimeout(()=>{
try{
@@ -572,16 +572,18 @@ function cleanArtist(s){
function showTitleCard(artist, title){
if(!title) return;
const card=qs('#tc');
const card=qs('#tc'), bug=qs('#ch-bug');
qs('#tc-artist').textContent = artist||'';
qs('#tc-title').textContent = title||'';
card.classList.remove('hide');
card.classList.add('show');
if(bug) bug.style.opacity='0';
clearTimeout(A.tcTimer);
// hold for 2.8s then fade out
A.tcTimer = setTimeout(()=>{
card.classList.remove('show');
card.classList.add('hide');
if(bug) bug.style.opacity='';
}, 2800);
}
@@ -981,7 +983,7 @@ function wireControls(){
localStorage.setItem('vf_shuffle', A.shuffled);
toast(A.shuffled?'\u21cc Shuffle ON':'Shuffle OFF');
};
qs('#b-sb').onclick=openSB;
qs('#b-sb').onclick=()=>{ openSB(); renderTab('channels'); };
qs('#b-shuf').classList.toggle('act',A.shuffled); // reflect default shuffle state
qs('#sb-close').onclick=closeSB;
qs('#ts').onclick=()=>{ try{A.player?.playVideo?.();}catch(e){} hideTap(); };
@@ -1044,7 +1046,7 @@ function wireControls(){
try{A.player?.setShuffle?.(A.shuffled);}catch(err){}
localStorage.setItem('vf_shuffle', A.shuffled);
toast(A.shuffled?'⇌ Shuffle ON':'Shuffle OFF');
} else if(e.code==='KeyC'){ openSB();
} else if(e.code==='KeyC'){ openSB(); renderTab('channels');
} else if(e.code==='KeyP'){ window.opener ? window.close() : popOut();
} else if(e.code==='KeyF'){
if(!document.fullscreenElement) document.documentElement.requestFullscreen?.().catch(()=>{});