html, body {
  margin: 0;
  height: 100%;
  font-family: Arial, sans-serif;
  background: #111;
  color: white;
}

body { display: flex; flex-direction: column; overflow: hidden; }
#app { display: flex; flex-direction: column; flex: 1; min-height: 0; }
header, #status-panel, footer { flex-shrink: 0; }

header {
  padding: 8px;
  background: #222;
  text-align: center;
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: center;
}

header input {
  flex: 1;
  max-width: 60%;
  padding: 6px;
  font-size: 14px;
  color: #222;
}

.tab-group {
  display: inline-flex;
  border: 1px solid #444;
  border-radius: 4px;
  overflow: hidden;
}

.tab-group .tab {
  background: #1a1a1a;
  color: #ccc;
  border: 0;
  padding: 6px 14px;
  font-size: 14px;
  cursor: pointer;
  transition: background 0.1s, color 0.1s;
}

.tab-group .tab + .tab {
  border-left: 1px solid #444;
}

.tab-group .tab:not([disabled]):hover {
  background: #2a2a2a;
  color: white;
}

.tab-group .tab[aria-selected="true"] {
  background: #007acc;
  color: white;
}

.tab-group .tab[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Alphabet mode: the Groups column becomes meaningless, hide it */
body.browse-alphabet #col-groups {
  display: none;
}

#status-panel {
  padding: 10px;
  background: #111;
  border-bottom: 1px solid #333;
  font-size: 15px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

#status-left {
  flex: 1;
  text-align: center;
}

#status-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Public UI live-status dot (replaces device tabs / SID / OBS) */
#live-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: #aaa;
  user-select: none;
}

#live-status .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #555;
}

#live-status.online .dot {
  background: #2c2;
  box-shadow: 0 0 6px rgba(40, 200, 40, 0.6);
}

#live-status.offline .dot {
  background: #c33;
  box-shadow: 0 0 6px rgba(200, 50, 50, 0.6);
}

/* Running-build chip — small, monospace, muted. Tells you which image
   you're looking at without taking up real estate. Clickable to copy
   the full SHA. */
.build-info {
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 10px;
  color: #555;
  letter-spacing: 0.04em;
  user-select: text;
}
.build-info:hover { color: #888; }
.build-info[hidden] { display: none; }

.nowplaying-row {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  justify-content: center;
}

.nowplaying-progress {
  font-size: 13px;
  color: #4aa3df;
  font-variant-numeric: tabular-nums;
  margin-top: 4px;
  display: inline-flex;
  gap: 14px;
  justify-content: center;
}

.nowplaying-progress #nowplaying-disk { color: #ddd; }


/* Public UI: small read-only device dots in the status panel */
#public-devices {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 2px 8px;
  border: none;
  background: transparent;
}

#public-devices .device-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: #ccc;
  background: #1a1a1a;
  border: 1px solid #333;
  padding: 2px 8px;
  border-radius: 3px;
}

#public-devices .device-chip .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #555;
}

#public-devices .device-chip.online .dot {
  background: #2c2;
  box-shadow: 0 0 4px rgba(40, 200, 40, 0.6);
}

#public-devices .device-chip.offline .dot {
  background: #c33;
  box-shadow: 0 0 4px rgba(200, 50, 50, 0.6);
}

/* SID chip indicator inside a device chip. Read-only mirror of the
   controller-side toggle — gives viewers a glance at what's making sound.
   6581 = warmer amber (the classic chip), 8580 = cooler cyan (the later
   chip). Fallbacks ("S1"/"S2") use neutral grey. */
#public-devices .device-chip .sid-badge {
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 10px;
  font-weight: 600;
  padding: 1px 5px;
  border-radius: 2px;
  background: #2a2a2a;
  border: 1px solid #444;
  color: #aaa;
  letter-spacing: 0.03em;
  margin-left: 4px;
}
#public-devices .device-chip .sid-badge.sid-6581 {
  background: rgba(192, 136, 40, 0.18);
  border-color: #c08828;
  color: #ffd58a;
}
#public-devices .device-chip .sid-badge.sid-8580 {
  background: rgba(74, 163, 223, 0.18);
  border-color: #4aa3df;
  color: #b3dcff;
}

