/* ===================================================================
   Sahrni Player v2 — cinematic dark UI. Mobile + TV in one build.
   Performance: body.lite (weak TV boxes) removes blur & heavy glows,
   keeps a cheap solid focus ring. Images are lazy-loaded.
   =================================================================== */

/* ── سهرة / "the evening" ──────────────────────────────────────────────
   The room is dark and warm; the screen is the only light source. Every surface is
   warm ink (a red-brown undertone, never blue-black) and the accent is an ember that
   reads like lamplight. This is the opposite of the cold cyan every competitor uses.
   --onAccent is the ink that sits ON the ember — never pure black, always warm.      */
:root{
  --bg:#100D0B; --bg2:#16120F; --surface:#1B1714; --surface2:#241D18; --card:#1F1915;
  --line:rgba(244,238,230,.09); --line2:rgba(244,238,230,.16);
  --text:#F4EEE6; --muted:#A4978A; --muted2:#6E635A;
  --accent:#E2703A; --accent2:#C4552A; --accentGrad:linear-gradient(135deg,#E8A44A,#D9552A);
  --onAccent:#160F0A;
  --gold:#E8A44A; --danger:#F0645C; --green:#4FB783;
  /* RGB triplets so glows/tints can follow the chosen accent. Before this, every glow was
     a hardcoded cyan — picking another theme left the halos the wrong colour. */
  --accentA:226,112,58; --accent2A:196,85,42; --bgA:16,13,11;
  --goldA:232,164,74; --greenA:79,183,131; --dangerA:240,100,92;
  --radius:16px; --radius-s:11px; --radius-l:22px;
  --shadow:0 14px 40px rgba(0,0,0,.6); --shadow-s:0 6px 18px rgba(0,0,0,.45);
  --glow:0 0 0 3px rgba(226,112,58,.55),0 0 26px rgba(226,112,58,.34);
  --focusRing:0 0 0 3px var(--accent);
  --ok:#4FB783;
}
/* Accent choices. The warm ink base never changes — only the light in the room does.
   Each keeps --onAccent dark enough to stay readable on its own accent. */
