/* ── Muvi web TV ────────────────────────────────────────────────────────────
   A television UI in a browser. Two things drive every decision here:

   1. The viewer is ~3m away with a remote, not 50cm away with a mouse. Type is
      large, hit targets are huge, and FOCUS IS THE CURSOR — an element that is
      focused must be unmistakable from across a room, which is why the ring is
      a 4px accent border plus a scale, never a subtle outline.
   2. Televisions overscan. Nothing meaningful may sit in the outer ~4%, and
      rails must pad BEYOND that inset because the focus ring and the 1.06
      scale overflow a card's own bounds.

   Colours and the font come from the main site (assets/site.css) so the two
   read as one product. ──────────────────────────────────────────────────── */

@font-face {
  font-family: 'IRANSansX';
  src: url('/assets/fonts/IRANSansX-Regular.woff2') format('woff2'),
       url('/assets/fonts/IRANSansX-Regular.ttf') format('truetype');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IRANSansX';
  src: url('/assets/fonts/IRANSansX-Medium.woff2') format('woff2'),
       url('/assets/fonts/IRANSansX-Medium.ttf') format('truetype');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IRANSansX';
  src: url('/assets/fonts/IRANSansX-DemiBold.woff2') format('woff2'),
       url('/assets/fonts/IRANSansX-DemiBold.ttf') format('truetype');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IRANSansX';
  src: url('/assets/fonts/IRANSansX-Bold.woff2') format('woff2'),
       url('/assets/fonts/IRANSansX-Bold.ttf') format('truetype');
  font-weight: 700; font-style: normal; font-display: swap;
}

:root {
  --accent: #e53935;
  --accent-dim: rgba(229, 57, 53, 0.22);
  --text: #ffffff;
  --text-dim: rgba(255, 255, 255, 0.62);
  --text-faint: rgba(255, 255, 255, 0.34);
  --chip: rgba(255, 255, 255, 0.10);
  --card: rgba(255, 255, 255, 0.06);
  --gold: #f5c518;

  /* Overscan inset. Rails deliberately pad past it — see .rail-row. */
  --safe: 4vw;
  --safe-y: 3.2vh;

  /* One knob for the whole layout, so the UI scales with the panel instead of
     assuming 1080p. Clamped because a 4K panel should not render 2× type. */
  --u: clamp(13px, 0.92vw, 20px);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  background: #000;
  color: var(--text);
  font-family: 'IRANSansX', system-ui, -apple-system, 'Segoe UI', sans-serif;
  overflow: hidden;               /* a TV app never scrolls the document */
  -webkit-font-smoothing: antialiased;
}

body { font-size: var(--u); }

#app { position: absolute; inset: 0; }
#overlay { position: fixed; inset: 0; pointer-events: none; z-index: 60; }

/* Focus ring and scale travel together — on a television the ring IS the
   cursor, and a scale without a ring reads as decoration rather than position. */
.focusable {
  outline: none;
  transition: transform .13s ease, box-shadow .13s ease, background-color .13s ease;
}
.focusable.on {
  box-shadow: 0 0 0 4px var(--accent), 0 10px 34px rgba(0,0,0,.6);
  transform: scale(1.06);
  z-index: 5;
}

/* ── Top navigation ─────────────────────────────────────────────────────── */