#btn-info-nowplaying {
  background: #1a1a1a;
  border: 1px solid #444;
  color: #aaa;
  padding: 3px 9px;
  font-size: 12px;
  border-radius: 4px;
  cursor: pointer;
  line-height: 1.3;
}

#btn-info-nowplaying:hover {
  background: #2a2a2a;
  color: #fff;
  border-color: #555;
}

#btn-info-nowplaying.active {
  background: #007acc;
  border-color: #007acc;
  color: #fff;
}

/* Username input — pinned to the upper-right of each details pane so it
   has a single, stable location regardless of mode. Sharing the same
   class name means one bind-and-sync path handles both modes. */
.pane-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 0 4px;
}
.user-handle-slot {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: #777;
  user-select: none;
  white-space: nowrap;
  flex-shrink: 0;
}
.user-handle-input {
  background: #1a1a1a;
  border: 1px solid #333;
  color: #ccc;
  font-size: 11px;
  font-family: inherit;
  padding: 2px 6px;
  border-radius: 3px;
  width: 110px;            /* fixed — no resize on focus, avoids jumping */
  min-width: 0;
  box-sizing: border-box;
}
.user-handle-input:focus {
  border-color: #007acc;
  outline: none;
  color: #fff;
}

/* Each device tab shows name + a status dot. The tab is also the "active
   device for enqueue" selector — click to switch which device new
   enqueues go to. */
#device-tabs .tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

#device-tabs .tab .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #555;          /* unknown / not yet checked */
}

#device-tabs .tab.online .dot {
  background: #2c2;
  box-shadow: 0 0 4px rgba(40, 200, 40, 0.6);
}

#device-tabs .tab.offline .dot {
  background: #c33;
  box-shadow: 0 0 4px rgba(200, 50, 50, 0.6);
}

/* (was: hide empty toggle — now we always render placeholders instead) */

/* ---- OBS settings button + popover ---- */
#btn-obs-settings {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #1a1a1a;
  border: 1px solid #444;
  color: #ccc;
  padding: 4px 10px;
  font-size: 13px;
  border-radius: 4px;
  cursor: pointer;
}

#btn-obs-settings:hover {
  background: #2a2a2a;
  color: #fff;
  border-color: #555;
}

#btn-obs-settings .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #555;
}

#btn-obs-settings.online .dot {
  background: #2c2;
  box-shadow: 0 0 4px rgba(40, 200, 40, 0.6);
}

#btn-obs-settings.offline .dot {
  background: #c33;
  box-shadow: 0 0 4px rgba(200, 50, 50, 0.6);
}

#btn-obs-settings.disabled .dot {
  background: #444;
}

#obs-popover {
  position: absolute;
  right: 10px;
  top: 84px;        /* below the status panel; works for the default font sizing */
  z-index: 50;
  width: 380px;
  background: #1a1a1a;
  border: 1px solid #444;
  border-radius: 6px;
  padding: 12px 14px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
  color: #ddd;
}

#obs-popover[hidden] { display: none; }

.obs-pop-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

.obs-pop-header h4 {
  margin: 0;
  font-size: 14px;
  color: #fff;
}

#btn-obs-close {
  background: transparent;
  border: 0;
  color: #aaa;
  font-size: 14px;
  cursor: pointer;
}

#btn-obs-close:hover { color: #fff; }

.obs-pop-status {
  font-size: 12px;
  color: #aaa;
  margin-bottom: 12px;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
}

.obs-pop-status.online  { color: #88e088; }
.obs-pop-status.offline { color: #f08080; }

.obs-pop-section {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.obs-pop-section > label,
.obs-pop-section h5 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: #888;
  margin: 0;
}

.obs-pop-section select {
  background: #0c0c0c;
  border: 1px solid #333;
  color: #ddd;
  font-size: 13px;
  padding: 4px 6px;
  border-radius: 3px;
  font-family: inherit;
}

.obs-device-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}

.obs-device-row .label {
  flex: 0 0 80px;
  font-size: 12px;
  color: #bbb;
}

.obs-device-row select {
  flex: 1;
}

#nowplaying-error {
  margin-top: 8px;
  padding: 8px 14px;
  background: rgba(200, 50, 50, 0.32);
  border: 1px solid rgba(220, 80, 80, 0.85);
  border-radius: 6px;
  color: #ffd0d0;
  font-size: 14px;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  text-align: left;
  word-break: break-word;
  max-width: 70vw;
  display: inline-flex;
  align-items: flex-start;
  gap: 10px;
  box-shadow: 0 0 8px rgba(200, 50, 50, 0.35);
}

