/* ---------------------------------------------------------------
   RTMP — "The Flyer on the Corkboard"
   Photocopied show-flyer world: paper, toner, one hazard-red spot.
   See /DESIGN.md for the full system.
   --------------------------------------------------------------- */

[hidden] {
  display: none !important;
}

:root {
  --paper: #f2ead9;
  --paper-raised: #faf4e6;
  --toner: #201c17;
  --toner-soft: #4a453d;
  --toner-faint: #6b6355;
  --rule-line: #d8cdb2;
  --hazard: #c62f1a;
  --hazard-deep: #8f2112;

  --font-display: 'Anton', 'Arial Narrow', sans-serif;
  --font-body: 'Courier Prime', 'Courier New', monospace;

  --shadow-pin: 3px 5px 0 rgba(32, 28, 23, 0.16);
  --shadow-lift: 5px 8px 0 rgba(32, 28, 23, 0.22);

  /* Player chrome is a deliberate always-dark exception (see DESIGN.md) —
     these are fixed regardless of [data-theme], unlike --paper/--toner
     above which intentionally flip per Room Theme. Never redefine these
     inside a [data-theme="..."] block; that's what broke contrast before:
     flyout text was reading --paper, which Cyberpunk/Midnight repoint to
     a near-black page-background color, turning it into dark-on-dark. */
  --player-ink: #f4ede2;
  --player-ink-soft: rgba(244, 237, 226, 0.68);
  --player-ink-faint: rgba(244, 237, 226, 0.4);
}

/* ---------------- Room Vibe Themes ---------------- */

[data-theme="cyberpunk"] {
  --paper: #0b0717;
  --paper-raised: #16102b;
  --toner: #e9d5ff;
  --toner-soft: #c084fc;
  --toner-faint: #7e22ce;
  --rule-line: #00f0ff;
  --hazard: #a855f7;
  --hazard-deep: #7e22ce;
}

[data-theme="midnight"] {
  --paper: #050505;
  --paper-raised: #121212;
  --toner: #f3f4f6;
  --toner-soft: #9ca3af;
  --toner-faint: #4b5563;
  --rule-line: #1f2937;
  --hazard: #38bdf8;
  --hazard-deep: #0284c7;
}

/* ---------------- Subtitle Customization Styles ---------------- */

/* These target the cue itself, not the container. The container holds the
   sub-* classes, but the text lives in a child element that declares its
   own colour and font-size (see .rtmp-player__captions div further down),
   and that declaration beat anything inherited from the parent — so
   picking Large or Yellow visibly did nothing. */
.rtmp-player__captions.sub-size-small .rtmp-player__cue { font-size: 0.9rem !important; }
.rtmp-player__captions.sub-size-normal .rtmp-player__cue { font-size: 1.25rem !important; }
.rtmp-player__captions.sub-size-large .rtmp-player__cue { font-size: 1.65rem !important; }
.rtmp-player__captions.sub-size-xlarge .rtmp-player__cue { font-size: 2.1rem !important; }

.rtmp-player__captions.sub-color-white .rtmp-player__cue { color: #ffffff !important; }
.rtmp-player__captions.sub-color-yellow .rtmp-player__cue { color: #ffe066 !important; }
.rtmp-player__captions.sub-color-cyan .rtmp-player__cue { color: #50e3c2 !important; }

.rtmp-player__captions.sub-bg-box .rtmp-player__cue {
  background: rgba(15, 12, 10, 0.85) !important;
  border-radius: 0;
  padding: 0.2rem 0.6rem;
}
.rtmp-player__captions.sub-bg-shadow .rtmp-player__cue {
  background: transparent !important;
  text-shadow: 2px 2px 4px #000000, -2px -2px 4px #000000;
}
.rtmp-player__captions.sub-bg-soft .rtmp-player__cue {
  background: rgba(15, 12, 10, 0.45) !important;
  border-radius: 0;
  padding: 0.2rem 0.6rem;
}

.rtmp-player__flyout-title {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--player-ink-faint);
  margin-top: 0.35rem;
  margin-bottom: 0.15rem;
}

.rtmp-player__flyout-row {
  display: flex;
  gap: 0.25rem;
  margin-bottom: 0.35rem;
}

.rtmp-player__sync-badge {
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  background: var(--hazard);
  color: var(--paper-raised);
  padding: 0.15rem 0.5rem;
  border-radius: 2px;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-left: 0.6rem;
  text-transform: uppercase;
}

.rtmp-player__sync-badge::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  background: #fff;
  border-radius: 50%;
  animation: pulse-dot 1.5s infinite;
}

@keyframes pulse-dot {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(0.8); }
}

.rtmp-player__sync-overlay {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(32, 28, 23, 0.75);
  z-index: 25;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(4px);
}

.rtmp-player__sync-overlay[hidden] {
  display: none !important;
}

.rtmp-player__sync-join-btn {
  font-family: var(--font-body);
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  background: var(--hazard);
  color: var(--paper-raised);
  border: 2px solid var(--toner);
  padding: 1rem 1.8rem;
  cursor: pointer;
  box-shadow: var(--shadow-lift);
  text-transform: uppercase;
  transition: transform 0.1s ease;
}

.rtmp-player__sync-join-btn:hover {
  background: var(--hazard-deep);
  transform: translate(2px, 2px);
}

/* ---- Waiting for everyone ----------------------------------------
   Shown to the whole room while the start is held for someone whose
   player hasn't buffered. Everyone sees the same card, so nobody is
   left wondering whether it's their own connection that's broken.
   Player chrome, so it uses the fixed --player-ink tokens rather than
   --toner, which the room themes repoint. */
.rtmp-player__hold {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(18, 16, 13, 0.82);
  z-index: 26;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(3px);
  padding: 1rem;
}

.rtmp-player__hold[hidden] { display: none !important; }

.rtmp-player__hold-card {
  position: relative;
  background: #1c1915;
  border: 1px solid rgba(244, 237, 226, 0.22);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  padding: 1.6rem 2rem 1.4rem;
  text-align: center;
  max-width: 22rem;
  transform: rotate(-0.6deg);
}

.rtmp-player__hold-stamp {
  position: absolute;
  top: -0.7rem;
  left: 1.2rem;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--hazard);
  background: #1c1915;
  border: 1px solid var(--hazard);
  padding: 0.15rem 0.5rem;
  transform: rotate(-3deg);
}

.rtmp-player__hold-line {
  font-family: var(--font-body);
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--player-ink);
  margin: 0.2rem 0 0.9rem;
}

.rtmp-player__hold-dots {
  display: flex;
  justify-content: center;
  gap: 0.4rem;
}

.rtmp-player__hold-dots span {
  width: 0.42rem;
  height: 0.42rem;
  background: var(--player-ink-soft);
  border-radius: 50%;
  animation: rtmp-hold-pulse 1.2s ease-in-out infinite;
}
.rtmp-player__hold-dots span:nth-child(2) { animation-delay: 0.18s; }
.rtmp-player__hold-dots span:nth-child(3) { animation-delay: 0.36s; }

@keyframes rtmp-hold-pulse {
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-0.18rem); }
}

/* Someone's connection is not coming back and the room wants to start.
   Quiet on purpose: leaving a person behind is the exception, not the
   button you reach for first. */
.rtmp-player__hold-btn {
  margin-top: 1.1rem;
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--player-ink-soft);
  background: transparent;
  border: 1px dashed var(--player-ink-faint);
  padding: 0.45rem 0.9rem;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.rtmp-player__hold-btn:hover {
  color: var(--player-ink);
  border-color: var(--player-ink-soft);
}

.rtmp-player__hold-btn[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .rtmp-player__hold-dots span { animation: none; opacity: 0.7; }
}

/* Watch Party Two-Column Layout & Chat Sidebar */
.watch-party-grid {
  display: grid;
  /* minmax(0, 1fr) rather than 1fr: a grid track sizes to min-content by
     default, so one unbreakable child — a long title, a row of buttons —
     drags the column past the viewport and scrolls the whole page
     sideways. The desktop rule below already did this; the single-column
     case, which is every phone, did not. */
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem;
  margin-top: 1rem;
}

.watch-party-main {
  min-width: 0;
}

@media (min-width: 960px) {
  .watch-party-grid {
    grid-template-columns: minmax(0, 1fr) 360px;
    align-items: stretch;
    gap: 1.5rem;
  }
}

.watch-party-sidebar {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 520px;
  max-height: 720px;
  padding: 0;
  overflow: hidden;
  background: var(--paper-raised);
  border: 1px solid var(--rule-line);
  box-shadow: var(--shadow-pin);
  border-radius: 0;
}

.sidebar-tabs {
  display: flex;
  border-bottom: 2px solid var(--toner);
  background: var(--paper-card);
}

.sidebar-tab {
  flex: 1;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.88rem;
  letter-spacing: 0.05em;
  padding: 0.75rem 0.5rem;
  background: transparent;
  border: none;
  border-right: 1px solid var(--toner-faint);
  color: var(--toner-soft);
  cursor: pointer;
  text-transform: uppercase;
}

.sidebar-tab:last-child {
  border-right: none;
}

