/* Reel on a TV, moved around with a remote (js/tv.js turns on html.tv). Where focus is has to
   read from across the room, and anything only a mouse can use steps aside. A remote gives
   focus, never a hover, so the rings here follow :focus as well as :focus-visible: focus placed
   by the page (a new page's Play, say) shows too. */

/* ---------- Size ---------- */
/* The whole page in proportion to the screen, so it looks the same whatever width the TV says it
   is: a 1080p Chromecast or Fire TV calls itself 960 wide, some boxes 1280, a TV's own browser
   1920. The type is 1.3% of the width (12.5 px at 960, 25 px at 1920), about what Google TV and
   Plex use, and the rest is sized from it. A screen that isn't 16:9 (a browser's own bar taking
   some height) goes by its height instead, so nothing runs off the bottom. The height is the
   screen's full height (tv.js --tv-h), so the on-screen keyboard coming up, which shortens the
   page in the Android app, doesn't shrink everything behind it.
   Everything keeps inside the 5% a TV may cut off at its edges (--safe-y top and bottom, the
   gutter at the sides). */
html.tv {
  --vh: calc(var(--tv-h, 100vh) / 100);
  font-size: min(1.3vw, calc(2.3111 * var(--vh)));
  --gutter: 5vw; --safe-y: calc(5 * var(--vh));
  /* The card size slider isn't on TVs, so an old choice from before can't make cards huge. */
  --card-scale: 1 !important;
  --ring-w: max(2px, 0.16rem);
}
/* The card size slider would hold left and right to itself; a TV keeps the size above. Casting
   is from phones and computers to a TV, not from one. */
html.tv .card-size, html.tv .cast-slot { display: none !important; }
html.tv body { line-height: 1.45; }
/* The header scrolls away with the page here, so what's scrolled to needn't clear it. */
html.tv { scroll-padding-top: var(--safe-y); }
html.tv .page { padding-bottom: calc(var(--safe-y) + 1.5rem); }

/* ---------- Focus ---------- */
html.tv :is(:focus, :focus-visible) { outline: var(--ring-w) solid var(--ring); outline-offset: 0.18rem; }
/* What takes focus only to hold it (a dialog with nothing in it to press, the picture) has no ring. */
html.tv :is(dialog, [tabindex="-1"]):focus { outline: none; }
/* Buttons light up: the theme's text colour behind, as TV apps mark the one OK presses. */
html.tv :is(.primary, .ghost, .pill-action, .chip-tab, .chip, .text-button):is(:focus, :focus-visible) {
  outline: var(--ring-w) solid var(--ring); outline-offset: 0.16rem; }
html.tv :is(.ghost, .pill-action, .chip-tab):is(:focus, :focus-visible) { background: var(--text); color: var(--bg); border-color: var(--text); }
html.tv :is(.ghost, .pill-action, .chip-tab):is(:focus, :focus-visible) svg { color: inherit; }
html.tv :is(.ghost, .pill-action, .chip-tab):is(:focus, :focus-visible) :is(small, .muted) { color: inherit; opacity: 0.8; }

/* ---------- Header ---------- */
/* Slim, and part of the page rather than stuck over it: it scrolls away as the remote goes down
   into the rows, and comes back at the top (tv.js scrolls up to it), as Google TV's does. Its
   links sit in a row, one press up from the page; the focused one is a pill. No blur behind it:
   a TV stick's graphics chip has to redraw that on every frame the page moves. */
html.tv .top { position: relative; min-height: 0; gap: 1rem; padding: var(--safe-y) var(--gutter) 0.5rem;
  -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--bg); border-bottom: 0; box-shadow: none; transition: none; }