#nowplaying-error[hidden] {
  display: none;
}

#nowplaying-error .err-icon {
  font-size: 18px;
  line-height: 1.2;
  flex-shrink: 0;
}

#nowplaying-error .err-text {
  flex: 1;
  line-height: 1.35;
}

#nowplaying-error .err-close {
  background: transparent;
  border: 0;
  color: #ffd0d0;
  cursor: pointer;
  font-size: 14px;
  padding: 0 4px;
  line-height: 1.2;
}

#nowplaying-error .err-close:hover {
  color: #fff;
}

/* #browse-view is the flex parent of main-columns + footer when the
   viewer is in Browse mode. It needs to participate in the #app flex
   chain so main-columns can shrink and the footer stays visible. */
#browse-view {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
#browse-view footer { flex-shrink: 0; }

#main-columns {
  display: flex;
  gap: 10px;
  padding: 8px;
  flex: 1;
  min-height: 0;     /* lets nested overflow:auto take effect */
}

.column {
  flex: 1;
  border: 1px solid #333;
  background: #0c0c0c;
  padding: 4px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* The leftmost column holds short labels (4-char years or single letters),
   so it doesn't need an equal share of horizontal space. */
#col-years {
  flex: 0 0 180px;
}

/* subtle border for focused column */
.column.focused {
  border-color: #007acc;
  box-shadow: 0 0 6px rgba(0, 122, 204, 0.6);
}

/* search active: year/group filters are paused — fade them out */
.column.search-active {
  opacity: 0.4;
}

.column h3 {
  text-align: center;
  margin: 4px 0;
  font-size: 16px;
}

ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

li {
  padding: 4px 6px;
  cursor: pointer;
}

/* selection highlight */
li.selected {
  background: white;
  color: black;
}

/* cursor highlight */
li.cursor {
  outline: 2px solid #00aaff;
  outline-offset: -2px;
}

.details-col {
  flex: 1.5;
  /* Block flow so details + timeline share one column scrollbar; timeline
     list keeps its own inner scroll (max-height below) so chat history
     stays browsable without losing the details above. */
  display: block;
}

.details-col > .details-header,
.details-col > #release-detail,
.details-col > #timeline-panel { flex: none; }
.details-col > #release-detail { overflow: visible; }
.details-col > #timeline-panel { display: block; min-height: 0; }

#release-detail {
  padding: 8px;
  font-size: 13px;
  line-height: 1.4;
}

#release-detail h4 {
  margin: 0 0 8px 0;
  font-size: 16px;
  color: #fff;
}

#release-detail h5 {
  margin: 12px 0 4px 0;
  font-size: 13px;
  color: #aaa;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

#release-detail ul {
  padding-left: 16px;
}

#release-detail li {
  padding: 1px 0;
  cursor: default;
}

#release-detail small {
  color: #888;
}

#release-detail a {
  color: #4aa3df;
}

.details-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 0 6px;
}

.details-header h3 {
  margin: 4px 0;
}

#btn-show-nowplaying {
  background: #1a1a1a;
  border: 1px solid #444;
  color: #aaa;
  padding: 3px 8px;
  font-size: 12px;
  border-radius: 4px;
  cursor: pointer;
}

#btn-show-nowplaying:hover {
  background: #2a2a2a;
  color: #fff;
  border-color: #555;
}

#btn-show-nowplaying.active {
  background: #007acc;
  border-color: #007acc;
  color: #fff;
}

