/* YouTube widget: the player and the library you pick from, in the house style
   (logo watermark, card sections, red accent). Two sections (player / library)
   carry data-system-card so they hide/reorder like System cards. Rendered into
   .youtube-widget-mount by youtube-widget.js.
   Broadcasting has its own widget and its own stylesheet now — see
   components/YouTubeLiveWidget. */
.youtube-panel { display: flex; }
.youtube-widget-mount { width: 100%; height: 100%; display: flex; min-height: 0; border-radius: inherit; }

/* A size container, so the cards below can answer "is this tile wide and short"
   rather than "is the WINDOW wide" — the same widget is a 32:9 strip on the
   Xeneon Edge and a tall column in a browser, and the right arrangement is not
   the same one. Containment is dropped while the player is expanded: it would
   otherwise become the containing block for the fullscreen card and the overlay
   would cover the tile instead of the screen. */
.yt-wrap {
  position: relative; box-sizing: border-box;
  container: ytw / size;
  width: 100%; height: 100%; min-height: 0;
  padding: 16px 18px; display: flex; flex-direction: column; gap: 11px;
  border-radius: inherit; overflow: hidden;
  background:
    radial-gradient(125% 95% at 100% -12%, rgba(255,0,0,0.16), transparent 55%),
    radial-gradient(100% 70% at 0% 112%, rgba(255,0,0,0.07), transparent 60%);
}
/* Faded YouTube logo watermark, centred behind the content. */
.yt-watermark {
  position: absolute; inset: 0; margin: auto; width: 46%; max-width: 230px;
  display: flex; align-items: center; justify-content: center;
  opacity: 0.08; pointer-events: none; z-index: 0;
}
.yt-watermark svg { width: 100%; height: auto; }
.yt-head, .yt-cards, .yt-setup { position: relative; z-index: 1; }

/* "No account connected" call-to-action — opens Settings → Streaming. With no
   account both cards below are taken off screen, so without this the tile is a
   watermark on an empty background and nothing says why. Same shape as the
   Discord widget's notice, in YouTube's red. */
.yt-setup {
  display: flex; align-items: center; gap: 8px; width: 100%; flex: 0 0 auto;
  margin: 2px 0 4px; padding: 8px 11px; border-radius: 10px; cursor: pointer;
  text-align: left; font: inherit; font-size: 0.8rem; font-weight: 700;
  color: #ff6b6b; background: rgba(255,0,0,0.10); border: 1px solid rgba(255,0,0,0.32);
}
/* `display: flex` above outranks the UA `[hidden]{display:none}` rule, so the
   notice needs an explicit guard or it never hides once an account is connected. */
.yt-setup[hidden] { display: none; }