.sidebar-tab.is-active {
  background: var(--paper-raised);
  color: var(--hazard);
  border-bottom: 3px solid var(--hazard);
}

.sidebar-panel {
  display: flex;
  flex-direction: column;
  flex: 1;
  height: calc(100% - 44px);
  overflow: hidden;
}

.chat-messages {
  flex: 1;
  padding: 0.8rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  font-family: var(--font-body);
}

.chat-msg {
  background: var(--paper-card);
  border: 1px solid var(--toner-faint);
  padding: 0.45rem 0.65rem;
  border-radius: 2px;
  font-size: 0.88rem;
}

.chat-msg-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.2rem;
}

.chat-sender {
  font-weight: 700;
  font-size: 0.8rem;
  color: var(--toner);
}

.chat-sender.is-host {
  color: var(--hazard);
}

.chat-time {
  font-size: 0.72rem;
  color: var(--toner-faint);
}

.chat-text {
  word-break: break-word;
  color: var(--toner);
  line-height: 1.35;
}

.chat-system-msg {
  font-size: 0.78rem;
  font-style: italic;
  color: var(--toner-faint);
  text-align: center;
  margin: 0.4rem 0;
}

.chat-form {
  display: flex;
  padding: 0.6rem;
  border-top: 2px solid var(--toner);
  background: var(--paper-card);
  gap: 0.4rem;
}

.chat-form input {
  flex: 1;
  font-family: var(--font-body);
  font-size: 0.88rem;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--toner);
  background: var(--paper-raised);
  color: var(--toner);
}

.participant-list {
  padding: 0.8rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  overflow-y: auto;
}

.participant-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0.7rem;
  background: var(--paper-card);
  border: 1px solid var(--toner-faint);
  border-radius: 2px;
}

.participant-name {
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--toner);
}

.participant-joined {
  font-size: 0.75rem;
  color: var(--toner-faint);
  margin-left: auto;
  margin-right: 0.5rem;
}

.participant-badge {
  font-size: 0.7rem;
  font-weight: 700;
  padding: 0.1rem 0.4rem;
  border-radius: 2px;
  text-transform: uppercase;
  background: var(--toner-faint);
  color: var(--paper-raised);
}

.participant-badge.host {
  background: var(--hazard);
}

/* Name Modal */
.name-modal {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(32, 28, 23, 0.85);
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(6px);
  padding: 1rem;
}

.name-modal[hidden] {
  display: none !important;
}

.name-modal-box {
  max-width: 420px;
  width: 100%;
  background: var(--paper-raised);
  text-align: left;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--toner-soft);
  background-color: var(--paper);
  background-image:
    radial-gradient(circle, rgba(32,28,23,0.05) 1px, transparent 1.4px);
  background-size: 14px 14px;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--toner);
  margin: 0 0 0.5rem;
  letter-spacing: 0.01em;
}

h1 { font-size: clamp(2.6rem, 7vw, 5.2rem); line-height: 0.92; }
h2, h3 { font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1; }

/* Most pages had no <h1> at all — their title was an <h2>, because Display
   size would shout over a page that isn't the hero. This keeps the element
   correct for screen readers and the document outline while holding Title
   scale, so "one display shout per screen" still holds. */
h1.page-title { font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1; }

p {
  color: var(--toner-soft);
  max-width: 68ch;
}

a { color: var(--toner); text-decoration-thickness: 1.5px; }
a:hover { color: var(--hazard); }

.container { max-width: 1400px; margin: 0 auto; padding: 0 1.5rem; }

/* ---------------- Header / torn tab nav ---------------- */

.site-header {
  padding-top: 1.5rem;
}

.tab-strip {
  display: flex;
  align-items: flex-end;
  gap: 0.4rem;
  list-style: none;
  margin: 0 0 0 0;
  padding: 0;
  flex-wrap: wrap;
}

.brand-tab {
  font-family: var(--font-display);
  font-size: 1.4rem;
  color: var(--toner);
  text-decoration: none;
  padding: 0.7rem 1.1rem 0.85rem;
  background: var(--paper-raised);
  border: 1px solid var(--rule-line);
  border-bottom: none;
  box-shadow: var(--shadow-pin);
  transform: rotate(-1deg);
  margin-right: 0.75rem;
}
.brand-tab:hover { color: var(--toner); }

.nav-tabs {
  display: flex;
  gap: 0.35rem;
  list-style: none;
  margin: 0;
  padding: 0;
  flex-wrap: wrap;
  align-items: flex-end;
}

.nav-tab {
  position: relative;
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--toner-soft);
  text-decoration: none;
  padding: 0.6rem 0.9rem 0.7rem;
  background: var(--paper-raised);
  border: 1px dashed var(--rule-line);
  border-bottom: none;
}
.nav-tab:hover { color: var(--hazard); border-color: var(--toner-faint); }
.nav-tab.is-active {
  color: var(--paper);
  background: var(--toner);
  border-color: var(--toner);
  transform: translateY(3px);
}

.nav-user {
  font-size: 0.78rem;
  color: var(--toner-faint);
  padding: 0.6rem 0.4rem;
}

.tab-strip-form { display: inline; margin: 0; }

/* ---------------- Buttons ---------------- */

.btn {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-radius: 0;
  border: 1px solid var(--toner);
  padding: 0.8rem 1.5rem;
  position: relative;
  cursor: pointer;
  transition: transform 0.12s ease, background 0.12s ease, color 0.12s ease;
}

.btn-tab {
  background: var(--toner);
  color: var(--paper);
  border-color: var(--toner);
  box-shadow: var(--shadow-pin);
  border-left: 3px dashed var(--paper);
}
.btn-tab:hover {
  background: var(--hazard);
  border-color: var(--hazard-deep);
  color: var(--paper-raised);
  box-shadow: var(--shadow-lift);
  transform: translate(-1px, -2px);
}

.btn-outline {
  background: transparent;
  color: var(--toner);
  border-color: var(--toner);
}
.btn-outline:hover {
  background: var(--toner);
  color: var(--paper);
}

.btn-primary { background: var(--toner); color: var(--paper); border-color: var(--toner); }
.btn-primary:hover { background: var(--hazard); border-color: var(--hazard-deep); }

.btn-block { width: 100%; text-align: center; display: block; }

/* ---------------- Page shell ---------------- */

.page-shell {
  flex: 1;
  padding: 2.5rem 0 4rem;
}

/* ---------------- Flyer cards ---------------- */

.flyer {
  background: var(--paper-raised);
  border: 1px solid var(--rule-line);
  filter: drop-shadow(3px 5px 0 rgba(32, 28, 23, 0.16));
  padding: 2.5rem;
  position: relative;
  transform: rotate(-0.6deg);
}
.flyer + .flyer { margin-top: 1.75rem; }
.flyer.tilt-r { transform: rotate(0.8deg); }
.flyer.tilt-flat { transform: rotate(0deg); }

.flyer::before {
  content: "";
  position: absolute;
  top: -7px;
  left: 50%;
  transform: translateX(-50%);
  width: 30px;
  height: 10px;
  border-left: 2px dashed var(--toner-faint);
  border-right: 2px dashed var(--toner-faint);
}

.flyer--torn {
  clip-path: polygon(
    0% 3%, 4% 0%, 9% 2%, 15% 0%, 21% 2.5%, 27% 0%, 33% 2%, 39% 0.5%, 45% 2.5%,
    51% 0%, 57% 2%, 63% 0.5%, 69% 2.5%, 75% 0%, 81% 2%, 87% 0.5%, 93% 2.5%, 100% 0%,
    100% 100%, 0% 100%
  );
  padding-top: 3rem;
}

/* ---------------- Hero ---------------- */

.hero { padding: 1rem 0 2.5rem; }

.hero-flyer {
  max-width: 620px;
  margin: 0 auto;
  text-align: center;
}

.hero-flyer .stamp {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--hazard);
  border: 2px solid var(--hazard);
  padding: 0.25rem 0.6rem;
  transform: rotate(-6deg);
  margin-bottom: 1.25rem;
}

.hero-flyer h1 { margin-bottom: 1rem; }

.hero-flyer .lead {
  margin: 0 auto 2rem;
  font-size: 1.02rem;
  color: var(--toner-soft);
}

/* Tear-off tab row along the bottom of the hero flyer */
.tear-tabs {
  display: flex;
  justify-content: center;
  border-top: 1px dashed var(--toner-faint);
  margin-top: 2rem;
  padding-top: 0;
}

.tear-tab {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--toner);
  text-decoration: none;
  border-left: 1px dashed var(--toner-faint);
  padding: 0.9rem 0.6rem;
  transition: background 0.12s ease, color 0.12s ease;
}
.tear-tab:first-child { border-left: none; }
.tear-tab:hover { background: var(--hazard); color: var(--paper-raised); }

/* ---------------- How it works (threaded steps) ---------------- */

.thread {
  margin-top: 3.5rem;
  position: relative;
  padding-top: 1.5rem;
  border-top: 1px dashed var(--rule-line);
}

.thread-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}

.thread-step {
  text-align: left;
}