/* ---- Star rating ---- */
.rating-block {
  margin: 6px 0 10px 0;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.stars {
  display: inline-flex;
  gap: 2px;
}

.stars button {
  background: transparent;
  border: 0;
  padding: 0 2px;
  font-size: 22px;
  line-height: 1;
  color: #555;
  cursor: pointer;
  transition: color 0.05s;
  font-family: inherit;
}

.stars button.active {
  color: #f5b400;
}

.stars button:hover {
  color: #ffd54a;
}

.rating-agg {
  font-size: 13px;
  color: #aaa;
}

.rating-agg .avg {
  color: #f5b400;
  font-weight: 600;
}

.rating-agg.empty {
  color: #666;
  font-style: italic;
}

#release-detail .cover {
  display: block;
  margin: 12px auto;
  max-width: 100%;
  max-height: 280px;
  border: 1px solid #333;
  background: #000;
  image-rendering: pixelated;     /* keep C64 art crisp when scaled */
}

#timeline-panel {
  padding: 8px;
  border-top: 1px solid #333;
  margin-top: 8px;
  font-size: 12px;
  display: flex;
  flex-direction: column;
}

#timeline-panel h5 {
  margin: 0 0 6px 0;
  font-size: 12px;
  color: #aaa;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

#timeline-list {
  list-style: none;
  padding: 0;
  margin: 0;
  min-height: 220px;
  max-height: 55vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

#timeline-list li {
  padding: 4px 6px;
  border-bottom: 1px solid #1a1a1a;
  line-height: 1.35;
  display: grid;
  grid-template-columns: 42px 16px 1fr;
  gap: 6px;
  align-items: baseline;
}

#timeline-list li.clickable { cursor: pointer; }
#timeline-list li.clickable:hover { background: rgba(255, 255, 255, 0.04); }

#timeline-list li .time {
  color: #666;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 11px;
}

#timeline-list li .icon {
  font-size: 13px;
  text-align: center;
  user-select: none;
}

#timeline-list li.event-queued .icon  { color: #4aa3df; }
#timeline-list li.event-random .icon  { color: #4aa3df; }
#timeline-list li.event-played .icon  { color: #2c2; }
#timeline-list li.event-failed .icon  { color: #c33; }
#timeline-list li.event-rated  .icon  { color: #f5b400; }
#timeline-list li.event-chat   .icon  { color: #aaa; }
#timeline-list li.event-sid    .icon  { color: #cc88f0; }

#timeline-list li .text {
  color: #ccc;
  word-break: break-word;
}

#timeline-list li .title {
  color: #ddd;
}

#timeline-list li .by {
  color: #777;
}

/* Per-user colour applied inline (see colorForUser in ui.js). The shared
   rule here just provides the weight so the badge stands out. */
#timeline-list li .user-name { font-weight: 600; }
#timeline-list li.event-chat .user-name { font-weight: 700; }

/* Chat-embedded links: only http(s), opens in new tab. Distinct color
   so they stand out from the message text but not so loud they hurt
   the timeline scan. */
#timeline-list li .chat-link {
  color: #4aa3df;
  text-decoration: underline;
  text-decoration-color: rgba(74, 163, 223, 0.4);
  word-break: break-all;
}
#timeline-list li .chat-link:hover {
  color: #6cb8e8;
  text-decoration-color: #6cb8e8;
}

#chat-form {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}

#chat-input {
  flex: 1;
  background: #1a1a1a;
  border: 1px solid #333;
  color: #ddd;
  font-size: 13px;
  font-family: inherit;
  padding: 5px 8px;
  border-radius: 3px;
}

#chat-input:focus {
  border-color: #007acc;
  outline: none;
}

#chat-send {
  background: #1a1a1a;
  border: 1px solid #444;
  color: #ccc;
  font-size: 12px;
  padding: 4px 12px;
  border-radius: 3px;
  cursor: pointer;
}

#chat-send:hover {
  background: #2a2a2a;
  color: #fff;
  border-color: #555;
}

footer {
  padding: 10px;
  background: #222;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
}

footer .btn-group {
  display: inline-flex;
  gap: 6px;
}

footer .btn-divider {
  width: 1px;
  align-self: stretch;
  background: #444;
}