/* Header */
.yt-head { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; min-width: 0; }
.yt-brand { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.yt-logo { font-size: 0.92rem; font-weight: 900; letter-spacing: 0.02em; color: #ff4d4d; }
/* Cards. The column scrolls as a whole: on a short tile the minimum heights below
   can add up to more than the tile has, and a card the user cannot reach is a card
   that does not exist. */
.yt-cards {
  flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 10px;
  overflow-y: auto; overscroll-behavior: contain;
}
.yt-cards::-webkit-scrollbar { width: 6px; }
.yt-cards::-webkit-scrollbar-thumb { border-radius: 999px; background: rgba(255,255,255,0.16); }
.yt-card {
  position: relative; min-width: 0; border-radius: 14px; padding: 12px 14px;
  background: rgba(255,255,255,0.028); border: 1px solid rgba(255,255,255,0.07);
}
.yt-card-label {
  font-size: 0.62rem; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-dim, #8b91a1); margin-bottom: 9px;
}
/* Inline failure text, used by the open-in-browser fallback. */
.yt-err { margin-top: 8px; font-size: 0.76rem; font-weight: 600; color: var(--color-danger); line-height: 1.35; }

/* ── Player (viewer mode) ─────────────────────────────────────────────────── */
/* Grows three times faster than the list: extra tile height should go to the
   video. No `min-height: 0` on purpose — that let the card shrink under its own
   controls on a short tile, and the transport ended up drawn over the list.
   Leaving the automatic minimum makes the column above scroll instead. */
.yt-card--player { flex: 3 1 auto; display: flex; flex-direction: column; gap: 8px; padding: 10px; }
/* Fitting a 16:9 box inside a box of any shape takes two steps, because neither
   half does it alone (measured in Chromium): a width-driven ratio with a
   max-height keeps the right height but not the right width, and a height-driven
   ratio with a max-width does the opposite. So .yt-stage-fit bounds the height
   and .yt-player-stage takes the correct width from it. Sizing the stage off the
   tile width alone let one video eat the whole tile and pushed the list, the only
   way to pick a video, off the bottom edge. */
/* Basis 0, not auto: with `auto` the wrapper's height came from the ratio box it
   contains, so the height cap below was measured against the very thing it was
   supposed to be capping and the video pushed the list out of the tile again. */
.yt-stage-wrap {
  flex: 1 1 0; min-height: 92px; min-width: 0;
  display: flex; align-items: center; justify-content: center;
}
.yt-stage-fit {
  width: 100%; min-width: 0; aspect-ratio: 16 / 9; max-height: 100%;
  display: flex; align-items: center; justify-content: center;
}
.yt-player-stage {
  position: relative; height: 100%; width: auto; max-width: 100%; aspect-ratio: 16 / 9;
  border-radius: 10px; overflow: hidden; background: #000;
  display: flex; align-items: center; justify-content: center;
}
.yt-frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.yt-player-empty { font-size: 0.78rem; font-weight: 600; opacity: 0.55; padding: 8px 12px; text-align: center; }

.yt-now { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.yt-now-title { font-size: 0.82rem; font-weight: 700; color: var(--text, #e7e9ee); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.yt-now-sub { font-size: 0.68rem; font-weight: 600; color: var(--text-dim, #8b91a1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.yt-seek-row { display: flex; align-items: center; gap: 8px; }
.yt-time { font-size: 0.64rem; font-weight: 700; color: var(--text-dim, #8b91a1); font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.yt-seek {
  flex: 1 1 auto; min-width: 0; height: 18px; margin: 0; cursor: pointer;
  -webkit-appearance: none; appearance: none; background: transparent;
}
.yt-seek::-webkit-slider-runnable-track { height: 4px; border-radius: 999px; background: rgba(255,255,255,0.16); }
.yt-seek::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; margin-top: -5px;
  width: 14px; height: 14px; border-radius: 50%; background: #ff2d2d; border: 0;
  box-shadow: 0 1px 4px rgba(0,0,0,0.5);
}
.yt-seek:disabled { opacity: 0.4; cursor: default; }

.yt-transport { display: flex; align-items: center; gap: 6px; }
.yt-transport-gap { flex: 1 1 auto; }
.yt-ib {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 9px; cursor: pointer; padding: 0;
  color: var(--text, #e7e9ee); background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.09);
  transition: background 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}
.yt-ib svg { width: 17px; height: 17px; }
.yt-ib:hover:not(:disabled) { background: rgba(255,0,0,0.16); border-color: rgba(255,0,0,0.4); }
.yt-ib:disabled { opacity: 0.35; cursor: default; }
.yt-ib.is-on { color: #ff4d4d; border-color: rgba(255,0,0,0.4); }
.yt-playpause { width: 40px; height: 40px; background: rgba(255,0,0,0.85); border-color: transparent; color: #fff; }
.yt-playpause:hover:not(:disabled) { background: rgba(255,0,0,1); }
.yt-playpause svg { width: 20px; height: 20px; }

/* Sits ON the picture, inside .yt-player-stage. It has to: when YouTube refuses a
   video it paints its own error over the whole frame, so our explanation has to
   cover that or it is never seen. It was a line of text under the transport before,
   and the reported symptom was a user staring at YouTube's raw error with our text
   nowhere in sight. Opaque, not translucent — the point is to replace what is
   underneath, not to sit on top of it. */
.yt-blocked {
  position: absolute; inset: 0; z-index: 3;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 12px 16px; text-align: center;
  background: rgba(8, 8, 10, 0.94);
  font-size: 0.74rem; font-weight: 600; color: var(--text, #e7e9ee);
}
.yt-blocked-txt { max-width: 30ch; line-height: 1.35; }
.yt-blocked-btn {
  font: inherit; font-size: 0.72rem; font-weight: 800; cursor: pointer;
  padding: 4px 10px; border-radius: 8px; color: #fff;
  background: rgba(255,0,0,0.8); border: 0;
}

/* Full-screen player. The card is only re-positioned, never re-parented: moving
   the iframe in the DOM reloads it and would restart the video.
   Two extra classes on purpose. The global panel theme styles .yt-card with a
   translucent background at the same specificity and later in the cascade, so the
   plain selector lost and the dashboard showed through the fullscreen player. */
.yt-card.yt-card--player.is-expanded {
  position: fixed; inset: 0; z-index: 5000; border-radius: 0; border: 0;
  background: #05070a; padding: 0; gap: 0;
  justify-content: flex-end;
}
/* Two stacking contexts sit between the card and the screen, and a z-index only
   ever competes inside its own: the card column (z-index 1, for the watermark)
   held the overlay under the top bar, and the shell (z-index 1) held it under the
   edge rails, which are fixed at 58 on the body. Both are lifted for as long as
   the player is expanded and put back the moment it is not. This is the WHOLE
   mechanism: the Fullscreen API would have settled it in one line, but on the
   kiosk leaving fullscreen tore the video down and left the Windows taskbar over
   the dashboard until the app was restarted, so the overlay does the job without
   ever touching the app's own window. */
body.yt-expanded .yt-cards { z-index: auto; }
body.yt-expanded .shell { z-index: 60; }
body.yt-expanded .yt-wrap { container-type: normal; }

/* ── Wide layout: the list moves beside the video ──────────────────────────── */
/* Stacked, a wide short tile gives the video only the height left over after the
   list, and a 16:9 box that short is tiny however wide the tile is: on the Edge's
   32:9 strip it came out around 230px across with empty space either side. Beside
   each other, the same tile gives the video the full height and roughly two
   thirds of the width.
   HEIGHT is what picks between them, not the aspect ratio. Stacking always pays a
   fixed cost — the transport plus the list, about 300px — so it is the short tile
   that suffers, and two tiles of the SAME shape want opposite answers: 841x625
   gains (131px tall stacked against 331 beside), 1562x1173 loses (858 against
   590). Above the cutoff stacking gives both a bigger video and the full width,
   so it stays the default. */
@container ytw (min-width: 620px) and (max-height: 760px) {
  .yt-cards {
    display: grid; gap: 10px;
    /* The list is a column of rows, so past a point extra width does nothing for
       it and everything for the video: capped, not a plain percentage. */
    grid-template-columns: minmax(0, 1fr) minmax(200px, min(32%, 360px));
    grid-template-rows: minmax(190px, 1fr);
    grid-auto-rows: auto;
  }
  .yt-card--player { grid-column: 1; grid-row: 1; }
  .yt-card--library { grid-column: 2; grid-row: 1; min-height: 0; }
  /* One of the pair switched off in the layout editor: the other takes the whole
     width instead of leaving an empty column beside it. */
  .yt-cards:has(> .yt-card--library[data-system-card-hidden="true"]) .yt-card--player,
  .yt-cards:has(> .yt-card--player[data-system-card-hidden="true"]) .yt-card--library { grid-column: 1 / -1; }
}
/* Full screen means the video gets the screen. Stacking the title, the seek bar
   and the transport UNDER it spent about a quarter of the height on chrome, and a
   16:9 video can only ever fill the shorter axis — on the Edge's 32:9 panel that
   left a modest rectangle in the middle of a lot of black. The controls float over
   the picture instead, the way every video player does at full screen, and the
   video gets the whole height: on a 2560x720 screen that is 720 tall instead of
   about 390, so a bit under twice as wide. */
.yt-card--player.is-expanded .yt-stage-wrap { position: absolute; inset: 0; min-height: 0; }
.yt-card--player.is-expanded .yt-player-stage { border-radius: 0; }
/* Legible over whatever frame the video happens to be on. */
.yt-card--player.is-expanded::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 210px; z-index: 1;
  background: linear-gradient(to top, rgba(0,0,0,0.88), rgba(0,0,0,0.55) 42%, transparent);
  pointer-events: none;
}
/* .yt-blocked is deliberately NOT in this list any more: it is no longer a row in
   the control strip, it is the layer covering the picture, and giving it
   `position: relative` here would drop it back behind the frame it has to hide. */
.yt-card--player.is-expanded .yt-now,
.yt-card--player.is-expanded .yt-seek-row,
.yt-card--player.is-expanded .yt-transport { position: relative; z-index: 2; padding-left: 20px; padding-right: 20px; }
.yt-card--player.is-expanded .yt-transport { padding-bottom: 16px; justify-content: center; gap: 10px; }
.yt-card--player.is-expanded .yt-seek-row { margin-bottom: 8px; }
.yt-card--player.is-expanded .yt-now-title { font-size: 1.05rem; }
.yt-card--player.is-expanded .yt-transport-gap { flex: 0 0 22px; }

/* The controls fade out a few seconds into a video and come back on a touch.
   Visibility, not display: a control that stops existing changes the layout of
   the row it was in, and the row would jump when it came back. */
.yt-idlecatch { display: none; }
.yt-card--player.is-expanded .yt-idlecatch { display: block; position: absolute; inset: 0; z-index: 1; pointer-events: none; }
/* Takes input ONLY while the controls are hidden: the embed is cross-origin, so a
   finger moving over the picture raises nothing this page can hear, and without a
   catcher there would be no way to bring the controls back. While they are up it
   is inert again, so YouTube's own captions and quality menus stay reachable. */
.yt-card--player.is-expanded.is-idle .yt-idlecatch { pointer-events: auto; cursor: none; }
.yt-card--player.is-expanded .yt-now,
.yt-card--player.is-expanded .yt-seek-row,
.yt-card--player.is-expanded .yt-transport,
.yt-card--player.is-expanded::after { transition: opacity 0.35s ease; }
.yt-card--player.is-expanded.is-idle .yt-now,
.yt-card--player.is-expanded.is-idle .yt-seek-row,
.yt-card--player.is-expanded.is-idle .yt-transport,
.yt-card--player.is-expanded.is-idle::after { opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .yt-card--player.is-expanded .yt-now,
  .yt-card--player.is-expanded .yt-seek-row,
  .yt-card--player.is-expanded .yt-transport,
  .yt-card--player.is-expanded::after { transition: none; }
}
/* No close button at full screen. It sits one button away from shrink and it does
   something else entirely — it unloads the video — so the two were a trap: press
   the wrong one and what you were watching is gone with no way back to it. Shrink
   and Escape both leave; closing is still there once the player is back in its
   tile. */
.yt-card--player.is-expanded .yt-stop { display: none; }

/* ── Library (tabs + rows) ────────────────────────────────────────────────── */
/* Tall enough to show the tabs plus a couple of videos: below that the list reads
   as an empty strip and there is nothing to tap. */
.yt-card--library { flex: 1 1 176px; min-height: 176px; display: flex; flex-direction: column; gap: 8px; overflow: hidden; }
/* Wrap rather than scroll sideways. In the side-by-side layout the list column is
   narrow enough that the fourth tab fell off the end of a row whose scrollbar is
   hidden, so Search was there and invisible. A second row of pills costs 34px and
   nothing is hidden. */
.yt-tabs { display: flex; flex-wrap: wrap; gap: 5px; flex: 0 0 auto; }
.yt-tab {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  min-height: 30px; padding: 0 10px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 0.7rem; font-weight: 800;
  color: var(--text-dim, #8b91a1); background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08);
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.yt-tab-ico { display: inline-flex; }
.yt-tab-ico svg { width: 13px; height: 13px; }
.yt-tab:hover { color: var(--text, #e7e9ee); }
.yt-tab.is-on { color: #fff; background: rgba(255,0,0,0.8); border-color: transparent; }

.yt-search-row { display: flex; gap: 6px; flex: 0 0 auto; }
.yt-search-input {
  flex: 1 1 auto; min-width: 0; box-sizing: border-box; font: inherit; font-size: 0.78rem;
  padding: 6px 10px; border-radius: 9px; color: var(--text, #e7e9ee);
  border: 1px solid rgba(255,255,255,0.12); background: rgba(0,0,0,0.28); outline: none;
}
.yt-search-input:focus { border-color: rgba(255,0,0,0.5); }
.yt-search-go {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; border-radius: 9px; cursor: pointer; padding: 0; color: #fff;
  background: rgba(255,0,0,0.8); border: 0;
}
.yt-search-go svg { width: 16px; height: 16px; }

.yt-crumb {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; align-self: flex-start;
  padding: 4px 10px 4px 6px; border-radius: 999px; cursor: pointer; font: inherit;
  font-size: 0.72rem; font-weight: 800; max-width: 100%;
  color: var(--text, #e7e9ee); background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.09);
}
.yt-crumb-ico { display: inline-flex; }
.yt-crumb-ico svg { width: 14px; height: 14px; }
.yt-crumb-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.yt-list { flex: 1 1 auto; display: flex; flex-direction: column; gap: 6px; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.yt-list::-webkit-scrollbar { width: 6px; }
.yt-list::-webkit-scrollbar-thumb { border-radius: 999px; background: rgba(255,255,255,0.16); }
.yt-row {
  display: flex; align-items: center; gap: 10px; width: 100%; flex: 0 0 auto;
  padding: 6px 8px; border-radius: 10px; cursor: pointer; text-align: left; font: inherit;
  border: 1px solid rgba(255,255,255,0.06); background: rgba(255,255,255,0.03);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.yt-row:hover { background: rgba(255,0,0,0.10); border-color: rgba(255,0,0,0.35); }
.yt-row-art {
  position: relative; width: 64px; height: 36px; flex: 0 0 auto; border-radius: 6px;
  background: rgba(255,255,255,0.07) center / cover no-repeat;
  box-shadow: 0 2px 6px rgba(0,0,0,0.35);
  display: inline-flex; align-items: center; justify-content: center; color: #ff4d4d;
}
.yt-row--pl .yt-row-art { width: 44px; height: 44px; border-radius: 8px; }
.yt-row-dur {
  position: absolute; right: 3px; bottom: 3px; padding: 0 4px; border-radius: 4px;
  font-size: 0.58rem; font-weight: 800; color: #fff; background: rgba(0,0,0,0.78);
  font-variant-numeric: tabular-nums;
}
.yt-row-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.yt-row-name {
  font-size: 0.8rem; font-weight: 700; color: var(--text, #e7e9ee);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* The channel name gives up its width to the tag, not the other way round: the tag
   is the short, fixed thing and the one carrying news. */
.yt-row-subline { display: flex; align-items: center; gap: 6px; min-width: 0; }
.yt-row-sub { font-size: 0.67rem; font-weight: 600; color: var(--text-dim, #8b91a1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.yt-row-tag {
  flex: 0 0 auto; font-size: 0.58rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; white-space: nowrap; padding: 1px 6px; border-radius: 999px;
  color: #ff8a8a; background: rgba(255,0,0,0.13); border: 1px solid rgba(255,0,0,0.28);
}
.yt-row-play {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%; color: #fff; background: rgba(255,0,0,0.85);
  opacity: 0; transform: scale(0.8); transition: opacity 0.15s ease, transform 0.15s ease;
}
.yt-row-play svg { width: 15px; height: 15px; margin-left: 1px; }
.yt-row:hover .yt-row-play, .yt-row:focus-visible .yt-row-play { opacity: 1; transform: scale(1); }
.yt-list-note { font-size: 0.78rem; opacity: 0.65; padding: 4px 2px; line-height: 1.4; }
.yt-list-err { color: var(--color-danger); opacity: 0.9; }

/* Touch surfaces have no hover, so the play affordance must always be visible. */
@media (hover: none) {
  .yt-row-play { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .yt-row, .yt-row-play, .yt-tab, .yt-ib { transition: none; }
}
