/* The player, as the TV's calm player (PlayerChrome.kt): no boxes. A gradient over the top with a round
   Back and the title; at the bottom one gradient with a thin gold scrubber (elapsed left, time left right)
   and round icon buttons. Everything fades, nothing slides. Every desktop control stays (volume, cast,
   resolution, audio and subtitles, sources, fullscreen). No blur, so mpv underneath stays cheap. */
.player-panel {
  --chrome-text: #f4f2ed;
  --panel: rgb(20 20 22 / .9);
  inset: 0;
  background: #050505;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  cursor: none;
}
.player-panel.controls-visible,
.player-panel.paused {
  cursor: default;
}
.player-chrome {
  opacity: 0;
  transition: opacity 320ms var(--ease);
  pointer-events: none;
}
.controls-visible .player-chrome,
.player-panel.paused .player-chrome {
  opacity: 1;
  pointer-events: auto;
}
.player-idle-surface {
  position: absolute;
  inset: 0;
  z-index: 1;
}
.player-panel video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.player-heading {
  position: absolute;
  inset: 0 0 auto;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 24px 48px 40px 40px;
  background: linear-gradient(rgb(0 0 0 / .4), transparent);
}
.player-heading h2 {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 16px;
  font-weight: 500;
  color: rgb(246 240 223 / .85);
  text-shadow: 0 1px 6px #000;
}
/* Round, unfilled buttons: a soft fill and a light icon on hover or focus, gold when on. */
.player-panel .icon-button {
  width: 40px;
  height: 40px;
  min-width: 40px;
  min-height: 40px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--chrome-text);
  transition: background 180ms, color 180ms;
}
.player-panel .icon-button svg {
  width: 20px;
  height: 20px;
}
.player-panel .icon-button:is(:hover, :focus-visible) {
  background: var(--glass);
  color: var(--accent-light);
}
.player-panel :is(.captions-active, #cast-toggle.connected, .icon-button[aria-expanded="true"]) {
  color: var(--accent);
}
/* Paused: one outlined gold ring with the play glyph, no fill and no glow. */
.player-center-toggle {
  position: absolute;
  z-index: 3;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent);
  background: transparent;
  color: var(--chrome-text);
  opacity: 0;
  pointer-events: none;
  transition: opacity 320ms;
}
.player-center-toggle svg {
  width: 22px;
  height: 22px;
}
.player-panel.paused .player-center-toggle {
  opacity: 1;
  pointer-events: auto;
}
/* A short line just above the scrubber ("No other source to try."). */
.playback-status {
  position: absolute;
  bottom: 132px;
  z-index: 3;
  max-width: 80%;
  text-align: center;
  font-size: 14px;
  color: rgb(244 242 237 / .8);
  text-shadow: 0 1px 6px #000;
  pointer-events: none;
}
.playback-status:empty,
#player-panel.is-loading #playback-status {
  visibility: hidden;
}
.player-panel #resume-play {
  position: absolute;
  top: 55%;
  z-index: 3;
}
.player-controls {
  position: absolute;
  inset: auto 0 0;
  z-index: 3;
  display: grid;
  gap: 8px;
  padding: 64px 48px max(24px, env(safe-area-inset-bottom));
  background: linear-gradient(transparent, rgb(0 0 0 / .6));
}
.scrub-row,
.control-row {
  display: flex;
  align-items: center;
  gap: 14px;
}
.control-spacer {
  flex: 1;
}
.time-display {
  flex-shrink: 0;
  min-width: 44px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: rgb(244 242 237 / .7);
  white-space: nowrap;
}
#time-remaining {
  text-align: right;
}
/* The scrubber: one hairline, the buffered part lighter, the played part gold; thicker and with a thumb
   and halo on hover or focus. */
