/* The shared library player's own chrome: one trigger in the host's control
   row, one status line, one settings popover (a bottom sheet at phone width).
   Self-contained on purpose: the desktop app, /m and the watch room each bring
   a different stylesheet, so every colour falls back through all three token
   sets (--text | --ink, --border | --line, --accent | --brass). */
.playback-quality, .playback-menu {
  --pb-text: var(--text, var(--ink, #eeeef4));
  --pb-mute: var(--text-dim, var(--muted, #abb0bd));
  --pb-line: var(--border-strong, var(--border, var(--line, #454854)));
  --pb-accent: var(--accent, var(--brass, #f6b544));
  --pb-surface: rgba(22, 24, 30, .97);
  --pb-hover: rgba(255, 255, 255, .09);
}

/* ── the trigger ── */
button.playback-quality {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
  min-height: 44px;
  max-width: 190px;
  padding: 0 12px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--pb-text);
  background: rgba(0, 0, 0, .45);
  border: 1px solid var(--pb-line);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}
/* Hosts style the spans of their control row (the watch room's `.transport span`):
   these two are named with enough weight to keep their own shape. */
button.playback-quality .playback-quality-text { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: inherit; font: inherit; }
/* Hover is a POINTER state. On a phone it latches onto the last thing tapped and
   stays there, so the control reads as still-selected. Guarded here; the
   aria-state and :focus halves stay outside, because those are real state. */
@media (hover: hover) {
  button.playback-quality:hover { border-color: var(--pb-mute); background: rgba(0, 0, 0, .6); }
  .vc-bar button.playback-quality:hover { background: rgba(255, 255, 255, .1); }
  .playback-status button:hover { background: var(--bg-hover, #363949); }
  .playback-menu button.playback-row:hover,
  .playback-menu button.playback-back:hover,
  .playback-menu button.playback-nudge:hover { background: var(--pb-hover); }
}
button.playback-quality[aria-expanded="true"] { border-color: var(--pb-accent); }
.playback-quality:focus-visible, .playback-status button:focus-visible,
.playback-menu button:focus-visible {
  outline: 2px solid var(--pb-accent, #f6b544);
  outline-offset: 2px;
}
button.playback-quality .playback-caret {
  width: 6px; height: 6px; flex: none; margin-top: -3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); opacity: .7;
  transition: transform .18s ease, margin .18s ease;
}
button.playback-quality[aria-expanded="true"] .playback-caret { transform: rotate(-135deg); margin-top: 3px; }
/* The desktop control bar is a row of 32px glyph buttons. */
.vc-bar button.playback-quality { min-height: 32px; padding: 0 10px; font-size: 12px; background: transparent; border-color: rgba(255, 255, 255, .22); }
.video-stage.in-popout .vc-bar button.playback-quality { min-height: 26px; padding: 0 7px; font-size: 11px; gap: 5px; }
@media (pointer: coarse) { .vc-bar button.playback-quality { min-height: 44px; } }

/* ── the status line ── */
.playback-status {
  position: absolute;
  top: 64px;
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 32px);
  box-sizing: border-box;
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 8px 12px;
  border-radius: 8px;
  color: var(--text, #eeeef4);
  background: var(--bg-elevated, #242631);
  border: 1px solid var(--border, #454854);
  font-size: 14px;
  line-height: 1.4;
  z-index: 8;
  pointer-events: none;
}
/* The phone player's top bar has no fixed height (a long title wraps it, the
   quality trigger wraps it again), so the status line is placed off the bar's
   MEASURED height — --chrome-top-h, published by the phone app's measureTop —
   clearing the rating strip that floats directly under it. Deliberately NOT in
   the max-width:480px block: #player exists only in the phone shell, and in
   LANDSCAPE that shell is wider than 480px, where the generic top:64px put the
   status line straight back on the stars. */
#player .playback-status { top: calc(var(--chrome-top-h, 78px) + 56px); }
.playback-status[hidden], .playback-status button[hidden] { display: none; }
.playback-status button {
  color: inherit;
  font: inherit;
  border: 1px solid var(--border, #454854);
  background: transparent;
  border-radius: 6px;
  min-width: 44px;
  min-height: 44px;
  padding: 0 10px;
  cursor: pointer;
  pointer-events: auto;
}
.playback-status button:active { opacity: .8; }

/* ── the settings popover ── */
.playback-menu {
  position: fixed;
  z-index: 1400;
  box-sizing: border-box;
  width: 320px;
  max-width: calc(100vw - 16px);
  max-height: min(70vh, 560px);
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  padding: 6px;
  color: var(--pb-text);
  background: var(--pb-surface);
  border: 1px solid var(--pb-line);
  border-radius: 12px;
  box-shadow: 0 16px 44px rgba(0, 0, 0, .62);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  font: 13px/1.35 system-ui, -apple-system, 'Segoe UI', sans-serif;
  text-align: left;
  animation: playback-menu-in .16s cubic-bezier(.22, .61, .36, 1);
}
@keyframes playback-menu-in { from { opacity: 0; transform: translateY(6px); } }
.playback-menu.is-sheet {
  left: 8px; right: 8px; top: auto;
  bottom: max(8px, env(safe-area-inset-bottom));
  width: auto; max-width: none; max-height: 72vh;
  border-radius: 16px;
  animation-name: playback-sheet-in;
}
@keyframes playback-sheet-in { from { opacity: 0; transform: translateY(24px); } }

.playback-menu-head {
  display: flex; align-items: center; gap: 4px;
  min-height: 32px; padding: 2px 6px 4px;
  color: var(--pb-mute);
  font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
}
.playback-menu button {
  font: inherit; color: inherit; text-align: left;
  background: transparent; border: 0; border-radius: 7px;
  cursor: pointer; margin: 0;
}
.playback-menu button.playback-back {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; min-width: 32px; height: 32px; min-height: 32px; padding: 0; margin-left: -4px;
}
.playback-menu button.playback-row {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 40px;
  padding: 6px 10px 6px 30px;
  font-weight: 400;
}
.playback-menu button.playback-row:active,
.playback-menu button.playback-back:active,
.playback-menu button.playback-nudge:active { background: rgba(255, 255, 255, .14); }
.playback-menu button:disabled { opacity: .45; cursor: default; background: transparent; }
.playback-menu button.playback-row.is-danger { color: #ff9a9a; }
/* The tick of the current choice: two borders, no glyph font needed. */
.playback-row.is-on::before {
  content: ''; position: absolute; left: 12px; top: 50%;
  width: 5px; height: 10px; margin-top: -8px;
  border-right: 2px solid var(--pb-accent); border-bottom: 2px solid var(--pb-accent);
  transform: rotate(45deg);
}
.playback-row.is-on .playback-row-label { color: var(--pb-accent); }
/* A switch (Auto play, Shuffle): the track on the right says on or off, not a tick. */
.playback-row.is-toggle.is-on::before { content: none; }
.playback-row.is-toggle.is-on .playback-row-label { color: inherit; }
.playback-row.is-toggle::after {
  content: ''; flex: none; width: 34px; height: 20px; border-radius: 999px;
  background: rgba(255, 255, 255, .16) radial-gradient(circle at 10px 50%, #d9dbe3 0 7px, transparent 7.5px);
  transition: background-color .18s ease, background-position .18s ease;
}
.playback-row.is-toggle.is-on::after {
  background: var(--pb-accent) radial-gradient(circle at 24px 50%, #15161b 0 7px, transparent 7.5px);
}
.playback-row-text { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.playback-row-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.playback-row-note { color: var(--pb-mute); font-size: 11.5px; line-height: 1.35; white-space: normal; }
.playback-row-value {
  flex: 0 1 auto; max-width: 58%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--pb-mute); font-variant-numeric: tabular-nums;
}
.playback-chevron {
  width: 6px; height: 6px; flex-shrink: 0;
  border-right: 1.5px solid currentColor; border-top: 1.5px solid currentColor;
  transform: rotate(45deg); opacity: .6;
}
.playback-chevron.is-back { transform: rotate(-135deg); margin-left: 3px; opacity: .9; }
.playback-sep { height: 1px; margin: 5px 6px; background: var(--pb-line); opacity: .7; flex-shrink: 0; }
.playback-hint { margin: 0; padding: 6px 10px 6px; color: var(--pb-mute); font-size: 11.5px; line-height: 1.45; text-wrap: pretty; }
.playback-hint.playback-link { color: var(--pb-text, inherit); overflow-wrap: anywhere; user-select: all; -webkit-user-select: all; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; }
.playback-spin {
  width: 14px; height: 14px; flex-shrink: 0; box-sizing: border-box;
  border: 2px solid var(--pb-line); border-top-color: var(--pb-accent); border-radius: 50%;
  animation: playback-spin .8s linear infinite;
}
@keyframes playback-spin { to { transform: rotate(360deg); } }

/* Subtitle size (Settings → Subtitle size; the attribute is set on the <video>).
   `:not(#\#)` lifts these over a host's own `#id::cue` rule (the desktop player's). */
video[data-pb-cue="s"]:not(#\#)::cue { font-size: .8em; }
video[data-pb-cue="l"]:not(#\#)::cue { font-size: 1.4em; }
video[data-pb-cue="xl"]:not(#\#)::cue { font-size: 1.85em; }

/* The cue layer: subtitles Hearth draws itself (playback.js "cue layer").
   Anchored by its bottom centre at the stored point; font size is set inline
   from the picture height and the viewer's scale.
   z-index 6: the player's <video> is 5 (styles.css `.modal.media-fullscreen
   video`), and so is the Upscaler's canvas, so a z-auto layer paints UNDER
   the picture and the subtitles vanish (2026-11-04). The markers (8), the
   on-screen echo (9) and the control bar (10) stay above it. */
.pb-cues {
  position: absolute; z-index: 6;
  transform: translate(-50%, -100%);
  width: max-content; max-width: 86%;
  padding: .15em .2em;
  line-height: 1.3; text-align: center;
  color: #fff; font-weight: 500;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .9), 0 0 4px rgba(0, 0, 0, .6);
  cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none;
  border-radius: 6px; outline: 1px dashed transparent;
  transition: outline-color .15s ease;
}
.pb-cues[hidden] { display: none; }
.pb-cues.is-preview { outline-color: rgba(255, 255, 255, .45); }
.pb-cues.is-preview .pb-cue > span { font-style: italic; opacity: .9; }
.pb-cues.is-preview .pb-cues-grip { opacity: .95; }
.pb-cues:hover, .pb-cues.is-dragging { outline-color: rgba(255, 255, 255, .45); }
.pb-cues.is-dragging { cursor: grabbing; }
.pb-cue { white-space: pre-line; overflow-wrap: break-word; }
.pb-cue > span {
  background: rgba(0, 0, 0, .55); padding: .02em .32em; border-radius: .18em;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
/* The corner grip: drag it up or right to grow the text. */
/* Corner brackets drawn with two borders, on transparent hit areas. The
   top-right one shows on hover; all four while adjusting on screen. */
.pb-cues-grip {
  position: absolute; width: 24px; height: 24px;
  opacity: 0; transition: opacity .15s ease; pointer-events: none;
}
.pb-cues-grip::before {
  content: ''; position: absolute; width: 10px; height: 10px;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .8));
}
.pb-cues-grip.is-tr { right: -12px; top: -12px; cursor: nesw-resize; pointer-events: auto; }
.pb-cues-grip.is-tl { left: -12px; top: -12px; cursor: nwse-resize; }
.pb-cues-grip.is-br { right: -12px; bottom: -12px; cursor: nwse-resize; }
.pb-cues-grip.is-bl { left: -12px; bottom: -12px; cursor: nesw-resize; }
.pb-cues-grip.is-tr::before { right: 6px; top: 6px; border-top: 2px solid #fff; border-right: 2px solid #fff; }
.pb-cues-grip.is-tl::before { left: 6px; top: 6px; border-top: 2px solid #fff; border-left: 2px solid #fff; }
.pb-cues-grip.is-br::before { right: 6px; bottom: 6px; border-bottom: 2px solid #fff; border-right: 2px solid #fff; }
.pb-cues-grip.is-bl::before { left: 6px; bottom: 6px; border-bottom: 2px solid #fff; border-left: 2px solid #fff; }
.pb-cues:hover .pb-cues-grip.is-tr, .pb-cues.is-dragging .pb-cues-grip.is-tr { opacity: .95; }
.pb-cues.is-editing .pb-cues-grip { opacity: 1; pointer-events: auto; }
@media (pointer: coarse) {
  .pb-cues-grip { width: 44px; height: 44px; }
  .pb-cues-grip.is-tr { right: -22px; top: -22px; } .pb-cues-grip.is-tl { left: -22px; top: -22px; }
  .pb-cues-grip.is-br { right: -22px; bottom: -22px; } .pb-cues-grip.is-bl { left: -22px; bottom: -22px; }
  .pb-cues-grip.is-tr::before, .pb-cues-grip.is-tl::before { top: 16px; } .pb-cues-grip.is-br::before, .pb-cues-grip.is-bl::before { bottom: 16px; }
  .pb-cues-grip.is-tr::before, .pb-cues-grip.is-br::before { right: 16px; } .pb-cues-grip.is-tl::before, .pb-cues-grip.is-bl::before { left: 16px; }
  .pb-cues .pb-cues-grip.is-tr { opacity: .7; }
}
/* Adjusting on screen: a solid frame, a tint, and the bar of Reset / Done under it. */
.pb-cues.is-editing { outline: 2px solid var(--pb-accent, var(--accent, #f6b544)); outline-offset: 4px; background: rgba(0, 0, 0, .18); cursor: move; }
.pb-cues-edit {
  display: none; position: absolute; left: 50%; top: calc(100% + 14px); transform: translateX(-50%);
  align-items: center; gap: 8px; padding: 6px 6px 6px 12px; white-space: nowrap;
  font-size: 13px; font-weight: 400; line-height: 1.3; text-shadow: none;
  background: rgba(18, 19, 24, .92); border: 1px solid rgba(255, 255, 255, .14); border-radius: 10px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .45); cursor: default;
}
.pb-cues.is-editing .pb-cues-edit { display: flex; }
.pb-cues.is-bar-above .pb-cues-edit { top: auto; bottom: calc(100% + 14px); }
.pb-cues-edit-tip { color: rgba(255, 255, 255, .72); margin-right: 4px; }
.pb-cues-edit-btn {
  min-height: 32px; padding: 0 12px; border-radius: 7px; cursor: pointer;
  color: #fff; background: rgba(255, 255, 255, .1); border: 1px solid rgba(255, 255, 255, .16); font: inherit;
}
.pb-cues-edit-btn:hover { background: rgba(255, 255, 255, .18); }
.pb-cues-edit-btn:focus-visible { outline: 2px solid var(--pb-accent, var(--accent, #f6b544)); outline-offset: 2px; }
.pb-cues-edit-btn.is-done { background: var(--pb-accent, var(--accent, #f6b544)); border-color: transparent; color: #15161b; font-weight: 600; }
@media (prefers-reduced-motion: reduce) { .pb-cues, .pb-cues-grip { transition: none; } }

/* A small label over a group of rows (Size / Position). */
.playback-menu-sub { margin: 8px 10px 2px; color: var(--pb-mute); font-size: 11px; letter-spacing: .06em; text-transform: uppercase; line-height: 1.4; }

/* Timing: the current shift, then five equal steps around it. */
.playback-timing { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; padding: 4px 10px 2px; align-items: center; }
.playback-timing-label { grid-column: span 3; color: var(--pb-mute); font-size: 11.5px; }
.playback-timing-value { grid-column: span 2; text-align: right; font-variant-numeric: tabular-nums; }
.playback-menu button.playback-nudge {
  min-width: 0; min-height: 32px; padding: 0 4px;
  text-align: center; font-size: 12px; font-variant-numeric: tabular-nums;
  border: 1px solid var(--pb-line);
}

/* Touch: every row is a full target. */
@media (pointer: coarse), (max-width: 520px) {
  .playback-menu { font-size: 15px; }
  .playback-menu button.playback-row { min-height: 48px; }
  .playback-menu button.playback-back { width: 44px; min-width: 44px; height: 44px; min-height: 44px; }
  .playback-menu button.playback-nudge { min-height: 44px; font-size: 13px; }
  .playback-row-note, .playback-hint, .playback-timing-label { font-size: 12.5px; }
  .playback-menu-head { font-size: 12px; min-height: 44px; }
}
@media (prefers-reduced-motion: reduce) {
  .playback-menu, .playback-menu.is-sheet { animation: none; }
  .playback-caret, button.playback-quality { transition: none; }
  /* A still ring reads as "busy" beside the word "Preparing…". */
  .playback-spin { animation: none; border-top-color: var(--pb-line); border-right-color: var(--pb-accent); }
}

/* ── phone layouts of the two hosts ── */
.player-top button.playback-quality { font-size: 14px; max-width: 150px; }
@media (max-width: 480px) {
  .player-top:has(.playback-quality) { flex-wrap: wrap; padding-bottom: 12px; }
  .player-top:has(.playback-quality) .p-title { order: -1; flex: 1 0 100%;
    /* Two lines: on its own row the title had the width but kept nowrap, so an
       episode was clipped to its series name. The bar publishes its measured
       height, so the stars and the status line follow it down. */
    white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .player-top .playback-quality { margin-left: auto; }
  .vc-bar:has(.playback-quality) { flex-wrap: wrap; }
  .vc-bar:has(.playback-quality) .vc-track-wrap { order: -1; flex-basis: 100%; }
  .vc-bar:has(.playback-quality) .vc-volume { display: none; }
  .vc-bar:has(.playback-quality) .vc-time { min-width: 0; font-size: 11px; }
}