.nav {
  position: absolute; top: 0; right: 0; left: 0;
  display: flex; align-items: center; gap: .9em;
  padding: var(--safe-y) var(--safe) 1.4em;
  z-index: 20;
  background: linear-gradient(#000 22%, rgba(0,0,0,.72) 62%, transparent);
}
.brand {
  color: var(--accent);
  font-weight: 700;
  font-size: 2.1em;
  letter-spacing: .01em;
  margin-inline-end: .5em;
}
.pill {
  border: 0;
  background: var(--chip);
  color: var(--text);
  font: inherit;
  font-weight: 500;
  font-size: 1.15em;
  padding: .72em 1.5em;
  border-radius: 2em;
  cursor: pointer;
  white-space: nowrap;
}
.pill.sel { background: var(--accent); }
.nav-days {
  margin-inline-start: auto;
  color: var(--gold);
  font-size: 1.02em;
  line-height: 1.35;
  text-align: center;
  font-weight: 500;
}
.nav-days.none { color: var(--text-faint); }

/* ── Scrolling body ─────────────────────────────────────────────────────── */

/* Native scrolling containers rather than transform math: `scrollIntoView`
   already does the right thing in RTL, and hand-rolled offsets in a
   right-to-left layout are a reliable source of off-by-one-viewport bugs.
   Scrollbars are hidden because a television has no pointer to drag them. */
.page {
  position: absolute; inset: 0;
  overflow-y: auto; overflow-x: hidden;
  padding-top: 6.6em;
  scrollbar-width: none;
  scroll-behavior: smooth;
}
.page::-webkit-scrollbar { display: none; }

.rail { margin-bottom: 2.2em; }
.rail-title {
  font-size: 1.6em; font-weight: 700;
  padding: 0 var(--safe) .7em;
}
/* Padding beyond the safe inset: the ring and the 1.06 scale overflow the card
   box, and a card at the edge of a rail would otherwise be clipped mid-ring. */
/* ⚠️ The vertical padding is load-bearing. `overflow-x: auto` makes the block
   axis clip too, so without room for the 1.06 scale and the 4px ring a focused
   card is shaved off at the top and bottom. */
.rail-row {
  display: flex; gap: 1.15em;
  padding: 1.1em calc(var(--safe) + .5em) 1.3em;
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;
  scroll-behavior: smooth;
}
.rail-row::-webkit-scrollbar { display: none; }

.card { flex: 0 0 auto; width: 13.2em; cursor: pointer; border-radius: .85em; }
.card .art {
  width: 100%; aspect-ratio: 2 / 3;
  border-radius: .85em; overflow: hidden;
  background: #14141a;
  display: block;
}
.card .art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card .cap { padding: .55em .2em 0; }
.card .cap b { display: block; font-size: 1.02em; font-weight: 500; line-height: 1.35;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.card .cap span { color: var(--text-faint); font-size: .92em; }

/* Continue-watching cards carry a progress bar, so they are wider and flatter. */
.card.wide { width: 17.5em; }
.card.wide .art { aspect-ratio: 16 / 9; }
.prog { height: .3em; background: rgba(255,255,255,.2); border-radius: 1em; margin-top: .45em; }
.prog i { display: block; height: 100%; background: var(--accent); border-radius: 1em; }

/* ── Detail ─────────────────────────────────────────────────────────────── */

.hero { position: absolute; inset: 0; z-index: 0; }
.hero img { width: 100%; height: 100%; object-fit: cover; opacity: .5; }
.hero::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(to left, rgba(0,0,0,.94) 26%, rgba(0,0,0,.55) 62%, rgba(0,0,0,.2)),
    linear-gradient(to top, #000 4%, transparent 46%);
}

.detail { position: relative; z-index: 1; padding: 0 var(--safe); max-width: 66%; }
.detail h1 { font-size: 3.1em; font-weight: 700; line-height: 1.18; }
.meta { display: flex; gap: 1.3em; align-items: center; flex-wrap: wrap;
  color: var(--text-dim); font-size: 1.15em; margin-top: .5em; }
.meta .star { color: var(--gold); }
.synopsis { margin-top: .9em; font-size: 1.12em; line-height: 1.85;
  color: rgba(255,255,255,.86);
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; }

.row { display: flex; gap: .8em; flex-wrap: wrap; margin-top: 1.15em; }

/* ── Link rows ──────────────────────────────────────────────────────────── */

.link {
  display: flex; align-items: center; gap: 1.2em;
  width: 100%; text-align: start;
  background: rgba(22, 22, 27, .92); border: 0; color: var(--text);
  font: inherit; padding: 1.05em 1.4em; border-radius: .9em; cursor: pointer;
}
.link .play { font-size: 1.5em; color: var(--text-dim); }
.link .who { flex: 1; }
.link .who b { display: block; font-size: 1.22em; font-weight: 600; }
.link .who span { color: var(--text-faint); font-size: .98em; }
.link .size { color: var(--text-dim); font-size: 1.02em; white-space: nowrap; }
.badge {
  font-size: .92em; font-weight: 700; padding: .34em .8em; border-radius: .5em;
  background: rgba(255,255,255,.14);
}
.badge.q4k { background: #6b3fa0; }
.badge.q1080 { background: #1f6fb2; }
.badge.q720 { background: #10736b; }

/* Above the hero, and opaque enough to read against it. The backdrop shows
   through a translucent row just enough to make Persian text at this size
   genuinely hard to read from a sofa. */
.list {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; gap: .7em;
  padding: .5em var(--safe) 2em;
}

/* ── Episodes ───────────────────────────────────────────────────────────── */

.ep { display: flex; gap: 1.1em; align-items: stretch; }
.ep .still { flex: 0 0 14em; aspect-ratio: 16/9; border-radius: .6em;
  overflow: hidden; background: #14141a; }
.ep .still img { width: 100%; height: 100%; object-fit: cover; }
.ep .body { flex: 1; min-width: 0; }
.ep .body p { color: var(--text-faint); font-size: .98em; line-height: 1.6; margin-top: .3em;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }

/* ── Pairing ────────────────────────────────────────────────────────────── */

.pair { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; gap: 5em; padding: var(--safe); }
.qr-side { display: flex; flex-direction: column; align-items: center; gap: 1em; }
.qr-cap { color: var(--text-dim); font-size: 1.12em; }
.pair .qr { background: #fff; padding: 1.5em; border-radius: 1.6em; line-height: 0; }
.pair .qr img, .pair .qr svg { width: 22em; height: 22em; display: block; }
.pair .side { max-width: 30em; }
.pair h1 { font-size: 2.6em; font-weight: 700; }
.pair p { color: var(--text-dim); font-size: 1.2em; margin-top: .6em; line-height: 1.8; }
.code {
  font-size: 4.2em; font-weight: 700; color: var(--gold);
  letter-spacing: .13em; margin: .45em 0 .2em; direction: ltr; text-align: start;
  font-variant-numeric: tabular-nums;
}
.get-app {
  display: flex; align-items: center; gap: 1em;
  margin-top: 1.3em; padding-top: 1.2em;
  border-top: 1px solid rgba(255,255,255,.10);
}
.get-app b { display: block; font-size: 1.1em; font-weight: 600; margin-bottom: .2em; }
.get-app span { color: var(--text-faint); font-size: 1em; line-height: 1.7; }
.pair .qr.small { padding: .55em; border-radius: .8em; flex: 0 0 auto; }
.pair .qr.small img { width: 7.5em; height: 7.5em; }

.steps { margin: 1em 1.2em 0 0; padding: 0; color: var(--text-dim);
  font-size: 1.06em; line-height: 1.95; }
.steps li { margin-bottom: .15em; }
.pair .url { color: var(--text-dim); font-size: 1.15em; margin-top: 1em; }
.pair .url { direction: rtl; text-align: start; }
.waiting { display: flex; align-items: center; gap: .7em; color: var(--text-faint);
  margin-top: 1.6em; font-size: 1.1em; }

/* ── Player ─────────────────────────────────────────────────────────────── */

/* ⚠️ The player is LEFT-TO-RIGHT, deliberately, while the rest of the app is
   RTL. A video transport is not prose: the progress bar fills with time, and
   time runs left-to-right on every player anyone has ever used. Mirroring it
   makes a familiar control read backwards — the elapsed time lands on the
   right, the bar drains instead of filling. Persian text inside still shapes
   correctly; bidi handles that on its own. */
/* ── Player ──────────────────────────────────────────────────────────────────
   A plain <video> plus our own transport. The browser's native controls are
   not used: on a television they are unreachable (no pointer, and the D-pad
   cannot enter the shadow DOM), and their layout is LTR-only with Latin
   digits. Everything below is focusable so the same UI serves a remote, a
   mouse and a touchscreen. */
.player {
  position: absolute; inset: 0; background: #000; z-index: 50;
  direction: ltr;
}
.player video { width: 100%; height: 100%; background: #000; display: block; }
/* Fullscreen puts .player itself in the fullscreen layer, so the controls come
   with it. The video alone would drop them. */
.player:fullscreen, .player:-webkit-full-screen { width: 100vw; height: 100vh; }

.controls {
  position: absolute; inset: auto 0 0 0;
  padding: 7em var(--safe) var(--safe-y);
  /* Reaches near-opaque well before the title, not after it: film content is
     often bright exactly where the transport sits, and white-on-white is the
     failure mode a gradient tuned on a dark scene never shows you. */
  background: linear-gradient(transparent, rgba(0,0,0,.18) 14%, rgba(0,0,0,.6) 38%, rgba(0,0,0,.9) 64%, rgba(0,0,0,.97) 100%);
  transition: opacity .25s ease, transform .25s ease;
  /* The title is Persian; the transport is not. Text flows RTL here and the
     bar, clock and button row each opt back into LTR below — a progress bar
     that filled right-to-left would be wrong in every language. */
  direction: rtl;
}
.controls.hide { opacity: 0; transform: translateY(1.2em); pointer-events: none; }
.controls h2 { font-size: 1.7em; font-weight: 600; }
.substate { color: var(--text-faint); font-size: 1.02em; margin-top: .3em; min-height: 1.4em; }

/* Cues sit above the transport rather than behind it. */
.player video::cue { font-family: 'IRANSansX', sans-serif; font-size: .92em;
  background: rgba(0,0,0,.62); line-height: 1.5; }
.player video::-webkit-media-text-track-container { bottom: 14%; }

/* ── Seek bar ──
   The hit area is deliberately taller than the painted track: on a touchscreen
   a .42em bar is unhittable, and on a mouse it demands precision nobody has. */
.pbar {
  direction: ltr; position: relative;
  margin: 1.1em 0 .35em; padding: .75em 0;
  cursor: pointer; outline: none;
}
.pbar .track {
  position: relative; height: .42em; border-radius: 1em;
  background: rgba(255,255,255,.26); overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0,0,0,.35);
}
/* Buffered ahead of the playhead — the difference between "stalled" and
   "still loading" is the first thing a viewer wants to know. */
.pbar .buf { position: absolute; inset: 0 auto 0 0; width: 0;
  background: rgba(255,255,255,.30); border-radius: 1em; }
.pbar .fill { position: absolute; inset: 0 auto 0 0; width: 0;
  background: var(--accent); border-radius: 1em; }
.pbar .knob {
  position: absolute; top: 50%; left: 0;
  width: 1.15em; height: 1.15em; margin: -.575em 0 0 -.575em;
  border-radius: 50%; background: var(--accent);
  box-shadow: 0 2px 10px rgba(0,0,0,.6);
  transform: scale(0); transition: transform .14s ease;
}
.pbar.on .knob, .pbar:hover .knob, .pbar.scrubbing .knob { transform: scale(1); }
.pbar.on .track, .pbar:hover .track { height: .58em; }
.pbar .track { transition: height .14s ease; }
/* The focus ring is drawn on the track, not the padded hit area, or it floats
   detached from the thing it is pointing at. */
.pbar.on { box-shadow: none; transform: none; }
.pbar.on .track { box-shadow: 0 0 0 .22em var(--accent-dim); }

/* Scrub bubble — the target time while dragging or D-pad seeking. Without it a
   held arrow key is a guess. */
.pbar .bubble {
  position: absolute; bottom: 100%; left: 0; transform: translateX(-50%);
  background: rgba(12,12,16,.96); border: 1px solid rgba(255,255,255,.16);
  padding: .3em .7em; border-radius: .45em; font-size: 1.05em;
  white-space: nowrap; opacity: 0; transition: opacity .14s ease;
  pointer-events: none;
}
.pbar.scrubbing .bubble { opacity: 1; }

.times { display: flex; justify-content: space-between; color: var(--text-dim);
  font-size: 1.02em; direction: ltr; }

/* ── Transport buttons ── */
.pbtns {
  direction: ltr; display: flex; align-items: center; gap: .55em;
  margin-top: 1.1em;
}
.pbtns .gap { flex: 1; }
.pbtn {
  background: var(--chip); border: 0; color: var(--text);
  font: inherit; font-size: 1em; line-height: 1;
  width: 2.9em; height: 2.9em; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; outline: none; position: relative;
  transition: background-color .14s ease, transform .13s ease, box-shadow .13s ease;
}
.pbtn:hover { background: rgba(255,255,255,.2); }
.pbtn.on { box-shadow: 0 0 0 4px var(--accent), 0 10px 34px rgba(0,0,0,.6); transform: scale(1.06); z-index: 5; }
.pbtn.primary { width: 3.6em; height: 3.6em; background: var(--accent); }
.pbtn.primary:hover { background: #f2453f; }
.pbtn.active { background: var(--accent-dim); box-shadow: inset 0 0 0 2px var(--accent); }
.pbtn.active.on { box-shadow: 0 0 0 4px var(--accent), 0 10px 34px rgba(0,0,0,.6); }
.pbtn svg { width: 1.35em; height: 1.35em; fill: currentColor; pointer-events: none; }
.pbtn.primary svg { width: 1.6em; height: 1.6em; }
/* Skip buttons carry their step as a numeral in the arrow's hollow centre.
   ⚠️ Absolutely positioned WITH insets: an abs-positioned flex child with no
   offsets falls back to its static position, which put the numeral off to the
   side of the glyph instead of inside it. */
.pbtn.skip .step {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding-top: .18em;
  font-size: .64em; font-weight: 700; letter-spacing: -.03em;
  pointer-events: none;
}
.pbtn svg.flip { transform: scaleX(-1); }
.pbtn[hidden] { display: none; }

/* Label that names the focused control, since a circle of glyphs is not
   self-describing on a screen three metres away. */
.pbtn-label {
  direction: rtl; color: var(--text-dim); font-size: 1.05em;
  min-height: 1.5em; margin-top: .7em; text-align: center;
}

/* ── Centre overlays ── */
.player .buffering {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  pointer-events: none;
}
.player .buffering .spinner { width: 3.4em; height: 3.4em; border-width: .22em; }
/* A paused film should say so from across the room, not only in the transport. */
.player .paused-badge {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 5.2em; height: 5.2em; border-radius: 50%;
  background: rgba(0,0,0,.55); border: 2px solid rgba(255,255,255,.28);
  display: flex; align-items: center; justify-content: center;
  pointer-events: none; opacity: 0; transition: opacity .18s ease;
}
.player .paused-badge svg { width: 2.2em; height: 2.2em; fill: #fff; }
.player .paused-badge.show { opacity: 1; }

/* ── Small shared pieces ────────────────────────────────────────────────── */

.spinner {
  width: 1.5em; height: 1.5em; border-radius: 50%;
  border: .17em solid rgba(255,255,255,.22); border-top-color: var(--accent);
  animation: spin .9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.center { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; flex-direction: column; gap: 1.1em; }
.note { color: var(--text-dim); font-size: 1.25em; text-align: center;
  max-width: 34em; line-height: 1.9; padding: 0 var(--safe); }

#hint {
  position: fixed; inset: auto var(--safe) .9em auto;
  display: flex; gap: 1.4em; color: rgba(255,255,255,.24); font-size: .95em; z-index: 70;
}
#hint[hidden] { display: none; }

.toast {
  position: fixed; inset: auto 0 8vh 0; margin: 0 auto; width: max-content; max-width: 70vw;
  background: rgba(20,20,24,.97); border: 1px solid rgba(255,255,255,.12);
  padding: 1em 1.7em; border-radius: .8em; font-size: 1.15em; z-index: 80;
}

/* The keyboard is the only place a dense grid of small targets is right, and
   it still has to be reachable one key at a time. */
.kb { display: grid; grid-template-columns: repeat(8, 1fr); gap: .55em; max-width: 44em; }
.key {
  background: var(--chip); border: 0; color: var(--text); font: inherit; font-size: 1.3em;
  padding: .55em 0; border-radius: .5em; cursor: pointer; text-align: center;
}
.key.wide { grid-column: span 2; font-size: 1.05em; }
.search-head { display: flex; gap: 1.2em; align-items: center; padding: 0 var(--safe) 1.2em; }
.search-box {
  flex: 1; background: var(--card); border-radius: .8em; padding: .85em 1.2em;
  font-size: 1.4em; min-height: 2.6em; color: var(--text);
}
.search-box.empty { color: var(--text-faint); }