.seek-wrap {
  --played: 0%;
  --h: 2px;
  position: relative;
  flex: 1;
  height: 24px;
  display: grid;
  align-items: center;
}
.seek-wrap:is(:hover, :focus-within) {
  --h: 3px;
}
.seek-wrap::before,
.seek-wrap::after,
.buffer-bar {
  content: "";
  position: absolute;
  left: 0;
  height: var(--h);
  border-radius: 2px;
  pointer-events: none;
}
.seek-wrap::before {
  width: 100%;
  background: rgb(255 255 255 / .12);
}
.buffer-bar {
  width: var(--buffer, 0%);
  background: rgb(255 255 255 / .25);
}
.seek-wrap::after {
  width: var(--played);
  background: color-mix(in srgb, var(--accent) 85%, transparent);
}
.player-panel input[type="range"] {
  padding: 0;
  border: 0;
  border-radius: 0;
  accent-color: var(--accent);
}
.seek {
  appearance: none;
  position: relative;
  z-index: 1;
  width: 100%;
  height: 24px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}
.seek::-webkit-slider-runnable-track {
  height: 3px;
  background: transparent;
}
.seek::-webkit-slider-thumb {
  appearance: none;
  width: 8px;
  height: 8px;
  margin-top: -2.5px;
  border-radius: 50%;
  background: var(--accent-light);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 25%, transparent);
  opacity: 0;
  transition: opacity 180ms;
}
.seek:is(:hover, :focus-visible)::-webkit-slider-thumb {
  opacity: 1;
}
.seek::-moz-range-thumb {
  width: 8px;
  height: 8px;
  border: 0;
  background: var(--accent-light);
}
.volume-control {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}
.volume {
  width: 76px;
  height: 40px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms;
}
.volume-control:is(:hover, :focus-within) .volume {
  opacity: 1;
  pointer-events: auto;
}
/* Menus and cards: bottom right, above the scrubber, one quiet surface rising 8px as they fade in. */
.player-menu,
.source-card {
  position: absolute;
  right: 48px;
  bottom: 112px;
  z-index: 4;
  width: min(320px, calc(100% - 32px));
  border: 1px solid var(--hairline-soft);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: 0 18px 60px rgb(0 0 0 / .6);
}
.player-menu {
  max-height: min(360px, 60svh);
  overflow: auto;
  padding: 10px 8px;
}
.player-menu h3 {
  margin: 8px 10px 4px;
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
}
.player-menu h3:not(:first-child) {
  margin-top: 14px;
}
.player-menu button {
  width: 100%;
  min-height: 40px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  font-size: 14px;
  text-align: left;
  color: var(--chrome-text);
}
.player-menu button > span {
  flex: 1;
}
.player-menu button small,
.audio-evidence {
  font-size: 12px;
  color: var(--muted);
}
.audio-evidence {
  margin: 4px 10px 8px;
  line-height: 1.5;
}
.player-menu button:is(:hover, :focus-visible),
.source-card button:is(:hover, :focus-visible) {
  outline: none;
  border-color: var(--accent);
  background: rgb(255 255 255 / .08);
}
/* The chosen row: a small gold dot before a gold-light label. */
.player-menu button:is([aria-checked="true"], [aria-pressed="true"]) {
  color: var(--accent-light);
}
.player-menu button::before {
  content: "";
  flex: 0 0 5px;
  height: 5px;
  border-radius: 50%;
}
.player-menu button:is([aria-checked="true"], [aria-pressed="true"])::before {
  background: var(--accent);
}
.player-menu button:disabled {
  opacity: .42;
  cursor: default;
}
#quality-menu .quality-download {
  margin-top: 6px;
  border-top-color: var(--hairline-soft);
}
#try-another-source {
  color: var(--accent);
}
/* The addon advice under the loading screen's words (what each addon answered, and a fix). */
.source-diagnostics {
  display: grid;
  gap: 4px;
  margin: 8px 0 14px;
  padding: 0;
  list-style: none;
}
#cast-menu { background: var(--panel); }
#cast-toggle { flex: 0 0 40px; }
.cast-destination { position: absolute; top: 84px; left: 40px; right: 40px; color: var(--accent); font-size: 14px; pointer-events: none; }
/* A source in trouble (ProblemCard): why, a hint, then Switch source (with a gold dot) and Keep waiting. */
.source-card {
  padding: 14px 8px 8px;
  cursor: default;
}
.player-panel:not(.controls-visible, .paused) :is(.source-card, .up-next-card) {
  bottom: 48px;
}
.card-message {
  margin: 0 10px 2px;
  font-size: 14px;
  font-weight: 500;
}
.card-hint {
  margin: 0 10px;
  font-size: 12px;
  color: var(--muted);
}
.source-card button {
  width: 100%;
  min-height: 40px;
  margin-top: 6px;
  padding: 0 10px 0 25px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  font-size: 14px;
  text-align: left;
  color: var(--chrome-text);
}
.source-card [data-card="switch"] {
  padding-left: 10px;
}
.source-card [data-card="switch"]::before {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin: 0 10px 2px 0;
  border-radius: 50%;
  background: var(--accent);
}
/* Up Next (UpNextCard): frameless, the words right-aligned over a shadow rising from the corner; a round
   play button whose gold ring runs down the episode countdown, and a quiet Cancel / Not now. */
