/* Watch portal - shared styles for the library and player pages. */
:root { color-scheme: dark; }
* { box-sizing: border-box; }
body {
  margin: 0; min-height: 100vh;
  font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  background: #0a0e16; color: #e8edf5;
}

/* ------------------------------------------------------------------ topbar */
.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 20px; border-bottom: 1px solid rgba(120,160,220,0.14);
  background: rgba(13,19,30,0.9); position: sticky; top: 0; z-index: 100;
  backdrop-filter: blur(6px);
}
.brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
.brand .logo {
  width: 30px; height: 30px; border-radius: 8px; flex: none;
  background: linear-gradient(135deg,#2fa9ff,#1c6cff);
  display: flex; align-items: center; justify-content: center; font-weight: 800; color: #fff;
}
.brand h1 { font-size: 15px; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brand .back { color: #9fb0c6; text-decoration: none; font-size: 20px; padding: 0 4px; }
.brand .back:hover { color: #fff; }
.who { color: #8a9bb2; font-size: 12px; display: flex; align-items: center; gap: 12px; flex: none; }
.who a { color: #2fa9ff; text-decoration: none; }
.sync-pill {
  padding: 3px 10px; border-radius: 999px; font-size: 11px; font-weight: 600;
  border: 1px solid rgba(120,160,220,0.25); color: #9fb0c6;
}
.sync-pill.ok { color: #35d07f; border-color: rgba(53,208,127,0.4); }
.sync-pill.warn { color: #ffb020; border-color: rgba(255,176,32,0.4); }

/* ----------------------------------------------------------------- library */
.library { max-width: 1100px; margin: 0 auto; padding: 28px 24px 60px; }
.library h2 { font-size: 18px; margin: 22px 0 14px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px,1fr)); gap: 18px; }
.tile {
  background: #111927; border: 1px solid rgba(120,160,220,0.14); border-radius: 14px;
  overflow: hidden; text-decoration: none; color: inherit; display: flex; flex-direction: column;
  transition: transform .12s ease, border-color .12s ease;
}
.tile:hover { transform: translateY(-2px); border-color: rgba(47,169,255,0.5); }
.thumb {
  aspect-ratio: 16/9; background: #0a0f18; position: relative;
  display: flex; align-items: center; justify-content: center;
}
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.play {
  position: absolute; width: 46px; height: 46px; border-radius: 50%;
  background: rgba(0,0,0,0.55); display: flex; align-items: center; justify-content: center;
}
.play::after {
  content: ""; border-style: solid; border-width: 8px 0 8px 13px;
  border-color: transparent transparent transparent #fff; margin-left: 3px;
}
.badge {
  position: absolute; left: 8px; top: 8px; font-size: 11px; font-weight: 700;
  padding: 2px 8px; border-radius: 6px; background: rgba(0,0,0,0.7); color: #cfd8e6;
}
.badge.live { background: #d62839; color: #fff; }
.badge.upcoming { background: rgba(47,169,255,0.85); color: #fff; }
.meta { padding: 12px 14px; }
.meta .t { font-weight: 700; font-size: 14px; margin: 0 0 4px; }
.meta .d {
  color: #8a9bb2; font-size: 12px; margin: 0; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.empty { color: #8a9bb2; padding: 60px 0; text-align: center; }

/* ------------------------------------------------------------------ player */
.hidden { display: none !important; }
/* U20-4: 100dvh (with the 100vh fallback for old browsers) - on iOS Safari
   100vh includes the band behind the collapsing toolbar, which pushed the
   whole bottom control bar off-screen on iPads. */
.player-body { display: flex; flex-direction: column; height: 100vh; height: 100dvh; overflow: hidden; }
/* Client 2026-10-10 (Z Fold, Edge for Android: "no play controls"): some
   mobile browsers report 100dvh INCLUDING a bottom toolbar that then covers
   the transport bar. The small viewport unit never counts a toolbar, so the
   bar stays reachable; when the toolbar hides, a thin band is left instead.
   The safe-area inset keeps the bar above a gesture bar. */
@supports (height: 100svh) {
  .player-body { height: 100svh; }
}
.controls { padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px)); }
/* Plan section 39 (Sunil's iPad, Safari 26, 2026-10-29): the player page is
   PINNED to the viewport. A fixed box needs no viewport unit, and iOS cannot
   scroll a document whose only content is a fixed box (it scrolled the page
   under the toolbar even with overflow hidden on the body, hiding the top
   bar and pushing the transport bar under the window edge). player.js adds
   the classes outside print / video capture and keeps max-height = the
   smallest height any API reports. */
html.vp-pinned { height: 100%; overflow: hidden; }
body.player-body.vp-pinned { position: fixed; inset: 0; width: 100%; height: auto; }
.player-main { flex: 1; min-height: 0; display: flex; flex-direction: column; }

/* Lobby (event details + channel pick + actions) */
.lobby {
  flex: 1; overflow-y: auto; width: 100%; max-width: 960px; margin: 0 auto;
  padding: 24px 20px 48px;
}
.hero { display: flex; gap: 22px; margin-bottom: 26px; }
.hero-img {
  flex: none; width: 320px; aspect-ratio: 16/9; border-radius: 14px;
  background-color: #0a0f18; background-size: cover; background-position: center;
  border: 1px solid rgba(120,160,220,0.16);
}
.hero-img.noimg { display: flex; align-items: center; justify-content: center; }
.hero-meta { min-width: 0; flex: 1; }
.hero-badges { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.status-badge {
  font-size: 11px; font-weight: 800; letter-spacing: 0.5px;
  padding: 3px 10px; border-radius: 999px; background: rgba(120,160,220,0.15); color: #cfd8e6;
}
.status-badge.live { background: #d62839; color: #fff; animation: pulse 1.6s infinite; }
.status-badge.upcoming { background: rgba(47,169,255,0.2); color: #7cc4ff; }
.status-badge.ended { background: rgba(120,160,220,0.12); color: #8a9bb2; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.65; } }
.cats { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.cat-chip {
  font-size: 11px; padding: 2px 9px; border-radius: 999px;
  border: 1px solid rgba(120,160,220,0.3); color: #b8c6da;
}
.hero-meta h2 { margin: 0 0 6px; font-size: 24px; }
.pub { display: flex; align-items: center; gap: 8px; color: #8a9bb2; font-size: 13px; margin-bottom: 8px; }
.pub img { width: 20px; height: 20px; border-radius: 5px; object-fit: cover; }
.when { color: #8a9bb2; font-size: 13px; margin-bottom: 4px; }
.desc { color: #b8c6da; font-size: 14px; line-height: 1.5; margin: 12px 0 0; white-space: pre-wrap; }

.lobby-h { font-size: 16px; margin: 8px 0 2px; }
.lobby .hint { color: #8a9bb2; font-size: 13px; margin: 4px 0 14px; }
.channel-list { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 26px; }
.channel-btn {
  --accent: #2fa9ff;
  display: flex; align-items: center; gap: 8px; padding: 12px 18px;
  background: #111927; color: #e8edf5; font-size: 14px; font-weight: 600;
  border: 2px solid rgba(120,160,220,0.2); border-radius: 12px; cursor: pointer;
}
.channel-btn img { width: 22px; height: 22px; object-fit: contain; }
.channel-btn:hover { border-color: var(--accent); }
.channel-btn.selected { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent); }
.lobby-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.primary-btn {
  padding: 13px 40px; border: none; border-radius: 10px; font-size: 15px; font-weight: 700;
  background: linear-gradient(135deg,#2fa9ff,#1c6cff); color: #fff; cursor: pointer;
}
.primary-btn:disabled { opacity: 0.4; cursor: default; }
.secondary-btn {
  padding: 13px 40px; border-radius: 10px; font-size: 15px; font-weight: 700; cursor: pointer;
  background: transparent; color: #7cc4ff; border: 2px solid rgba(47,169,255,0.55);
}
.secondary-btn:hover:not(:disabled) { background: rgba(47,169,255,0.12); }
.secondary-btn:disabled { opacity: 0.4; cursor: default; }
.picker-status { margin-top: 14px; color: #8a9bb2; font-size: 13px; min-height: 18px; }

/* Stage - fills everything between the header and the transport bar, so it is
   landscape on a desktop and portrait on a phone. Node rects are fractions of
   this box, matching the schedule's normalized stage convention. */
.stage-wrap {
  flex: 1; min-height: 0; display: flex; width: 100%;
  align-items: stretch; background: #000;
}
.rail {
  width: 60px; flex: none; display: flex; flex-direction: column; gap: 14px;
  align-items: center; padding: 12px 0; overflow-y: auto; overflow-x: hidden;
  background: #05070c; scrollbar-width: none;
}
.rail-channels, .rail-icons, .rail-actions {
  display: flex; flex-direction: column; gap: 12px; align-items: center;
}
.rail-channels:not(:empty) + .rail-icons:not(:empty),
.rail-channels:not(:empty) + .rail-actions:not(:empty),
.rail-actions:not(:empty) + .rail-icons:not(:empty) {
  border-top: 1px solid rgba(120,160,220,0.18); padding-top: 12px;
}
/* Channel chips (left rail) - circular, accent ring when selected. */
.rail-chip {
  --accent: #2fa9ff;
  width: 42px; height: 42px; border-radius: 50%; cursor: pointer; padding: 0;
  border: 1.5px solid rgba(255,255,255,0.35); background: #101827; color: #e8edf5;
  font-size: 15px; font-weight: 700; overflow: hidden;
  display: flex; align-items: center; justify-content: center; flex: none;
}
.rail-chip img { width: 100%; height: 100%; object-fit: cover; }
.rail-chip:hover { border-color: var(--accent); }
.rail-chip.selected {
  border: 2.5px solid var(--accent);
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 55%, transparent);
}
/* Schedule glyphs (ui.setRailIcons) - bordered circles like the app. */
.rail-glyph {
  width: 40px; height: 40px; border-radius: 50%; overflow: hidden; flex: none;
  border: 1px solid rgba(255,255,255,0.35);
  box-shadow: 0 0 8px rgba(0,255,255,0.09);
  display: flex; align-items: center; justify-content: center; background: #0a0f18;
}
.rail-glyph img { width: 100%; height: 100%; object-fit: cover; }
/* Action buttons (right rail). */
.rail-action {
  width: 42px; height: 42px; border-radius: 50%; cursor: pointer; padding: 9px;
  border: 1px solid rgba(255,255,255,0.28); background: transparent; color: #9fb0c6;
  display: flex; align-items: center; justify-content: center; flex: none;
}
.rail-action svg { width: 100%; height: 100%; }
.rail-action:hover { color: #fff; border-color: rgba(47,169,255,0.7); background: rgba(47,169,255,0.1); }
/* Event info sheet (right-rail info action). */
.info-sheet {
  position: absolute; inset: 0; z-index: 70; display: flex;
  align-items: center; justify-content: center; background: rgba(5,8,14,0.6);
  cursor: pointer;
}
.info-card {
  max-width: 440px; width: calc(100% - 48px); max-height: 80%; overflow-y: auto;
  background: #101827; border: 1px solid rgba(120,160,220,0.3); border-radius: 14px;
  padding: 20px 22px; cursor: default;
}
.info-card h3 { margin: 0 0 10px; font-size: 18px; }
.info-card p { margin: 0 0 8px; font-size: 13px; line-height: 1.5; color: #cfd8e6; white-space: pre-wrap; }
.info-card p.muted { color: #8a9bb2; }
.stage-box {
  position: relative; flex: 1; min-width: 0; background: #000; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
/* Letterboxed to a phone-landscape ratio so the normalized cue rects land in
   the SAME proportions viewers see on the mobile app - a full-width desktop
   window no longer stretches the layout (black bars fill the difference). */
.stage {
  position: relative;
  /* U15-E: DEVICE stage aspect (2.4513:1, measured on-phone) - matches the
     app and the admin previews so layouts keep the same proportions.
     Plan section 27: this is the PHONE default; the player sets an inline
     aspect-ratio from the schedule's stage preset (16:9 for "wide"). */
  aspect-ratio: 2.4513;
  width: 100%;
  max-height: 100%;
  max-width: 100%;
  /* U21-C bugfix (client: "background color of the web viewer is not
     used"): the U17-J ui.setBackground node paints at z -100, and without
     a stacking context here negative-z children paint BEHIND the ancestors'
     backgrounds - i.e. under .stage-box's black. isolate scopes the z order
     to the stage so the colour shows (letterbox around it stays black). */
  isolation: isolate;
}
/* U17: the portrait stage (9:19.5) is height-bound and centred. */
.stage.portrait {
  aspect-ratio: 0.4615;
  width: auto;
  height: 100%;
  margin: 0 auto;
}
.stage-node { position: absolute; overflow: hidden; }
.stage-node img, .stage-node video { width: 100%; height: 100%; object-fit: contain; display: block; }
/* Plan section 37: inline SVG object - the host fills the node, the <svg>
   fills the host (preserveAspectRatio carries the fit). */
.stage-node .svg-host { width: 100%; height: 100%; display: block; overflow: hidden; }
.stage-node .svg-host > svg { width: 100%; height: 100%; display: block; }
/* Layer legend sheet (left-rail layers action). */
.layer-card { max-width: 360px; }
.layer-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.layer-head h3 { margin: 0; }
.layer-close {
  width: 32px; height: 32px; border-radius: 8px; border: 1px solid rgba(120,160,220,0.3);
  background: transparent; color: #cfd8e6; font-size: 20px; line-height: 1; cursor: pointer;
}
.layer-close:hover, .layer-close:focus-visible { color: #fff; border-color: rgba(47,169,255,0.7); outline: none; }
.layer-card h4 { margin: 12px 0 4px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; color: #8a9bb2; }
.layer-row {
  display: flex; align-items: center; gap: 10px; padding: 8px 6px; border-radius: 8px;
  font-size: 14px; color: #e6edf7; cursor: pointer; min-height: 40px;
}
.layer-row:hover { background: rgba(47,169,255,0.08); }
.layer-row input { width: 18px; height: 18px; accent-color: #2fa9ff; cursor: pointer; }
.layer-row input:focus-visible { outline: 2px solid #2fa9ff; outline-offset: 2px; }
.layer-row.off span { color: #8a9bb2; text-decoration: line-through; text-decoration-color: rgba(138,155,178,0.6); }
body.video-chrome #layerSheet, body.video-mode #layerSheet { display: none !important; }
.stage-map { background: #0b1420; }
.stage-text {
  width: 100%; height: 100%; display: flex; justify-content: center;
  /* U15 safe centering: fitting text centres, overflowing text top-anchors
     so it spills downward only (plain `center` bleeds off the top). The
     first declaration is the fallback for browsers without `safe`. */
  align-items: center;
  align-items: safe center;
  font-size: 18px; line-height: 1.3; white-space: pre-wrap; word-break: break-word;
  /* U15: NO inset at all - the rect edge IS the text edge on every side, so
     fitted boxes render identically here, in the editor and on the phone
     (text taller than its box spills past the edge instead of clipping). */
  padding: 0;
}
.stage-btn {
  width: 100%; height: 100%; cursor: pointer; font-size: 15px; font-weight: 600;
  border: none; color: #fff; background: rgba(28,108,255,0.9);
}
.stage-btn:hover { filter: brightness(1.1); }
/* Plan section 43.8: a Choice input drawn as buttons. */
.stage-choice { display: flex; flex-wrap: wrap; gap: 0.35em; align-items: stretch; }
.stage-choice-vertical { flex-direction: column; }
.stage-choice-grid { display: grid; grid-template-columns: repeat(var(--choice-cols, 2), minmax(0, 1fr)); }
.stage-choice-btn {
  position: relative; flex: 1 1 auto; min-width: 0; padding: 0.35em 0.9em; border-radius: 999px; cursor: pointer;
  border: 2px solid transparent; color: #111827; font: inherit; font-weight: 600; text-align: center;
  box-shadow: 0 1px 2px rgba(0,0,0,0.35);
}
.stage-choice-btn:hover { filter: brightness(1.06); }
.stage-choice-btn[aria-pressed="true"] { border-color: #2fa9ff; box-shadow: 0 0 0 2px rgba(47,169,255,0.45), 0 1px 2px rgba(0,0,0,0.35); padding-right: 1.6em; }
.stage-choice-btn[aria-pressed="true"]::after {
  content: "\2713"; position: absolute; right: 0.6em; top: 50%; transform: translateY(-50%); font-size: 0.9em; line-height: 1;
}
/* Plan section 43.7: on-stage layer legend (checkbox per toggleable layer). */
.stage-legend {
  width: 100%; height: 100%; box-sizing: border-box; overflow: auto; border-radius: 0.6em;
  padding: 0.5em 0.7em; font-size: 13px; line-height: 1.25; display: flex; flex-direction: column; gap: 0.3em;
  scrollbar-width: thin;
}
.stage-legend-title { font-weight: 700; letter-spacing: 0.02em; margin-bottom: 0.15em; }
.stage-legend-rows { display: flex; flex-direction: column; gap: 0.2em; }
.stage-legend-horizontal .stage-legend-rows { flex-direction: row; flex-wrap: wrap; gap: 0.3em 1em; }
.stage-legend-grid .stage-legend-rows { display: grid; grid-template-columns: repeat(var(--legend-cols, 2), minmax(0, 1fr)); gap: 0.25em 0.8em; }
.stage-legend-row { display: flex; align-items: center; gap: 0.5em; cursor: pointer; min-height: 1.6em; }
.stage-legend-row input { width: 1.1em; height: 1.1em; accent-color: #2fa9ff; cursor: pointer; flex: none; margin: 0; }
.stage-legend-row.off span { opacity: 0.6; text-decoration: line-through; }
/* Plan section 43.4: a selector button (sets a variable) in its pressed state. */
.stage-btn[aria-pressed] { position: relative; }
.stage-btn-pressed { outline: 3px solid rgba(255,255,255,0.9); outline-offset: -3px; box-shadow: 0 0 0 2px rgba(0,0,0,0.35) inset; }
.stage-btn-pressed::after {
  content: "¹3"; position: absolute; right: 0.45em; top: 50%; transform: translateY(-50%);
  font-size: 0.9em; line-height: 1; opacity: 0.95;
}
/* Plan section 15.49 SECTION CARDS: grid inside the cards node. The
   player sets the column count inline (block width / 15.5em, 1-4, or the
   author's fixed count); rows are content-sized so a short node scrolls
   instead of squashing the cards. Type is em-based so the update loop
   scales it with the stage like every other node. */
.stage-cards {
  width: 100%; height: 100%; overflow-y: auto;
  display: grid; grid-template-columns: 1fr; grid-auto-rows: max-content;
  gap: 0.9em; padding: 0.15em 0.2em 0.6em;
  box-sizing: border-box; align-content: start; scrollbar-width: thin;
}
.stage-card {
  display: flex; flex-direction: column; text-align: left; cursor: pointer; padding: 0; margin: 0;
  border: 1px solid rgba(255,255,255,0.14); border-radius: 0.9em; overflow: hidden;
  background: rgba(255,255,255,0.06); color: #fff; font: inherit;
  transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
}
.stage-card:hover { background: rgba(255,255,255,0.11); border-color: rgba(255,255,255,0.3); transform: translateY(-1px); }
.stage-card:focus-visible { outline: 3px solid #7cc4ff; outline-offset: 2px; }
.stage-card-featured { border-color: rgba(124,196,255,0.7); box-shadow: 0 0 0 1px rgba(124,196,255,0.35) inset; }
.stage-card-media { position: relative; width: 100%; aspect-ratio: 16 / 9; background: #1b2230; overflow: hidden; flex: none; }
.stage-card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.stage-card-media-empty { display: flex; align-items: center; justify-content: center; font-size: 2.4em; font-weight: 700; color: rgba(255,255,255,0.35); background: linear-gradient(135deg, #223047, #141a24); }
.stage-card-body { display: flex; flex-direction: column; gap: 0.35em; padding: 0.7em 0.8em 0.75em; min-height: 0; }
.stage-card-title { font-size: 1.05em; font-weight: 700; line-height: 1.25; }
.stage-card-summary { font-size: 0.86em; line-height: 1.35; color: rgba(255,255,255,0.82); display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.stage-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 0.5em; margin-top: auto; padding-top: 0.25em; font-size: 0.8em; }
.stage-card-meta { color: rgba(255,255,255,0.6); }
.stage-card-action { color: #9fd0ff; font-weight: 700; white-space: nowrap; }
/* Overlay template: the picture fills the card, text sits on a dark panel
   (about 70% black, feathered upward) so it reads on any photo. */
.stage-cards-overlay .stage-card { position: relative; aspect-ratio: 4 / 3; }
.stage-cards-overlay .stage-card-media { position: absolute; inset: 0; aspect-ratio: auto; }
.stage-cards-overlay .stage-card-body {
  position: absolute; left: 0; right: 0; bottom: 0; padding-top: 1.6em;
  /* Client 2026-09-23: on a narrow (portrait) card the panel used to grow
     taller than the card and push its own TITLE out of the top, leaving the
     middle of the summary as the only visible text. The panel is now capped
     at the card and clips at the bottom, so the title is always the first
     thing visible; title and summary are clamped too. */
  max-height: 100%; box-sizing: border-box; overflow: hidden;
  background: linear-gradient(to top, rgba(0,0,0,0.68) 0, rgba(0,0,0,0.68) calc(100% - 1.5em), rgba(0,0,0,0));
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
}
.stage-cards-overlay .stage-card-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.stage-cards-overlay .stage-card-summary { -webkit-line-clamp: 2; }
/* Information template: a text card - accent edge, larger title, no picture. */
.stage-cards-info .stage-card { border-left: 0.3em solid #7cc4ff; background: rgba(255,255,255,0.08); }
.stage-cards-info .stage-card-media { display: none; }
.stage-cards-info .stage-card-body { padding: 0.8em 0.9em 0.85em; gap: 0.45em; }
.stage-cards-info .stage-card-title { font-size: 1.15em; }
/* Compact list template: thumbnail left, one-line summary, one column. */
.stage-cards-list { grid-template-columns: 1fr !important; gap: 0.5em; }
.stage-cards-list .stage-card { flex-direction: row; align-items: stretch; }
.stage-cards-list .stage-card-media { width: 7.5em; aspect-ratio: auto; flex: none; }
.stage-cards-list .stage-card-body { flex: 1; padding: 0.55em 0.8em; }
.stage-cards-list .stage-card-summary { -webkit-line-clamp: 1; }
/* U35-E1: numbered menu buttons - fixed number column, label wraps beside it. */
.stage-btn-numbered { display: flex; align-items: center; gap: 0.45em; text-align: left; }
.stage-btn-num { flex: none; min-width: 1.4em; text-align: right; opacity: 0.9; }
.stage-btn-label { flex: 1; min-width: 0; white-space: normal; }
/* U35-E5: tappable objects - outline on hover/focus (never colour alone), chevron on text. */
.stage-tap:hover, .stage-tap:focus-visible { outline: 2px solid rgba(255,255,255,0.7); outline-offset: 2px; }
.stage-tap-chev { opacity: 0.75; font-weight: 700; }
/* U36-B1: pill look (text box on) - brighten the pill instead of drawing a
   sharp rectangle around the node rect. */
.stage-tap-boxed:hover, .stage-tap-boxed:focus-visible { outline: none; }
.stage-tap-boxed:hover .stage-text, .stage-tap-boxed:focus-visible .stage-text {
  filter: brightness(1.18);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.55);
}
.countdown {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px;
  background: rgba(5,8,14,0.78); z-index: 50;
}
.countdown .cd-label { color: #8a9bb2; font-size: 14px; letter-spacing: 1px; text-transform: uppercase; }
.countdown .cd-time { font-size: 44px; font-weight: 800; font-variant-numeric: tabular-nums; }
.overlay-msg {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(5,8,14,0.85); z-index: 60; font-size: 17px; color: #cfd8e6;
}

/* Transport bar */
.controls {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 10px 16px; background: rgba(13,19,30,0.95);
  border-top: 1px solid rgba(120,160,220,0.14); flex: none; flex-wrap: wrap;
}
.icon-btn {
  width: 38px; height: 38px; border-radius: 50%; border: none; cursor: pointer;
  background: linear-gradient(135deg,#2fa9ff,#1c6cff); color: #fff; font-size: 15px;
  display: flex; align-items: center; justify-content: center; flex: none;
}
.icon-btn:hover { filter: brightness(1.1); }
.controls .chip {
  background: rgba(47,169,255,0.15); border: 1px solid rgba(47,169,255,0.4);
  color: #7cc4ff; font-size: 12px; font-weight: 700; padding: 4px 12px; border-radius: 999px;
  white-space: nowrap;
}
.controls .chip.mode.live { background: rgba(214,40,57,0.18); border-color: rgba(214,40,57,0.6); color: #ff7b8a; animation: pulse 1.6s infinite; }
.controls .chip.mode.free { background: rgba(37,194,104,0.15); border-color: rgba(37,194,104,0.45); color: #5fe39a; }
.controls .pos { color: #8a9bb2; font-size: 13px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.controls .seek { flex: 1; min-width: 120px; accent-color: #2fa9ff; }
.controls .spacer { flex: 1; }
/* U35-E6: page indicator between the clock and the seek bar. */
.controls .pagenav { display: inline-flex; align-items: center; gap: 4px; color: #8a9bb2; font-size: 12px; white-space: nowrap; }
.controls .pagenav .icon-btn { width: 26px; height: 26px; font-size: 16px; line-height: 1; }
.controls .chapters {
  background: #111927; color: #cfd8e6; border: 1px solid rgba(120,160,220,0.25);
  border-radius: 8px; padding: 6px 10px; font-size: 12px; max-width: 200px;
}
.controls .vol { display: flex; align-items: center; gap: 8px; color: #8a9bb2; font-size: 12px; }
.controls .vol input { width: 100px; accent-color: #2fa9ff; }
.ghost-btn {
  background: transparent; color: #9fb0c6; border: 1px solid rgba(120,160,220,0.25);
  border-radius: 8px; padding: 7px 14px; font-size: 12px; cursor: pointer; white-space: nowrap;
}
.ghost-btn:hover { color: #fff; border-color: rgba(47,169,255,0.6); }

/* Plan section 39 (Sunil's iPad photo, 2026-10-29 11:21): on a tablet the
   transport bar WRAPPED onto a second row that fell under the screen edge.
   Above the phone breakpoint the bar is ONE row: the seek bar, the Sections
   select and the volume slider give way (shrink) instead of wrapping, and on
   narrower tablets the gaps, the "Vol" word and the button padding go first.
   Phones (<= 900px) keep wrapping as before. */
@media (min-width: 901px) {
  .controls { flex-wrap: nowrap; overflow: hidden; }
  .controls > * { flex-shrink: 0; }
  .controls .seek { flex: 1 1 60px; min-width: 60px; }
  .controls .spacer { flex: 0 1 0px; min-width: 0; }
  .controls .chapters { flex: 0 1 180px; min-width: 70px; text-overflow: ellipsis; }
  .controls .vol { flex: 0 1 auto; min-width: 0; }
  .controls .vol input { width: clamp(44px, 7vw, 100px); min-width: 0; }
}
@media (min-width: 901px) and (max-width: 1180px) {
  .controls { gap: 6px; padding-left: 10px; padding-right: 10px; }
  .controls .seek { min-width: 40px; }
  .controls .chapters { min-width: 56px; }
  .controls .vol > span { display: none; }
  .controls .vol input { width: clamp(36px, 6vw, 100px); }
  .controls .chip { padding: 4px 9px; }
  .narmodes button { padding: 5px 8px; }
  .controls .ghost-btn { padding: 7px 10px; }
}

/* PATHS (plan section 20): the guided-path bar sits above the transport. */
.pathbar {
  display: flex; align-items: center; gap: 10px; width: 100%; flex: none;
  padding: 6px 16px; background: rgba(18,28,44,0.97);
  border-top: 1px solid rgba(47,169,255,0.35);
}
.pathbar .icon-btn { width: 30px; height: 30px; font-size: 18px; line-height: 1; }
.pathbar .icon-btn:disabled, .pathbar-next:disabled { opacity: 0.35; cursor: default; filter: none; }
.pathbar-label { color: #dbe7f7; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.pathbar-track { flex: 1; min-width: 40px; height: 4px; border-radius: 999px; background: rgba(120,160,220,0.2); overflow: hidden; }
.pathbar-fill { display: block; height: 100%; width: 0; background: linear-gradient(90deg,#2fa9ff,#1c6cff); transition: width 0.3s ease; }
.pathbar-next {
  border: none; cursor: pointer; border-radius: 999px; padding: 6px 14px; font-size: 12px; font-weight: 700;
  color: #fff; background: linear-gradient(135deg,#2fa9ff,#1c6cff); white-space: nowrap;
}
.pathbar-next.waiting { box-shadow: 0 0 0 3px rgba(47,169,255,0.35); animation: pulse 1.6s infinite; }

/* Plan section 26: Narrative View Modes. The stage and the Narrative Panel
   share one column: panel docked on the right (30%, 260-420px), or on top in
   a portrait viewport (30% of the height). Never an overlay: menus and
   buttons sit at the stage's bottom right. */
.stage-col { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: row; }
.stage-col.nar-top { flex-direction: column-reverse; }
.stage-col .stage-box { flex: 1; min-width: 0; min-height: 0; }
.nar-panel {
  position: relative; flex: none; display: flex; flex-direction: column;
  width: clamp(260px, 30%, 420px); min-height: 0;
  /* Plan section 24.7: the section may recolour the SURFACE (variables set
     by NarrativePanel._applyPanel); the header chrome keeps its own look. */
  background: var(--nar-bg, #0f141d); border-left: 1px solid rgba(120,160,220,0.16); color: var(--nar-fg, #d9e2ef);
  transition: background-color 0.3s ease, color 0.3s ease;
}
.nar-panel .nar-body { font-family: var(--nar-font, inherit); }
.nar-themed .nar-block { color: color-mix(in srgb, var(--nar-fg, #d9e2ef) 72%, transparent); }
.nar-themed .nar-block.active { color: var(--nar-fg, #f2f6fb); }
.nar-themed .nar-section { color: color-mix(in srgb, var(--nar-fg, #6f88a8) 60%, transparent); }
.nar-themed .nar-block::after { border-bottom-color: color-mix(in srgb, var(--nar-fg, #7a8fb0) 25%, transparent); }
.nar-themed .nar-block.active .nar-sent.speaking {
  background: color-mix(in srgb, var(--nar-fg, #2fa9ff) 16%, transparent);
  box-shadow: 0 2px 0 color-mix(in srgb, var(--nar-fg, #2fa9ff) 55%, transparent);
}
/* Side dock: the panel is as tall as the rendered stage (player.js sets
   --stage-h), centred beside it, so a letterboxed 16:9 stage and its panel
   read as one frame instead of a short stage next to a full-height column. */
.stage-col:not(.nar-top) .nar-panel { align-self: center; height: min(100%, var(--stage-h, 100%)); }
.stage-col.nar-top .nar-panel { width: 100%; height: 30%; border-left: none; border-bottom: 1px solid rgba(120,160,220,0.16); }
.nar-head {
  display: flex; align-items: center; gap: 8px; flex: none;
  padding: 6px 8px 6px 14px; border-bottom: 1px solid rgba(120,160,220,0.1);
}
.nar-title { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: #8a9bb2; }
.nar-ticker { display: none; flex: 1; min-width: 0; font-size: 13px; color: #d9e2ef; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nar-collapse {
  margin-left: auto; width: 28px; height: 28px; border-radius: 6px; cursor: pointer; flex: none;
  border: 1px solid rgba(120,160,220,0.25); background: transparent; color: #9fb0c6; font-size: 16px; line-height: 1;
}
.nar-collapse::before { content: "\203A"; }
.stage-col.nar-top .nar-collapse::before { content: "\2303"; font-size: 13px; }
.nar-collapse:hover { color: #fff; border-color: rgba(47,169,255,0.6); }
.nar-body { flex: 1; min-height: 0; overflow-y: auto; padding: 8px 18px; scrollbar-width: thin; outline: none; }
/* Trailing room so the last sentence can still scroll up into the comfort
   zone (inside the list: padding on the scroller would stop it shrinking). */
.nar-list { max-width: 36em; margin: 0 auto; padding-bottom: 30vh; }
.nar-section {
  margin: 18px 0 8px; font-size: 11px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: #6f88a8;
}
.nar-section.untitled { margin-top: 10px; }
.nar-block {
  position: relative; font-size: var(--nar-size, 16px); line-height: 1.55; white-space: pre-wrap; word-break: break-word;
  color: #aebbcc; padding: 2px 0 2px 12px; border-left: 3px solid transparent;
}
/* Semantic boundary between narratives: a centred half-width rule. */
.nar-block::after {
  content: ""; display: block; width: 50%; margin: 14px auto 12px;
  border-bottom: 1px solid rgba(120,160,220,0.22);
}
.nar-block.active { color: #f2f6fb; font-weight: 600; border-left-color: #2fa9ff; }
.nar-sent { border-radius: 3px; transition: background-color 0.35s ease, box-shadow 0.35s ease; }
.nar-block.active .nar-sent.speaking {
  background: rgba(47,169,255,0.16); box-shadow: 0 2px 0 rgba(47,169,255,0.55);
}
.nar-return {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
  border: none; border-radius: 999px; padding: 7px 16px; cursor: pointer; font-size: 12px; font-weight: 700;
  color: #fff; background: linear-gradient(135deg,#2fa9ff,#1c6cff); box-shadow: 0 4px 14px rgba(0,0,0,0.45);
}
.nar-return::before { content: "Following paused \00B7  "; font-weight: 500; opacity: 0.85; }
/* Collapsed: a slim edge tab (right) or a one-line ticker (top). */
.nar-panel.collapsed { width: 36px; }
.nar-panel.collapsed .nar-body, .nar-panel.collapsed .nar-return, .nar-panel.collapsed .nar-title { display: none; }
.nar-panel.collapsed .nar-head { flex-direction: column; padding: 8px 4px; border: none; }
.nar-panel.collapsed .nar-collapse::before { content: "\2039"; }
.stage-col.nar-top .nar-panel.collapsed { width: 100%; height: auto; }
.stage-col.nar-top .nar-panel.collapsed .nar-head { flex-direction: row; padding: 6px 8px 6px 14px; }
.stage-col.nar-top .nar-panel.collapsed .nar-ticker { display: block; }
.stage-col.nar-top .nar-panel.collapsed .nar-collapse::before { content: "\2304"; }
@media (prefers-reduced-motion: reduce) {
  .nar-sent { transition: none; }
  .nar-panel { transition: none; }
}

/* Transport: narrative mode segmented control + speed stepper. */
.narmodes { display: inline-flex; border: 1px solid rgba(120,160,220,0.3); border-radius: 8px; overflow: hidden; flex: none; }
.narmodes button {
  background: transparent; color: #9fb0c6; border: none; padding: 6px 10px; font-size: 12px; cursor: pointer; white-space: nowrap;
}
.narmodes button + button { border-left: 1px solid rgba(120,160,220,0.25); }
.narmodes button[aria-pressed="true"] { background: rgba(47,169,255,0.22); color: #fff; font-weight: 700; }
.ratectl { display: inline-flex; align-items: center; gap: 2px; flex: none; }
.rate-btn {
  width: 28px; height: 28px; border-radius: 50%; cursor: pointer; font-size: 16px; line-height: 1;
  border: 1px solid rgba(120,160,220,0.3); background: transparent; color: #cfd8e6;
}
.rate-btn:disabled { opacity: 0.35; cursor: default; }
.rate-val {
  min-width: 46px; padding: 4px 6px; border: none; background: transparent; cursor: pointer;
  color: #cfd8e6; font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.rate-val.changed { color: #5fe39a; }
.nar-choice {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px; width: 100%; flex: none;
  padding: 8px 16px; background: rgba(18,28,44,0.97); border-top: 1px solid rgba(47,169,255,0.35);
  font-size: 13px; color: #dbe7f7;
}
.nar-choice-q { margin-right: 4px; }
.nar-choice button {
  border: 1px solid rgba(47,169,255,0.5); background: rgba(47,169,255,0.12); color: #fff;
  border-radius: 999px; padding: 5px 14px; font-size: 12px; font-weight: 600; cursor: pointer;
}
.nar-choice button.nar-choice-x { margin-left: auto; border: none; background: transparent; color: #9fb0c6; font-size: 18px; padding: 0 6px; }

/* Small screens: stack the hero, tighten the transport bar. */
@media (max-width: 720px) {
  .hero { flex-direction: column; }
  .hero-img { width: 100%; }
  .controls { gap: 8px; padding: 8px 10px; }
  .controls .vol input { width: 70px; }
  .rail { width: 48px; gap: 10px; }
  .rail-chip, .rail-action { width: 34px; height: 34px; }
  .rail-action { padding: 7px; }
  .rail-glyph { width: 32px; height: 32px; }
  .narmodes button { padding: 5px 7px; font-size: 11px; }
  .nar-block { font-size: 15px; }
}

/* Plan section 36: inside an authorised website's iframe the host owns the
 * chrome - no portal bar (Back to events / Sign out); the player fills the
 * frame. */
body.embedded .topbar { display: none; }

/* U44-B vector capture: when the headless browser PRINTS the page (page
 * size = the stage), only the stage may exist - everything else hides and
 * the stage itself is pinned at the page origin by an inline style the
 * capturer applies after join. */
@media print {
  body.print-mode .topbar,
  body.print-mode #lobby,
  body.print-mode #controls,
  body.print-mode #railLeft,
  body.print-mode #railRight,
  body.print-mode #audioUnlockPill,
  body.print-mode #countdown,
  body.print-mode #overlayMsg {
    display: none !important;
  }
  body.print-mode {
    margin: 0;
    background: transparent;
  }
}

/* ------------------------------------------------------------ U44 print */
/* Headless frame capture (print=1): only the stage, nothing else.
   Sunil 2026-10-14: a video with `chrome=frame|full` keeps the top bar,
   rails and play bar (body.video-chrome). */
body.print-mode:not(.video-chrome) .topbar,
body.print-mode:not(.video-chrome) #controls,
body.print-mode:not(.video-chrome) #railLeft,
body.print-mode:not(.video-chrome) #railRight,
body.print-mode #audioUnlockPill,
body.print-mode #countdown,
body.print-mode #overlayMsg,
body.print-mode #narPanel,
body.print-mode #narChoice {
  display: none !important;
}
body.video-chrome #stageBox { background: var(--video-bands, #141414); }
body.video-chrome #infoSheet { display: none !important; }
/* The clock status pill reads "syncing" in a paused capture - never in a video. */
body.print-mode #syncStatus { display: none !important; }
/* Burned-in caption: bottom of the stage, readable on any picture. */
.video-caption {
  position: absolute; left: 6%; right: 6%; bottom: 4%; z-index: 90; pointer-events: none;
  text-align: center; font-size: clamp(14px, 3.6vh, 44px); line-height: 1.25; font-weight: 500;
  color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.9), 0 0 10px rgba(0,0,0,0.6);
}
.video-caption:not(.hidden) { display: block; }
.video-caption > span, .video-caption { white-space: pre-wrap; }
.video-caption { background: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,0)); }
.video-caption:not(:empty)::before { content: ""; }
.video-caption:not(:empty) { background: rgba(0,0,0,0.55); border-radius: 8px; padding: 0.35em 0.6em; display: inline-block; left: 50%; right: auto; transform: translateX(-50%); max-width: 88%; }

/* ---------------------------------------------------- plan section 28 video */
/* Video export capture (print=1&video=1): the stage column IS the output
   frame. Chromium's viewport equals the MP4 size, the rails are gone, the
   stage box fills the frame and letterboxes the stage (bands painted by the
   capturer in the stage background colour), and in "read" view the docked
   Narrative Panel stays inside the frame. */
body.video-mode #stageWrap { position: fixed; inset: 0; width: 100vw; height: 100vh; background: #000; }
body.video-mode #stageCol { width: 100%; height: 100%; }
body.video-mode #stageBox { background: var(--video-bands, #141414); }
body.video-mode #pathBar, body.video-mode #infoSheet { display: none !important; }
body.print-mode.print-read #narPanel { display: flex !important; }
body.print-mode.print-read #narPanel .nar-collapse, body.print-mode.print-read #narPanel .nar-return { display: none !important; }
