/* TV mode (Android TV / Google TV, 29 Oct, concept C: the side rail with a balancer strip). Everything here sits under body.tv, the way the
   phone sits under body.phone, so the computer and phone layouts never see it. Sizes are in --u, one 960th of the screen width: a 1080p or
   4K Google TV lays the page out 960 CSS px wide, so 1 --u is one CSS px there and everything scales the same on any TV. 10-foot rules: text
   16 --u and up, buttons 40 --u and up, a 4 --u ring in the pane's own colour, 24/32 --u overscan-safe margins. */
body.tv { --u: calc(100vw / 960); --tvRailW: calc(var(--u) * 268); --tvPad: calc(var(--u) * 24) calc(var(--u) * 32); background: var(--bg); cursor: none; }
body.tv.wallmode { overflow: hidden; }      /* the wall fills the screen; a signed-out page still scrolls */
body.tv :focus-visible { outline: none; }
/* what a TV never shows: the top bar, the footer, the wall's tool rows, the left rail of avatars, the chat column, the extras under the wall,
   the skip link, hover tips. Pulse and Clarity live behind the top bar's menus, so they stay out of reach too. */
body.tv > .skip, body.tv > header.top, body.tv > footer.foot, body.tv.wallmode .watch > .tools, body.tv .wallwrap > .rail, body.tv .wallwrap > .vsplit,
body.tv .wallwrap > .side, body.tv .extrabox, body.tv .fsplit, body.tv .pane > .pane-bar, body.tv .tourchip, body.tv .tc-strip { display: none !important; }
body.tv.wallmode main.view.watch { position: fixed; inset: 0; padding: var(--tvPad); display: flex; flex-direction: column; min-height: 0; }
body.tv .wallwrap { display: flex !important; flex: 1; min-height: 0; transition: padding-left .22s cubic-bezier(.2, .8, .2, 1); }
body.tv.tvrail-open .wallwrap { padding-left: calc(var(--tvRailW) - var(--u) * 16); }
body.tv .stagecol { flex: 1; min-width: 0; height: 100%; overflow: visible !important; }
body.tv .stage { overflow: visible !important; }
body.tv .stage { gap: calc(var(--u) * 14); padding: calc(var(--u) * 8); height: 100%; }
/* the pane: a plate on top (a native Twitch page covers the picture, so nothing is drawn on it), the picture under it */
body.tv .pane { grid-template-rows: calc(var(--u) * 36) minmax(0, 1fr); border: 0; border-radius: calc(var(--u) * 12); overflow: visible; background: #000; transition: box-shadow .15s, opacity .15s; }
body.tv .pane.focus { box-shadow: none; }
body.tv .pane > .tvplate, body.tv .pane > .tvbar { grid-row: 1; grid-column: 1; }
body.tv .pane > .pane-body { grid-row: 2; grid-column: 1; border-radius: 0 0 calc(var(--u) * 12) calc(var(--u) * 12); overflow: hidden; }
body.tv .pane > .pane-fx { inset: calc(var(--u) * 36) 0 0 0; }
body.tv .pane .pane-body iframe { pointer-events: none; }
body.tv .pane.tvfocus, body.tv .pane.tvlit { box-shadow: 0 0 0 calc(var(--u) * 4) var(--pc), 0 0 calc(var(--u) * 22) calc(var(--u) * 2) color-mix(in srgb, var(--pc) 45%, transparent); z-index: 2; }
body.tv.tvrail-open .pane:not(.tvlit) { opacity: .82; }
/* fix2: a grid, so the name grows to its full width before the game gets any room (minmax(0, max-content) is sized ahead of 1fr). The name only
   ellipsizes when it alone does not fit; the game (with its separator) shrinks first and hides when there is no real room for it. */
body.tv .tvplate { display: grid; grid-template-columns: auto minmax(0, max-content) minmax(0, 1fr) auto auto; grid-auto-flow: column; align-items: center; gap: 0; min-width: 0; padding: 0 calc(var(--u) * 12); background: var(--card); border-radius: calc(var(--u) * 12) calc(var(--u) * 12) 0 0; font: 600 calc(var(--u) * 15) var(--body); color: var(--text); white-space: nowrap; }
body.tv .tvplate[hidden] { display: none; }
body.tv .tvplate .dot { margin-right: calc(var(--u) * 8); width: calc(var(--u) * 10); height: calc(var(--u) * 10); background: var(--pc); }
body.tv .tvplate b { font-weight: 800; font-size: calc(var(--u) * 16); overflow: hidden; text-overflow: ellipsis; min-width: 0; }
body.tv .tvplate .tvgame { min-width: 0; padding-left: calc(var(--u) * 8);      /* spacing as padding, not a grid gap: an empty game column costs the name nothing */
  overflow: hidden; text-overflow: ellipsis; color: var(--muted); font-size: calc(var(--u) * 14); container-type: inline-size; }
body.tv .tvplate .tvsep { font-style: normal; font-weight: 700; }
body.tv .tvplate small { font-size: inherit; }
@container (max-width: 3.5em) { body.tv .tvplate .tvgame > * { display: none; } }      /* no room for more than a letter or two: no game, no separator */
body.tv .tvplate em { font-style: normal; font-weight: 800; color: var(--pc); font-size: calc(var(--u) * 15); margin-left: calc(var(--u) * 12); }
body.tv .tvmeter { margin-left: calc(var(--u) * 8); flex: none; width: calc(var(--u) * 56); height: calc(var(--u) * 5); border-radius: 99px; background: color-mix(in srgb, var(--pc) 22%, transparent); overflow: hidden; }
body.tv .tvmeter i { display: block; height: 100%; background: var(--pc); border-radius: 99px; transition: width .15s; }
body.tv .pane.tvfocus .tvplate, body.tv .pane.tvlit .tvplate { background: color-mix(in srgb, var(--pc) 18%, var(--card)); }
body.tv .pane.muted .tvplate b { color: var(--muted); }
/* the pane bar (OK on a pane): big buttons where the plate was */
body.tv .pane.tvbar-open { grid-template-rows: calc(var(--u) * 56) minmax(0, 1fr); }
body.tv .pane.tvbar-open > .pane-fx { inset: calc(var(--u) * 56) 0 0 0; }
body.tv .tvbar { display: flex; align-items: center; gap: calc(var(--u) * 8); padding: 0 calc(var(--u) * 10); background: color-mix(in srgb, var(--pc) 22%, var(--card)); border-radius: calc(var(--u) * 12) calc(var(--u) * 12) 0 0; min-width: 0; overflow: hidden; }
body.tv .tvbar-n { font: 800 calc(var(--u) * 16) var(--body); margin-right: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* buttons, 10-foot */
body.tv .tvbtn { display: inline-flex; align-items: center; justify-content: center; gap: calc(var(--u) * 8); min-height: calc(var(--u) * 40); padding: 0 calc(var(--u) * 16); border-radius: calc(var(--u) * 10); border: calc(var(--u) * 2) solid transparent; background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text); font: 700 calc(var(--u) * 16) var(--body); cursor: pointer; flex: none; transition: transform .12s, background .12s, border-color .12s; }
body.tv .tvbtn svg { width: calc(var(--u) * 20); height: calc(var(--u) * 20); }
body.tv .tvbtn.primary { background: var(--grad); color: var(--ink); }
body.tv .tvbtn.on { border-color: color-mix(in srgb, var(--accent) 60%, transparent); }
body.tv .tvbtn:focus, body.tv .tvcard:focus, body.tv .tvrail-it:focus { border-color: var(--accent2); box-shadow: 0 0 0 calc(var(--u) * 3) color-mix(in srgb, var(--accent) 55%, transparent), 0 0 calc(var(--u) * 22) calc(var(--u) * -4) var(--accent); transform: scale(1.04); outline: none; }
body.tv .tvbar .tvbtn:focus { border-color: #fff; box-shadow: 0 0 0 calc(var(--u) * 3) var(--pc); }
/* the rail */
body.tv .tvrail { position: fixed; z-index: 60; left: 0; top: 0; bottom: 0; width: var(--tvRailW); padding: calc(var(--u) * 18) calc(var(--u) * 16) calc(var(--u) * 14) calc(var(--u) * 32); display: flex; flex-direction: column; gap: calc(var(--u) * 6); background: linear-gradient(90deg, #0E0C0B 70%, rgba(14, 12, 11, .92)); border-right: 1px solid var(--line); transform: translateX(-104%); transition: transform .22s cubic-bezier(.2, .8, .2, 1); font: 600 calc(var(--u) * 16) var(--body); color: var(--text); }
body.tv .tvrail.in { transform: none; }
body.tv:not(.tvrail-open) .tvrail { visibility: hidden; transition: transform .22s cubic-bezier(.2, .8, .2, 1), visibility 0s .22s; }
/* the brand (fix2): the shared top-bar lockup (.brand + .wordmark from app.css), untouched; only zoomed as a whole for 10-foot viewing (--tvs = width / 960,
   set by tv.js, so it is the desktop size on a 960-wide TV page and twice that at 1920). The desktop hides .wordmark under 1100 px wide; a TV keeps it
   (:where keeps this as weak as that rule, so a theme's own display on .wordmark still wins). */
body.tv .tvbrand { zoom: var(--tvs, 1); align-self: flex-start; font-weight: 400; }      /* 400: the page's own weight, which the top bar's lockup sits in (the rail and link screen set 500/600 around it) */
:where(body.tv .tvbrand) .wordmark { display: inline; }
.tvrail-brand { margin-bottom: calc(var(--u) * 2); }
.tvrail-menu { display: grid; gap: calc(var(--u) * 2); }
body.tv .tvrail-it { display: flex; align-items: center; gap: calc(var(--u) * 12); min-height: calc(var(--u) * 32); padding: 0 calc(var(--u) * 12); border-radius: calc(var(--u) * 10); border: calc(var(--u) * 2) solid transparent; background: none; color: var(--text); font: 700 calc(var(--u) * 16) var(--body); text-align: left; cursor: pointer; }
body.tv .tvrail-it svg { width: calc(var(--u) * 20); height: calc(var(--u) * 20); color: var(--accent2); }
body.tv .tvrail-it:focus { transform: none; background: color-mix(in srgb, var(--accent) 16%, transparent); }
.tvrail-h { display: flex; align-items: baseline; justify-content: space-between; margin-top: calc(var(--u) * 6); color: var(--accent); font-size: calc(var(--u) * 13); letter-spacing: .08em; text-transform: uppercase; } .tvrail-h small { color: var(--muted); text-transform: none; letter-spacing: 0; font-size: calc(var(--u) * 13); }
.tvrows { display: grid; gap: calc(var(--u) * 6); min-height: 0; overflow: visible; }  /* four rows fit at 960 and 1080 (29 Oct), so the focus glow is never clipped */
.tvrows.many { overflow-y: auto; scrollbar-width: none; flex: 0 1 auto; padding: calc(var(--u) * 3); margin: calc(var(--u) * -3); }
body.tv .tvrow { display: grid; gap: calc(var(--u) * 5); padding: calc(var(--u) * 6) calc(var(--u) * 12) calc(var(--u) * 8); border-radius: calc(var(--u) * 10); border: calc(var(--u) * 2) solid color-mix(in srgb, var(--pc) 45%, transparent); background: color-mix(in srgb, var(--pc) 8%, transparent); outline: none; }
body.tv .tvrow:focus { border-color: var(--pc); background: color-mix(in srgb, var(--pc) 18%, transparent); box-shadow: 0 0 calc(var(--u) * 22) calc(var(--u) * -4) var(--pc); }
.tvrow-t { display: flex; align-items: center; gap: calc(var(--u) * 8); min-width: 0; } .tvrow-t .dot { width: calc(var(--u) * 10); height: calc(var(--u) * 10); background: var(--pc); }
.tvrow-t b { font-size: calc(var(--u) * 16); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; } .tvrow-t em { margin-left: auto; font-style: normal; font-weight: 800; color: var(--pc); }
.tvrow-track { position: relative; height: calc(var(--u) * 6); border-radius: 99px; background: color-mix(in srgb, var(--pc) 22%, transparent); }
.tvrow-track i { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 99px; background: var(--pc); transition: width .12s; }
.tvrow-track span { position: absolute; top: 50%; width: calc(var(--u) * 14); height: calc(var(--u) * 14); margin: calc(var(--u) * -7) 0 0 calc(var(--u) * -7); border-radius: 50%; background: #fff; box-shadow: 0 0 0 calc(var(--u) * 2) var(--pc); transition: left .12s; }
.tvrow.muted { opacity: .6; } .tvrow.muted em { color: var(--muted); }
.tvrail-empty { color: var(--muted); }
.tvrail-hint { margin-top: auto; color: var(--muted); font-size: calc(var(--u) * 13); } .tvrail-hint b { color: var(--text); }
/* dialogs and the link screen */
body.tv .tvdlg, body.tv .tvlink { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; padding: var(--tvPad); background: rgba(6, 5, 4, .86); color: var(--text); font: 500 calc(var(--u) * 16) var(--body); }
.tvdlg-card { min-width: calc(var(--u) * 380); max-width: calc(var(--u) * 760); display: grid; gap: calc(var(--u) * 14); justify-items: start; padding: calc(var(--u) * 26) calc(var(--u) * 30); border-radius: calc(var(--u) * 16); background: var(--card); border: 1px solid var(--line); border-top: calc(var(--u) * 3) solid var(--accent); box-shadow: 0 calc(var(--u) * 20) calc(var(--u) * 60) rgba(0, 0, 0, .6); }
.tvdlg-card h2 { margin: 0; font: var(--slant) 900 calc(var(--u) * 26) var(--display); text-transform: var(--caps); } .tvdlg-card p { margin: 0; color: var(--muted); }
.tvdlg-acts { display: flex; gap: calc(var(--u) * 12); flex-wrap: wrap; }
.tvdlg-list { display: grid; gap: calc(var(--u) * 8); width: 100%; } body.tv .tvbtn.wide { justify-content: flex-start; width: 100%; min-height: calc(var(--u) * 52); } body.tv .tvbtn.wide small { margin-left: auto; color: var(--muted); font-weight: 500; font-size: calc(var(--u) * 14); }
.tvexit .tvdlg-card { justify-items: center; text-align: center; }
.tvpick-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: calc(var(--u) * 10); width: 100%; }
body.tv .tvcard { display: grid; gap: calc(var(--u) * 4); text-align: left; padding: calc(var(--u) * 12) calc(var(--u) * 14); min-height: calc(var(--u) * 64); border-radius: calc(var(--u) * 12); border: calc(var(--u) * 2) solid var(--line); background: var(--bg2); color: var(--text); font: 700 calc(var(--u) * 16) var(--body); cursor: pointer; } body.tv .tvcard small { color: var(--muted); font-weight: 500; font-size: calc(var(--u) * 13); }
.tvdlg-empty { color: var(--muted); }
/* the link screen (L1 / L2) */
body.tv .tvlink { background: radial-gradient(ellipse at 20% 100%, rgba(120, 60, 200, .16), transparent 55%), radial-gradient(ellipse at 90% 0%, rgba(255, 90, 0, .12), transparent 50%), #0B0A09; }
.tvl-card { width: 100%; max-width: calc(var(--u) * 880); display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: calc(var(--u) * 36); align-items: center; }
.tvl-h { margin: calc(var(--u) * 14) 0 calc(var(--u) * 6); font: var(--slant) 900 calc(var(--u) * 38) var(--display); text-transform: var(--caps); line-height: 1.05; } .tvl-h em { font-style: inherit; color: var(--accent); }
.tvl-sub { margin: 0 0 calc(var(--u) * 18); color: var(--muted); }
.tvl-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: calc(var(--u) * 14); }
.tvl-steps li { display: flex; align-items: center; gap: calc(var(--u) * 12); } .tvl-steps li > i { flex: none; display: grid; place-items: center; width: calc(var(--u) * 28); height: calc(var(--u) * 28); border-radius: 50%; background: var(--grad); color: var(--ink); font: 900 calc(var(--u) * 15) var(--body); font-style: normal; }
.tvl-steps em { font-style: normal; color: var(--accent2); font-weight: 700; }
.tvl-wait { display: flex; align-items: center; gap: calc(var(--u) * 10); margin: calc(var(--u) * 28) 0 0; color: var(--muted); }
/* waiting (fix1): no spinner. fix2, no visible loops: the dot is still, and pulses once (1.6 s) when a code arrives or New Code refreshes it
   (drawCode makes a new dot each time, so the one pulse plays again). Reduced motion: no pulse. */
.tvl-waitdot { flex: none; width: calc(var(--u) * 12); height: calc(var(--u) * 12); border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 calc(var(--u) * 4) color-mix(in srgb, var(--accent) 22%, transparent); }
.tvl-waitdot.fresh { animation: tvpulse1 1.6s ease-out 1; }
@keyframes tvpulse1 { 0% { box-shadow: 0 0 0 calc(var(--u) * 4) color-mix(in srgb, var(--accent) 22%, transparent); } 40% { box-shadow: 0 0 0 calc(var(--u) * 9) color-mix(in srgb, var(--accent) 10%, transparent); } 100% { box-shadow: 0 0 0 calc(var(--u) * 4) color-mix(in srgb, var(--accent) 22%, transparent); } }
@media (prefers-reduced-motion: reduce) { .tvl-waitdot, .tvl-waitdot.fresh { animation: none; } body.tv .tvrail, body.tv .wallwrap { transition: none; } }
.tvl-right { display: grid; justify-items: center; gap: calc(var(--u) * 8); padding: calc(var(--u) * 22); border-radius: calc(var(--u) * 16); background: var(--card); border: 1px solid var(--line); border-top: calc(var(--u) * 3) solid var(--accent); }
.tvl-qr { padding: calc(var(--u) * 10); border-radius: calc(var(--u) * 10); background: #fff; line-height: 0; } .tvl-qr svg { width: calc(var(--u) * 200); height: calc(var(--u) * 200); }
.tvl-code { font: 900 calc(var(--u) * 34) ui-monospace, "Roboto Mono", monospace; letter-spacing: .14em; color: #fff; }
.tvl-url { color: var(--accent2); font-weight: 800; } .tvl-fine { color: var(--muted); font-size: calc(var(--u) * 13); }
.tvl-acts { display: flex; gap: calc(var(--u) * 12); margin-top: calc(var(--u) * 8); }
.tvl-demo { position: absolute; left: 50%; bottom: calc(var(--u) * 24); transform: translateX(-50%); margin: 0; padding: calc(var(--u) * 6) calc(var(--u) * 14); border-radius: 99px; background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent2); font-size: calc(var(--u) * 14); white-space: nowrap; }
.tvl-card.linked { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); }
.tvl-card.linked.solo { grid-template-columns: minmax(0, 1fr); width: auto; max-width: calc(var(--u) * 560); height: auto; margin: auto; place-self: center; justify-items: start; }      /* 31 Oct: no in-app twitch.tv sign-in to offer, so just the hello and Go to the Wall */
.tvl-card.linked.solo .tvl-acts { margin-top: calc(var(--u) * 18); }
.tvl-hi { display: flex; align-items: center; gap: calc(var(--u) * 16); } .tvl-hi .tvl-h { margin: calc(var(--u) * 2) 0; }
.tvl-av { flex: none; display: grid; place-items: center; width: calc(var(--u) * 72); height: calc(var(--u) * 72); border-radius: 50%; border: calc(var(--u) * 3) solid var(--good); color: var(--good); background: rgba(157, 255, 58, .08); } .tvl-av svg { width: calc(var(--u) * 34); height: calc(var(--u) * 34); }
.tvl-ok { color: var(--good); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; font-size: calc(var(--u) * 13); }
.tvl-live { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: calc(var(--u) * 8); margin-top: calc(var(--u) * 16); } .tvl-lc { padding: calc(var(--u) * 8) calc(var(--u) * 10); border-radius: calc(var(--u) * 8); background: var(--card); border: 1px solid var(--line); display: grid; } .tvl-lc b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: calc(var(--u) * 14); } .tvl-lc small { color: var(--muted); font-size: calc(var(--u) * 12); }
.tvl-later { margin-top: calc(var(--u) * 26); color: var(--muted); }
.tvl-opt { display: grid; gap: calc(var(--u) * 10); padding: calc(var(--u) * 22); border-radius: calc(var(--u) * 16); background: var(--card); border: 1px solid var(--line); border-top: calc(var(--u) * 3) solid var(--accent); } .tvl-opt h2 { margin: 0; font: 900 calc(var(--u) * 22) var(--body); } .tvl-opt p { margin: 0; color: var(--muted); }
.tvl-kicker { color: var(--accent); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; font-size: calc(var(--u) * 12); }
/* toasts: bigger and clear of the overscan edge */
body.tv .toasts { right: calc(var(--u) * 32); bottom: calc(var(--u) * 24); z-index: 95; } body.tv .toast { font-size: calc(var(--u) * 16); padding: calc(var(--u) * 12) calc(var(--u) * 18); }
/* ---------- speed (31 Oct, his Hisense A7: "everything was slow"). Cheaper paint on a slow TV chip; looks the same apart from the softer glows ---------- */
body.tv .wallwrap { transition: none; }      /* the wall steps over for the rail at once: an animated padding was a relayout on every frame */
body.tv .pane { transition: none; }
body.tv .pane.tvfocus, body.tv .pane.tvlit { box-shadow: 0 0 0 calc(var(--u) * 4) var(--pc); }      /* a crisp ring, no blurred glow */
body.tv .tvbtn:focus, body.tv .tvcard:focus, body.tv .tvrail-it:focus { box-shadow: 0 0 0 calc(var(--u) * 3) color-mix(in srgb, var(--accent) 70%, transparent); }
body.tv .tvrow:focus { box-shadow: none; }
body.tv .tvrail { transition-duration: .14s; will-change: transform; contain: layout paint; }
body.tv:not(.tvrail-open) .tvrail { transition: transform .14s cubic-bezier(.2, .8, .2, 1), visibility 0s .14s; }
body.tv *, body.tv *::before, body.tv *::after { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }      /* frosted glass is the costliest paint a TV can do */
/* 31 Oct phase 2: no endless motion on a TV (his slow TV): Alphie stands still there, as under reduced motion */
body.tv .epx-alphie, body.tv .epx-alphie * { animation: none !important; }