html.tv .top.over-art:not(.nav-open) { background: transparent; }
html.tv .top::before { inset: 0 0 -2rem; }
html.tv .top .wordmark { font-size: 1.45rem; }
html.tv .top .wordmark-logo { height: 1.9rem; }
html.tv .top .search-form { flex: 0 1 10rem; min-width: 6rem; }
html.tv .top .search { height: 2.3rem; padding: 0 0.9rem 0 2.2rem; font-size: 0.9rem; }
html.tv .search-icon { left: 0.8rem; width: 0.95rem; height: 0.95rem; margin-top: -0.475rem; }
html.tv .top .search:focus { box-shadow: none; outline: var(--ring-w) solid var(--ring); outline-offset: 0.16rem; background: color-mix(in srgb, var(--text) 16%, transparent); }
html.tv .account-menu summary { width: 2.3rem; height: 2.3rem; min-height: 0; font-size: 0.9rem; }
html.tv .account-menu summary #me-avatar .avatar { font-size: 0.9rem; }
html.tv .top .nav-toggle { width: 2.3rem; height: 2.3rem; }
html.tv .top:not(.compact-nav) .nav { gap: 0.3rem; padding: 0.25rem; margin: -0.25rem; }
html.tv .top:not(.compact-nav) .nav a { padding: 0.35rem 0.85rem; border-radius: 999px; font-size: 0.95rem; line-height: 1.4; }
html.tv .top:not(.compact-nav) .nav a::after { left: 0.85rem; right: 0.85rem; bottom: 0.12rem; transition: none; }
html.tv #top .wordmark:is(:focus, :focus-visible) { border-radius: 0.5rem; outline-offset: 0.3rem; }
html.tv .nav a:is(:focus, :focus-visible) { outline: none; background: var(--text); color: var(--bg); }
html.tv .top:not(.compact-nav) .nav a:is(:focus, :focus-visible)::after { opacity: 0; }
/* The account menu and the folded links: a few rows, clear of the bottom of the screen. */
html.tv .account-links { top: calc(100% + 0.4rem); width: 15rem; max-height: calc(100vh - 2 * var(--safe-y) - 3.5rem); }
html.tv :is(.account-links, .top.compact-nav .nav, .more-menu) > :is(a, button, .ghost) { min-height: 2.2rem; padding: 0.35rem 0.8rem; }
html.tv .account-people :is(a, button) { min-height: 2.2rem; }
html.tv :is(.account-links, .top.compact-nav .nav, .more-menu) :is(a, button):is(:focus, :focus-visible) { outline: none; background: var(--text); color: var(--bg); }
html.tv .account-menu[open] .account-links, html.tv .top.compact-nav .nav { animation: none; }
html.tv .top.compact-nav .nav { max-height: calc(100vh - 2 * var(--safe-y) - 3.5rem); }

/* ---------- Home ---------- */
/* The banner fills most of the first screen, with the top of the first row showing under it. */
html.tv .home-page > .banner:first-child { height: calc(72 * var(--vh)); }
html.tv .home-page > .banner:first-child .banner-text { padding-bottom: 5.25rem; max-width: 34rem; }
html.tv .home-page > .banner:first-child + .visually-hidden + .home-section { margin-top: -3.25rem; }
html.tv .home-page > .banner:first-child .banner-nav { bottom: 5.5rem; }
html.tv .banner-text { padding-inline: var(--gutter); gap: 0.5rem; }
html.tv .banner-label { font-size: 0.72rem; }
html.tv .banner-title { font-size: calc(2.5rem * var(--type-scale, 1)); line-height: 1.05; }
html.tv .banner-logo { max-height: 5.5rem; max-width: 22rem; }
html.tv .banner-meta { font-size: 0.85rem; }
html.tv .banner-overview { font-size: 0.95rem; max-width: 30rem; -webkit-line-clamp: 2; margin: 0.1rem 0 0.35rem; }
html.tv .banner .actions { gap: 0.5rem; margin-top: 0.2rem; }
html.tv .banner .actions :is(.primary, .ghost) { min-height: 2.2rem; padding: 0.35rem 1.1rem; font-size: 0.85rem; }
html.tv .banner .actions .ghost { -webkit-backdrop-filter: none; backdrop-filter: none; background: color-mix(in srgb, var(--text) 22%, transparent); }
html.tv .banner-nav { right: var(--gutter); }
/* A still picture: the slow zoom (Ken Burns) repaints a picture the size of the screen on every
   frame, which a TV stick can't keep up with while the remote moves. The fade stays. */
html.tv .banner-slide.shown .banner-art, html.tv .banner-slide.leaving .banner-art { animation: none; }
html.tv .banner-art { will-change: auto; transform: none; }
/* The banner is one stop: left and right change the title, OK opens it. Its own buttons aren't
   stops, so the one OK stands for (the title's Details, a slide's own button) wears the ring. */
html.tv .banner:focus { outline: none; }
html.tv .banner:focus .banner-slide.shown .actions > a.ghost,
html.tv .banner:focus .banner-own.shown .actions > a.primary {
  outline: var(--ring-w) solid var(--text); outline-offset: 0.18rem; background: var(--text); color: var(--bg); }

/* Rows: about seven posters or four wide pictures across, running off the right of the screen
   as Google TV's do (the next one peeks in), with no fade at their edges: a fade is a mask the
   graphics chip redraws on every frame a row slides. */