footer button {
  padding: 7px 12px;
  font-size: 14px;
  background: #1a1a1a;
  color: #ddd;
  border: 1px solid #444;
  border-radius: 4px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background 0.1s, color 0.1s, border-color 0.1s;
}

footer button:hover {
  background: #2a2a2a;
  color: #fff;
  border-color: #555;
}

footer button:active {
  background: #007acc;
  border-color: #007acc;
  color: #fff;
}

footer button .icon {
  font-size: 15px;
  line-height: 1;
}

/* The play/pause toggle gets a subtle highlight when paused so the next
   click action is obvious. */
footer button#btn-playpause[data-state="paused"] {
  background: #2a4a6a;
  border-color: #4a7aa0;
  color: #fff;
}

/* =====================================================================
   Watch vs Browse modes — a single switcher at the top picks one or the
   other. The stream iframe is *always* mounted (just hidden in browse)
   so audio keeps playing while viewers pick the next item.
   ===================================================================== */

/* Mode switcher sits at the left of the status panel so it's in the same
   spot regardless of mode, and the header row is free for browse chrome. */
#mode-tabs {
  flex-shrink: 0;
}
#mode-tabs .tab {
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 4px 10px;
}

/* In the new status-left, mode tabs sit side-by-side with the now-playing
   text. Override the inherited centered layout. */
#status-left {
  display: flex;
  align-items: center;
  gap: 12px;
  text-align: left;
}
#status-left .nowplaying-block {
  flex: 1;
  min-width: 0;
}
#status-left .nowplaying-row { justify-content: flex-start; }
#status-left .nowplaying-progress { justify-content: flex-start; }

/* Browse-mode filter bar (Demos/Games + Year/Alphabet + search). Lives
   BELOW the status panel so the status panel — and the mode switcher
   inside it — anchors at the exact same y position regardless of mode. */
#browse-filter-bar {
  flex-shrink: 0;
  padding: 8px;
  background: #1a1a1a;
  border-bottom: 1px solid #333;
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: center;
}
#browse-filter-bar input {
  flex: 1;
  max-width: 60%;
  padding: 6px;
  font-size: 14px;
  color: #222;
}

/* Browse-only header chrome: hidden in watch mode. */
body.mode-watch  .browse-only { display: none !important; }
body.mode-watch  #browse-view { display: none !important; }

/* Browse mode: hide browse-only chrome stays visible (it IS browse mode).
   The watch-view is moved off-screen rather than display:none so the
   stream iframe stays mounted and audio keeps playing while viewers
   pick the next item. */
body.mode-browse #watch-view {
  position: absolute;
  left: -10000px;
  top: 0;
  width: 1280px;     /* arbitrary; iframe needs non-zero dimensions */
  height: 720px;
  pointer-events: none;
  visibility: hidden; /* hides everything else; iframe still plays audio */
}
/* Iframe must stay rendered, so override the parent visibility for it only. */
body.mode-browse #watch-stream-frame { visibility: visible; }

/* ---- Watch view layout ----
   Desktop layout (nested grid, draggable splitters):
     ┌──────────────────────────────┬─┬────────┐
     │ stream                       │ │        │
     ├──────────────────────────────┤ │  time  │
     │ ─── split-h ─────────────────┤ │  line  │
     ├────────────┬─────────────────┤ │   +    │
     │ details    │ queue           │ │  chat  │
     └────────────┴─────────────────┴─┴────────┘
   --watch-side-px controls the timeline column width.
   --watch-bot-px  controls the details/queue row height.
*/
#watch-view {
  flex: 1;
  min-height: 0;
  display: grid;
  gap: 0;
  padding: 8px;
  grid-template-columns: minmax(0, 1fr) 6px var(--watch-side-px, 340px);
  grid-template-rows: minmax(0, 1fr);
  grid-template-areas: "main splitV timeline";
}

.watch-main {
  grid-area: main;
  min-width: 0;
  min-height: 0;
  display: grid;
  gap: 0;
  grid-template-rows: minmax(0, 1fr) 6px var(--watch-bot-px, 220px);
  grid-template-areas:
    "stream"
    "splitH"
    "bottom";
}