.thread-step .num {
  font-family: var(--font-display);
  font-size: 1.6rem;
  color: var(--hazard);
  display: block;
  line-height: 1;
  margin-bottom: 0.35rem;
}

.thread-step .label {
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--toner);
  display: block;
  margin-bottom: 0.3rem;
}

.thread-step p { font-size: 0.9rem; margin: 0; }

/* ---------------- Page header ---------------- */

.page-title { margin-bottom: 1.75rem; }
.page-title p { margin-top: 0.4rem; }

/* ---------------- Forms ---------------- */

.field { margin-bottom: 1.5rem; }

.field-label {
  display: block;
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--toner);
  margin-bottom: 0.5rem;
}

input[type="text"],
input[type="password"],
input[type="file"] {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--toner);
  background: var(--paper);
  border: 1px solid var(--rule-line);
  border-radius: 2px;
  padding: 0.75rem 0.9rem;
}
input[type="text"]:focus,
input[type="password"]:focus {
  outline: none;
  border-color: var(--toner);
}
input::placeholder { color: var(--toner-faint); }

.field-hint {
  color: var(--toner-faint);
  font-size: 0.8rem;
  margin-top: 0.4rem;
}

.upload-progress { margin-top: 1rem; }
.upload-progress-track {
  height: 8px;
  background: var(--paper);
  border: 1px solid var(--rule-line);
}
.upload-progress-fill {
  height: 100%;
  width: 100%;
  background: var(--hazard);
  /* Scaled, not resized: this updates on every uploaded chunk, and animating
     width relayouts the page each time. transform stays on the compositor. */
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 120ms ease;
}
.upload-progress-label {
  margin-top: 0.4rem;
  font-size: 0.78rem;
  color: var(--toner-faint);
}

/* Pre-upload codec warning — the one moment where stopping the user is
   the helpful act, so it takes the hazard stamp and the page's one red. */
.codec-warning {
  margin: 1rem 0;
  padding: 1.25rem;
  background: var(--paper-raised);
  border: 2px solid var(--hazard);
  box-shadow: var(--shadow-pin);
}
.codec-warning-title {
  font-family: var(--font-display);
  font-size: 1.35rem;
  color: var(--hazard);
  letter-spacing: 0.01em;
  margin-bottom: 0.5rem;
}
.codec-warning-body {
  font-family: var(--font-body);
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--toner-soft);
  margin: 0 0 1rem;
}
.codec-warning-label {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--toner-faint);
  margin-bottom: 0.35rem;
}
/* Carries a filename, so it must not be uppercased the way the
   eyebrow labels above it are. */
.codec-warning-hint {
  font-family: var(--font-body);
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--toner-faint);
}
.codec-warning-cmd {
  font-family: var(--font-body);
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--paper);
  background: var(--toner);
  padding: 0.75rem 0.9rem;
  margin: 0 0 0.9rem;
  overflow-x: auto;
  white-space: pre;
}
.codec-warning-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1rem;
}

/* ---------------- Alerts ---------------- */

.notice {
  border: 1px dashed var(--rule-line);
  background: var(--paper-raised);
  color: var(--toner-soft);
  font-size: 0.9rem;
  padding: 0.9rem 1.1rem;
  margin-bottom: 1.25rem;
}
.notice--error {
  border-color: var(--hazard);
  color: var(--hazard-deep);
}

/* ---------------- Typed memo (about/contact) ---------------- */

.memo-line {
  display: flex;
  gap: 1rem;
  padding: 0.7rem 0;
  border-bottom: 1px dashed var(--rule-line);
}
.memo-line:last-child { border-bottom: none; }
.memo-line .k {
  flex: 0 0 110px;
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--toner-faint);
}
.memo-line .v {
  color: var(--toner);
  /* A flex child will not shrink below its content by default, so a long
     unbreakable address (an email, a URL) pushed the page 72px wider than a
     320px phone and gave every page a horizontal scroll. */
  min-width: 0;
  overflow-wrap: anywhere;
}

.memo-line .v a {
  color: var(--hazard);
  text-decoration: underline;
}

/* Below this the label column and the value cannot share a line honestly. */
@media (max-width: 460px) {
  .memo-line { flex-direction: column; gap: 0.2rem; }
  .memo-line .k { flex: none; }
}

/* ---------------- Ticket stub (session/player page) ---------------- */

.ticket {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1.2rem;
  background: var(--paper-raised);
  border: 1px solid var(--rule-line);
  box-shadow: var(--shadow-pin);
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.5rem;
  position: relative;
  transform: rotate(-0.4deg);
}

.ticket-stamp {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--hazard);
  border: 2px solid var(--hazard);
  padding: 0.4rem 0.6rem;
  transform: rotate(-8deg);
  flex-shrink: 0;
}

.ticket-info {
  flex: 1;
  min-width: 200px;
}
.ticket-info .session-name {
  margin: 0 0 0.25rem 0;
  line-height: 1.2;
}
.ticket-info .session-name a { color: inherit; }
.ticket-info .meta {
  font-size: 0.8rem;
  color: var(--toner-faint);
  margin: 0;
  line-height: 1.3;
}

.ticket-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-left: auto;
  flex-shrink: 0;
}

/* Where the room stopped, on the row for the room. Reads as a hand stamp
   on the ticket rather than another line of metadata, because it is the
   one thing here that answers "can we just carry on?". */
.resume-line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.5rem 0 0;
}
.resume-mark {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--hazard);
  border: 1px dashed var(--hazard);
  padding: 0.2rem 0.5rem;
  transform: rotate(-1.2deg);
}

.btn-sm { padding: 0.5rem 0.9rem; font-size: 0.7rem; }

.btn-danger { border-color: var(--hazard); color: var(--hazard); }
.btn-danger:hover { background: var(--hazard); color: var(--paper); }

.ticket--library { align-items: flex-start; }

.subtitle-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.75rem 0 0;
  padding: 0;
}
.subtitle-chip {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--paper);
  border: 1px solid var(--rule-line);
  padding: 0.3rem 0.3rem 0.3rem 0.7rem;
  font-size: 0.78rem;
  color: var(--toner-soft);
}
.subtitle-chip form { margin: 0; }
.subtitle-chip-remove {
  background: none;
  border: none;
  color: var(--toner-faint);
  font-size: 1rem;
  line-height: 1;
  padding: 0.15rem 0.4rem;
  cursor: pointer;
}
.subtitle-chip-remove:hover { color: var(--hazard); }

.subtitle-add-form {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
  flex-wrap: wrap;
}
.subtitle-add-form input[type="file"] {
  max-width: 130px;
  font-size: 0.7rem;
}
.subtitle-add-form input[type="text"] {
  width: 140px;
  font-size: 0.78rem;
  padding: 0.5rem 0.6rem;
}

@media (max-width: 768px) {
  .ticket-actions { flex-wrap: wrap; width: 100%; }
  .subtitle-add-form { flex-wrap: wrap; }
}

.player-frame {
  background: var(--toner);
  padding: 0.5rem;
  border: 1px solid var(--toner);
}

/* ---------------- Custom Player ---------------- */
/* The one place this system goes dark: a projector beam in a paper world.
   See DESIGN.md "Player" component. */

.rtmp-player {
  position: relative;
  overflow: hidden;
  background: #000;
  outline: none;
  -webkit-user-select: none;
  user-select: none;
}

.rtmp-player video {
  display: block;
  width: 100%;
  max-height: 78vh;
  cursor: pointer;
}

.rtmp-player video::cue {
  font-family: var(--font-body);
  font-size: 1.05rem;
  background: rgba(0,0,0,0.65);
  color: #fff;
  padding: 0.1em 0.35em;
}

.rtmp-player.is-fullscreen,
.rtmp-player.is-fullscreen video {
  width: 100%;
  height: 100%;
  max-height: none;
}

.rtmp-player.is-fullscreen { display: flex; align-items: center; }

.rtmp-player--audio {
  padding: 3rem 1.5rem 1.5rem;
  background:
    radial-gradient(circle at 50% 35%, rgba(198,47,26,0.14), transparent 60%),
    var(--toner);
  text-align: center;
}

.rtmp-player--audio::before {
  content: 'Audio Session';
  display: block;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper);
  opacity: 0.55;
  margin-bottom: 1.25rem;
}

.rtmp-player--audio audio { display: none; }

.rtmp-player:not(.is-playing) video { cursor: pointer; }
.rtmp-player.is-playing:not(.is-active) video { cursor: none; }

/* Idle-fade overlay (bottom scrim, always faintly present for legibility) */
.rtmp-player__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0,0,0,0.75), transparent 55%);
  opacity: 0;
  transition: opacity 260ms cubic-bezier(0.4,0,0.2,1);
  pointer-events: none;
}
.rtmp-player.is-active .rtmp-player__overlay,
.rtmp-player--audio .rtmp-player__overlay { opacity: 1; }