html.tv .home-section { padding-bottom: var(--section-space, 1.1rem); }
html.tv .home-section:not(.has-own-bg) { padding-block-start: calc(0.5rem + var(--section-padding, 0rem)); }
html.tv .section > h2 { font-size: calc(var(--heading-size, 1.2rem) * var(--type-scale, 1)); margin-bottom: 0.55rem; }
html.tv .home-section-description { font-size: 0.85rem; margin: -0.35rem 0 0.7rem; }
html.tv .section .rail { margin-inline: calc(-1 * var(--gutter)); }
html.tv .section .rail > .row { padding: 0.6rem var(--gutter) 0.7rem; margin: -0.6rem 0 0; scroll-padding-inline: var(--gutter); }
html.tv .home-section .row { gap: var(--card-gap, 1.1rem); }
html.tv .row.wide:not(.home-section .row) { grid-auto-columns: 14.6rem; gap: 1.1rem; }
html.tv .row.posters:not(.home-section .row) { grid-auto-columns: 8.4rem; gap: 1.1rem; }
/* A row the owner gave a background of its own is a card inset from the edges: it stays inside. */
html.tv .home-section.has-own-bg .rail { margin-inline: 0; }
html.tv .home-section.has-own-bg .rail > .row { padding-inline: 0.45rem; }
html.tv .home-section .row.posters { grid-auto-columns: var(--card-size, 8.4rem); }
html.tv .home-section .row.wide { grid-auto-columns: var(--card-size-wide, 14.6rem); }
html.tv .home-section .row.collections { grid-auto-columns: 14.6rem; }
/* (As specific as the fades' own rules for a row part way along, .rail:not(.at-start):not(.at-end).) */
html.tv :is(.rail, .rail.at-start.at-end) .row { -webkit-mask-image: none; mask-image: none; }
/* Rows and the page glide by themselves (tv.js): the browser's smooth scrolling starts over from
   standing still on every press, and snapping would pull against them. */
html.tv .row { scroll-snap-type: none; }
html.tv, html.tv:focus-within, html.tv .row { scroll-behavior: auto; }
/* A hero row (Expanded): the open title smaller than on a computer, so the row fits on screen
   with its words. The titles open and close at once rather than widening over half a second,
   which lays the row out again on every frame; the row still glides and the pictures still fade. */
html.tv .row.expanded { --expanded-width: 24rem; }
html.tv .home-expanded-card { transition: none; }
html.tv .home-expanded-copy { padding-top: 0.55rem; animation: none; }
html.tv .home-expanded-copy > .muted { font-size: 0.8rem; height: 1.2rem; }
html.tv .home-expanded-copy h3 { font-size: 1.15rem; margin: 0.2rem 0 0; }
html.tv .home-expanded-overview { font-size: 0.85rem; line-height: 1.5; height: 3em; -webkit-line-clamp: 2; margin: 0.3rem 0 0; }
html.tv .hero-short h3 { font-size: 0.9rem; margin-top: 0.5rem; }
html.tv .hero-short p { font-size: 0.8rem; }

/* ---------- Cards ---------- */
html.tv .card h3 { margin: 0.45rem 0 0.05rem; font-size: 0.9rem; line-height: 1.35; }
html.tv .card p { font-size: 0.8rem; line-height: 1.35; min-height: 1.35em; }
html.tv .grid { grid-template-columns: repeat(auto-fill, minmax(8.4rem, 1fr)); gap: 1.3rem 1.1rem; }
html.tv .grid.wide { grid-template-columns: repeat(auto-fill, minmax(14.6rem, 1fr)); }
html.tv .badge { -webkit-backdrop-filter: none; backdrop-filter: none; background: color-mix(in srgb, var(--bg) 92%, transparent); font-size: 0.7rem; }
/* Pictures show as they arrive rather than fading in: each fade is a layer of its own for half a
   second, and a row gliding along brings in a dozen at once. */
html.tv .art img[data-fade] { opacity: 1; transition: none; }
/* Each card is one stop (views.js): Continue watching's words, an episode row's name and buttons,
   On now's channel and programme links and a Coming soon card's My list aren't stops of their own
   (holding OK reaches what they did, tv.js). The focused card grows a little, with the ring on its
   picture and its words lit, so the card shows as one. Only the one card moves, and only its
   transform (no shadow to repaint on each frame of the change). */
html.tv .card .art, html.tv .card-play .art, html.tv .ep-thumb .art { transition: transform 0.16s ease-out; box-shadow: none; }
html.tv .card:hover .art { transform: none; box-shadow: none; }
html.tv :is(.card, .card-play, .card-about, .ep-thumb, .hero-open, .home-expand-pick, .upcoming-open, .trailer-card, .live-tune, .collection-tile):focus { outline: none; }
html.tv :is(.card:focus, .card-play:focus, .upcoming-open:focus, .trailer-card:focus, .live-tune:focus) .art,
html.tv .ep-thumb:focus .art {
  outline: var(--ring-w) solid var(--ring); outline-offset: 0.16rem; transform: scale(1.05); box-shadow: none; }