.up-next-card {
  position: absolute;
  right: 48px;
  bottom: 112px;
  z-index: 3;
  max-width: 440px;
  display: grid;
  justify-items: end;
  gap: 4px;
  text-align: right;
  cursor: default;
}
.up-next-card::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -140px -48px -112px -220px;
  background: radial-gradient(ellipse at 100% 100%, rgb(0 0 0 / .55), transparent 70%);
  pointer-events: none;
}
.up-next-label {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--accent);
}
.up-next-title {
  max-width: 100%;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 22px;
  font-weight: 500;
  color: #f6f0df;
}
.up-next-actions {
  margin-top: 12px;
  display: flex;
  align-items: center;
  gap: 22px;
}
.up-next-actions button {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0;
  border: 0;
  background: transparent;
  font-size: 15px;
  color: var(--chrome-text);
}
.up-next-ring {
  position: relative;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hairline);
  border-radius: 50%;
  background: rgb(255 255 255 / .06);
  transition: background 180ms;
}
.up-next-ring svg {
  width: 20px;
  height: 20px;
}
.up-next-ring .countdown-ring {
  position: absolute;
  top: -1px;
  left: -1px;
  width: 48px;
  height: 48px;
  rotate: -90deg;
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
}
.up-next-card.counting .countdown-ring {
  stroke-dashoffset: 0;
}
.up-next-play:is(:hover, :focus-visible) .up-next-ring {
  background: rgb(255 255 255 / .15);
}
.quiet-action {
  opacity: .7;
  text-decoration: underline 1px transparent;
  text-underline-offset: 4px;
}
.up-next-actions button:is(:hover, :focus-visible) {
  outline: none;
  color: var(--accent-light);
  opacity: 1;
}
.quiet-action:is(:hover, :focus-visible) {
  text-decoration-color: var(--accent);
}
/* Skip intro (SkipIntroCard): one quiet pill where Up Next sits, gold words and a small dismiss. */
.skip-intro-pill {
  position: absolute;
  right: 48px;
  bottom: 112px;
  z-index: 3;
  display: flex;
  padding: 4px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: rgb(10 10 12 / .78);
  box-shadow: 0 12px 32px rgb(0 0 0 / .35);
}
.skip-intro-pill button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 12px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font: inherit;
}
.skip-intro-go {
  padding-left: 20px !important;
  font-weight: 600;
  color: var(--accent-light) !important;
}
.skip-intro-pill svg {
  width: 17px;
  height: 17px;
}
.skip-intro-pill button:is(:hover, :focus-visible) {
  outline: none;
  background: rgb(255 255 255 / .1);
  color: var(--text);
}
.up-next-seconds {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--muted);
}
/* While a title starts: its poster in a constellation, as on the TV's quiet loading screen. One centred
   column (poster, title, episode, stage, detail) under the wordmark. The stars and the poster share one
   unit (the poster's height): the constellation's viewBox is 3.6 by 1.6 units around the poster. */