[data-theme="ember"]{ --accentA:226,112,58; --accent2A:196,85,42; --accent:#E2703A; --accent2:#C4552A; --accentGrad:linear-gradient(135deg,#E8A44A,#D9552A); --onAccent:#160F0A; --glow:0 0 0 3px rgba(226,112,58,.55),0 0 26px rgba(226,112,58,.34); }
[data-theme="gold"]{ --accentA:232,180,74; --accent2A:200,145,43; --accent:#E8B44A; --accent2:#C8912B; --accentGrad:linear-gradient(135deg,#F2CE72,#C8912B); --onAccent:#181206; --glow:0 0 0 3px rgba(232,180,74,.55),0 0 26px rgba(232,180,74,.34); }
[data-theme="rose"]{ --accentA:224,104,95; --accent2A:190,64,56; --accent:#E0685F; --accent2:#BE4038; --accentGrad:linear-gradient(135deg,#EE8B82,#BE4038); --onAccent:#1A0C0A; --glow:0 0 0 3px rgba(224,104,95,.55),0 0 26px rgba(224,104,95,.34); }
[data-theme="sage"]{ --accentA:127,176,105; --accent2A:90,138,71; --accent:#7FB069; --accent2:#5A8A47; --accentGrad:linear-gradient(135deg,#A3C98F,#5A8A47); --onAccent:#0D1409; --glow:0 0 0 3px rgba(127,176,105,.55),0 0 26px rgba(127,176,105,.34); }
/* kept so anyone who already picked the old cyan keeps it — retuned to sit on warm ink */
[data-theme="cyan"]{ --accentA:79,195,217; --accent2A:46,147,172; --accent:#4FC3D9; --accent2:#2E93AC; --accentGrad:linear-gradient(135deg,#7FDCEC,#2E93AC); --onAccent:#04141A; --glow:0 0 0 3px rgba(79,195,217,.55),0 0 26px rgba(79,195,217,.34); }
[data-theme="violet"]{ --accentA:167,139,250; --accent2A:124,58,237; --accent:#A78BFA; --accent2:#7C3AED; --accentGrad:linear-gradient(135deg,#C4B5FD,#7C3AED); --onAccent:#0F0A1A; --glow:0 0 0 3px rgba(167,139,250,.55),0 0 26px rgba(167,139,250,.34); }

@font-face{ font-family:'Tajawal'; font-style:normal; font-weight:400 900; font-display:swap; src:local('Tajawal'); }

*{ box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
html,body{ margin:0; padding:0; height:100%; background:#0B0908; color:var(--text);
  font-family:'Tajawal','Noto Kufi Arabic','Segoe UI',system-ui,Tahoma,Arial,sans-serif; -webkit-font-smoothing:antialiased; overflow:hidden; }
img{ display:block; max-width:100%; }
button{ font-family:inherit; cursor:pointer; border:0; background:none; color:inherit; }
input{ font-family:inherit; }
.hide{ display:none !important; }
.sp{ flex:1; }

/* lazy images */
img.lz{ background:var(--card); transition:opacity .25s; opacity:0; }
img.lz.ld{ opacity:1; }
body.lite img.lz{ transition:none; }

/* blur helper — only when NOT lite */
.blur{ background:rgba(var(--bgA),.94); }
body:not(.lite) .blur{ background:rgba(var(--bgA),.82); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); }

/* ============ Splash ============ */
#splash{ position:fixed; inset:0; z-index:200; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px;
  background:radial-gradient(760px 520px at 50% 34%,rgba(var(--accentA),.20),transparent 62%),var(--bg);
  transition:opacity .3s ease; }
#splash.hide{ opacity:0; pointer-events:none; }
/* The mark scales in, the name rises after it — the whole intro lands in ~0.5s, then holds. */
#splash .lg{ width:96px; height:96px; border-radius:26px; background:var(--accentGrad); color:var(--onAccent);
  display:grid; place-items:center; box-shadow:0 16px 44px rgba(var(--accentA),.45);
  animation:splashMark .5s cubic-bezier(.2,.9,.25,1) both, splashGlow 2.2s ease-in-out .5s infinite; }
#splash .lg svg{ width:54px; height:54px; }
#splash .nm{ display:flex; align-items:baseline; gap:10px; animation:splashRise .45s cubic-bezier(.2,.9,.25,1) .18s both; }
#splash .nm b{ font-size:30px; font-weight:900; letter-spacing:-.5px; color:var(--text); }
#splash .nm i{ font-size:24px; font-weight:700; font-style:normal; color:var(--accent); }
#splash .sub{ font-size:13px; color:var(--muted); animation:splashRise .45s cubic-bezier(.2,.9,.25,1) .3s both; }
@keyframes splashMark{ from{ opacity:0; transform:scale(.72); } to{ opacity:1; transform:scale(1); } }
@keyframes splashRise{ from{ opacity:0; transform:translateY(9px); } to{ opacity:1; transform:none; } }
@keyframes splashGlow{ 0%,100%{ box-shadow:0 16px 44px rgba(var(--accentA),.45); } 50%{ box-shadow:0 16px 60px rgba(var(--accentA),.72); } }
/* lite mode / low-end TVs: no animation, just the mark */
body.lite #splash .lg,body.lite #splash .nm,body.lite #splash .sub{ animation:none; }
.spin{ width:34px; height:34px; border-radius:50%; border:3px solid rgba(255,255,255,.14); border-top-color:var(--accent); animation:sp 1s linear infinite; }
@keyframes sp{ to{ transform:rotate(360deg); } }

/* ============ App shell ============ */
#app{ position:fixed; inset:0; display:flex; flex-direction:column; background:
  radial-gradient(900px 500px at 85% -8%,rgba(var(--accent2A),.16),transparent 62%),
  radial-gradient(700px 480px at -5% 8%,rgba(var(--accentA),.10),transparent 60%),var(--bg); }
body.lite #app{ background:var(--bg); }
#content{ position:relative; flex:1; overflow:hidden; }
.view{ position:absolute; inset:0; overflow-y:auto; overflow-x:hidden; -webkit-overflow-scrolling:touch;
  opacity:0; transform:translateY(8px); pointer-events:none; transition:opacity .22s,transform .22s; }
.view.on{ opacity:1; transform:none; pointer-events:auto; }
body.lite .view{ transition:none; transform:none; }
.view::-webkit-scrollbar{ width:0; }

/* Topbar */
/* The fade used to start at the very top, so by the middle of the bar the background was
   already half transparent — and the bar is sticky, so anything scrolling underneath showed
   THROUGH the title. On the empty-playlist screen that read as a rendering fault: the device
   ID printed straight over the word "Sahrni".
   Content passing under a sticky header is normal; being able to read it through the header
   is not. Solid behind the text, fading only in the last stretch so the edge stays soft. */
.topbar{ position:sticky; top:0; z-index:30; display:flex; align-items:center; gap:12px; padding:16px 18px 10px;
  background:linear-gradient(var(--bg) 0, var(--bg) 72%, rgba(var(--bgA),0) 100%); }
.brand{ display:flex; align-items:center; gap:9px; font-weight:900; font-size:19px; }
.brand .lg{ width:32px; height:32px; border-radius:9px; background:var(--accentGrad); display:grid; place-items:center; }
body:not(.lite) .brand .lg{ box-shadow:0 5px 16px rgba(var(--accentA),.45); }
.brand .lg svg{ width:18px; height:18px; }
.iconbtn{ width:40px; height:40px; border-radius:12px; background:var(--surface); border:1px solid var(--line); display:grid; place-items:center; color:var(--text); }
.iconbtn svg{ width:19px; height:19px; }
.iconbtn:active{ background:var(--surface2); }
.pill{ display:inline-flex; align-items:center; gap:6px; padding:6px 12px; border-radius:999px; font-weight:700; font-size:12px; white-space:nowrap; }
.pill.trial{ background:rgba(var(--goldA),.16); color:var(--gold); border:1px solid rgba(var(--goldA),.3); }
.pill.ok{ background:rgba(var(--greenA),.16); color:var(--green); border:1px solid rgba(var(--greenA),.3); }
.pill.live{ background:rgba(var(--dangerA),.16); color:var(--danger); border:1px solid rgba(var(--dangerA),.3); }
.pill .dot{ width:7px; height:7px; border-radius:50%; background:currentColor; }
body:not(.lite) .pill .dot{ box-shadow:0 0 8px currentColor; }

/* Hero */
.hero{ position:relative; height:270px; margin:2px 16px 6px; border-radius:var(--radius-l); overflow:hidden; }
body:not(.lite) .hero{ box-shadow:var(--shadow); }
.hero img{ width:100%; height:100%; object-fit:cover; }
.hero .grad{ position:absolute; inset:0; background:linear-gradient(180deg,rgba(var(--bgA),0) 20%,rgba(var(--bgA),.35) 55%,rgba(var(--bgA),.96) 100%); }
.hero .side{ position:absolute; inset:0; background:linear-gradient(90deg,rgba(var(--bgA),.85),transparent 55%); }
.hero .body{ position:absolute; right:20px; bottom:18px; left:20px; }
.hero .tag{ display:inline-flex; gap:8px; align-items:center; font-size:12px; font-weight:700; color:var(--accent); margin-bottom:8px; }
.hero .tag svg{ width:14px; height:14px; }
.hero h1{ margin:0 0 8px; font-size:27px; font-weight:900; letter-spacing:-.3px; }
.hero .meta{ display:flex; gap:12px; color:var(--muted); font-size:13px; font-weight:600; margin-bottom:14px; flex-wrap:wrap; }
.hero .meta b{ color:var(--gold); }
.hero .cta{ display:flex; gap:10px; }

.btn{ display:inline-flex; align-items:center; justify-content:center; gap:8px; height:44px; padding:0 20px; border-radius:13px; font-weight:800; font-size:15px; transition:transform .12s; }
.btn svg{ width:18px; height:18px; }
.btn.play{ background:var(--accentGrad); color:var(--onAccent); }
body:not(.lite) .btn.play{ box-shadow:0 8px 22px rgba(var(--accentA),.4); }
.btn.ghost{ background:rgba(255,255,255,.08); border:1px solid var(--line2); color:var(--text); }
.btn.block{ width:100%; }
.btn:active{ transform:scale(.97); }
.btn.sm{ height:38px; font-size:13px; padding:0 14px; border-radius:11px; }

/* Rails */
.rail{ margin:20px 0 6px; }
.rail .head{ display:flex; align-items:center; justify-content:space-between; padding:0 18px 12px; }
.rail .head h3{ margin:0; font-size:17px; font-weight:800; }
.rail .head a{ font-size:13px; color:var(--muted); font-weight:700; }
.row{ display:flex; gap:13px; overflow-x:auto; overflow-y:hidden; padding:2px 18px 8px; scroll-snap-type:x proximity; }
.row::-webkit-scrollbar{ height:0; }
.card{ flex:0 0 auto; width:126px; scroll-snap-align:start; position:relative; }
.card .thumb{ width:126px; height:186px; border-radius:var(--radius-s); overflow:hidden; background:var(--card); position:relative; border:1px solid var(--line); }
body:not(.lite) .card .thumb{ box-shadow:var(--shadow-s); }
.card .thumb img{ width:100%; height:100%; object-fit:cover; }
.card .rank{ position:absolute; top:8px; right:8px; background:rgba(var(--bgA),.78); border:1px solid var(--line2); border-radius:8px; padding:2px 8px; font-size:12px; font-weight:900; color:var(--gold); }
.card .badge{ position:absolute; bottom:8px; left:8px; background:var(--accent); color:var(--onAccent); border-radius:7px; padding:2px 7px; font-size:11px; font-weight:800; }
.card .prog{ position:absolute; left:8px; right:8px; bottom:8px; height:4px; border-radius:4px; background:rgba(255,255,255,.25); overflow:hidden; }
.card .prog i{ display:block; height:100%; background:var(--accent); }
.card .t{ margin-top:8px; font-size:13px; font-weight:700; line-height:1.3; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.card .s{ font-size:11px; color:var(--muted); font-weight:600; }

.card.ch{ width:180px; }
.card.ch .thumb{ width:180px; height:104px; display:grid; place-items:center; background:linear-gradient(160deg,#16223a,#0d1626); }
.card.ch .thumb .lg{ max-width:66%; max-height:56%; object-fit:contain; }
.card.ch .liveb{ position:absolute; top:8px; right:8px; display:flex; gap:5px; align-items:center; background:rgba(var(--dangerA),.94); color:#fff; border-radius:6px; padding:2px 7px; font-size:10px; font-weight:800; }
.card.ch .liveb i{ width:6px; height:6px; border-radius:50%; background:#fff; }
.card.ch .now{ margin-top:7px; font-size:11px; color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* poster grid (movies/series full) */
.grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:14px; padding:6px 16px 16px; }
.grid .card,.grid .card .thumb{ width:100%; }
.grid .card .thumb{ height:0; padding-bottom:148%; }
.grid .card .thumb img{ position:absolute; inset:0; }

/* Bottom nav (mobile) */
#tabbar{ height:74px; background:rgba(var(--bgA),.96); border-top:1px solid var(--line); display:flex; z-index:40; padding-bottom:6px; flex:0 0 auto; }
body:not(.lite) #tabbar{ background:rgba(var(--bgA),.85); backdrop-filter:blur(18px); -webkit-backdrop-filter:blur(18px); }
#tabbar button{ flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; color:var(--muted2); font-size:11px; font-weight:700; transition:color .15s; }
#tabbar button svg{ width:23px; height:23px; }
#tabbar button.on{ color:var(--accent); }
body:not(.lite) #tabbar button.on svg{ filter:drop-shadow(0 0 10px rgba(var(--accentA),.6)); }
.pad{ height:20px; }

/* chips */
.chips{ display:flex; gap:9px; overflow-x:auto; padding:6px 16px 14px; }
.chips::-webkit-scrollbar{ height:0; }
.chip{ flex:0 0 auto; padding:9px 16px; border-radius:999px; background:var(--surface); border:1px solid var(--line); font-weight:700; font-size:13px; color:var(--muted); }
.chip.on{ background:var(--accentGrad); color:var(--onAccent); border-color:transparent; }

/* Live list */
.clist{ padding:0 12px 12px; }
.crow{ display:flex; align-items:center; gap:12px; padding:11px; border-radius:14px; margin-bottom:8px; background:var(--surface); border:1px solid var(--line); }
.crow .num{ width:34px; text-align:center; font-weight:900; color:var(--muted); font-size:15px; }
.crow .lg{ width:52px; height:52px; border-radius:11px; background:linear-gradient(160deg,#16223a,#0d1626); display:grid; place-items:center; flex:0 0 auto; overflow:hidden; }
.crow .lg img{ max-width:76%; max-height:66%; object-fit:contain; }
.crow .info{ flex:1; min-width:0; }
.crow .info .nm{ font-weight:800; font-size:15px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.crow .info .pg{ font-size:12px; color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-top:2px; }
.crow .info .bar{ height:3px; border-radius:3px; background:rgba(255,255,255,.12); margin-top:7px; overflow:hidden; }
.crow .info .bar i{ display:block; height:100%; background:var(--accent); }
.crow .fav{ width:38px; height:38px; border-radius:10px; display:grid; place-items:center; color:var(--muted2); background:rgba(255,255,255,.05); }
.crow .fav.on{ color:var(--gold); }
.crow.playing{ border-color:rgba(var(--accentA),.5); }
.crow.playing .num{ color:var(--accent); }

/* Details */
/* Was a fixed 340px — on a short/landscape screen that ate half the height and pushed Play
   below the fold. Scale it to the viewport with a cap, and shrink hard when height is tight,
   so the poster, synopsis and buttons all land on one screen without scrolling. */
.det-hero{ position:relative; height:44vh; max-height:360px; min-height:200px; overflow:hidden; }
/* #detImg had no height, so the img's height:100% resolved against an auto-height parent and
   the backdrop rendered at its natural size — spilling out of the hero and covering the whole
   screen. The overlay, correctly clipped to the hero, then ended in a hard black seam across
   the middle of the picture: the "black box". Pin the wrapper to the hero and clip it. */
#detImg{ position:absolute; inset:0; }
.det-hero img{ width:100%; height:100%; object-fit:cover; display:block; }
/* Fully transparent at the top so the image reads clean, then a long gentle ramp that only
   gets dark where the text actually sits. No flat plateau, no visible edge. */
.det-hero .grad{ position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg,rgba(var(--bgA),0) 0%,rgba(var(--bgA),.06) 42%,rgba(var(--bgA),.34) 66%,rgba(var(--bgA),.78) 86%,var(--bg) 100%); }
/* the title sits over the picture, so give it its own lift instead of darkening the image */
.det-body h1{ text-shadow:0 2px 14px rgba(0,0,0,.5); }
.det-back{ position:absolute; top:14px; }
/* A remote HAS a back key, so the on-screen one is noise there — and worse, it was the
   focus landing spot when a screen opened: search opened focused on Back instead of the
   text box, settings on Back instead of the first option. Touch keeps every one of these:
   on a phone or the iPhone web app they are the only way back. display:none also removes
   them from focus.js, so data-foc-first falls through to the real first control. */
body.dpad .det-back{ display:none; }
body.dpad .topbar [data-act="back"]{ display:none; }
html[dir="rtl"] .det-back{ right:14px; }
html[dir="ltr"] .det-back{ left:14px; }
.det-body{ padding:0 20px 20px; margin-top:-60px; position:relative; z-index:3; }
.det-body .plot{ font-size:14px; color:var(--muted); line-height:1.65; margin:0 0 14px;
  display:-webkit-box; -webkit-line-clamp:4; -webkit-box-orient:vertical; overflow:hidden; }
.det-body h1{ font-size:25px; font-weight:900; margin:0 0 10px; }
.det-meta{ display:flex; flex-wrap:wrap; gap:8px; margin-bottom:14px; }
.tagm{ padding:4px 11px; border-radius:8px; background:var(--surface2); border:1px solid var(--line); font-size:12px; font-weight:700; color:var(--muted); }
.tagm.rate{ color:var(--gold); border-color:rgba(var(--goldA),.3); }
.det-cta{ display:flex; gap:11px; margin-bottom:8px; flex-wrap:wrap; }
/* Landscape phone: the whole detail must fit without scrolling to reach Play. */
@media (max-height:560px){
  .det-hero{ height:40vh; max-height:230px; min-height:150px; }
  .det-body{ margin-top:-44px; padding-bottom:14px; }
  .det-body h1{ font-size:20px; margin-bottom:6px; }
  .det-meta{ margin-bottom:8px; }
  .det-body .plot{ -webkit-line-clamp:2; margin-bottom:10px; }
}

/* season selector + episodes */
.seasonbar{ display:flex; gap:8px; overflow-x:auto; padding:6px 0 12px; }
.seasonbar::-webkit-scrollbar{ height:0; }
.eprow{ display:flex; align-items:center; gap:12px; padding:11px; border-radius:12px; margin-bottom:8px; background:var(--surface); border:1px solid var(--line); }
.eprow .n{ width:30px; text-align:center; font-weight:900; color:var(--muted); }
.eprow .nm{ flex:1; font-weight:700; font-size:14px; }
.eprow .pl{ width:36px; height:36px; border-radius:9px; background:var(--accentGrad); display:grid; place-items:center; color:var(--onAccent); }
.eprow .pl svg{ width:16px; height:16px; }

/* Kids */
.kids-lock{ position:absolute; inset:0; z-index:120; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:clamp(10px,3vh,30px) 30px; text-align:center; overflow-y:auto; -webkit-overflow-scrolling:touch;
  background:radial-gradient(700px 400px at 50% 12%,rgba(124,58,237,.25),transparent 60%),linear-gradient(180deg,#0b1020,#06090f);
  overflow-y:auto; -webkit-overflow-scrolling:touch; }
body.lite .kids-lock{ background:#0b1020; }
/* The expiry wall reuses .kids-lock so focus.js traps the remote inside it (it treats that
   class as the only focusable region). position:fixed, not absolute: the PIN pad sits over
   the app container, but this has to cover the player too, which is outside it. */
.sub-lock{ position:fixed; z-index:400; }
.sub-lock p{ max-width:420px; }
.sub-lock .subhow{ color:var(--muted); font-size:clamp(11px,1.5vh,13px); max-width:420px; margin-bottom:6px; }
.sub-lock .subportal{ font-weight:800; font-size:clamp(13px,1.9vh,16px); color:var(--accent); margin-bottom:clamp(6px,1.6vh,14px); word-break:break-all; }
.sub-lock .subids{ display:flex; gap:clamp(10px,3vw,26px); margin-bottom:clamp(6px,1.6vh,14px); flex-wrap:wrap; justify-content:center; }
.sub-lock .subids div{ background:rgba(255,255,255,.06); border-radius:10px; padding:8px 14px; min-width:130px; }
.sub-lock .subids span{ display:block; font-size:11px; color:var(--muted); margin-bottom:2px; }
.sub-lock .subids b{ font-size:clamp(13px,1.9vh,16px); letter-spacing:.5px; }
.sub-lock .submsg{ min-height:18px; font-size:clamp(11px,1.5vh,13px); color:var(--muted); margin-bottom:8px; }

/* First-run terms gate. Same trap as .sub-lock (focus.js only treats .kids-lock as
   focusable), but this is a paragraph the customer has to READ, so it is start-aligned
   and the 290px cap on .kids-lock p is lifted. */
.terms-lock{ position:fixed; z-index:410; background:linear-gradient(180deg,#120d0a,#080605); }
.terms-lock .tbox{ max-width:min(640px,90vw); text-align:start; }
.terms-lock .tbox p{ color:var(--muted); font-size:clamp(12px,1.7vh,15px); line-height:1.75; margin:0 0 clamp(6px,1.4vh,12px); max-width:none; }
.terms-lock .turl{ color:var(--accent); font-weight:800; font-size:clamp(12px,1.6vh,14px); word-break:break-all; margin-bottom:clamp(8px,2vh,16px); }

/* Empty-playlist screen: one centred block, code included. */
.empty.pl-empty{ padding:clamp(18px,6vh,48px) 24px; gap:10px; }
.empty.pl-empty .idcard{ width:min(420px,88vw); margin:6px 0 2px; direction:ltr; text-align:left; }
.pl-cta{ display:flex; gap:10px; flex-wrap:wrap; justify-content:center; }
.empty.pl-empty .pl-note{ color:var(--muted2); font-size:clamp(11px,1.5vh,13px); line-height:1.6; max-width:min(460px,90vw); }
/* #homeBody is deliberately excluded from the topbar clearance rule (the Home hero runs
   under the bar), so this screen has to reserve that height itself on TV. */
body.tv .empty.pl-empty{ padding-top:clamp(78px,13vh,130px); }
/* No playlist: the empty screen takes the whole app. Hiding the rail also removes those
   buttons from focus.js, so the remote has nowhere else to go. */
body.noplaylist #sidenav,
body.noplaylist #tabbar{ display:none; }
body.noplaylist .topbar{ pointer-events:none; }
body.noplaylist .topbar .iconbtn{ display:none; }
body.tv.noplaylist .empty.pl-empty{ padding-top:clamp(56px,9vh,96px); }
.kids-lock .em{ font-size:clamp(24px,5vh,52px); margin-bottom:clamp(0px,.6vh,4px); line-height:1.1; }
.kids-lock h2{ margin:0 0 clamp(2px,.8vh,6px); font-size:clamp(16px,2.6vh,22px); font-weight:900; }
.kids-lock p{ color:var(--muted); margin:0 0 clamp(6px,2vh,16px); font-size:clamp(12px,1.7vh,14px); max-width:290px; }
.pindots{ display:flex; gap:clamp(9px,1.6vh,14px); margin-bottom:clamp(7px,2vh,16px); }
.pindots i{ width:clamp(10px,1.6vh,14px); height:clamp(10px,1.6vh,14px); border-radius:50%; background:rgba(255,255,255,.16); }
.pindots i.f{ background:var(--accent); }
.pinpad{ display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(6px,1.1vh,10px); width:min(236px,72vw); margin:0 auto; }
.pinpad button{ height:clamp(36px,7vh,54px); border-radius:clamp(9px,1.6vh,14px); background:var(--surface); border:1px solid var(--line); font-size:clamp(16px,2.9vh,22px); font-weight:800; }
/* a short landscape phone can't show 5 rows at 60px — shrink so Cancel/0/Clear stay visible */
.pinpad button:active{ background:var(--surface2); }
.pinpad button.wide{ font-size:clamp(12px,2vh,15px); }
.pinpad button svg{ width:clamp(17px,2.8vh,23px); height:clamp(17px,2.8vh,23px); }
.kids-badge{ position:absolute; top:14px; z-index:35; }
html[dir="rtl"] .kids-badge{ left:14px; }
html[dir="ltr"] .kids-badge{ right:14px; }
.kbtn{ display:inline-flex; align-items:center; gap:7px; padding:8px 14px; border-radius:999px; background:rgba(124,58,237,.2); border:1px solid rgba(124,58,237,.4); color:#C4B5FD; font-weight:700; font-size:12px; }

/* pick-list (kids curation, playlists) */
.picklist{ padding:4px 16px 16px; }
.pickrow{ display:flex; align-items:center; gap:12px; padding:12px; border-radius:12px; margin-bottom:8px; background:var(--surface); border:1px solid var(--line); }
.pickrow .nm{ flex:1; font-weight:700; font-size:14px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.chk{ width:26px; height:26px; border-radius:8px; border:2px solid var(--line2); flex:0 0 auto; display:grid; place-items:center; }
.chk.on{ background:var(--accent); border-color:var(--accent); color:var(--onAccent); }
.chk svg{ width:16px; height:16px; opacity:0; }
.chk.on svg{ opacity:1; }

/* Player overlay */
#player{ position:absolute; inset:0; background:#000; z-index:100; display:none; }
#player.on{ display:block; }
#sv-video{ position:absolute; inset:0; width:100%; height:100%; object-fit:contain; background:#000; }
.pgrad{ position:absolute; inset:0; pointer-events:none; background:linear-gradient(180deg,rgba(0,0,0,.5),transparent 22%,transparent 62%,rgba(0,0,0,.85)); opacity:1; transition:opacity .3s; }
#player.hidectrl .pgrad,#player.hidectrl .ptop,#player.hidectrl .pbot{ opacity:0; pointer-events:none; }
.ptop{ position:absolute; top:0; left:0; right:0; padding:18px 20px; display:flex; align-items:center; gap:14px; transition:opacity .3s; }
.ptop .nm{ font-weight:900; font-size:18px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pbot{ position:absolute; bottom:0; left:0; right:0; padding:20px; transition:opacity .3s; }
.scrub{ height:5px; border-radius:5px; background:rgba(255,255,255,.22); margin-bottom:14px; overflow:hidden; }
.scrub i{ display:block; height:100%; width:0; background:var(--accentGrad); }
.ptime{ display:flex; justify-content:space-between; font-size:12px; color:var(--muted); margin-bottom:8px; font-variant-numeric:tabular-nums; }
.pctrl{ display:flex; align-items:center; gap:18px; justify-content:center; }
.pctrl .big{ width:64px; height:64px; border-radius:50%; background:var(--accentGrad); display:grid; place-items:center; }
body:not(.lite) .pctrl .big{ box-shadow:0 8px 26px rgba(var(--accentA),.5); }
.pctrl .big svg{ width:28px; height:28px; color:var(--onAccent); }
.pctrl .sm{ width:46px; height:46px; border-radius:50%; background:rgba(255,255,255,.12); display:grid; place-items:center; }
.pctrl .sm svg{ width:22px; height:22px; }
.pmeta{ position:absolute; top:18px; display:flex; gap:8px; }
html[dir="rtl"] .pmeta{ left:20px; } html[dir="ltr"] .pmeta{ right:20px; }
.pbadge{ position:absolute; inset:0; display:none; align-items:center; justify-content:center; flex-direction:column; gap:14px; color:#fff; }
#player.loading .pbadge.load{ display:flex; }
#player.err .pbadge.error{ display:flex; }
.pbadge .spin{ width:44px; height:44px; }

/* track sheet */
.sheet{ position:absolute; left:0; right:0; bottom:0; z-index:110; background:var(--surface); border-top:1px solid var(--line2); border-radius:20px 20px 0 0; padding:16px 18px 24px; transform:translateY(110%); transition:transform .25s; }
.sheet.on{ transform:none; }
.sheet h4{ margin:2px 0 12px; font-size:15px; }
.sheet .opt{ display:flex; align-items:center; justify-content:space-between; padding:12px 6px; border-bottom:1px solid var(--line); font-weight:700; }
.sheet .opt.sel{ color:var(--accent); }

/* forms / modal */
#modal{ position:absolute; inset:0; z-index:130; display:none; align-items:center; justify-content:center; padding:20px; background:rgba(2,4,8,.7); }
#modal.on{ display:flex; }
.card-box{ width:100%; max-width:440px; background:var(--surface); border:1px solid var(--line2); border-radius:20px; padding:22px; }
.card-box h3{ margin:0 0 16px; font-size:18px; }
.field{ margin-bottom:12px; }
.field label{ display:block; font-size:12px; color:var(--muted); font-weight:700; margin-bottom:6px; }
.field input,.field select{ width:100%; height:46px; border-radius:12px; background:var(--bg2); border:1px solid var(--line2); color:var(--text); padding:0 14px; font-size:15px; font-weight:600; }
.field input:focus,.field select:focus{ outline:none; border-color:var(--accent); }
.seg{ display:flex; background:var(--bg2); border:1px solid var(--line2); border-radius:12px; padding:4px; gap:4px; }
.seg button{ flex:1; height:38px; border-radius:9px; font-weight:700; color:var(--muted); font-size:14px; }
.seg button.on{ background:var(--accentGrad); color:var(--onAccent); }
.modal-cta{ display:flex; gap:10px; margin-top:18px; }

/* settings rows */
.setgroup{ padding:6px 16px; }
.setgroup .gt{ font-size:12px; color:var(--muted2); font-weight:800; text-transform:uppercase; letter-spacing:.6px; padding:14px 4px 8px; }
.setrow{ display:flex; align-items:center; gap:12px; padding:14px; border-radius:13px; margin-bottom:8px; background:var(--surface); border:1px solid var(--line); }
.setrow .ic{ width:38px; height:38px; border-radius:10px; background:var(--surface2); display:grid; place-items:center; flex:0 0 auto; color:var(--accent); }
.setrow .ic svg{ width:19px; height:19px; }
.setrow .tx{ flex:1; min-width:0; }
.setrow .tx .a{ font-weight:800; font-size:15px; }
.setrow .tx .b{ font-size:12px; color:var(--muted); margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.setrow .val{ color:var(--muted); font-weight:700; font-size:13px; }
.swatch{ display:flex; gap:8px; }
.swatch{ display:flex; gap:10px; flex-wrap:wrap; }
.swatch b{ width:30px; height:30px; border-radius:50%; display:block; border:2px solid transparent; }
.swatch b.on{ border-color:#fff; }
.swatch b.foc.focus,.pavsw b.foc.focus{ transform:scale(1.12); }
body.tv .swatch b{ width:40px; height:40px; }   /* readable and easy to land on at 3 metres */

/* activation / id card */
.idcard{ margin:8px 16px; padding:18px; border-radius:18px; background:linear-gradient(135deg,rgba(var(--accentA),.14),rgba(var(--accent2A),.10)); border:1px solid var(--line2); }
.idcard .r{ display:flex; justify-content:space-between; align-items:center; padding:8px 0; }
.idcard .k{ font-size:12px; color:var(--muted); font-weight:700; }
.idcard .v{ font-size:20px; font-weight:900; letter-spacing:1px; font-variant-numeric:tabular-nums; }
.idcard .v.mono{ font-size:16px; letter-spacing:.5px; }

/* empty states */
.empty{ display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding:60px 30px; gap:14px; color:var(--muted); }
.empty .em{ font-size:50px; }
.empty h3{ margin:0; color:var(--text); font-size:19px; }
.empty p{ margin:0; font-size:14px; max-width:280px; }

/* toast + loader */
#toast{ position:fixed; left:50%; bottom:96px; transform:translateX(-50%) translateY(20px); background:var(--surface2); border:1px solid var(--line2); color:var(--text); padding:12px 20px; border-radius:12px; font-weight:700; font-size:14px; z-index:300; opacity:0; pointer-events:none; transition:.25s; max-width:86%; text-align:center; }
#toast.show{ opacity:1; transform:translateX(-50%); }
#loader{ position:fixed; inset:0; z-index:150; display:none; align-items:center; justify-content:center; flex-direction:column; gap:16px; background:rgba(4,6,11,.72); }
#loader.show{ display:flex; }
#loader .t{ font-weight:700; color:var(--muted); }

/* search */
.searchbar{ display:flex; align-items:center; gap:10px; margin:6px 16px 12px; padding:0 14px; height:50px; background:var(--surface); border:1px solid var(--line2); border-radius:14px; }
.searchbar input{ flex:1; background:none; border:0; color:var(--text); font-size:16px; height:100%; }
.searchbar input:focus{ outline:none; }
.searchbar svg{ width:20px; height:20px; color:var(--muted); }

/* =================== TV MODE =================== */
#app{ flex-direction:row; }
#tabbar{ display:none; }
/* The rail used to be cold blue-grey (rgba(12,18,30)) — a leftover from the old palette that
   made it look bolted on from another app. It is warm سهرة ink now, so it reads as part of
   the product. The active tab gets an ember pill AND a bar on the inline edge (the TiviMate/
   Netflix cue), Settings is pushed to the bottom, and the label tag on focus is styled to
   match. Icons sit in evenly-sized soft cells instead of floating. */
#sidenav{ display:flex; width:88px; flex:0 0 auto; flex-direction:column; align-items:center; padding:18px 0 14px; gap:4px; z-index:40;
  background:var(--bg2); border-inline-end:1px solid var(--line); }
#sidenav .lg{ width:42px; height:42px; border-radius:12px; background:var(--accentGrad); display:grid; place-items:center; margin-bottom:16px; flex:0 0 auto; }
body:not(.lite) #sidenav .lg{ box-shadow:0 6px 16px rgba(var(--accentA),.4); }
#sidenav .lg svg{ width:22px; height:22px; }
.navi{ width:58px; height:50px; border-radius:14px; display:grid; place-items:center; color:var(--muted); position:relative; flex:0 0 auto; transition:color .15s, background .15s; }
.navi svg{ width:25px; height:25px; }
.navi:hover{ color:var(--text); }
/* the active tab: warm tint + ember icon + a bar on the inline-start edge */
.navi.on{ color:var(--accent); background:rgba(var(--accentA),.15); }
.navi.on:before{ content:''; position:absolute; inset-inline-start:-9px; top:11px; bottom:11px; width:3px; border-radius:0 3px 3px 0; background:var(--accent); }
/* Settings drops to the bottom of the rail, away from the content tabs */
.navi[data-k="settings"]{ margin-top:auto; }
/* focus label: a clean tag that slides in from the icon */
.navi .lbl{ position:absolute; inset-inline-start:66px; white-space:nowrap; background:var(--surface2); border:1px solid var(--line2);
  padding:7px 13px; border-radius:10px; font-size:14px; font-weight:700; opacity:0; transform:translateX(-6px); pointer-events:none;
  transition:opacity .14s, transform .14s; box-shadow:var(--shadow-s); z-index:50; }
[dir=rtl] .navi .lbl{ transform:translateX(6px); }
.navi.focus .lbl{ opacity:1; transform:none; }

#content{ flex:1; }
body.tv .topbar{ position:absolute; top:0; left:0; right:0; z-index:20; background:linear-gradient(rgba(var(--bgA),.65),transparent); }
/* The TV topbar is absolute so it can float over the Home hero. Every other screen is a plain
   list, so it must reserve the topbar's height or the first row hides underneath it. */
body.tv .view > .topbar + *:not(#homeBody){ margin-top:66px; }
body.tv .view > .topbar + .gwrap{ margin-top:66px; height:calc(100% - 66px); }
body.tv .clock{ position:absolute; top:20px; z-index:25; font-weight:800; font-size:18px; }
html[dir="rtl"] body.tv .clock{ inset-inline-start:40px; left:40px; right:auto; }
body.tv .hero{ height:44vh; margin:0; border-radius:0; }   /* leaves the first rail on screen */
body.tv .hero .body{ right:44px; left:44px; bottom:34px; }
body.tv .hero h1{ font-size:40px; }
body.tv .hero .tag{ font-size:17px; }
body.tv .hero .meta{ font-size:16px; }
body.tv .btn{ height:54px; font-size:19px; padding:0 26px; }
body.tv .rail .head{ padding:0 44px 14px; }
body.tv .rail .head h3{ font-size:26px; }
body.tv .rail .head a{ font-size:16px; }
body.tv .row{ padding:2px 44px 12px; gap:18px; }

/* ── 10-foot UI ───────────────────────────────────────────────────────────
   A TV is read from ~3 m, so type needs ~1.5× its phone size and nothing may fall
   below 18px. The old build scaled the hero and section headings but left the poster
   TITLES at 13px with no override at all, and packed 10 posters across 1920 — both
   unreadable from a sofa. 230px cards give ~7 across with the 8th peeking, which is
   what tells the eye the row scrolls.                                              */
body.tv .card{ width:230px; }
body.tv .card .thumb{ width:230px; height:338px; }
body.tv .card .t{ font-size:20px; margin-top:10px; }
body.tv .card .s{ font-size:16px; }
body.tv .card .badge{ font-size:14px; padding:3px 10px; border-radius:8px; }
body.tv .card .rank{ font-size:16px; padding:3px 10px; }
body.tv .card.ch{ width:300px; }
body.tv .card.ch .thumb{ width:300px; height:169px; }

/* live channel rows were phone-sized on TV too */
body.tv .crow{ padding:14px; gap:16px; }
body.tv .crow .num{ width:44px; font-size:19px; }
body.tv .crow .lg{ width:64px; height:64px; }
body.tv .crow .info .nm{ font-size:20px; }
body.tv .crow .info .pg{ font-size:16px; }
body.tv .crow .archmark{ font-size:15px; }
body.tv .live2 .catrow{ font-size:18px; padding:14px 14px; }
body.tv .pill{ font-size:15px; padding:8px 16px; }
body.tv .setrow .a{ font-size:19px; }
body.tv .setrow .b{ font-size:16px; }

/* 720p sets (older LG webOS, some Tizen) lay out at 1280 CSS px. The 1080p card would
   leave under 5 posters on screen and look comical, so scale the row down — the type
   stays large because the viewer distance has not changed. */
@media (max-width:1400px){
  body.tv .card{ width:165px; }
  body.tv .card .thumb{ width:165px; height:242px; }
  body.tv .card.ch{ width:214px; }
  body.tv .card.ch .thumb{ width:214px; height:120px; }
  body.tv .row{ padding:2px 32px 12px; gap:14px; }
  body.tv .rail .head{ padding:0 32px 12px; }
  body.tv .rail .head h3{ font-size:22px; }
  body.tv .hero .body{ right:32px; left:32px; }
  body.tv .hero h1{ font-size:32px; }
  body.tv .chips,body.tv .clist,body.tv .picklist,body.tv .grid,body.tv .det-body{ padding-left:32px; padding-right:32px; }
  body.tv .grid{ grid-template-columns:repeat(4,1fr); }
}
body.tv .chips{ padding:14px 44px; }
body.tv .clist,body.tv .picklist{ padding:0 44px 20px; }
body.tv .grid{ grid-template-columns:repeat(5,1fr); gap:16px; padding:14px 44px; }
body:not(.tv) .grid{ grid-template-columns:repeat(4,1fr); }
body.tv .det-body{ padding:0 44px 30px; }
body.tv .det-hero{ height:46vh; max-height:460px; }
body.tv .det-body h1{ font-size:32px; }
body.tv .det-body .plot{ font-size:17px; -webkit-line-clamp:3; max-width:900px; }

/* focus rings */
.foc{ transition:transform .12s; }
body.lite .foc{ transition:none; }
.card.foc.focus .thumb,.card.ch.foc.focus .thumb{ box-shadow:var(--focusRing); transform:scale(1.05); }
body:not(.lite) .card.foc.focus .thumb{ box-shadow:var(--glow); transform:scale(1.06); }
.crow.foc.focus,.eprow.foc.focus,.pickrow.foc.focus,.setrow.foc.focus,.chip.foc.focus{ box-shadow:var(--focusRing); }
.btn.foc.focus,.iconbtn.foc.focus,.navi.foc.focus,.pinpad button.foc.focus,.seg button.foc.focus,.sheet .opt.foc.focus,.swatch b.foc.focus,.pavsw b.foc.focus{ box-shadow:var(--focusRing); }
body:not(.lite) .navi.foc.focus{ box-shadow:var(--glow); }
.foc.focus{ outline:none; }

/* phone landscape safety */
@media (max-height:480px) and (orientation:landscape){
  .hero{ height:180px; }
}

/* ---- brand mark box (crescent + play) ---- */

/* settings row chevron (small, not giant) */
.setrow > svg{ width:22px; height:22px; flex:0 0 auto; color:var(--muted2); }

/* ===================================================================
   V1.01 — Live 2-column (categories left / channels right) + polish
   =================================================================== */
.view.live2{ display:flex; flex-direction:column; overflow:hidden; }
.live2 .livewrap{ flex:1; min-height:0; display:flex; align-items:stretch; }
.live2 .catcol{ width:38%; max-width:300px; min-width:116px; overflow-y:auto; padding:8px 8px 24px; border-inline-end:1px solid var(--line); }
.live2 .chcol{ flex:1; min-width:0; overflow-y:auto; padding:8px 10px 24px; }
/* ---- Kids "pick allowed content": same two columns as Channels ---- */
.pkhd{ font-size:10px; font-weight:800; letter-spacing:.6px; color:var(--muted2); padding:2px 8px 8px; }
.live2 .catrow .pknm{ display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* per-group counter, so a parent sees what is allowed without opening every group */
.pkn{ display:inline-block; margin-top:4px; font-size:10px; font-weight:800; color:var(--muted2);
  background:rgba(255,255,255,.06); border-radius:5px; padding:1px 6px; }
.pkn.on{ background:var(--accent); color:var(--onAccent); }
/* one press allows the whole group (was 80 presses for a kids group) */
.pkall{ display:flex; align-items:center; gap:10px; width:100%; text-align:start; margin-bottom:9px;
  padding:12px 12px; border-radius:12px; font-size:14px; font-weight:800; color:var(--accent);
  background:rgba(var(--accentA),.12); border:1px solid rgba(var(--accentA),.35); }
.pkall.on{ background:rgba(var(--accentA),.2); }
.pkall .chk{ flex:0 0 auto; }
.pkall.foc.focus{ box-shadow:var(--focusRing); }
body.tv .pkhd{ font-size:12px; }
body.tv .pkn{ font-size:12px; }
body.tv .pkall{ font-size:17px; padding:15px 14px; }
.live2 .catcol::-webkit-scrollbar,.live2 .chcol::-webkit-scrollbar{ width:0; }
.live2 .catrow{ display:block; width:100%; text-align:start; padding:12px 12px; margin-bottom:6px; border-radius:11px;
  color:var(--text); font-weight:700; font-size:14px; background:transparent; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.live2 .catrow.on{ background:var(--surface2); color:var(--accent); }
.live2 .clist{ padding:0; }
.live2 .crow{ margin-bottom:8px; }
.live2 .catrow.foc.focus{ box-shadow:var(--focusRing); background:var(--surface2); }
body.tv .live2 .catcol{ width:26%; max-width:300px; min-width:190px; padding:18px 10px 30px; }
body.tv .live2 .chcol{ padding:18px 22px 30px; }

/* focusable text inputs (search + add-playlist modal) show a ring on TV */
input.foc.focus{ box-shadow:var(--focusRing); border-radius:8px; }

/* distinct playback error box (no MAC/Key card) */
.errbox h3{ color:var(--danger); }
.errbox .em{ opacity:.9; }

/* =================== LANDSCAPE RAIL (mobile) =================== */
body:not(.tv) #sidenav{ width:64px; padding:14px 0; gap:6px; }
body:not(.tv) #sidenav .lg{ width:34px; height:34px; border-radius:10px; margin-bottom:10px; }
body:not(.tv) #sidenav .lg svg{ width:19px; height:19px; }
body:not(.tv) .navi{ width:46px; height:44px; border-radius:12px; }
body:not(.tv) .navi svg{ width:21px; height:21px; }
body:not(.tv) .navi .lbl{ display:none; }
.crow.playing{ border-color:var(--accent); background:rgba(var(--accentA),.07); }

/* =================== VOD groups-first =================== */
.vod2 .vsearch{ margin:10px 12px 6px; }
.vod2 #vodGrid{ padding:2px 12px 26px; }
.vod2 .vhint{ padding-top:70px; }

/* modal fits landscape screens: scroll inside the card */
#modal{ align-items:flex-start; }
#modal .card-box{ max-height: calc(100vh - 36px); overflow-y: auto; margin: auto; }

/* =================== VOD two-level (groups -> full-screen grid) =================== */
.vodg .vglist{ max-width:820px; width:100%; margin:14px auto 0; padding:6px 18px 28px; }
.vodg .vgtitle{ font-size:22px; font-weight:800; margin:6px 4px 16px; }
.vodg .vgrow{ width:100%; display:flex; justify-content:space-between; align-items:center; padding:15px 18px; margin-bottom:10px; border-radius:14px; background:var(--surface); border:1px solid var(--line); font-weight:700; font-size:15px; color:var(--text); }
.vodg .vgrow .arr{ color:var(--muted); font-size:20px; line-height:1; }
body.tv .vodg .vglist{ margin-top:40px; }
.vodc .vsearch{ margin:10px 16px 6px; }
.vodc #vodGrid{ padding:2px 16px 26px; }
.pickrow .del{ color:#ff5b5b; width:40px; height:40px; border-radius:10px; display:grid; place-items:center; background:rgba(255,91,91,.12); flex:0 0 auto; }
.pickrow .del svg{ width:20px; height:20px; }

/* immersive detail screens: hide the side rail */
body.immersive #sidenav{ display:none; }
/* selected + focused group rows (movies/series) — same language as Live */
.vodg .vgrow.on{ background:var(--surface2); color:var(--accent); border-color:var(--accent); }
.vodg .vgrow.on .arr{ color:var(--accent); }
.vodg .vgrow.foc.focus{ box-shadow:var(--focusRing); background:var(--surface2); border-color:var(--accent); }

/* settings-style screens keep a normal (in-flow) topbar even on TV */
.sheet .topbar{ position:relative; background:none; }
body.tv .sheet .topbar{ padding:18px 44px 10px; }
body.tv .sheet .setgroup:first-of-type{ margin-top:2px; }
/* playlist row + its own delete button (remote friendly) */
.pickline{ display:flex; align-items:stretch; gap:10px; margin-bottom:8px; }
.pickline .pickrow{ flex:1; margin-bottom:0; }
.pickline .delbtn{ width:56px; flex:0 0 auto; border-radius:12px; display:grid; place-items:center;
  background:rgba(255,91,91,.12); border:1px solid rgba(255,91,91,.35); color:#ff5b5b; }
.pickline .delbtn svg{ width:22px; height:22px; }
.pickline .delbtn.foc.focus{ background:#ff5b5b; color:#fff; box-shadow:var(--focusRing); }

/* d-pad focus works in every device mode — keep the ring visible everywhere */
.foc.focus{ outline:none; }
.card.foc.focus, .vgrow.foc.focus, .crow.foc.focus, .catrow.foc.focus,
.pickrow.foc.focus, .setrow.foc.focus, .navi.foc.focus, .iconbtn.foc.focus,
.btn.foc.focus, .chip.foc.focus, .delbtn.foc.focus{ box-shadow:var(--focusRing); }

/* NOTE: the TV type scale lives in ONE place — the 10-foot block further up. Earlier
   passes added competing `body.tv` rules down here with smaller values; because they came
   later they silently won, which is why poster titles rendered at 14px on a 1080p screen.
   Only genuinely-unique TV rules belong here. */
body.tv .vodg .vgrow{ font-size:19px; padding:17px 20px; }
body.tv .searchbar input{ font-size:20px; }

/* home on TV: hero + first rail both visible at 100% zoom */
body.tv .hero .body{ bottom:20px; }
body.tv .hero .tag{ display:none; }   /* the eyebrow is noise on a 44vh hero */
body.tv .hero .meta{ margin-bottom:10px; }
body.tv .rail{ margin-top:2px; }
body.tv .rail .head h2{ font-size:22px; }

/* channel rows: the name is the hero */
.crow .lg{ width:38px; height:38px; border-radius:8px; }
.crow .num{ width:30px; font-size:13px; }
.crow .info .nm{ font-size:16px; font-weight:800; }
/* catch-up marker: this channel keeps an archive you can rewind into */
.crow .archmark{ margin-inline-start:7px; font-size:12px; opacity:.75; color:var(--accent); vertical-align:1px; }
.crow .favmark{ width:22px; flex:0 0 auto; display:grid; place-items:center; color:transparent; }
.crow .favmark svg{ width:18px; height:18px; }
.crow .favmark.on{ color:#F2C14E; }
.crow.focus .favmark:not(.on){ color:rgba(255,255,255,.22); }   /* hint on the selected row only */
.crow .okhint{ display:none; font-size:10px; color:var(--muted2); background:rgba(255,255,255,.06);
  border-radius:5px; padding:2px 7px; margin-inline-start:8px; white-space:nowrap; flex:0 0 auto; }
.crow.focus .okhint{ display:block; }
/* (TV sizes for .crow intentionally live in the single 10-foot block above — do not
   re-declare them here; later duplicates are what shrank the rows on real TVs.) */

/* ---- transparent channel list over live playback (web player: Samsung/LG/phone-web) ----
   The container/row rules were missing entirely: only the three star rules below existed
   (still in the old blue palette). The JS created and toggled the panel correctly, but with
   no positioning it rendered as an unstyled block BELOW the video — invisible. jsdom tests
   cannot see that; a live browser session did. */
#p-chans{ position:absolute; top:0; bottom:0; width:min(400px,38%); display:none;
  flex-direction:column; z-index:40; padding:18px 14px 18px 18px;
  background:linear-gradient(90deg, rgba(var(--bgA),.88) 0%, rgba(var(--bgA),.72) 70%, rgba(var(--bgA),0) 100%); }
html[dir="ltr"] #p-chans{ left:0; }
html[dir="rtl"] #p-chans{ right:0; background:linear-gradient(270deg, rgba(var(--bgA),.88) 0%, rgba(var(--bgA),.72) 70%, rgba(var(--bgA),0) 100%); }
#p-chans.on{ display:flex; }
#pch-title{ font-size:12px; font-weight:800; letter-spacing:.08em; text-transform:uppercase;
  color:var(--muted); padding:0 6px 12px; }
#pch-list{ flex:1; overflow-y:auto; -webkit-overflow-scrolling:touch; }
#pch-list::-webkit-scrollbar{ width:0; }
#p-chans .pch-row{ display:flex; align-items:center; gap:10px; padding:10px 12px; margin-bottom:5px;
  border-radius:11px; cursor:pointer; }
#p-chans .pch-row .n{ width:34px; flex:0 0 auto; text-align:center; font-weight:800; font-size:13px; color:var(--muted2); }
#p-chans .pch-row .m{ flex:1; min-width:0; font-weight:700; font-size:14px; color:var(--text);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
#p-chans .pch-row.cur{ box-shadow:inset 0 0 0 1px rgba(var(--accentA),.55); }
#p-chans .pch-row.cur .m{ color:var(--accent); }
#p-chans .pch-row.sel{ background:var(--accentGrad); }
#p-chans .pch-row.sel .n,#p-chans .pch-row.sel .m{ color:var(--onAccent); }
#p-chans .pch-row .s{ width:20px; text-align:center; color:transparent; font-size:13px; flex:0 0 auto; }
#p-chans .pch-row .s.on{ color:var(--gold); }
#p-chans .pch-row.sel .s:not(.on){ color:rgba(0,0,0,.25); }
body.tv #p-chans .pch-row{ padding:12px 13px; }
body.tv #p-chans .pch-row .m{ font-size:16px; }
body.tv #pch-title{ font-size:13px; }

/* typed channel number overlay (web player) */
#p-num{ position:absolute; top:28px; inset-inline-end:34px; z-index:80; background:rgba(0,0,0,.6); color:#fff;
  font-size:34px; font-weight:800; padding:6px 22px; border-radius:10px; display:none; }
#p-num.on{ display:block; }

/* ── EPG guide ────────────────────────────────────────────────────────────
   One scroller (.gscroll) owns both axes. The ruler is sticky to the TOP only, so it
   scrolls sideways with the columns it labels; the channel column is sticky to the
   INLINE-START only, so it survives horizontal scroll but scrolls away vertically.
   --gchw is that column's width and the now-line is offset by it. */
.gwrap{ --gchw:116px; position:relative; height:100%; }
.gscroll{ position:relative; height:100%; overflow:auto; overscroll-behavior:contain; }
.gscroll::-webkit-scrollbar{ width:0; height:0; }

.gtime{ position:sticky; top:0; z-index:14; display:flex; width:max-content; background:var(--bg2); border-bottom:1px solid var(--line2); }
.gt-pad{ position:sticky; inset-inline-start:0; z-index:15; flex:0 0 var(--gchw);
  width:var(--gchw); min-width:0; max-width:var(--gchw); background:var(--bg2); border-inline-end:1px solid var(--line2); }
.gt-scale{ position:relative; height:32px; flex:0 0 auto; }
.gt-tick{ position:absolute; top:0; bottom:0; font-style:normal; font-size:11px; color:var(--muted2);
  padding-inline-start:5px; border-inline-start:1px solid var(--line); display:flex; align-items:center; }
.gt-tick.hr{ color:var(--text); border-inline-start-color:var(--line2); font-weight:800; font-size:12px; }

.grows{ position:relative; width:max-content; }
.gnow{ position:absolute; top:0; bottom:0; width:2px; background:var(--accent); z-index:9; pointer-events:none; opacity:.75; }
.grow{ display:flex; align-items:stretch; border-bottom:1px solid var(--line); min-height:54px; }
/* A flex item's automatic minimum size is its MIN-CONTENT — so `flex: 0 0 116px` alone is a
   suggestion, and a long channel name silently overrides it. That is why every row's column
   ended at a different place, staggered by name length, while the empty .gt-pad sat at a
   correct 116px. Explicit width + min-width:0 + max-width leaves nothing to negotiate. */
.gch{ position:sticky; inset-inline-start:0; z-index:10; flex:0 0 var(--gchw);
  width:var(--gchw); min-width:0; max-width:var(--gchw); overflow:hidden;
  display:flex; align-items:center; gap:7px;
  padding:0 9px; background:var(--bg2); border-inline-end:1px solid var(--line2); }
.gch.foc.focus{ box-shadow:var(--focusRing); border-color:transparent; z-index:11; position:relative; }
.gch b{ color:var(--muted2); font-size:12px; min-width:22px; text-align:center; flex:0 0 auto; }
.gch span{ flex:1; min-width:0; font-size:13px; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.gch .ar{ color:var(--accent); font-style:normal; font-size:12px; opacity:.8; flex:0 0 auto; }
.gprogs{ position:relative; flex:0 0 auto; }
/* the "no guide" note must stay where the eye is, not an hour off to the left */
.gload{ position:sticky; inset-inline-start:10px; float:inline-start; margin-top:18px; color:var(--muted2); font-size:12px; white-space:nowrap; }

.gp{ position:absolute; top:4px; bottom:4px; overflow:hidden; text-align:start; padding:0 7px; border-radius:7px;
  background:var(--surface); border:1px solid var(--line); color:var(--text);
  display:flex; flex-direction:column; justify-content:center; gap:1px; }
.gp b{ font-size:10px; color:var(--muted2); font-weight:700; line-height:1.1; }
.gp span{ font-size:12px; font-weight:600; line-height:1.2; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* Too narrow for any text. Drawn as a slim dim bar rather than a bordered empty box —
   an empty box looks like a bug; a bar looks like a short programme, which it is. */
.gp.bare{ padding:0; border:0; border-radius:3px; top:16px; bottom:16px; background:var(--line2); }
/* what is on now is the anchor: filled, not merely outlined */
.gp.live{ background:rgba(var(--accentA),.20); border-color:var(--accent); }
.gp.live b{ color:var(--accent); }
.gp.live span{ color:var(--text); font-weight:800; }
.gp.bare.live{ background:var(--accent); top:12px; bottom:12px; }
/* finished, but reachable: OK on it plays the archive */
.gp.past{ opacity:.55; }
.gp.foc.focus{ box-shadow:var(--focusRing); border-color:transparent; z-index:11; }

@media (min-width:700px){ .gwrap{ --gchw:190px; } .gch span{ font-size:14px; } .gt-scale{ height:34px; } }

body.tv .gwrap{ --gchw:300px; }
body.tv .gt-scale{ height:40px; }
body.tv .gt-tick{ font-size:13px; }
body.tv .gt-tick.hr{ font-size:16px; }
body.tv .grow{ min-height:70px; }
body.tv .gch b{ font-size:16px; min-width:34px; }
body.tv .gch span{ font-size:18px; }
body.tv .gch .ar{ font-size:16px; }
body.tv .gp b{ font-size:12px; }
body.tv .gp span{ font-size:15px; }
body.tv .gload{ font-size:15px; }
@media (max-width:1400px){ body.tv .gwrap{ --gchw:240px; } }

/* ── Family profiles ──────────────────────────────────────────────────────
   Avatar tints are fixed hues, deliberately NOT --accent: a profile must stay
   recognisable at a glance even when the household changes the accent colour. */
.profgrid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(140px,1fr)); gap:14px; padding:14px 16px; }
.profcard{ position:relative; display:flex; flex-direction:column; align-items:center; gap:9px; padding:16px 10px 13px;
  border-radius:var(--radius); background:var(--surface); border:1px solid var(--line); text-align:center; }
.profcard.on{ border-color:var(--accent); background:var(--surface2); }
.profcard.dim{ opacity:.5; }
.profcard.foc.focus{ box-shadow:var(--focusRing); border-color:transparent; }
.pav{ width:66px; height:66px; border-radius:50%; display:grid; place-items:center; font-size:26px; font-weight:900; color:#160F0A; }
.pav.add{ background:var(--surface2); border:1px dashed var(--line2); color:var(--muted); }
.pav.add svg{ width:24px; height:24px; }
.pnm{ font-size:15px; font-weight:800; max-width:100%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.psub{ font-size:11px; color:var(--muted2); min-height:14px; }
.profcard.on .psub{ color:var(--accent); }
/* manage mode: the grid announces "you are editing" and the cards show it */
.profgrid.mng .profcard{ outline:2px dashed var(--accent); outline-offset:-3px; }
/* avatar tints — a0..a5, mirrored by AVC in screens-extra.js */
.pav.a0,.pavsw .a0{ background:#E2703A; } .pav.a1,.pavsw .a1{ background:#E8B44A; }
.pav.a2,.pavsw .a2{ background:#E0685F; } .pav.a3,.pavsw .a3{ background:#7FB069; }
.pav.a4,.pavsw .a4{ background:#4FC3D9; } .pav.a5,.pavsw .a5{ background:#A78BFA; }
.pavsw b{ width:24px; height:24px; border-radius:50%; }

body.tv .profgrid{ grid-template-columns:repeat(auto-fill,minmax(190px,1fr)); gap:20px; padding:18px 24px; }
body.tv .pav{ width:92px; height:92px; font-size:36px; }
body.tv .pnm{ font-size:20px; }
body.tv .psub{ font-size:14px; min-height:18px; }

/* The clock used to be positioned absolutely because it REPLACED the topbar on TV. It now
   lives inside the topbar next to the search button, so it has to sit in normal flow —
   otherwise it floats over the title. */
body.tv .topbar .clock{ position:static; inset:auto; margin-inline-end:14px; font-weight:800; font-size:18px; color:var(--muted); }
.topbar .clock{ position:static; inset:auto; margin-inline-end:12px; font-size:14px; color:var(--muted2); }
/* the category filter, revealed only when asked for */
.searchbar.vsearch.hide{ display:none; }

/* ---------- content locks ---------- */
/* small padlock beside a locked channel's name in the list */
.lkmark{ margin-inline-start:6px; font-size:12px; opacity:.9; }
/* padlock chip over a locked poster/card thumbnail */
.thumb .lkbadge{ position:absolute; top:6px; inset-inline-start:6px; background:rgba(0,0,0,.55);
  border-radius:8px; padding:2px 6px; font-size:12px; line-height:1; }
body.tv .lkmark{ font-size:14px; }
body.tv .thumb .lkbadge{ font-size:14px; padding:3px 7px; }

/* =================== COMPACT TV (a box owner picked the phone option) ===================
   Same TV layout, rendered smaller. `zoom` rather than transform:scale because zoom
   reflows: focus rectangles, scroll maths and hit areas all stay correct, which a
   transform would silently break. The player overlay lives OUTSIDE #app on purpose,
   so video always fills the real screen regardless of this. */
body.compact #app{ zoom:.85; }