html.tv .card.resume .card-play:is(:focus, :focus-visible) .art { transform: scale(1.05); box-shadow: none; }
html.tv :is(.card:focus, .card:focus-within) h3 { color: var(--ring); }
/* An episode's row and a channel in On now: the whole row lights up behind its picture's ring. */
html.tv .ep-row:focus-within, html.tv .live-item:focus-within { background: color-mix(in srgb, var(--text) 8%, transparent); }
html.tv .ep-row:focus-within .ep-head h3 a, html.tv .live-item:focus-within .live-text h2 a { color: var(--ring); }
html.tv .live-item { padding: 0.35rem; margin: -0.35rem; border-radius: calc(var(--radius) + 0.35rem); }
html.tv .home-expanded-card:has(> .hero-open:focus) .home-expand-pick .art,
html.tv .home-expand-pick:focus .art { box-shadow: 0 0 0 var(--ring-w) var(--ring); }
html.tv .card.person:focus .face { outline: var(--ring-w) solid var(--ring); outline-offset: 0.16rem; }
html.tv .pl-tile:focus { outline: none; }
html.tv .pl-tile:focus .collage { outline: var(--ring-w) solid var(--ring); outline-offset: 0.16rem; }
html.tv .collection-tile:focus .art { outline: var(--ring-w) solid var(--ring); outline-offset: 0.16rem; }
html.tv .collection-back :is(.cb-wide, .cb-tall) { transition: none; }
html.tv .card.resume .play-mark, html.tv .card.resume .art::after { transition: none; }
/* A remote always has a card focused, so Continue watching's play mark is on that card only, not
   on every card as a touch screen has it: what OK does, where OK is. */
html.tv .card.resume .play-mark { opacity: 0; }
html.tv .card.resume .card-play:focus .play-mark { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.tv .card .art, html.tv .card-play .art, html.tv .ep-thumb .art { transition: none; }
  html.tv :is(.card:focus, .card-play:focus, .ep-thumb:focus, .upcoming-open:focus, .trailer-card:focus, .live-tune:focus) .art { transform: none; }
}

/* Rows slide to the focused card themselves (tv.js), so they don't snap, their arrows (for mice)
   go, and they leave room for the ring and the growth, which their scrolling would otherwise
   clip. */
html.tv .rail-btn { display: none !important; }

/* ---------- Pages ---------- */
/* Pages come in without sliding: each part of a page moving in at once is a lot of big layers
   for a TV stick. The grey outlines of a loading page don't shimmer, for the same reason. */
html.tv #page > * { animation: none; }
html.tv .sk { animation: none; background: color-mix(in srgb, var(--text) 7%, transparent); }
html.tv .sk-poster { flex-basis: 8.4rem; }
html.tv .sk-row { gap: 1.1rem; }
html.tv .sk-grid { grid-template-columns: repeat(auto-fill, minmax(8.4rem, 1fr)); gap: 1.3rem 1.1rem; }
html.tv .sk-banner { height: calc(72 * var(--vh)); }
html.tv .sk-hero { height: calc(62 * var(--vh) + var(--top-h)); }
html.tv .page-head { padding-top: 1rem; }
html.tv .page-title { font-size: calc(2rem * var(--type-scale, 1)); }
html.tv h1 { font-size: calc(1.75rem * var(--type-scale, 1)); }
html.tv .toolbar h1 { font-size: 1.6rem; }
html.tv .toolbar { margin-bottom: 0.8rem; }
html.tv .filter-bar { gap: 0.45rem; margin-bottom: 1rem; }
html.tv :is(.filter-bar, .toolbar) select { min-height: 2.2rem; padding: 0.3rem 0.7rem; font-size: 0.85rem; }
html.tv .toolbar .sort { font-size: 0.85rem; }
html.tv .chip { padding: 0.3rem 0.7rem; font-size: 0.8rem; }
html.tv .empty strong { font-size: 1.15rem; }

/* Buttons a little smaller than a computer's, which are sized for a pointer. */
html.tv :is(.primary, .ghost) { min-height: 2.3rem; padding: 0.4rem 1.2rem; font-size: 0.875rem; }
html.tv :is(button, a).small { min-height: 2.1rem; padding: 0.3rem 0.9rem; font-size: 0.85rem; }
html.tv .pill-action { min-height: 2.3rem; padding: 0.3rem 1rem 0.3rem 0.8rem; font-size: 0.85rem; }
html.tv .pill-action.icon-only { width: 2.3rem; }
html.tv .pill-action svg { width: 1.1rem; height: 1.1rem; }
html.tv .chip-tab { min-height: 2.1rem; padding: 0.3rem 0.9rem; font-size: 0.85rem; }
html.tv .field input:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="range"]), html.tv .field select, html.tv .field textarea, html.tv .inline-form input, html.tv .settings-select {
  min-height: 2.7rem; padding: 0.5rem 0.85rem; }