.player-loading {
  --unit: clamp(140px, 24vh, 220px);
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 6px;
  padding: 96px 24px 150px;
  overflow: hidden;
  background: var(--base-bg);
  text-align: center;
  pointer-events: none;
  transition: opacity 450ms;
}
/* The wordmark top left; the player's own title stays away until the picture shows. */
.loading-wordmark {
  position: absolute;
  top: 30px;
  left: 96px;
  font-size: 22px;
}
#player-panel.is-loading #playing-title {
  visibility: hidden;
}
.player-loading .loading-stage {
  position: relative;
  width: calc(var(--unit) * 2 / 3);
  height: var(--unit);
  margin: 0 0 18px;
  translate: 0 -12px;
}
.player-loading .loading-stage::before {
  content: "";
  position: absolute;
  inset: -40%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) calc(10% + 10% * var(--p, 0)), transparent), transparent);
}
.player-loading .constellation {
  position: absolute;
  left: 50%;
  top: calc(var(--unit) * -0.45);
  width: calc(var(--unit) * 3.6);
  height: calc(var(--unit) * 1.6);
  translate: -50% 0;
  transition: opacity 600ms var(--ease);
}
.player-loading img {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 14px;
  border: 1px solid color-mix(in srgb, var(--accent) calc(22% + 28% * var(--p, 0)), transparent);
  filter: grayscale(calc(1 - var(--p, 0))) brightness(calc(.55 + .45 * var(--p, 0)));
  transition: filter 900ms var(--ease), border-color 900ms var(--ease);
}
/* Before anyone answers: three faint lights circle the poster. */
.loading-orbit {
  position: absolute;
  inset: 0;
  display: none;
  animation: orbit 6s linear infinite;
}
.player-loading.searching .loading-orbit {
  display: block;
}
.loading-orbit i {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 5px;
  height: 5px;
  margin: -2.5px;
  border-radius: 50%;
  background: var(--accent-light);
  opacity: .35;
  transform: rotate(calc(var(--n, 0) * 120deg)) translateX(calc(var(--unit) * .62));
}
.loading-orbit i:nth-child(2) { --n: 1; }
.loading-orbit i:nth-child(3) { --n: 2; }
@keyframes orbit {
  to { rotate: 1turn; }
}
.player-loading .loading-title {
  max-width: 70vw;
  font-size: 24px;
  font-weight: 700;
  line-height: 1.2;
}
.player-loading .loading-episode {
  color: var(--meta);
  font-size: var(--fs-meta);
}
.player-loading :is(.loading-episode, .loading-detail):empty {
  display: none;
}
:is(.player-loading, .search-waiting) .loading-headline {
  margin-top: 8px;
  font-size: 15px;
  font-weight: 500;
  color: rgb(247 247 248 / .85);
}
:is(.player-loading, .search-waiting) .loading-detail {
  color: var(--muted);
  font-size: 13px;
}
.player-loading.failed .loading-headline {
  color: var(--accent-light);
}
.player-loading .loading-extra {
  max-width: 560px;
  color: var(--muted);
  font-size: 14px;
  pointer-events: auto;
}
.player-loading .loading-extra:empty {
  display: none;
}
/* Living, not frozen: lit stars breathe and each new line draws itself in (also while searching). */
:is(.player-loading, .search-waiting) .constellation .halo {
  transform-box: fill-box;
  transform-origin: center;
  animation: star-breathe 6s ease-in-out infinite;
  animation-delay: var(--delay, 0ms);
}
:is(.player-loading, .search-waiting) .constellation .link {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: line-draw 1100ms var(--ease) forwards;
}
@keyframes star-breathe {
  0%, 100% { opacity: .12; scale: 1; }
  50% { opacity: .3; scale: 1.5; }
}
@keyframes line-draw {
  to { stroke-dashoffset: 0; }
}
/* Nothing could start: the poster stays grey, the stars rest, and the words say why. */
.player-loading.failed .constellation {
  opacity: .35;
}
.player-loading.failed .constellation * {
  animation-play-state: paused;
}
.player-loading.revealed {
  opacity: 0;
}
/* The breathing mark (HoldFrame.kt): a hairline ring whose gold arc fills with the torrent's buffer, the
   gold bar and dot inside, breathing. Alone over a stalled picture, or over the last frame of the old
   source (letterboxed, dimmed) while another starts. Words only after a long wait. */