/* Top-left title, fades with the rest of the chrome */
.rtmp-player__title {
  position: absolute;
  top: 0; left: 0; right: 0;
  padding: 1.5rem 2rem;
  background: linear-gradient(to bottom, rgba(0,0,0,0.6), transparent);
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 220ms cubic-bezier(0.4,0,0.2,1), transform 220ms cubic-bezier(0.4,0,0.2,1);
  pointer-events: none;
}
.rtmp-player.is-active .rtmp-player__title { opacity: 1; transform: translateY(0); }
.rtmp-player__title-name {
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 2.4vw, 1.6rem);
  color: var(--player-ink) !important;
  letter-spacing: 0.01em;
}

/* Custom-rendered captions — deliberately not the native <track> box.
   The overlay scrim and control bar sit in front of the video in normal
   DOM stacking and would otherwise cover it. z-index puts this above
   both regardless of active/idle state. */
.rtmp-player__captions {
  position: absolute;
  left: 0; right: 0;
  bottom: 6rem;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0 2rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 100ms ease;
}
.rtmp-player__captions.is-visible { opacity: 1; }
.rtmp-player__captions div {
  background: rgba(0,0,0,0.72);
  color: #fff;
  font-family: var(--font-body);
  font-size: 1.05rem;
  line-height: 1.35;
  text-align: center;
  padding: 0.15em 0.5em;
  max-width: 85%;
}

/* Center play/pause — our hazard-red on Netflix's clean circular scrim */
.rtmp-player__center-play {
  position: absolute;
  top: 50%; left: 50%;
  width: 72px; height: 72px;
  transform: translate(-50%, -50%) scale(0.9);
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,0.45);
  color: var(--player-ink) !important;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: opacity 200ms ease, transform 200ms cubic-bezier(0.4,0,0.2,1), background 150ms ease;
  opacity: 0;
  pointer-events: none;
}
.rtmp-player__center-play svg { width: 32px; height: 32px; color: var(--hazard); margin-left: 3px; }
.rtmp-player__center-play svg path { fill: var(--hazard); }
.rtmp-player.is-active:not(.is-playing) .rtmp-player__center-play,
.rtmp-player:not(.is-playing) .rtmp-player__center-play {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
}
.rtmp-player__center-play:hover { background: rgba(0,0,0,0.6); transform: translate(-50%, -50%) scale(1.06); }
.rtmp-player.is-buffering .rtmp-player__center-play { opacity: 0; pointer-events: none; }

/* Buffering spinner */
.rtmp-player__spinner {
  position: absolute;
  top: 50%; left: 50%;
  width: 44px; height: 44px;
  margin: -22px 0 0 -22px;
  border: 3px solid rgba(242,234,217,0.25);
  border-top-color: var(--hazard);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  animation: rtmp-spin 850ms linear infinite;
}
.rtmp-player.is-buffering .rtmp-player__spinner { opacity: 1; }
@keyframes rtmp-spin { to { transform: rotate(360deg); } }

/* On-screen confirmation flash for keyboard/click actions (play, ±10s,
   volume, mute) — center icon in a soft circle, with a level meter for
   volume changes. Silent-succeeding shortcuts read as broken; this is
   the fix. */
.rtmp-player__flash {
  position: absolute;
  top: 50%; left: 50%;
  width: 86px; height: 86px;
  transform: translate(-50%, -50%) scale(0.85);
  border-radius: 50%;
  background: rgba(0,0,0,0.55);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms ease, transform 180ms ease;
  z-index: 3;
}
.rtmp-player__flash.is-flashing { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.rtmp-player__flash-icon { width: 34px; height: 34px; color: var(--hazard); }
.rtmp-player__flash-icon svg { width: 100%; height: 100%; }
.rtmp-player__flash-meter {
  display: none;
  width: 44px; height: 3px;
  background: rgba(242,234,217,0.3);
  border-radius: 2px;
  overflow: hidden;
}
.rtmp-player__flash.has-meter .rtmp-player__flash-meter { display: block; }
.rtmp-player__flash-meter-fill { height: 100%; width: 0%; background: var(--hazard); }

/* Hover scrub-thumbnail preview (real decoded frame, drawn to canvas) */
.rtmp-player__preview {
  position: absolute;
  bottom: 4.75rem;
  left: 0;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 120ms ease;
  pointer-events: none;
  z-index: 2;
}
.rtmp-player__preview.is-visible { opacity: 1; }
.rtmp-player__preview-frame {
  width: 160px; height: 90px;
  background: #000;
  border: 2px solid var(--player-ink);
  box-shadow: 0 4px 0 rgba(0,0,0,0.35);
  overflow: hidden;
}
.rtmp-player__preview-canvas { width: 100%; height: 100%; display: block; }
.rtmp-player__preview-time {
  text-align: center;
  margin-top: 0.35rem;
  font-family: var(--font-body);
  font-size: 0.72rem;
  color: var(--player-ink) !important;
  background: rgba(0,0,0,0.7);
  padding: 0.1rem 0.4rem;
  display: inline-block;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}

/* Control bar */
.rtmp-player__bar {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 2.25rem 0 0.85rem;
  background: linear-gradient(to top, rgba(0,0,0,0.88), rgba(0,0,0,0.6) 65%, transparent);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 220ms cubic-bezier(0.4,0,0.2,1), transform 220ms cubic-bezier(0.4,0,0.2,1);
  pointer-events: none;
}
.rtmp-player.is-active .rtmp-player__bar,
.rtmp-player--audio .rtmp-player__bar,
.rtmp-player.is-scrubbing .rtmp-player__bar {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

/* Generous invisible hit area around a thin visual line — the old bar had
   no hit area beyond the 4px line itself, which is why clicks missed. */
.rtmp-player__scrub {
  position: relative;
  height: 18px;
  margin: 0 1.5rem 0.35rem;
  display: flex;
  align-items: center;
  cursor: pointer;
}
.rtmp-player__scrub-track {
  position: relative;
  width: 100%;
  height: 3px;
  border-radius: 2px;
  background: rgba(255,255,255,0.28);
  transition: height 120ms ease;
  overflow: visible;
}
.rtmp-player__scrub:hover .rtmp-player__scrub-track,
.rtmp-player.is-scrubbing .rtmp-player__scrub-track { height: 5px; }

.rtmp-player__scrub-buffered,
.rtmp-player__scrub-played {
  position: absolute; top: 0; left: 0; bottom: 0;
  width: 0%;
  border-radius: 2px;
}
.rtmp-player__scrub-buffered { background: rgba(255,255,255,0.35); }
.rtmp-player__scrub-played { background: var(--hazard); }

.rtmp-player__scrub-thumb {
  position: absolute;
  top: 50%; left: 0%;
  width: 13px; height: 13px;
  background: var(--hazard);
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0,0,0,0.5);
  transform: translate(-50%, -50%) scale(0);
  transition: transform 120ms ease;
}
.rtmp-player__scrub:hover .rtmp-player__scrub-thumb,
.rtmp-player.is-scrubbing .rtmp-player__scrub-thumb { transform: translate(-50%, -50%) scale(1); }

.rtmp-player__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 0 1.25rem;
  width: 100%;
}
.rtmp-player__cluster { display: flex; align-items: center; gap: 0.9rem; flex-shrink: 0; }
.rtmp-player__cluster--left { flex: 1; min-width: 0; }
.rtmp-player__cluster--right { flex-shrink: 0; }

.rtmp-player__btn {
  background: none;
  border: none;
  padding: 0;
  width: 32px; height: 32px;
  color: var(--player-ink) !important;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: transform 140ms cubic-bezier(0.4,0,0.2,1), opacity 140ms ease, color 140ms ease;
  opacity: 0.92;
  flex-shrink: 0;
}
.rtmp-player__btn svg { width: 22px; height: 22px; display: block; }
.rtmp-player__btn:hover { opacity: 1; transform: translateY(-1px); color: var(--hazard) !important; }
.rtmp-player__play svg { width: 25px; height: 25px; }

.rtmp-player__volume { display: flex; align-items: center; gap: 0.35rem; flex-shrink: 0; }
.rtmp-player__vol-slider {
  -webkit-appearance: none;
  appearance: none;
  width: 0;
  height: 3px;
  background: rgba(242,234,217,0.3);
  outline: none;
  opacity: 0;
  transition: width 180ms cubic-bezier(0.4,0,0.2,1), opacity 180ms ease;
}
.rtmp-player__volume:hover .rtmp-player__vol-slider,
.rtmp-player__vol-slider:focus { width: 64px; opacity: 1; }
.rtmp-player__vol-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--player-ink);
  cursor: pointer;
}
.rtmp-player__vol-slider::-moz-range-thumb {
  width: 10px; height: 10px; border: none; border-radius: 50%;
  background: var(--player-ink); cursor: pointer;
}

.rtmp-player__time {
  font-family: var(--font-body);
  font-size: 0.84rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--player-ink) !important;
  opacity: 0.92;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  white-space: nowrap;
  flex-shrink: 0;
  margin-left: 0.6rem;
}
.rtmp-player__time-sep { opacity: 0.5; }