/* A text box the remote is on but not typing in is read-only for the moment (tv.js), so it
   doesn't take the remote's keys: it looks as it always does. */
html.tv :is(input, textarea)[data-tv-readonly] { color: inherit; }

/* A title's page: the picture across the top, with the title, Play and the rest over it. */
html.tv .hero { min-height: calc(62 * var(--vh)); }
html.tv #page > .hero:first-child:not(.plain) { min-height: calc(62 * var(--vh) + var(--top-h)); }
html.tv .hero-inner { grid-template-columns: 10.5rem minmax(0, 1fr); gap: 2rem; padding: 1.5rem var(--gutter) 0; }
html.tv .hero.no-poster .hero-inner { grid-template-columns: minmax(0, 1fr); }
html.tv .hero-info { gap: 0.7rem; max-width: 46rem; }
html.tv .hero h1 { font-size: 2.3rem; }
html.tv .hero h1.long-title { font-size: 1.8rem; }
html.tv .hero .meta { font-size: 0.9rem; }
html.tv .play-main { min-height: 2.6rem !important; padding: 0 1.4rem 0 1.1rem !important; font-size: 0.95rem !important; }
html.tv .play-main svg { width: 1.2rem; height: 1.2rem; }
html.tv .version-pick select { min-height: 2.3rem; }
html.tv .resume-line { font-size: 0.85rem; }
html.tv .detail { padding-top: 1.1rem; max-width: 56rem; }
html.tv .overview { font-size: 0.95rem; line-height: 1.55; }
html.tv .section.flush { padding-top: 1rem; }
html.tv .face { width: 5.5rem; height: 5.5rem; }
html.tv .row.people { grid-auto-columns: 6.5rem; gap: 1.1rem; }
html.tv .person h3 { font-size: 0.85rem; }
/* Seasons and episodes. */
html.tv .season-section { margin-top: 1.4rem; }
html.tv .season-bar { margin-bottom: 0.7rem; }
html.tv .ep-row { grid-template-columns: 12rem minmax(0, 1fr) auto; gap: 0.4rem 1rem; padding: 0.5rem; }
html.tv .ep-head h3 { font-size: 1rem; }
html.tv :is(.ep-meta, .ep-overview) { font-size: 0.85rem; }
html.tv .ep-thumb:focus .play-hover { opacity: 1; }

/* The TV guide scrolls as focus moves through it, so its scrollbars are only in the way. It fits
   under the page's heading, clear of the bottom of the screen. */
html.tv .guide-scroll { scrollbar-width: none; max-height: calc(100vh - 2 * var(--safe-y) - 6rem); }
html.tv .guide-scroll::-webkit-scrollbar { display: none; }
html.tv .guide { --guide-col: 10rem; }
html.tv .guide-row { height: 3.4rem; }
/* A programme's details (channels.js): the picture beside the words rather than above them, so
   the whole card fits inside the screen's edges with no scrolling. A long description stops after
   four lines and the buttons are always showing, at the foot of the words; Watch live has focus
   first. Back closes it, so there's no Close. */
html.tv dialog.modal.prog-dialog { width: min(58rem, 90vw); padding: 1.4rem; }
html.tv dialog.modal.prog-dialog[open] { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 1.5rem; align-items: stretch; }
html.tv dialog.modal.prog-dialog:not(:has(> .prog-pic)) { grid-template-columns: minmax(0, 1fr); width: min(40rem, 90vw); }
html.tv .prog-pic { align-self: start; }
html.tv .prog-pic .art { margin: 0; }
html.tv .prog-body { display: flex; flex-direction: column; min-width: 0; }
html.tv .prog-close { display: none; }
html.tv .prog-dialog .dialog-head { margin-bottom: 0.3rem; }
html.tv .prog-dialog h2 { font-size: 1.35rem; line-height: 1.25; }
html.tv .prog-sub { margin: 0 0 0.25rem; font-size: 0.95rem; }
html.tv .prog-when { margin: 0; font-size: 0.85rem; }
html.tv .prog-overview:not(:empty) { margin: 0.6rem 0 0.4rem; font-size: 0.9rem; line-height: 1.5; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; overflow: hidden; }
html.tv .prog-dialog .prog-rec { margin: 0.4rem 0 0; }
html.tv .prog-dialog .prog-body > .actions { margin-top: auto; padding-top: 0.75rem; }
html.tv .ch-badge.on-art { -webkit-backdrop-filter: none; backdrop-filter: none; background: color-mix(in srgb, var(--bg) 88%, transparent); }