/* Iframe just fills the cell — let the embedded player handle its own
   letterboxing internally. The earlier 16:9 container-query trick made
   the iframe shrink awkwardly when splitters were dragged, which felt
   worse than the occasional black bar inside the player. */
#watch-view .watch-stream {
  grid-area: stream;
  position: relative;
  background: #000;
  border: 1px solid #333;
  border-radius: 4px;
  overflow: hidden;
  min-height: 0;
}
#watch-view .watch-stream iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
#watch-stream-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: #777;
  text-align: center;
  padding: 20px;
}
#watch-stream-empty p { margin: 0; font-size: 16px; }
#watch-stream-empty small { color: #555; }

.watch-bottom {
  grid-area: bottom;
  min-height: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

#watch-view .watch-details,
#watch-view .watch-queue,
#watch-view .watch-timeline {
  border: 1px solid #333;
  background: #0c0c0c;
  border-radius: 4px;
  padding: 6px 8px;
  overflow-y: auto;
  min-height: 0;
}

#watch-view h3 {
  margin: 2px 0 6px 0;
  font-size: 14px;
  color: #aaa;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

#watch-view .watch-timeline {
  grid-area: timeline;
  display: flex;
  flex-direction: column;
  margin-left: 0;
  font-size: 12px;     /* timeline-list inherits — keeps it tight */
}
#watch-view .watch-timeline h5 {
  margin: 0 0 6px 0;
  font-size: 12px;
  color: #aaa;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
#watch-view .watch-timeline #timeline-list {
  flex: 1;
  min-height: 0;
  max-height: none;     /* override the bridge-wide 55vh cap */
  font-size: 12px;
}
/* The bridge-wide rule sets min-height: 220px on #timeline-list, intended
   for the "one scrollbar over details + timeline" layout. In the watch
   panel the list takes whatever vertical space the grid row offers, so
   reset the floor. */
#watch-view .watch-timeline #timeline-list { min-height: 0; }
#watch-view .watch-timeline #chat-form {
  margin-top: 8px;
}