/* Speed / subtitle flyout menus */
.rtmp-player__menu { position: relative; }
.rtmp-player__flyout {
  position: absolute;
  bottom: calc(100% + 0.85rem);
  right: -0.5rem;
  min-width: 108px;
  background: rgba(20,18,15,0.95);
  border: 1px solid rgba(242,234,217,0.18);
  padding: 0.35rem 0;
  display: none;
  flex-direction: column;
  /* JS clamps max-height to the room above the bar (fitFlyoutToPlayer), since
     the player clips overflow and a tall menu would lose its top sections off
     the edge. Scrolling here is what makes that clamp usable. */
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(244,237,226,0.35) transparent;
}
.rtmp-player__flyout::-webkit-scrollbar { width: 6px; }
.rtmp-player__flyout::-webkit-scrollbar-track { background: transparent; }
.rtmp-player__flyout::-webkit-scrollbar-thumb {
  background: rgba(244,237,226,0.35);
  border-radius: 0;
}
.rtmp-player__menu.is-open .rtmp-player__flyout { display: flex; }
.rtmp-player__flyout-item {
  background: none;
  border: none;
  color: var(--player-ink);
  font-family: var(--font-body);
  font-size: 0.82rem;
  text-align: left;
  padding: 0.45rem 0.9rem;
  cursor: pointer;
  opacity: 0.75;
}
.rtmp-player__flyout-item:hover { opacity: 1; background: rgba(244,237,226,0.08); }
.rtmp-player__flyout-item.is-selected { opacity: 1; color: var(--hazard); }

/* Consolidated Settings flyout — Room Theme / Speed / Quality / Audio /
   Subtitle Style used to each be their own top-level icon (8 icons
   crammed into the right cluster). They're sub-sections of one gear menu
   now, the way Netflix/YouTube fold everything but the frequent actions
   (captions, fullscreen) behind a single settings affordance. */
.rtmp-player__flyout--settings {
  width: 236px;
  max-height: min(70vh, 420px);
  overflow-y: auto;
}
.rtmp-player__settings-section { padding: 0.3rem 0; }
.rtmp-player__settings-section .rtmp-player__flyout-title { margin-left: 0.9rem; }
.rtmp-player__settings-divider {
  height: 1px;
  margin: 0.3rem 0.9rem;
  background: rgba(244,237,226,0.12);
}
.rtmp-player__flyout-row { flex-wrap: wrap; }
.rtmp-player__flyout-row .rtmp-player__flyout-item { padding: 0.4rem 0.6rem; }

@media (max-width: 560px) {
  .rtmp-player__center-play { width: 58px; height: 58px; }
  .rtmp-player__center-play svg { width: 26px; height: 26px; }
  .rtmp-player__title { padding: 1rem 1.1rem; }
  .rtmp-player__bar { padding: 1.5rem 0 0.6rem; }
  .rtmp-player__scrub { margin: 0 1rem 0.3rem; }
  .rtmp-player__row { padding: 0 1rem; gap: 0.4rem; }
  .rtmp-player__cluster { gap: 0.65rem; }
  .rtmp-player__time { font-size: 0.68rem; }
  .rtmp-player__preview { display: none; }
}

/* ---------------- Footer ---------------- */

.site-footer {
  border-top: 1px dashed var(--rule-line);
  padding: 2rem 0;
  text-align: center;
}
.footer-tab {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  color: var(--toner-faint);
}
.footer-tab strong {
  font-family: var(--font-display);
  color: var(--toner);
  font-weight: 400;
  letter-spacing: 0.01em;
  margin-right: 0.4rem;
}

/* ---------------- Responsive ---------------- */

@media (max-width: 768px) {
  .flyer { padding: 1.75rem; transform: rotate(0deg); }
  .flyer + .flyer { margin-top: 1.25rem; }
  .thread-steps { grid-template-columns: 1fr; gap: 1.75rem; }
  .tear-tabs { flex-wrap: wrap; }
  .ticket { flex-direction: column; align-items: flex-start; gap: 1rem; transform: rotate(0deg); }
}

@media (max-width: 560px) {
  .tab-strip { gap: 0.3rem; }
  .brand-tab { margin-right: 0.35rem; }
}

/* ---------------- Floating Emoji & Reaction Dock ---------------- */

.player-frame {
  position: relative;
  overflow: hidden;
}

.emoji-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 20;
  overflow: hidden;
}

.floating-emoji {
  position: absolute;
  bottom: 10%;
  font-size: 2.4rem;
  user-select: none;
  animation: floatUpEmoji 2.2s cubic-bezier(0.25, 1, 0.5, 1) forwards;
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.4));
}

@keyframes floatUpEmoji {
  0% {
    opacity: 0;
    transform: translateY(20px) scale(0.6) rotate(0deg);
  }
  15% {
    opacity: 1;
    transform: translateY(-20px) scale(1.2) rotate(-8deg);
  }
  50% {
    transform: translateY(-120px) scale(1.4) rotate(8deg);
  }
  100% {
    opacity: 0;
    transform: translateY(-240px) scale(1) rotate(-12deg);
  }
}

.reaction-bar {
  display: flex;
  align-items: center;
  /* Label, six emoji, the picker button and "Bookmark Scene" don't fit
     across a phone; without wrapping the row just ran off the side and
     took the page's horizontal scroll with it. */
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.75rem;
  padding: 0.6rem 1rem;
  background: var(--paper-card);
  border: 2px solid var(--toner);
  border-radius: 0;
}

.reaction-label {
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--toner-soft);
  letter-spacing: 0.08em;
  margin-right: 0.4rem;
}

.btn-reaction {
  background: var(--paper-raised);
  border: 1px solid var(--toner-faint);
  border-radius: 0;
  font-size: 1.35rem;
  padding: 0.3rem 0.6rem;
  cursor: pointer;
  transition: transform 0.15s ease, background 0.15s ease;
}

.btn-reaction:hover {
  transform: scale(1.2) translateY(-2px);
  background: var(--paper);
  border-color: var(--hazard);
}

.btn-reaction:active {
  transform: scale(0.95);
}

/* ---------------- Host Controls & Announcement Components ---------------- */

.announcement-banner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  background: var(--hazard);
  color: var(--paper-raised);
  padding: 0.65rem 1.25rem;
  border-radius: 0;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.9rem;
  margin-bottom: 1rem;
  box-shadow: var(--shadow-pin);
}

.announcement-text {
  flex: 1;
}

.btn-banner-close {
  background: transparent;
  border: none;
  color: var(--paper-raised);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.8;
}

.btn-banner-close:hover {
  opacity: 1;
}

.intermission-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(32, 28, 23, 0.92);
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(4px);
}

.intermission-box {
  background: var(--paper);
  border: 3px solid var(--hazard);
  padding: 2rem 3rem;
  text-align: center;
  max-width: 480px;
  box-shadow: var(--shadow-lift);
}

.intermission-icon {
  font-size: 3rem;
  display: block;
  margin-bottom: 0.5rem;
}

.intermission-box h2 {
  font-family: var(--font-display);
  font-size: 1.8rem;
  color: var(--toner);
  margin: 0 0 0.5rem 0;
}

.intermission-timer {
  font-family: var(--font-display);
  font-size: 3.5rem;
  color: var(--hazard);
  letter-spacing: 0.05em;
  margin: 0.75rem 0;
}

.host-control-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--paper-raised);
  border: 2px dashed var(--hazard);
  border-radius: 0;
}

.host-toolbar-label {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.78rem;
  color: var(--hazard);
  letter-spacing: 0.08em;
  margin-right: 0.4rem;
}

.btn-host-ctrl {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.8rem;
  padding: 0.4rem 0.75rem;
  background: var(--paper-card);
  border: 1px solid var(--toner-soft);
  color: var(--toner);
  border-radius: 0;
  cursor: pointer;
  transition: all 0.15s ease;
}

.btn-host-ctrl:hover {
  background: var(--hazard);
  color: var(--paper-raised);
  border-color: var(--hazard);
}

.host-speed-select-wrap {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--toner);
}

.host-speed-select {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.8rem;
  padding: 0.35rem 0.5rem;
  background: var(--paper-card);
  border: 1px solid var(--toner-soft);
  border-radius: 0;
  color: var(--toner);
  cursor: pointer;
}

.btn-kick {
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 700;
  padding: 0.15rem 0.4rem;
  background: transparent;
  border: 1px solid var(--hazard);
  color: var(--hazard);
  border-radius: 0;
  cursor: pointer;
  margin-left: auto;
}

.btn-kick:hover {
  background: var(--hazard);
  color: var(--paper-raised);
}

/* ---------------- UX Enhancement Components ---------------- */

.ticket-actions {
  display: flex;
  align-items: center;
  /* This redeclares the rule further up, which had flex-wrap: wrap.
     Losing it kept the share / QR / shortcuts / status row on one line,
     and that single unbreakable row was what pushed the whole page
     wider than a phone screen. */
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-left: auto;
}

.btn-ticket-action {
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 700;
  padding: 0.35rem 0.6rem;
  background: var(--paper-card);
  border: 1px solid var(--toner-soft);
  color: var(--toner);
  border-radius: 0;
  cursor: pointer;
  transition: all 0.15s ease;
}

.btn-ticket-action:hover {
  background: var(--toner);
  color: var(--paper-raised);
}

.conn-status-badge {
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 700;
  padding: 0.35rem 0.6rem;
  background: var(--paper-card);
  border: 1px solid var(--rule-line);
  border-radius: 0;
  color: var(--toner-soft);
}