/* Your settings: the menu and the page each keep inside the screen's edges. */
html.tv .settings { grid-template-columns: calc(13rem + var(--gutter)) minmax(0, 1fr); }
html.tv .shell-nav-head, html.tv .shell-nav-list { padding-left: var(--gutter); }
html.tv .shell-nav-list { padding-bottom: var(--safe-y); }
html.tv .shell-nav-list a { min-height: 2.2rem; padding: 0.35rem 0.8rem; font-size: 0.85rem; }
html.tv .shell-nav-list a:is(:focus, :focus-visible) { outline: none; background: var(--text); color: var(--bg); }
html.tv .settings-main { padding-right: var(--gutter); padding-left: 2rem; }
html.tv .settings-main::after { height: var(--safe-y); }

/* ---------- Signing in ---------- */
/* As on phones and computers (style.css, First screens), sized to the screen and inside the edges
   a TV may cut off. Signing in has two cards side by side: a code to approve from a phone, so
   nobody has to type a password with the remote, and the password beside it. The Android app's
   own server picker (android/ui) is drawn the same way. */
html.tv .auth { --card-w: 25rem; --field-h: 2.8rem; min-height: calc(100 * var(--vh)); padding: var(--safe-y) var(--gutter); }
html.tv .auth .wordmark { font-size: 2.6rem; }
html.tv .auth .wordmark.long { font-size: 2rem; }
html.tv #auth .wordmark .wordmark-logo { height: 4rem; }
html.tv #auth .wordmark .wordmark-logo:has(+ span) { height: 1.15em; }
html.tv .auth-cards { margin-top: 1.4rem; gap: 2rem; }
html.tv .auth-card { padding: 1.4rem 1.7rem 1.6rem; }
html.tv .auth-card > :is(h1, h2) { margin-bottom: 1rem; font-size: 1.3rem; }
html.tv .auth-card > h1:has(+ .auth-text:not([hidden])) { margin-bottom: 0.4rem; }
html.tv .auth-text { margin-bottom: 1rem; }
html.tv .auth .stack { gap: 0.75rem; }
html.tv .auth .stack > .primary, html.tv .auth-alt > .primary { min-height: 2.8rem; font-size: 0.95rem; }
html.tv .auth-alt { margin-top: 1rem; gap: 0.5rem; }
html.tv .auth-alt > .auth-back { top: var(--safe-y); left: calc(var(--gutter) + 0.5rem); }
/* The code card: the QR code beside the code. */
html.tv .auth-side .code-box { gap: 1rem; }
html.tv .auth-side .code-show { grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 1.25rem; text-align: left; }
html.tv .auth-side .code-how { margin: 0; }
/* Asking for an account on a TV (join.js): the QR code beside the address, in the main card. */
html.tv #auth.auth:has(.join-tv) { --card-w: 34rem; }
html.tv .join-tv .code-show { grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 1.25rem; text-align: left; }
html.tv .join-tv .code-how { margin: 0; }
html.tv .join-address { font-size: 1.35rem; }
html.tv .device-code { font-size: 2.3rem; }
html.tv .device-qr { width: 8.5rem; height: 8.5rem; }
/* A button that reads as a link is as wide as its words. */
html.tv button.link { width: auto; min-height: 0; background: none; border: 0; }
html.tv .brand-welcome { font-size: 0.9rem; }
html.tv .server-list .server { min-height: 3rem; padding-block: 0.45rem; }
html.tv .server-list .server:is(:focus, :focus-visible) { outline: var(--ring-w) solid var(--ring); outline-offset: 0.16rem; background: var(--text); color: var(--bg); }
html.tv .server-list .server:is(:focus, :focus-visible) small { color: inherit; opacity: 0.8; }

