/* Stream page — layout + streamer list. Shares tokens with assets/css/styles.css. */

/* The shared header's --shadow-md has a 42px blur with only 12px margin
   below it, which bleeds down onto .stream-player's top edge. Twitch's
   player treats that bleed as its video being occluded and refuses to
   autoplay ("style visibility" error) — tighten it on this page only. */
.page-header {
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
}

.stream-container {
  display: flex;
  flex: 1;
  gap: 10px;
  height: 100%;
  width: 100%;
  min-height: 0;
  position: relative;
  justify-content: center;
}

.stream-grid {
  flex: 1;
  display: grid;
  gap: 8px;
  /* Twitch's embed refuses to autoplay below ~400x300px ("style visibility"
     error) — keep comfortable headroom above that floor at every breakpoint. */
  min-width: 460px;
  min-height: 340px;
  overflow: auto;
}

.stream-grid[data-count="1"] { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.stream-grid[data-count="2"] { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr; }
.stream-grid[data-count="3"],
.stream-grid[data-count="4"] { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }

.stream-tile {
  /* The header bar is a real row above the player rather than a layer on top of
     it, so the tile has to be tall enough for both: Twitch's 300px floor is on
     the video, and the bar is not part of the video. The +2px is this tile's own
     top and bottom border, which the floor below is measured across.
     The room stays reserved even though the bar spends most of its life
     collapsed — hover reopens it at any moment, and a tile sized for the closed
     bar would drop the video under the floor the instant it did. Closed, the
     player simply runs 30px taller than its minimum. */
  --tile-header-h: 30px;
  --tile-video-floor: 300px;
  display: none;
  flex-direction: column;
  position: relative;
  background: var(--bg);
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  /* A wide-blur shadow (--shadow-md) visually bleeds across the gap into the
     adjacent panel. Twitch's player treats that bleed as its video being
     occluded and refuses to autoplay ("style visibility" error) — keep the
     blur radius tighter than the gap so it can't reach across. */
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
  transition: border-color 0.24s var(--ease), box-shadow 0.24s var(--ease);
  min-width: 400px;
  min-height: calc(var(--tile-video-floor) + var(--tile-header-h) + 2px);
}

.stream-tile.is-visible { display: flex; }

/* Focus is shown with the border alone. The amber ring read as a gold frame
   around the video, and the 24px blur under it broke the same rule the note on
   .stream-tile above exists for: a wide shadow bleeds past the tile, Twitch counts
   that as its video being occluded, and refuses to play. Slot 0 is always focused,
   so this landed on exactly the tile you watch. Keep the shadow inside the gap. */
.stream-tile.is-focused {
  border-color: var(--border-strong);
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
}

.stream-tile.is-empty.is-focused { box-shadow: none; }

.stream-tile-body { flex: 1; min-height: 0; min-width: 0; }
.stream-tile-body iframe,
.stream-tile-body > div { width: 100%; height: 100%; }

.stream-tile-placeholder {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.stream-tile.is-empty { border-style: dashed; }
.stream-tile.is-empty .stream-tile-placeholder { display: flex; }
.stream-tile.is-empty:hover { border-color: var(--accent-border); }
.stream-tile.is-empty .stream-tile-header { display: none; }

.stream-tile-placeholder-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  transition: color 0.15s;
}
.stream-tile.is-empty:hover .stream-tile-placeholder-label,
.stream-tile.is-empty.is-focused .stream-tile-placeholder-label { color: var(--accent-strong); }

/* Above the player, never over it.
   Twitch refuses to autoplay an embed it considers obscured ("minimum
   requirements for autoplay were not met: style visibility") and keeps checking
   afterwards, pausing if anything covers the video. As an absolutely positioned
   strip this bar was exactly that — so it had to hide itself, and appearing on
   hover meant it lay over the video every time the pointer crossed the tile you
   were watching. In the flow it is outside the video box altogether, so the
   player is never covered whether the bar is up or down.
   The legend plate the panels elsewhere on the site carry, at tile scale.

   At rest the bar collapses to nothing and the player takes the space back: the
   row still exists, it is simply zero tall, and .stream-tile-body is the only
   flex child left with height to claim. Hovering the tile opens it again. This
   is a resize of the video, not a layer over it — the distinction the whole
   Twitch problem turns on — so the embed keeps playing through it. The border
   collapses with the height because a border-box element cannot go below its
   own border: left at 1px it would leave a hairline ruled across the picture. */
.stream-tile-header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 0;
  padding: 0 10px;
  overflow: hidden;
  background: var(--well);
  border-bottom: 0 solid var(--border);
  transition: height 0.18s var(--ease), border-bottom-width 0.18s var(--ease), border-color 0.2s var(--ease);
  /* Closing waits longer than opening, so sweeping the pointer back across a
     tile you just left costs nothing. See the note below on why both wait. */
  transition-delay: 0.22s;
}