.toast-banner {
  position: fixed;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--toner);
  color: var(--paper-raised);
  padding: 0.75rem 1.5rem;
  border-radius: 0;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.88rem;
  z-index: 999;
  box-shadow: var(--shadow-lift);
  animation: fadeInToast 0.3s ease;
}

@keyframes fadeInToast {
  from { opacity: 0; transform: translate(-50%, 10px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

.unmute-banner {
  background: var(--hazard);
  color: var(--paper-raised);
  padding: 0.6rem 1rem;
  text-align: center;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
  border-radius: 0;
  margin-bottom: 0.75rem;
  box-shadow: var(--shadow-pin);
}

.shortcuts-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem 1rem;
  font-family: var(--font-body);
  font-size: 0.85rem;
  margin-top: 1rem;
  text-align: left;
}

kbd {
  background: var(--paper-card);
  border: 1px solid var(--toner);
  border-radius: 0;
  box-shadow: 0 2px 0 var(--toner);
  padding: 0.15rem 0.4rem;
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--toner);
}

.chat-time-link {
  color: var(--hazard);
  text-decoration: underline;
  cursor: pointer;
  font-weight: 700;
}

.chat-time-link:hover {
  color: var(--hazard-deep);
}

/* ---------------- Theater Mode & Personal Party Components ---------------- */

body.cinema-mode-active {
  background: #0f0d0b !important;
  color: #e0d8cc !important;
}

body.cinema-mode-active .site-header,
body.cinema-mode-active .site-footer,
body.cinema-mode-active .ticket,
body.cinema-mode-active .reaction-bar,
body.cinema-mode-active .host-control-toolbar,
body.cinema-mode-active .watch-party-sidebar {
  opacity: 0.35;
  transition: opacity 0.25s ease;
}

body.cinema-mode-active .site-header:hover,
body.cinema-mode-active .ticket:hover,
body.cinema-mode-active .reaction-bar:hover,
body.cinema-mode-active .host-control-toolbar:hover,
body.cinema-mode-active .watch-party-sidebar:hover {
  opacity: 1;
}

body.cinema-mode-active .player-frame {
  box-shadow: 0 0 40px rgba(0, 0, 0, 0.9);
  border-color: var(--hazard);
}

.resume-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: var(--paper-card);
  border: 2px solid var(--hazard);
  padding: 0.65rem 1rem;
  border-radius: 0;
  margin-bottom: 1rem;
  font-family: var(--font-body);
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--toner);
}

.resume-banner-btns {
  display: flex;
  gap: 0.5rem;
}

.btn-resume-action {
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 700;
  padding: 0.3rem 0.65rem;
  background: var(--hazard);
  color: var(--paper-raised);
  border: none;
  border-radius: 0;
  cursor: pointer;
}

.btn-resume-action.secondary {
  background: var(--paper-raised);
  color: var(--toner);
  border: 1px solid var(--toner-soft);
}

.bookmarks-list {
  padding: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.bookmark-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0.75rem;
  background: var(--paper-card);
  border: 1px solid var(--toner-soft);
  border-radius: 0;
  cursor: pointer;
  transition: background 0.15s ease;
}

.bookmark-item:hover {
  background: var(--paper);
  border-color: var(--hazard);
}

.bookmark-time {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--hazard);
  font-size: 0.9rem;
}

.bookmark-note {
  font-family: var(--font-body);
  font-size: 0.8rem;
  color: var(--toner-soft);
}

/* ---------------- Custom Paper Dropdown Styling ---------------- */

.custom-dropdown-wrap {
  position: relative;
  display: inline-block;
}

.btn-custom-dropdown {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.8rem;
  padding: 0.4rem 0.75rem;
  background: var(--paper-card);
  border: 1px solid var(--toner-soft);
  color: var(--toner);
  border-radius: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  transition: all 0.15s ease;
}

.btn-custom-dropdown:hover {
  background: var(--hazard);
  color: var(--paper-raised);
  border-color: var(--hazard);
}

.custom-dropdown-menu {
  position: absolute;
  top: calc(100% + 0.3rem);
  left: 0;
  min-width: 140px;
  background: var(--paper);
  border: 2px solid var(--toner);
  border-radius: 0;
  box-shadow: var(--shadow-lift);
  z-index: 100;
  padding: 0.3rem 0;
  display: flex;
  flex-direction: column;
}

.custom-dropdown-option {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.82rem;
  padding: 0.45rem 0.85rem;
  color: var(--toner);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}

.custom-dropdown-option:hover {
  background: var(--paper-raised);
  color: var(--hazard);
}

.custom-dropdown-option.is-active {
  background: var(--hazard);
  color: var(--paper-raised);
}

/* ---------------- Action & Chat Toast Notifications in Player ---------------- */

.rtmp-player__action-toast {
  position: absolute;
  top: 1.25rem;
  left: 50%;
  transform: translateX(-50%) translateY(-10px);
  background: rgba(32, 28, 23, 0.92);
  border: 1px solid var(--hazard);
  color: var(--paper-raised);
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 700;
  padding: 0.45rem 1rem;
  border-radius: 0;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4);
  z-index: 35;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease, transform 200ms ease;
  white-space: nowrap;
}

.rtmp-player__action-toast.is-showing {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.rtmp-player__chat-toast {
  position: absolute;
  top: 1.25rem;
  right: 1.25rem;
  max-width: 320px;
  background: rgba(20, 18, 15, 0.92);
  border: 1px solid rgba(244, 237, 226, 0.18);
  color: var(--player-ink);
  font-family: var(--font-body);
  font-size: 0.84rem;
  padding: 0.6rem 0.85rem;
  border-radius: 0;
  box-shadow: 0 4px 12px rgba(0,0,0,0.5);
  z-index: 35;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease, transform 200ms ease;
  transform: translateY(-8px);
}

.rtmp-player__chat-toast.is-showing {
  opacity: 1;
  transform: translateY(0);
}

.rtmp-player__chat-toast-sender {
  font-weight: 700;
  color: var(--hazard);
  margin-bottom: 0.15rem;
  font-size: 0.78rem;
}

.rtmp-player__chat-toast-text {
  color: var(--player-ink);
  word-break: break-word;
  line-height: 1.3;
}

.sidebar-mute-btn {
  background: transparent;
  border: none;
  font-size: 1rem;
  padding: 0.5rem 0.7rem;
  cursor: pointer;
  color: var(--toner);
  border-left: 1px dashed var(--toner-faint);
  transition: background 0.12s ease, color 0.12s ease;
}

.sidebar-mute-btn:hover {
  background: var(--paper-raised);
  color: var(--hazard);
}

.name-modal-box--centered { text-align: center; }

.qr-code-wrap { margin: 1rem 0; }

.qr-code-img {
  width: 180px;
  height: 180px;
  border: 2px solid var(--toner);
  /* Reserve the space so opening the modal doesn't jump when the SVG lands. */
  background: var(--paper-raised);
}

/* ---------------- Focus ----------------
   The stylesheet had no focus styling at all beyond killing the outline on
   inputs, so keyboard users were navigating on whatever the browser drew —
   invisible against the black player chrome. One system rule, in ink, with
   an offset so it reads as a struck rule around the control rather than a
   glow. WCAG 2.4.7. */

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--hazard);
  outline-offset: 2px;
  border-radius: 0;
}

/* On the dark player the red ring alone is hard to find; pair it with paper. */
.rtmp-player :where(button, input, [tabindex]):focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

/* Inputs replaced the ring with a border shift, which vanishes on a field
   that already has a dark border. Keep the border shift, restore the ring. */
input[type="text"]:focus-visible,
input[type="password"]:focus-visible,
input[type="file"]:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--hazard);
  outline-offset: 1px;
}

/* ---------------- Touch targets ----------------
   Everything a finger can hit gets 44px on a coarse pointer (WCAG 2.5.5).
   Desktop keeps its tighter, flyer-like rhythm — this is additive, not a
   global inflation of the design. */