/* Who's watching, its PIN pad, and everyone's pictures. */
html.tv .profiles { padding: var(--safe-y) var(--gutter); animation: none; }
html.tv .profiles-inner { gap: 0.75rem; }
html.tv .profiles-mark { margin-bottom: 0.25rem; font-size: 1.6rem; }
html.tv .profiles-mark .wordmark-logo { height: 2.4rem; }
html.tv .profiles h1 { font-size: 2.2rem; }
html.tv .profile-tiles { gap: 1.6rem; margin: 1.25rem 0 0.25rem; }
html.tv .profile-tile { --face: 6.75rem; gap: 0.6rem; font-size: 1rem; }
html.tv .profile-tile:is(:focus, :focus-visible) .avatar { box-shadow: 0 0 0 0.2rem var(--bg), 0 0 0 0.45rem var(--text); transform: scale(1.08); }
html.tv .profile-tile:is(:focus, :focus-visible) { color: var(--text); outline: none; }
html.tv .pin-mark { width: 1.7rem; height: 1.7rem; }
html.tv .profiles-actions { margin-top: 0.75rem; }
/* The PIN pad: who and the dots on the left, the keys on the right. */
html.tv .pin-panel { grid-template-columns: minmax(0, 20rem) auto; grid-template-rows: 1fr repeat(6, auto) 1fr; column-gap: 5rem; row-gap: 0.7rem; align-items: center; }
html.tv .pin-panel > * { grid-column: 1; }
html.tv .pin-panel > .avatar { grid-row: 2; }
html.tv .pin-panel > h1 { grid-row: 3; font-size: 1.7rem; }
html.tv .pin-panel > .pin-help { grid-row: 4; margin: 0; }
html.tv .pin-panel > .pin-dots { grid-row: 5; }
html.tv .pin-panel > .pin-error { grid-row: 6; }
html.tv .pin-panel > .pin-password { grid-row: 7; margin: 0; }
html.tv .pin-panel > .pin-keys { grid-column: 2; grid-row: 1 / -1; }
html.tv .pin-keys { gap: 0.65rem 0.9rem; margin: 0; }
html.tv .pin-key { width: 3.6rem; height: 3.6rem; font-size: 1.35rem; }
html.tv .pin-key.pin-word { font-size: 0.8rem; }
html.tv .pin-key svg { width: 1.3rem; height: 1.3rem; }
html.tv .pin-key:is(:focus, :focus-visible) { outline: none; background: var(--text); color: var(--bg); }
html.tv .pin-dot { width: 0.85rem; height: 0.85rem; }

/* ---------- Dialogs and messages ---------- */
html.tv dialog.modal { max-width: 90vw; max-height: calc(100vh - 2 * var(--safe-y)); padding: 1.3rem 1.5rem; }
html.tv dialog.modal .actions { gap: 0.5rem; }
html.tv .toasts { bottom: var(--safe-y); }
html.tv .toast { max-width: 60vw; font-size: 0.9rem; }
html.tv .more-menu { animation: none; }
html.tv dialog[open], html.tv dialog[open]::backdrop { animation: none; }

/* A trailer on a TV is the whole screen, like the film: no heading or YouTube link (Back closes
   it). Coming soon's too: its card has its own My list button, so the words and button that
   would sit off the bottom of the screen (where OK could press it unseen) go. */