/* ---- Splitter handles ---- */
.watch-split-v,
.watch-split-h {
  background: #1a1a1a;
  position: relative;
}
.watch-split-v {
  grid-area: splitV;
  cursor: col-resize;
  margin: 0 4px;
  width: 6px;
}
.watch-split-h {
  grid-area: splitH;
  cursor: row-resize;
  margin: 4px 0;
  height: 6px;
}
.watch-split-v:hover,
.watch-split-h:hover,
.watch-split-v.dragging,
.watch-split-h.dragging { background: #007acc; }
/* Subtle "grip" indicator centered in the handle */
.watch-split-v::before {
  content: "";
  position: absolute;
  left: 1px; right: 1px;
  top: 50%; transform: translateY(-50%);
  height: 30px;
  background: linear-gradient(#444, #444) center/2px 24px no-repeat;
  border-radius: 2px;
  pointer-events: none;
}
.watch-split-h::before {
  content: "";
  position: absolute;
  top: 1px; bottom: 1px;
  left: 50%; transform: translateX(-50%);
  width: 30px;
  background: linear-gradient(#444, #444) center/24px 2px no-repeat;
  border-radius: 2px;
  pointer-events: none;
}
/* Block selection / iframe pointer-events while dragging so the cursor
   tracks reliably across the iframe. */
body.watch-dragging,
body.watch-dragging * {
  user-select: none !important;
  cursor: inherit !important;
}
body.watch-dragging iframe { pointer-events: none; }

/* ---- Cover + meta side-by-side row (details panes) ---- */
/* Flex row: image on the left, year/by/type stacked next to it. Wraps
   the meta below the image when the pane is too narrow to fit both. */
.cover-meta-row {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  flex-wrap: wrap;
  margin: 8px 0;
}
.cover-meta-row .cover {
  flex: 0 0 auto;
  margin: 0;                  /* override the centered margin from generic .cover rule */
}
.cover-meta-row .release-meta {
  flex: 1 1 180px;            /* expand if there's room, drop to a new row under ~180px */
  min-width: 0;
  font-size: 13px;
  color: #ccc;
}
.cover-meta-row .release-meta .meta-line {
  margin-bottom: 4px;
}

/* When the meta sits alone (no image), don't force the flex container. */
.release-meta:not(.cover-meta-row .release-meta) {
  font-size: 13px;
  color: #ccc;
}

/* ---- "Now playing" badge in the watch-details header ---- */
.np-badge {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  background: rgba(44, 200, 44, 0.18);
  border: 1px solid #2c2;
  color: #88e088;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  border-radius: 3px;
  vertical-align: middle;
  text-transform: uppercase;
}
.np-badge[hidden] { display: none; }

/* ---- Online users panel (collapsible, right of the timeline body) ---- */

/* Header row: "Live timeline" h5 on the left, [user handle + Online toggle]
   on the right so all chat-related controls are clustered near the input. */
.timeline-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
  flex-wrap: wrap;
}
.timeline-header-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.timeline-header-actions .user-handle-slot {
  /* same compact look as the slot in the browse-mode details header */
  margin: 0;
}

#watch-view .watch-timeline .timeline-header h5 {
  margin: 0;       /* override the default h5 top margin from base styles */
}

.online-toggle {
  background: #1a1a1a;
  border: 1px solid #333;
  color: #ccc;
  font-size: 11px;
  font-family: inherit;
  padding: 2px 8px;
  border-radius: 3px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.online-toggle:hover { background: #2a2a2a; border-color: #555; }
.online-toggle.open  { background: #2a4a6a; border-color: #4a7aa0; color: #fff; }
.online-toggle .online-caret { font-size: 9px; color: #888; }
.online-toggle.open .online-caret { color: #ccc; }

/* The "online" status dot is always green — it's a presence indicator
   distinct from the per-user colour, which lives on the name. */
.online-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #2c2;
  display: inline-block;
  box-shadow: 0 0 4px rgba(40, 200, 40, 0.6);
  flex-shrink: 0;
}

/* Timeline body wraps the chat list and the floating online overlay.
   position:relative is the anchor for the overlay's absolute positioning. */
.timeline-body {
  flex: 1;
  min-height: 0;
  position: relative;
  display: flex;
}
#watch-view .watch-timeline .timeline-body #timeline-list {
  flex: 1;
  min-width: 0;
}

/* Online panel floats over the right edge of the timeline-body — never
   reflows the chat list. Height grows with content (one row per user)
   but stops at half the timeline-body's height so it never dominates. */
.online-panel {
  position: absolute;
  top: 0;
  right: 20px;
  /* no `bottom` → height shrinks to content */
  max-height: 50%;
  width: 150px;
  background: #1a1a1a;
  border: 1px solid #333;
  border-radius: 4px;
  padding: 6px 8px;
  box-shadow: -4px 0 12px rgba(0, 0, 0, 0.4);
  overflow-y: auto;
  z-index: 10;
  font-size: 11px;
  line-height: 1.4;
}
.online-panel[hidden] { display: none; }
.online-panel .online-empty {
  color: #555;
  font-style: italic;
  padding: 4px 0;
}
.online-panel .online-user {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 2px 4px 2px 2px;
  border-radius: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.online-panel .online-user.self {
  background: rgba(255, 255, 255, 0.06);
}
.online-panel .online-user .name {
  font-weight: 600;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.online-panel .online-user .qcount {
  color: #f5b400;
  font-size: 10px;
  flex-shrink: 0;
}

/* ---- Toast notifications (transient errors / rate limits) ---- */
.ui-toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 1000;
  background: #2a2a2a;
  color: #eee;
  border: 1px solid #444;
  padding: 10px 18px;
  border-radius: 6px;
  font-size: 13px;
  font-family: Arial, sans-serif;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.6);
  max-width: 80vw;
  pointer-events: none;
}
.ui-toast[hidden] { display: none; }
.ui-toast.warn  { background: #6a4a14; border-color: #c08828; color: #fff5dc; }
.ui-toast.error { background: #6a1a1a; border-color: #c04040; color: #ffd0d0; }

/* Watch-mode details/release card */
#watch-release-detail {
  font-size: 13px;
  line-height: 1.4;
  color: #ccc;
}
#watch-release-detail h4 {
  margin: 0 0 6px 0;
  font-size: 16px;
  color: #fff;
}
#watch-release-detail .cover {
  display: block;
  margin: 8px auto;
  max-width: 100%;
  max-height: 180px;
  border: 1px solid #333;
  background: #000;
  image-rendering: pixelated;
}
#watch-release-detail small { color: #888; }
#watch-release-detail .meta-line { color: #aaa; margin-bottom: 4px; }
#watch-release-detail .empty {
  color: #666;
  font-style: italic;
  text-align: center;
  padding: 12px;
}

/* Watch-mode queue (read-only list) */
#watch-queue-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
#watch-queue-list li {
  padding: 4px 6px;
  border-bottom: 1px solid #1a1a1a;
  cursor: default;
  font-size: 13px;
  line-height: 1.35;
}
#watch-queue-list li.clickable { cursor: pointer; }
#watch-queue-list li.clickable:hover { background: rgba(255, 255, 255, 0.04); }
#watch-queue-list li .pos {
  color: #555;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 11px;
  margin-right: 6px;
}
#watch-queue-list li .by {
  color: #4aa3df;
  font-size: 11px;
  margin-left: 6px;
}
#watch-queue-list .empty,
#watch-top-list .empty {
  color: #666;
  font-style: italic;
  text-align: center;
  padding: 12px;
}