@media (hover: none), (pointer: coarse) {
  .nav-tab,
  .brand-tab {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  .sidebar-tab,
  .sidebar-mute-btn { min-height: 44px; }

  .rtmp-player__btn { width: 44px; height: 44px; }

  .rtmp-player__center-play { width: 64px; height: 64px; }

  /* Nine controls at finger size cannot share one line on a phone — they
     used to collide, the time display sitting on top of the fullscreen
     icon. Give each cluster its own line instead of shrinking the targets
     back below the point of being tappable. */
  @media (max-width: 560px) {
    .rtmp-player__row { flex-wrap: wrap; row-gap: 0.3rem; }
    .rtmp-player__cluster--left,
    .rtmp-player__cluster--right { flex: 1 1 100%; }
    .rtmp-player__cluster--right { justify-content: flex-end; }
  }

  /* Smallest phones: still two lines, just tighter. 40px stays well clear of
     the 24px WCAG 2.5.8 floor while keeping every control reachable. */
  /* On a small phone the video itself is only ~140px tall, so stacking the
     controls costs more than it buys — four lines of chrome under a
     letterbox. Carry fewer controls instead, on one line: seeking is on the
     scrub bar, chat is in the panel below the player, and everything else
     lives behind the gear. Both reappear as the viewport grows. */
  @media (max-width: 400px) {
    .rtmp-player__btn { width: 40px; height: 40px; }
    .rtmp-player__btn svg { width: 20px; height: 20px; }
    .rtmp-player__cluster { gap: 0.3rem; }
    .rtmp-player__time { font-size: 0.62rem; }
    /* Volume goes too: the slider never opens without hover, and a phone has
       hardware volume keys. */
    .rtmp-player__back10,
    .rtmp-player__fwd10,
    .rtmp-player__volume,
    .rtmp-player__fs-chat-btn { display: none; }
    .rtmp-player__row { flex-wrap: nowrap; justify-content: space-between; }
    .rtmp-player__cluster--left,
    .rtmp-player__cluster--right { flex: 0 0 auto; }
    /* Compressed clusters were pushing their children over the next cluster. */
    .rtmp-player__time { flex-shrink: 0; white-space: nowrap; }
  }

  /* iPhone SE class: 254px of usable bar. 36px still clears the 24px WCAG
     2.5.8 floor comfortably, and nothing overflows off-screen. */
  @media (max-width: 360px) {
    .rtmp-player__btn { width: 36px; height: 36px; }
    .rtmp-player__btn svg { width: 18px; height: 18px; }
    .rtmp-player__time { font-size: 0.58rem; }
    .rtmp-player__cluster { gap: 0.2rem; }
  }

  .btn,
  .btn-ticket-action,
  .btn-host-ctrl,
  .btn-custom-dropdown { min-height: 44px; }

  .btn-reaction { min-width: 44px; min-height: 44px; }

  .subtitle-chip-remove {
    min-width: 44px;
    min-height: 44px;
    padding: 0.5rem;
  }

  /* Vertical tear-tabs read as a thin strip; a finger needs the width. */
  .tear-tab { min-width: 44px; }

  /* min-height does nothing to an inline box, which is why these stayed 38px. */
  .session-name a {
    display: inline-block;
    min-height: 44px;
    line-height: 44px;
  }

  .chat-msg-actions button { min-height: 44px; }

  .subtitle-add-form input[type="file"],
  .subtitle-add-form input[type="text"] { min-height: 44px; }

  .sidebar-mute-btn { min-width: 44px; }
}

/* Inline links inside a sentence are deliberately left at text size — WCAG
   2.5.5 exempts them, and padding them out would break the paragraph they
   sit in. */

/* ---------------- Host chat strip ----------------
   An editor's mark along the top of the pad: the host's one destructive
   chat control, kept quiet until it is needed. */

.chat-host-strip {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  justify-content: flex-end;
  padding: 0.4rem 0.6rem;
  border-bottom: 1px dashed var(--rule-line);
  background: var(--paper-card);
}

.chat-host-strip--confirm { justify-content: space-between; }

.chat-host-strip__ask {
  font-family: var(--font-body);
  font-size: 0.74rem;
  color: var(--toner-soft);
  line-height: 1.3;
}

.btn-chat-clear {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  background: transparent;
  color: var(--toner-soft);
  border: 1px solid var(--rule-line);
  border-radius: 0;
  /* 44px tall on touch via the min-height below; compact on the desktop rail. */
  padding: 0.4rem 0.7rem;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}

.btn-chat-clear:hover,
.btn-chat-clear:focus-visible {
  color: var(--hazard);
  border-color: var(--hazard);
}

.btn-chat-clear--go {
  background: var(--hazard);
  border-color: var(--hazard);
  color: var(--paper-raised);
}

.btn-chat-clear--go:hover,
.btn-chat-clear--go:focus-visible {
  background: var(--hazard-deep);
  border-color: var(--hazard-deep);
  color: var(--paper-raised);
}

.btn-chat-clear--cancel:hover,
.btn-chat-clear--cancel:focus-visible {
  color: var(--toner);
  border-color: var(--toner);
}

@media (hover: none) {
  .btn-chat-clear { min-height: 44px; padding: 0.5rem 0.9rem; }
}

/* ---------------- Message Hover Actions & Reactions ---------------- */

.chat-msg {
  position: relative;
  transition: background 0.15s ease;
  padding: 0.45rem 0.6rem;
  border-radius: 0;
}

.chat-msg:hover {
  background: rgba(0, 0, 0, 0.04);
}

.chat-msg-actions {
  position: absolute;
  top: -0.85rem;
  right: 0.5rem;
  display: none;
  background: var(--paper);
  border: 1px solid var(--toner);
  border-radius: 0;
  padding: 0.15rem 0.4rem;
  box-shadow: var(--shadow-lift);
  z-index: 10;
  gap: 0.2rem;
  align-items: center;
}

.chat-msg:hover .chat-msg-actions {
  display: flex;
}


.btn-msg-react,
.btn-msg-reply {
  background: transparent;
  border: none;
  font-size: 0.85rem;
  cursor: pointer;
  padding: 0.1rem 0.25rem;
  border-radius: 0;
  line-height: 1;
  transition: transform 0.1s ease, background 0.1s ease;
}

.btn-msg-react:hover,
.btn-msg-reply:hover {
  transform: scale(1.25);
  background: var(--paper-raised);
}

.btn-msg-reply {
  font-size: 0.75rem;
  font-weight: bold;
  color: var(--toner);
  border-left: 1px solid var(--toner-faint);
  margin-left: 0.2rem;
  padding-left: 0.35rem;
}

.chat-quote-block {
  font-size: 0.76rem;
  color: var(--toner-soft);
  background: var(--paper-card);
  /* A perforation, not a coloured side-tab: a quoted message is not the live
     thing on screen, so it does not earn hazard red (see the One Red Rule). */
  border-left: 1px dashed var(--rule-line);
  padding: 0.2rem 0.45rem;
  margin-bottom: 0.25rem;
  border-radius: 2px;
  word-break: break-word;
}

.chat-quote-sender {
  font-weight: 700;
  color: var(--hazard);
  margin-right: 0.3rem;
}

.chat-msg-reactions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: 0.25rem;
}

.reaction-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  font-size: 0.72rem;
  font-weight: 700;
  background: var(--paper-card);
  border: 1px solid var(--toner-faint);
  padding: 0.1rem 0.35rem;
  border-radius: 0;
  cursor: pointer;
  user-select: none;
  transition: all 0.12s ease;
}

.reaction-pill:hover {
  border-color: var(--hazard);
  color: var(--hazard);
  transform: scale(1.05);
}

.chat-reply-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--paper-card);
  /* This one IS the live state, so it keeps the red — as a stamped outline
     rather than a coloured strip down one side. */
  border: 1px solid var(--hazard);
  padding: 0.35rem 0.6rem;
  font-size: 0.78rem;
  color: var(--toner);
  margin-bottom: 0.35rem;
  border-radius: 2px;
}

.btn-cancel-reply {
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--toner-soft);
  font-size: 0.85rem;
  font-weight: bold;
}

.btn-cancel-reply:hover {
  color: var(--hazard);
}

/* ---------------- Fullscreen Side Chat Drawer ---------------- */

.rtmp-player__fs-chat {
  position: absolute;
  top: 1rem;
  right: 1rem;
  bottom: 4.5rem;
  width: 320px;
  max-width: calc(100% - 2rem);
  background: rgba(20, 18, 15, 0.88);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(230, 220, 205, 0.2);
  border-radius: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
  opacity: 0.95;
  transition: opacity 300ms ease, transform 300ms ease;
}

.rtmp-player__fs-chat.is-idle {
  opacity: 0.22;
}

.rtmp-player__fs-chat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid rgba(230, 220, 205, 0.15);
  color: var(--player-ink);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.9rem;
  letter-spacing: 0.05em;
}

.rtmp-player__fs-chat-close {
  background: transparent;
  border: none;
  color: var(--player-ink);
  cursor: pointer;
  font-size: 1.1rem;
  opacity: 0.7;
  transition: opacity 0.12s ease;
}

.rtmp-player__fs-chat-close:hover {
  opacity: 1;
  color: var(--hazard);
}

.rtmp-player__fs-chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.rtmp-player__fs-chat-messages .chat-msg {
  background: rgba(35, 30, 25, 0.7);
  color: var(--player-ink);
  border: 1px solid rgba(230, 220, 205, 0.1);
}

.rtmp-player__fs-chat-form {
  display: flex;
  padding: 0.5rem;
  gap: 0.4rem;
  border-top: 1px solid rgba(230, 220, 205, 0.15);
}

.rtmp-player__fs-chat-input {
  flex: 1;
  background: rgba(10, 8, 5, 0.7);
  border: 1px solid rgba(230, 220, 205, 0.2);
  color: var(--player-ink);
  font-family: var(--font-body);
  font-size: 0.8rem;
  padding: 0.4rem 0.6rem;
  border-radius: 0;
  outline: none;
}

.rtmp-player__fs-chat-input:focus {
  border-color: var(--hazard);
}