html.tv dialog.modal.trailer-dialog, html.tv dialog.modal.trailer-dialog:has(.trailer-about) { width: 100vw; height: 100vh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; border-radius: 0; background: #000; }
html.tv .trailer-dialog :is(.dialog-head, .trailer-about) { display: none; }
html.tv .trailer-dialog .trailer-frame { width: 100%; height: 100%; aspect-ratio: auto; border-radius: 0; }

/* ---------- The player ---------- */
/* The player already fills the screen, and the TV has its own volume. Its bars keep inside the
   screen's edges, with lighter shading over the picture. */
html.tv #ctl-full, html.tv #ctl-pip, html.tv #ctl-volume { display: none; }
html.tv .stage video:focus { outline: none; }
html.tv .player-bar { padding: var(--safe-y) var(--gutter) 2rem; background: linear-gradient(to bottom, rgb(0 0 0 / 0.65), transparent); }
html.tv .controls { padding: 2rem var(--gutter) var(--safe-y); background: linear-gradient(to top, rgb(0 0 0 / 0.7), transparent); }
html.tv .now h1 { font-size: 1.15rem; }
html.tv .now-sub { font-size: 0.85rem; }
html.tv .ctl { width: 2.5rem; height: 2.5rem; }
html.tv .ctl svg { width: 1.4rem; height: 1.4rem; }
html.tv #ctl-play svg { width: 1.75rem; height: 1.75rem; }
html.tv .ctl-main { width: 2.9rem; height: 2.9rem; }
html.tv .ctl-labelled { width: auto; font-size: 0.85rem; }
html.tv .ctl-labelled svg { width: 1.2rem; height: 1.2rem; }
html.tv .ctl-time { min-height: 2.5rem; font-size: 0.85rem; }
html.tv .ctl:is(:focus, :focus-visible) { outline: var(--ring-w) solid var(--ring); outline-offset: 2px; border-radius: 50%; background: rgb(255 255 255 / 0.18); }
html.tv .ctl-labelled:is(:focus, :focus-visible), html.tv .ctl-time:is(:focus, :focus-visible) { border-radius: var(--control-radius); }
html.tv .timeline:is(:focus, :focus-visible) { outline: none; }
html.tv .timeline:focus .tl-thumb,
/* Seeking from the picture: the timeline shows what left and right are moving. */
html.tv .stage:has(video:focus):not(.idle) .tl-thumb { box-shadow: 0 0 0 0.25rem var(--ring); transform: scale(1.25); }
html.tv .timeline:focus .tl-track { height: 7px; }
/* Menus, cards and Up next sit above the controls and inside the screen's edges. */
html.tv .player-menu { right: var(--gutter); bottom: calc(var(--safe-y) + 5.25rem); max-height: calc(100% - 2 * var(--safe-y) - 9rem); width: 20rem; padding: 0.9rem 1.1rem 1rem; gap: 0.7rem; animation: none; }
html.tv .player-menu :is(select, input, button):focus { outline: var(--ring-w) solid var(--ring); outline-offset: 2px; }
html.tv .choice select { min-height: 2.3rem; padding: 0.35rem 0.7rem; font-size: 0.9rem; }
html.tv .player-menu .check { min-height: 2.2rem; }
html.tv :is(.skip, .up-next) { right: var(--gutter); bottom: calc(var(--safe-y) + 5.25rem); }
html.tv .up-next { width: 20rem; padding: 0.9rem 1.1rem; }
html.tv .rate-card { left: var(--gutter); }
html.tv :is(.panel-float, .party) { top: calc(var(--safe-y) + 3.25rem); max-height: calc(100% - 2 * var(--safe-y) - 9rem); overflow-y: auto; }
html.tv .playback-info { left: var(--gutter); top: calc(var(--safe-y) + 3.25rem); }
html.tv .mini-guide { top: calc(var(--safe-y) + 3.25rem); right: var(--gutter); bottom: calc(var(--safe-y) + 5.25rem); }
html.tv .chapter-pics { bottom: calc(var(--safe-y) + 5rem); padding-inline: var(--gutter); }
html.tv .player-error { padding: var(--safe-y) var(--gutter); }
html.tv .stage > .toasts { bottom: calc(var(--safe-y) + 5.5rem); }
html.tv .danmaku { top: calc(var(--safe-y) + 3rem); }
html.tv .danmaku-reacts { right: var(--gutter); }
html.tv .dm { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgb(0 0 0 / 0.55); }
html.tv .live-filler-box { padding: calc(var(--safe-y) + 3rem) var(--gutter) var(--safe-y); }
/* Watch together's panel as a sheet down the right of the screen (party.css): its words and its
   Close keep inside the edges, however the sheet itself is drawn. Its note, likewise. */
html.tv #player #party-panel.party-panel { padding-top: max(2rem, var(--safe-y)); padding-right: max(2rem, var(--gutter)); padding-bottom: max(2rem, var(--safe-y)); }
html.tv #player #party-panel.party-panel .party-close { margin: 0; }
html.tv #player .party-note { right: var(--gutter); top: calc(var(--safe-y) + 3.25rem); }

/* ---------- Everywhere ---------- */
/* No blur behind anything: each one is redrawn by the graphics chip whenever what's behind it
   moves, and TV sticks have little to spare. */
html.tv :is(.top, .badge, .rail-btn, .banner-arrow, .banner .ghost, .ch-badge, .dm, .tab-bar) { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
html.tv .party-card-who::before { animation: none; }
html.tv .top:not(.compact-nav) .nav a::after { transition: none; }
/* Nothing scrolls by a scrollbar on a TV: the remote moves focus and what has it comes into view. */
html.tv :is(.settings-main, .shell-nav-list, dialog.modal, .player-menu, .panel-float, .party, .talk-log, .mg-list, .account-links, .guide-scroll) { scrollbar-width: none; }
html.tv :is(.settings-main, .shell-nav-list, dialog.modal, .player-menu, .panel-float, .party, .talk-log, .mg-list, .account-links, .guide-scroll)::-webkit-scrollbar { display: none; }

/* Words for a TV's remote, or for the mouse and keyboard (game.html). */
html:not(.tv) .tv-only, html.tv .not-tv { display: none; }
/* And for a phone's touch screen (game.html marks phones). */
html:not(.phone) .phone-only, html.phone .not-phone { display: none; }

/* A game opened on a TV (game-player.js): one line and Back, in the middle of the screen. */
html.tv .game-start.elsewhere .game-start-inner { grid-template-columns: minmax(0, 1fr); max-width: 40rem; }
html.tv .game-start.elsewhere h1 { font-size: 1.6rem; }

/* Server settings and the site editor stay on computers and phones (main.js shows a page that
   says so); the ways into them go. */
html.tv #admin-link, html.tv #admin-home-link, html.tv #admin-shortcut { display: none !important; }
html.tv .tv-manage .actions { margin-top: 1.2rem; }