.player-mark {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 14px;
  opacity: 0;
  transition: opacity 320ms;
  pointer-events: none;
}
.player-mark.shown {
  opacity: 1;
}
.player-mark.held {
  background: #000;
}
.player-mark.held img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: brightness(.75);
}
.breathing-mark {
  position: relative;
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  animation: breathe 1200ms ease-in-out infinite alternate;
}
.breathing-mark svg {
  position: absolute;
  inset: 0;
  rotate: -90deg;
  fill: none;
  stroke-width: 1.5;
}
.mark-ring {
  stroke: rgb(255 255 255 / .15);
}
.mark-arc {
  stroke: color-mix(in srgb, var(--accent) 90%, transparent);
  stroke-dasharray: 100;
  stroke-dashoffset: calc(100 - 100 * var(--arc, 0));
  opacity: 0;
  transition: stroke-dashoffset 600ms var(--ease);
}
.player-mark.ring .mark-arc {
  opacity: 1;
}
.mark-bar {
  width: 5px;
  height: 22px;
  border-radius: 3px;
  background: linear-gradient(var(--accent-light), var(--accent));
  translate: -4px 0;
}
.mark-dot {
  position: absolute;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  translate: 5px 8px;
}
@keyframes breathe {
  from { scale: .94; opacity: .6; }
  to { scale: 1; opacity: 1; }
}
.mark-words {
  position: relative;
  margin: 0;
  font-size: 13px;
  color: rgb(244 242 237 / .75);
  text-shadow: 0 1px 6px #000;
}
/* Low motion: still stars, whole lines, a still mark; the search field's gold line rests out of sight. */
body[data-motion="low"] :is(.player-loading *, .search-waiting *, .search.busy #search-input, .breathing-mark) {
  animation: none;
  stroke-dashoffset: 0;
}
@media (prefers-reduced-motion: reduce) {
  :is(.player-loading *, .search-waiting *, .search.busy #search-input, .breathing-mark) {
    animation: none;
    stroke-dashoffset: 0;
  }
}
@media (hover: none), (pointer: coarse) {
  .volume,
  .seek::-webkit-slider-thumb {
    opacity: 1;
    pointer-events: auto;
  }
}
@media (max-width: 600px) {
  .player-heading { padding: 16px; }
  .player-panel .icon-button { width: 44px; height: 44px; min-width: 44px; }
  .player-controls { padding: 48px 16px max(12px, env(safe-area-inset-bottom)); }
  .control-row { gap: 0; }
  .volume { position: absolute; bottom: 64px; left: 56px; width: 80px; }
  :is(.player-menu, .source-card) { right: 10px; left: 10px; width: auto; bottom: 100px; }
  .up-next-card { right: 16px; left: 16px; bottom: 100px; }
  .player-loading { --unit: clamp(130px, 24vh, 190px); padding: 72px 16px 140px; }
  .loading-wordmark { left: 72px; top: 16px; }
  .cast-destination { top: 76px; left: 20px; right: 20px; }
}