.rtmp-player__fs-chat-submit {
  background: var(--hazard);
  color: var(--paper-raised);
  border: none;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.78rem;
  padding: 0.4rem 0.75rem;
  border-radius: 0;
  cursor: pointer;
}

/* ---------------- Emoji Picker Flyout ---------------- */

#btn-more-emojis {
  position: relative;
}

.btn-msg-more {
  position: relative;
  background: transparent;
  border: none;
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
  padding: 0.1rem 0.3rem;
  border-radius: 0;
  line-height: 1;
  color: var(--toner);
  transition: transform 0.1s ease, background 0.1s ease;
}

.btn-msg-more:hover {
  transform: scale(1.25);
  background: var(--paper-raised);
  color: var(--hazard);
}

/* A touch screen has no hover, so gating these behind it left reactions
   and Reply with no way to be triggered at all from a phone. Lay them out
   inline under the message instead of as an overlay only hover reveals,
   with targets big enough to hit with a thumb.
   Placed after the base button rules deliberately — these share their
   specificity, so earlier in the file they'd simply lose. */
@media (hover: none) {
  .chat-msg-actions {
    position: static;
    display: flex;
    flex-wrap: wrap;
    margin-top: 0.4rem;
    padding: 0;
    gap: 0.1rem;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
  }
  .btn-msg-react,
  .btn-msg-more,
  .btn-msg-reply {
    font-size: 1rem;
    line-height: 1;
    padding: 0.45rem 0.55rem;
  }
  .btn-msg-reply {
    border-left: none;
    margin-left: 0.2rem;
    padding-left: 0.55rem;
  }
  /* Scaling on tap makes the control jump out from under the finger. */
  .btn-msg-react:hover,
  .btn-msg-more:hover,
  .btn-msg-reply:hover {
    transform: none;
  }
}

.emoji-picker-flyout {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  width: 270px;
  background: var(--paper);
  border: 2px solid var(--toner);
  border-radius: 0;
  box-shadow: var(--shadow-lift);
  z-index: 150;
  padding: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.emoji-picker-search {
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.8rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--toner-faint);
  border-radius: 0;
  background: var(--paper-card);
  color: var(--toner);
  box-sizing: border-box;
}

.emoji-picker-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 0.2rem;
  overflow-y: auto;
  max-height: 150px;
  padding-right: 0.15rem;
}

.emoji-picker-item {
  background: transparent;
  border: none;
  font-size: 1.15rem;
  cursor: pointer;
  padding: 0.2rem 0.1rem;
  border-radius: 0;
  text-align: center;
  line-height: 1.1;
  transition: transform 0.1s ease, background 0.1s ease;
}

.emoji-picker-item:hover {
  transform: scale(1.3);
  background: var(--paper-raised);
}

/* A guest in a locked room keeps volume, captions, settings and chat; only
   the transport belongs to the host. Disabled rather than hidden, so the
   controls do not appear to have gone missing. */
.rtmp-player.is-guest-locked .rtmp-player__play,
.rtmp-player.is-guest-locked .rtmp-player__center-play,
.rtmp-player.is-guest-locked .rtmp-player__back10,
.rtmp-player.is-guest-locked .rtmp-player__fwd10,
.rtmp-player.is-guest-locked .rtmp-player__scrub {
  pointer-events: none;
  opacity: 0.4;
}

.rtmp-player.is-guest-locked .rtmp-player__scrub-thumb { display: none; }

/* ---------------- Locked room ----------------
   A refused ticket, in the same world as the ones that get you in: the
   stub is still a stub, it just has NO ENTRY printed across it. */

.locked-shell {
  display: flex;
  justify-content: center;
  padding: 2rem 0 3rem;
}

.locked-flyer {
  max-width: 34rem;
  text-align: center;
  padding: 3.5rem 2.5rem 2.75rem;
  transform: rotate(-0.9deg);
}

.locked-stamp {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(1.5rem, 5vw, 2.1rem);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--hazard);
  border: 3px solid var(--hazard);
  padding: 0.5rem 1.1rem;
  margin: 0 0 1.9rem;
  transform: rotate(-7deg);
  /* The ink of a rubber stamp sits unevenly on paper. */
  opacity: 0.88;
}

/* An out-of-date link is a refused ticket too, so it wears the same stub.
   Muted rather than hazard red: nobody is being kept out on purpose here,
   the address simply moved. */
.locked-stamp--expired {
  color: var(--toner-soft);
  border-color: var(--toner-soft);
  transform: rotate(4deg);
}

.locked-heading {
  font-family: var(--font-display);
  font-size: clamp(2rem, 6vw, 2.9rem);
  letter-spacing: -0.01em;
  line-height: 1.05;
  margin: 0 0 1rem;
  color: var(--toner);
}

.locked-lede {
  margin: 0 auto 1.1rem;
  max-width: 30rem;
  color: var(--toner-soft);
  line-height: 1.6;
}

.locked-ask {
  margin: 0 auto 2rem;
  max-width: 30rem;
  color: var(--toner);
  line-height: 1.6;
}

.locked-ask strong { color: var(--hazard); }

.locked-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
}

/* These are buttons, not prose links. */
.locked-actions .btn { text-decoration: none; }

/* One authored moment: the stamp lands once, the way it would be pressed. */
@media (prefers-reduced-motion: no-preference) {
  .locked-stamp {
    animation: locked-stamp-press 460ms cubic-bezier(0.16, 1, 0.3, 1) both;
  }
}

@keyframes locked-stamp-press {
  from {
    transform: rotate(-14deg) scale(1.5);
    opacity: 0;
    filter: blur(3px);
  }
  to {
    transform: rotate(-7deg) scale(1);
    opacity: 0.88;
    filter: blur(0);
  }
}

/* Has to follow the base rule: `animation` above is shorthand, so it
   resets animation-name, and these two selectors have equal specificity. */
@media (prefers-reduced-motion: no-preference) {
  .locked-stamp--expired { animation-name: locked-stamp-press-expired; }
}

@keyframes locked-stamp-press-expired {
  from {
    transform: rotate(11deg) scale(1.5);
    opacity: 0;
    filter: blur(3px);
  }
  to {
    transform: rotate(4deg) scale(1);
    opacity: 0.88;
    filter: blur(0);
  }
}

@media (max-width: 560px) {
  .locked-flyer { padding: 3rem 1.5rem 2.25rem; }
  .locked-actions .btn { width: 100%; text-align: center; }
}






/* ---------------- Reel loader ----------------
   An Academy leader — the countdown target on the head of a reel. An
   indeterminate wait wants a hand that keeps sweeping, not a bar that
   claims to know how far along it is.

   The same markup serves the in-page loader here and the standalone
   waking shell (static/myapp/waking.html). The shell inlines its own copy
   of these rules on purpose: it has to render when the server it would
   fetch this stylesheet from is exactly what has not answered yet. */

.leader { display: block; }
.leader__ring { fill: none; stroke: currentColor; stroke-width: 2; opacity: 0.5; }
.leader__ring--outer { stroke-width: 3; opacity: 0.8; }
.leader__cross { stroke: currentColor; stroke-width: 1.5; opacity: 0.3; }
.leader__wedge { fill: var(--hazard); opacity: 0.18; transform-origin: 100px 100px; }
.leader__hand { stroke: var(--hazard); stroke-width: 3; transform-origin: 100px 100px; }

@media (prefers-reduced-motion: no-preference) {
  .leader__wedge,
  .leader__hand { animation: leader-sweep 2.4s linear infinite; }
}

@keyframes leader-sweep {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* Sits over the player box, which is the system's one dark surface, so it
   takes the player's ink rather than the page's toner. */
.reel-loader {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  background: var(--toner);
  color: var(--player-ink);
  text-align: center;
  padding: 1rem;
}

.reel-loader[hidden] { display: none; }

/* Fades rather than cutting, so the first frame of the film is not
   preceded by a flash of black. */
.reel-loader.is-done {
  opacity: 0;
  pointer-events: none;
  transition: opacity 260ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .reel-loader.is-done { transition: none; }
}

.leader--player {
  width: min(8rem, 26vh);
  height: min(8rem, 26vh);
}

/* The strokes above are set in a 200-unit viewBox, so at the smaller size
   used here they render around a pixel wide and the target goes to mush
   against the player's near-black. Heavier and more opaque, purely to hold
   up at this scale — light ink on a dark surface needs more of both than
   the same drawing on paper. */
.leader--player .leader__ring { stroke-width: 3; opacity: 0.55; }
.leader--player .leader__ring--outer { stroke-width: 4.5; opacity: 0.95; }
.leader--player .leader__cross { stroke-width: 2; opacity: 0.34; }
.leader--player .leader__wedge { opacity: 0.32; }
.leader--player .leader__hand { stroke-width: 4.5; }

.reel-loader__label {
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--player-ink-soft);
}

/* On a letterboxed phone the player box is short enough that the target
   and the label together crowd it out. */
@media (max-height: 420px), (max-width: 400px) {
  .leader--player { width: min(5rem, 22vh); height: min(5rem, 22vh); }
  .reel-loader { gap: 0.75rem; }
  .reel-loader__label { font-size: 0.7rem; letter-spacing: 0.1em; }
}