/* ---- Up next / Top rated tab strip ---- */
.watch-queue-tabs {
  display: flex;
  gap: 0;
  margin: 0 0 6px 0;
  border-bottom: 1px solid #2a2a2a;
}
.watch-queue-tab {
  background: transparent;
  border: 0;
  color: #888;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 6px 12px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  letter-spacing: 0.04em;
  margin-bottom: -1px;
}
.watch-queue-tab:hover { color: #ccc; }
.watch-queue-tab.active {
  color: #4aa3df;
  border-bottom-color: #4aa3df;
}
/* Tiny inline tag that sits right after the "Top rated" tab label, e.g.
   "Top rated [24h]". Clicking toggles the viewer's pick between 24h and
   all-time. Vertically aligned with the tab text. */
.top-window-chip {
  margin-left: -6px;          /* hug the tab label */
  align-self: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: #888;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
}
.top-window-chip::before { content: "["; color: #555; }
.top-window-chip::after  { content: "]"; color: #555; }
.top-window-chip:hover { color: #4aa3df; }
.top-window-chip:hover::before,
.top-window-chip:hover::after { color: #4aa3df; }

/* ---- Top rated list ---- */
#watch-top-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
#watch-top-list li.top-item {
  padding: 6px 6px;
  border-bottom: 1px solid #1a1a1a;
  cursor: pointer;
  font-size: 13px;
  line-height: 1.35;
}
#watch-top-list li.top-item:hover { background: rgba(255, 255, 255, 0.04); }
#watch-top-list li.top-item .pos {
  color: #555;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 11px;
  margin-right: 6px;
}
#watch-top-list li.top-item .rating-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 3px;
  font-size: 11px;
}
#watch-top-list li.top-item .stars-mini {
  color: #f5b400;
  font-size: 12px;
  letter-spacing: 1px;
}
#watch-top-list li.top-item .avg {
  color: #f5b400;
  font-weight: 600;
}
#watch-top-list li.top-item .vcount { color: #777; }

/* Responsive: on narrow screens stack everything vertically and hide the
   draggable splitters (they only make sense on a true multi-pane layout). */
@media (max-width: 900px) {
  #watch-view {
    grid-template-columns: 1fr;
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas:
      "main"
      "timeline";
  }
  .watch-split-v { display: none; }
  .watch-main {
    grid-template-rows: minmax(220px, 45vh) auto auto;
    grid-template-areas:
      "stream"
      "bottom-d"
      "bottom-q";
  }
  .watch-split-h { display: none; }
  .watch-bottom {
    grid-template-columns: 1fr;
    grid-row: bottom-d / bottom-q;
  }
  #watch-view .watch-timeline { min-height: 280px; }
}