/* focus-within, not hover alone: collapsed, the close button is still in the tab
   order, and a bar that stayed shut would put keyboard focus on a control nobody
   can see.

   The delay is the point, not the polish. Opening the bar resizes the embed, and
   a pointer flicked in and out of a tile resizes it again on every crossing —
   which Twitch's player answers by pausing, while one deliberate hover it sits
   through happily. A delay makes the two cases the same case: while it is
   running the height simply holds its old value, so a crossing shorter than the
   delay is cancelled before the first pixel moves and the video is never
   resized at all. Slow hover behaves exactly as before, a hair later.
   Keyboard focus is deliberate by nature and opens immediately. */
.stream-tile:hover .stream-tile-header,
.stream-tile:focus-within .stream-tile-header {
  height: var(--tile-header-h);
  border-bottom-width: 1px;
  transition-delay: 0.14s;
}

.stream-tile:focus-within .stream-tile-header { transition-delay: 0s; }

/* Nothing hovers on a touchscreen, and the close button is the only way to clear
   a tile — on a device with no pointer the bar stays up for good rather than
   sealing the stream in. */
@media (hover: none) {
  .stream-tile-header {
    height: var(--tile-header-h);
    border-bottom-width: 1px;
  }
}

/* One tile carries the sound. The bar says which without a word: an amber rule
   under the focused tile and an amber label, the same lit-legend signal the
   panels on the other pages use for live data. */
.stream-tile.is-focused .stream-tile-header { border-bottom-color: var(--accent-border); }
.stream-tile.is-focused .stream-tile-label { color: var(--accent-strong); }

/* The annunciator lamp, at tile scale: lit in the platform's colour, with the
   glow that tells it apart from a printed dot. */
.stream-tile-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--text-faint);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.35);
}
.stream-tile[data-platform="twitch"] .stream-tile-dot {
  background: #a970ff;
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.35), 0 0 8px rgba(169, 112, 255, 0.75);
}
.stream-tile[data-platform="youtube"] .stream-tile-dot {
  background: #ff6a4a;
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.35), 0 0 8px rgba(255, 106, 74, 0.75);
}

.stream-tile-label {
  flex: 1;
  min-width: 0;
  font-family: var(--font-legend);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: color 0.2s var(--ease);
}

.stream-tile-close {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface-raised);
  color: var(--text-faint);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.stream-tile-close:hover {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 18%, var(--surface-raised));
  color: var(--danger);
}

.stream-chat {
  flex: 0 0 390px;
  width: 390px;
  min-height: 0;
  background: var(--surface);
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
  position: relative;
  transition: border-color 0.24s var(--ease);
}

.stream-container:hover .stream-tile:not(.is-focused),
.stream-container:hover .stream-chat {
  border-color: var(--border-strong);
}

.stream-chat::before {
  content: 'Live Chat';
  position: absolute;
  top: 10px;
  left: 12px;
  z-index: 6;
  font-size: 10px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--text-faint);
  pointer-events: none;
}

iframe { width: 100%; height: 100%; border: none; display: block; }

/* header controls: compact so the whole toolbar fits one row where there is room
   for one. Below ~1000px the toolbar alone is wider than the viewport, so the
   nowrap has to lift or it drags the whole page into horizontal scroll. */
.controls { gap: 6px; flex-wrap: nowrap; }
@media (max-width: 1000px) {
  .controls { flex-wrap: wrap; }
}
.controls .home-button,
.controls button,
.controls .dropbtn {
  height: 36px;
  padding: 0 12px;
  font-size: 11px;
}
.stream-url-input { width: 260px; height: 36px; font-size: 12px; padding: 0 12px; flex: 0 1 260px; min-width: 120px; }

#loadStreamBtn {
  border-color: var(--accent-border);
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 22%, var(--surface-raised)), var(--surface));
  color: var(--text);
}
#loadStreamBtn:hover { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-soft), 0 10px 22px rgba(0, 0, 0, 0.3); }

.dropdown-content { width: min(88vw, 480px); min-width: min(420px, 88vw); max-width: 480px; max-height: 70vh; overflow-y: auto; overflow-x: hidden; }
.dropdown-content::-webkit-scrollbar { width: 4px; }
.dropdown-content::-webkit-scrollbar-track { background: transparent; }
.dropdown-content::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
.dropdown.force-closed .dropdown-content { display: none !important; }

.streamer-dropdown-title { padding: 4px 6px 2px; font-size: 10px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint); }
.streamer-dropdown-subtitle { padding: 0 6px 6px; font-size: 10px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-strong); }
.youtube-scan-status { padding: 0 6px 6px; font-size: 10px; color: var(--accent-strong); min-height: 14px; }
.streamer-divider { border-top: 1px solid var(--border); margin: 6px 0 4px; }

.streamer-action {
  display: block;
  text-align: center;
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 650;
  text-decoration: none;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  transition: background 0.15s, border-color 0.15s;
}
.streamer-action:hover { background: var(--surface-hover); border-color: var(--accent-border); color: #fff; }
.streamer-action-add { color: var(--accent-strong); }
.streamer-action-twitch { color: #cab7ff; }
.streamer-action-youtube { color: #ffac98; }

.stream-live-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; align-items: start; }
.stream-live-section { min-width: 0; }
.stream-live-section-title { padding: 6px 6px 4px; font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
.stream-live-title-twitch { color: #d7c3ff; }
.stream-live-title-youtube { color: #ffb193; }

.stream-live-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 8px;
  margin-bottom: 4px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  transition: border-color 0.15s;
}
.stream-live-row:hover { border-color: var(--accent-border); }

.stream-open-link { display: flex; align-items: center; gap: 8px; text-decoration: none; color: var(--text); flex-grow: 1; min-width: 0; }
.stream-live-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 600; text-transform: capitalize; }
.stream-live-viewers { font-size: 10px; color: var(--text-muted); }

.stream-remove-btn { background: none; border: none; color: color-mix(in srgb, var(--danger) 60%, var(--text-faint)); cursor: pointer; font-size: 16px; margin-left: 6px; padding: 0 2px; flex-shrink: 0; transition: all 0.2s; }
.stream-remove-btn:hover { color: var(--danger); transform: scale(1.15); }

.stream-live-empty, .stream-list-empty { padding: 8px; font-size: 12px; color: var(--text-faint); text-align: center; }

/* theater mode */
body.stream-theater-mode { background: #05070a; }
body.stream-theater-mode > .page { margin: 0; padding: 0; max-width: none !important; width: 100vw; height: 100dvh; }
body.stream-theater-mode > .page > .page-header { display: none; }
body.stream-theater-mode .main { overflow: visible; margin: 0; padding: 0; }
body.stream-theater-mode .stream-container { position: fixed; inset: 0; gap: 0; border-radius: 0; background: #05070a; z-index: 30; }
body.stream-theater-mode .stream-grid,
body.stream-theater-mode .stream-chat { height: 100dvh; }
body.stream-theater-mode .stream-tile { border-radius: 0; border-top: 0; border-bottom: 0; }
body.stream-theater-mode .stream-grid { border-left: 0; }
body.stream-theater-mode .stream-chat { border-radius: 0; border-top: 0; border-bottom: 0; border-right: 0; }

@media (max-width: 1200px) {
  .stream-chat { flex-basis: 340px; width: 340px; }
  .stream-url-input { width: 260px; }
}

@media (max-width: 980px) {
  .stream-container { flex-direction: column; }
  .stream-chat { width: 100%; flex: 0 0 340px; }
  /* .stream-tile keeps its base min-height here — Twitch refuses to
     autoplay below ~300px tall, so this floor can't be relaxed on mobile. */
  .stream-grid[data-count="2"] { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }
  .stream-grid[data-count="3"],
  .stream-grid[data-count="4"] { grid-template-columns: 1fr; grid-template-rows: repeat(4, 1fr); }
}

@media (max-width: 760px) {
  .controls { flex-wrap: wrap; justify-content: flex-start; }
  .stream-url-input { width: 100%; margin: 0; }
  .dropdown-content { min-width: 92vw; width: 92vw; }
  .stream-layout-group { order: 10; }
}

/* Below this the 460/400px autoplay floor is wider than the viewport itself, so
   holding it can only push the whole page sideways — the grid was forcing a
   480px document on a 390px phone. The floor is unreachable here whatever we do,
   so drop it and let the tile fit: Twitch may need a tap to start rather than
   autoplaying, which is a better trade than a page that scrolls horizontally. */
@media (max-width: 520px) {
  .stream-grid { min-width: 0; }
  .stream-tile { min-width: 0; }
}

.stream-layout-group {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 2px;
}
.stream-layout-label {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-right: 2px;
  white-space: nowrap;
}
.stream-layout-btn {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.stream-layout-btn:hover { border-color: var(--accent-border); color: var(--text); }
.stream-layout-btn.is-active {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 22%, var(--surface-raised));
  color: #fff;
}
