/* styles.css — studio surfaces in the "Ember Studio" design language.
   Semantic redesign tokens live in tokens.css (loaded before this file); the
   Gipity brand + Water base come from gipity-theme.css. Dark stage is committed.
   Every functional id / data-testid / body[data-screen] display selector is
   preserved — this is a restyle of containers + a re-composition of the control
   bar, not a rebuild. User text still enters via textContent elsewhere. */

/* ── Global stage ground ──────────────────────────────────────────────────── */
/* Water.css caps `body { max-width: 800px }`. Every app surface manages its own
   width (.studio-main, .landing, .tile-grid, .summary, the editor), so on desktop
   that cap squeezes the WHOLE studio into 800px — tiny lobby tiles + a cramped
   dock. Lift the cap; the component max-widths + margin:auto still center content. */
body { max-width: none; background: var(--stage-0); color: var(--ink); }
body.studio, body[data-screen="landing"] { background: var(--stage-0); }
body.studio {
  box-sizing: border-box; width: 100%; min-height: 100vh; min-height: 100dvh;
  margin: 0; padding: 0; overflow-x: hidden;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── Shared button tiers ──────────────────────────────────────────────────── */
/* PRIMARY — ember gradient, one hero action per view. */
.primary-btn {
  background: var(--grad-ember);
  color: var(--on-accent);
  border: none;
  border-radius: var(--r-btn);
  box-shadow: var(--shadow-accent);
  font-weight: 700;
  transition: filter var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.primary-btn:hover { background: var(--grad-ember); filter: brightness(1.06); }
.primary-btn:active { transform: scale(.98); }
.primary-btn:focus-visible { outline: none; box-shadow: var(--focus-ring), var(--shadow-accent); }

/* SECONDARY — solid elevated fill. */
.secondary-btn { background: var(--stage-3); color: var(--ink); border: 1px solid var(--line); }
.secondary-btn:hover { background: var(--stage-4); }
.secondary-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* GHOST — transparent utility. */
button.ghost { background: transparent; color: var(--ink-dim); border: 1px solid var(--line); }
button.ghost:hover { background: var(--stage-2); color: var(--ink); }
button.ghost:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Shared disabled state — one app-wide rule so a busy/blocked CTA reads as
   inert (dimmed, no interactive shadow, not-allowed cursor) instead of looking
   clickable. Applies to both button tiers. */
.primary-btn:disabled, .secondary-btn:disabled {
  opacity: .55;
  cursor: not-allowed;
  box-shadow: none;
}

/* Scoped inputs on the stage. */
.arm-fields select, .arm-fields input, #title-input, #join-input {
  background: var(--stage-2);
  border: 1px solid var(--line);
  border-radius: var(--r-input);
  color: var(--form-text);
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none; box-shadow: var(--focus-ring); border-color: var(--accent-line);
}

/* ── Landing ──────────────────────────────────────────────────────────────── */
.landing { max-width: 980px; margin-inline: auto; padding-top: var(--s-8); }

/* Loading placeholder — shown while requireUser() resolves so the landing isn't
   blank during the initial auth check. */
.landing-loading {
  display: flex; align-items: center; justify-content: center; gap: var(--s-3);
  color: var(--ink-dim); font-size: var(--text-sm); padding: var(--s-6) 0;
}
.landing-spinner {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--line-strong); border-top-color: var(--accent);
  animation: landing-spin .7s linear infinite;
}
@keyframes landing-spin { to { transform: rotate(360deg); } }

.landing-nav { position: absolute; top: var(--s-4); right: var(--s-4); margin: 0; z-index: 5; }
.nav-editor-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; text-decoration: none;
  min-height: 44px; /* phone-friendly touch target */
  color: var(--ink-dim); background: var(--stage-2); border: 1px solid var(--line);
  border-radius: var(--r-btn); padding: 8px 16px; font-weight: 600; font-size: var(--text-sm);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.nav-editor-btn:hover { color: var(--ink); border-color: var(--accent-line); }
/* Phone: the absolutely-positioned nav wraps to two rows of 44px pills and lands
   on top of the kicker/wordmark — the first thing a cold visitor sees. Drop it
   back into the flow above the hero and split the width evenly. */
@media (max-width: 620px) {
  .landing-nav {
    position: static; display: flex; gap: var(--s-2);
    padding: var(--s-3) var(--s-4) 0;
  }
  .nav-editor-btn { flex: 1; padding: 8px 10px; }
  .landing { padding-top: var(--s-5); }
}

.hero { text-align: center; margin-bottom: var(--s-7); }
.kicker {
  display: inline-block; font-size: var(--text-xs); font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: var(--r-chip); padding: 3px 12px; margin-bottom: var(--s-4);
}
.wordmark {
  background: var(--grad-ember);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  margin: 0 0 var(--s-3);
}
.tagline {
  color: var(--ink-dim); font-size: var(--text-lg);
  max-width: 54ch; margin: 0 auto;
}

#landing-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--s-4);
}
.card {
  position: relative;
  background: var(--stage-2);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: var(--s-5);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: var(--grad-ember); }
.card-glyph {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--stage-3); color: var(--accent); border: 1px solid var(--line);
  margin-bottom: var(--s-2);
}
.card h2 { margin-top: 0; }
.card-sub { color: var(--ink-dim); font-size: var(--text-sm); margin-top: 0; }
.card form { display: flex; flex-direction: column; gap: var(--s-2); }
.card input { width: 100%; }
.card button { align-self: flex-start; }

/* ── Showcase (pre-auth product preview) ──────────────────────────────────────
   A cold, signed-out visitor sees exactly what the product does BEFORE any gate.
   The left column is a lightweight CSS/SVG studio mock; the right column is the
   record → edit → publish arc. No media files, no network requests. */
.showcase {
  display: grid;
  grid-template-columns: 1.1fr .9fr;
  gap: var(--s-6);
  align-items: center;
  margin-bottom: var(--s-7);
}
@media (max-width: 760px) {
  .showcase { grid-template-columns: 1fr; gap: var(--s-5); }
}

/* CSS-only studio mock */
.stage-preview {
  position: relative;
  background: var(--stage-1);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: var(--s-3);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.stage-preview::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% -20%, var(--accent-soft), transparent 62%);
}
.sp-bar { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-3); position: relative; }
.sp-rec {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--text-xs); font-weight: 700; letter-spacing: .06em; color: var(--on-record);
  background: var(--rec); border-radius: var(--r-chip); padding: 3px 10px;
}
.sp-rec-dot { width: 8px; height: 8px; border-radius: 50%; background: #fff; box-shadow: var(--rec-glow); }
.sp-clock { font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--text-sm); color: var(--ink); }
.sp-4k {
  margin-left: auto; font-size: var(--text-xs); font-weight: 600; color: var(--ink-dim);
  background: var(--stage-3); border: 1px solid var(--line); border-radius: var(--r-chip); padding: 2px 10px;
}
.sp-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2); }
.sp-tile {
  position: relative; aspect-ratio: 16 / 10; border-radius: var(--r-sm);
  background: linear-gradient(160deg, var(--stage-3), var(--stage-2));
  border: 1px solid var(--line); overflow: hidden;
  display: flex; align-items: flex-end; justify-content: center; padding: 10px;
}
.sp-av { position: absolute; top: 9px; left: 9px; width: 22px; height: 22px; border-radius: 50%; background: var(--grad-ember); }
.sp-tile:nth-child(2) .sp-av { background: linear-gradient(135deg, #4f8cff, #8b5cf6); }
.sp-tile:nth-child(3) .sp-av { background: linear-gradient(135deg, #35c46b, #0ea5a3); }
.sp-tile:nth-child(4) .sp-av { background: linear-gradient(135deg, #f5a623, #ff6a3d); }
.sp-wave { display: flex; align-items: flex-end; gap: 3px; height: 30px; }
.sp-wave i { width: 4px; border-radius: 2px; background: var(--accent); opacity: .8; }
.sp-wave i:nth-child(1) { height: 35%; }
.sp-wave i:nth-child(2) { height: 70%; }
.sp-wave i:nth-child(3) { height: 100%; }
.sp-wave i:nth-child(4) { height: 55%; }
.sp-wave i:nth-child(5) { height: 85%; }
.sp-wave i:nth-child(6) { height: 45%; }
.sp-wave i:nth-child(7) { height: 65%; }
.sp-tile:nth-child(2) .sp-wave i { background: #6f9bff; }
.sp-tile:nth-child(3) .sp-wave i { background: #35c46b; }
.sp-tile:nth-child(4) .sp-wave i { background: var(--warn); }
.sp-timeline { margin-top: var(--s-3); display: flex; flex-direction: column; gap: 6px; }
.sp-lane {
  height: 9px; border-radius: 5px; background: var(--stage-2);
  border: 1px solid var(--line); position: relative; overflow: hidden;
}
.sp-lane::after {
  content: ""; position: absolute; top: 0; bottom: 0; border-radius: 5px;
  background: linear-gradient(90deg, var(--accent-soft), var(--accent-line));
}
.sp-lane:nth-child(1)::after { left: 5%;  right: 30%; }
.sp-lane:nth-child(2)::after { left: 22%; right: 12%; }
.sp-lane:nth-child(3)::after { left: 9%;  right: 46%; }

/* Value-prop list (record → edit → publish) */
.value-props { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-4); }
.value-props li { display: flex; gap: var(--s-3); align-items: flex-start; }
.vp-glyph {
  flex: none; width: 38px; height: 38px; border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--stage-2); border: 1px solid var(--line); color: var(--accent);
}
.vp-text b { display: block; color: var(--ink); font-size: var(--text-base); margin-bottom: 2px; }
.vp-text span { color: var(--ink-dim); font-size: var(--text-sm); line-height: 1.4; }

.landing-error, .studio-error {
  margin-top: var(--s-4);
  color: var(--ink);
  background: var(--stage-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-card);
  padding: var(--s-3) var(--s-4);
}
.studio-error { margin: var(--s-5); }

/* ── Auth gate ────────────────────────────────────────────────────────────── */
#auth-gate { margin: var(--s-5) auto; max-width: 420px; }
.auth-card {
  position: relative;
  background: var(--stage-2);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: var(--s-5);
  max-width: 420px;
  margin-inline: auto;
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.auth-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: var(--grad-ember); }
.auth-card h2 { margin-top: 0; }
.auth-blurb { color: var(--ink-dim); font-size: var(--text-sm); }
.auth-error { color: var(--danger); font-size: var(--text-sm); }

/* ── Studio header ────────────────────────────────────────────────────────── */
.studio-header {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-4);
  background: var(--stage-1);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 10; flex-wrap: wrap;
}
.s-title { font-weight: 600; color: var(--ink); font-size: var(--text-lg); }
.header-spacer { flex: 1 1 auto; }
.rec-timer {
  font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ink);
  background: var(--stage-2); border: 1px solid var(--rec-ring);
  padding: var(--s-1) var(--s-3); border-radius: var(--r-chip); font-size: var(--text-sm);
  display: inline-flex; align-items: center; gap: 6px;
}
.rec-timer::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--rec); box-shadow: 0 0 0 3px var(--rec-ring);
  animation: chip-pulse 1s ease-in-out infinite;
}
.conn-badge {
  font-size: var(--text-xs); padding: var(--s-1) var(--s-3); border-radius: var(--r-chip);
  border: 1px solid var(--line); color: var(--ink-dim); background: var(--stage-2);
  min-height: auto; margin: 0; cursor: pointer;
}
.conn-badge::after { content: " ▾"; font-size: 0.85em; opacity: 0.75; }
.conn-badge[aria-expanded="true"] { box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 28%, transparent); }
.qos-badge {
  max-width: 44ch; font-size: var(--text-xs); padding: var(--s-1) var(--s-3);
  border-radius: var(--r-chip); color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 55%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, var(--stage-2));
}
.conn-connected,
.conn-ready { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.conn-waiting,
.conn-reconnecting { color: var(--primary); border-color: color-mix(in srgb, var(--primary) 55%, transparent); }
/* A dropped connection is a PROBLEM — flag it in caution amber so it's visually
   distinct from the harmless "Local only" offline state (which stays faint). */
.conn-lost {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 55%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, var(--stage-2));
}
/* 'degraded' (fleet finding #1): presence and video are fine, but the channel a
   record command travels on has DROPPED. It must not look like the harmless
   "connecting" blue — a take started here silently misses somebody. */
.conn-degraded {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 55%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, var(--stage-2));
}
.conn-offline { color: var(--ink-faint); }
.folder-badge {
  font-size: var(--text-xs); color: var(--ink-dim);
  background: var(--stage-2); border: 1px solid var(--line);
  border-radius: var(--r-chip); padding: var(--s-1) var(--s-3);
  max-width: 40ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.connection-details {
  position: fixed; z-index: 80; top: 58px; right: var(--s-4); width: min(430px, calc(100vw - 24px));
  max-height: calc(100vh - 76px); overflow: auto; padding: var(--s-4);
  color: var(--ink); background: var(--stage-1); border: 1px solid var(--line);
  border-radius: var(--r-card); box-shadow: var(--shadow-card);
}
.connection-details[hidden] { display: none; }
.connection-details-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s-3); }
.connection-details-head h2 { margin: 2px 0 0; font-size: var(--text-lg); }
.connection-details-head button { margin: 0; }
.connection-summary { margin: var(--s-3) 0; padding: var(--s-3); border-radius: var(--r-card); background: var(--stage-2); }
.connection-summary[data-health="good"] { color: var(--ok); }
.connection-summary[data-health="warning"] { color: var(--warn); }
.connection-summary[data-health="bad"] { color: var(--danger); }
.connection-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin: 0; overflow: hidden; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--line); }
.connection-metrics > div { min-width: 0; padding: var(--s-3); background: var(--stage-2); }
.connection-metrics dt { color: var(--ink-faint); font-size: var(--text-xs); }
.connection-metrics dd { margin: 4px 0 0; color: var(--ink); font-size: var(--text-sm); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.connection-safety { margin: var(--s-3) 0 0; color: var(--ink-dim); font-size: var(--text-xs); }
@media (max-width: 600px) {
  .connection-details { top: auto; right: 0; bottom: 0; width: 100%; max-height: 82vh; border-radius: var(--r-card) var(--r-card) 0 0; }
  .connection-metrics { grid-template-columns: 1fr; }
}

/* ── Screens + layout shell ───────────────────────────────────────────────── */
.screen { display: none; }
body[data-screen="arm"] #arm-screen { display: block; }
body[data-screen="lobby"] #stage,
body[data-screen="recording"] #stage {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s-4); min-height: calc(100vh - 160px); padding-bottom: 120px;
}
body[data-screen="summary"] #summary-screen { display: block; }
.studio-main { padding: var(--s-5); max-width: 1200px; margin: 0 auto; background: var(--stage-0); }
.studio-columns { display: flex; gap: var(--s-5); align-items: flex-start; }
.studio-screens { flex: 1 1 auto; min-width: 0; }

/* ── Arm screen — Riverside "green room" split ────────────────────────────── */
/* Workspace/live-session actions do not apply until Enter. Their arm-screen
   equivalents already live in the setup panel, so keeping them in the header
   only creates a second row on phones. Connection health remains visible. */
body[data-screen="arm"] .workspace-switcher,
body[data-screen="arm"] #invite-btn,
body[data-screen="arm"] .live-btn,
body[data-screen="arm"] .folder-badge,
body[data-screen="arm"] .qos-badge,
body[data-screen="arm"] .rec-timer { display: none !important; }
body[data-screen="arm"] .studio-header { flex-wrap: nowrap; }
body[data-screen="arm"] .s-title {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.arm { max-width: 1180px; margin-inline: auto; }
.arm-lobby {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: var(--s-5); align-items: start;
}
.arm-preview-column {
  display: flex; flex-direction: column; gap: var(--s-2);
  min-width: 0; min-height: 0;
}
/* Live camera preview: <video> fills the frame; the empty/placeholder state sits
   on top and is hidden once a stream is attached (.is-live on the container). */
.arm-preview {
  box-sizing: border-box; position: relative; aspect-ratio: 16 / 9; background: #000;
  border: 1px solid var(--line); border-radius: var(--r-tile);
  box-shadow: var(--shadow-tile); overflow: hidden;
}
.arm-preview-video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; background: #000;
  transform: scaleX(-1);            /* mirror the self-view, like a real green room */
  display: none;
}
.arm-preview.is-live .arm-preview-video { display: block; }
.arm-preview.is-live .arm-preview-empty { display: none; }
.arm-preview-empty {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s-3); color: var(--ink-faint); text-align: center; padding: var(--s-4);
}
.arm-preview-cap { font-size: var(--text-sm); max-width: 26ch; }
.arm-preview-foot {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  width: 100%; min-width: 0; margin-inline: auto;
}
.arm-info-disclosure {
  position: relative; display: block; align-items: normal; min-width: 0; margin: 0; padding: 0;
  color: var(--ink-dim); background: var(--stage-1);
  border: 1px solid var(--line); border-radius: var(--r-sm);
}
.arm-info-disclosure[open], .arm-save[open], .qr-card[open] { padding: 0; }
.arm-info-disclosure > summary,
.arm-save > summary,
.qr-card > summary {
  box-sizing: border-box; display: flex; align-items: center; gap: var(--s-2);
  min-height: 40px; margin: 0; padding: var(--s-2) var(--s-3);
  color: var(--ink); cursor: pointer; list-style: none; font-size: var(--text-sm);
  font-weight: 650; line-height: 1.2;
}
.arm-info-disclosure > summary::-webkit-details-marker,
.arm-save > summary::-webkit-details-marker,
.qr-card > summary::-webkit-details-marker { display: none; }
.arm-info-disclosure > summary::marker,
.arm-save > summary::marker,
.qr-card > summary::marker { content: ""; }
.arm-info-disclosure[open] > summary,
.arm-save[open] > summary,
.qr-card[open] > summary { margin: 0; }
.arm-info-disclosure > summary:hover,
.arm-info-disclosure > summary:focus,
.arm-save > summary:hover,
.arm-save > summary:focus,
.qr-card > summary:hover,
.qr-card > summary:focus { text-decoration: none; }
.arm-info-disclosure > summary:focus-visible,
.arm-save > summary:focus-visible,
.qr-card > summary:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.arm-info-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: 0 0 auto; margin-left: auto;
  color: var(--accent); border: 1px solid var(--accent-line);
  border-radius: 50%; font-size: 12px; font-weight: 800; font-style: normal;
}
.arm-info-disclosure > p {
  margin: 0; padding: 0 var(--s-3) var(--s-3);
  color: var(--ink-dim); font-size: var(--text-sm); line-height: 1.4;
}
.headphones-hint { flex: 1 1 220px; padding: 0; border-left-width: 1px; }
.arm-preview-foot .arm-disk { flex: 0 1 auto; }
.arm-panel {
  display: grid; grid-template-rows: minmax(0, 1fr);
  min-width: 0; min-height: 0; max-width: 100%; overflow: hidden;
}
.arm-settings-scroll {
  display: flex; flex-direction: column; gap: var(--s-2);
  box-sizing: border-box; width: 100%; min-width: 0; min-height: 0; max-width: 100%;
  overflow-x: hidden; overflow-y: auto;
  overscroll-behavior: contain;
}
.arm-panel-head {
  display: flex; align-items: baseline; flex-direction: row; flex-wrap: wrap;
  justify-content: flex-start; gap: var(--s-2); min-width: 0; text-align: left;
}
.arm-panel-head .kicker { flex: 0 0 auto; margin: 0; }
.arm-panel-head h2 { font-size: clamp(1.15rem, 2.6vw, 1.45rem); line-height: 1.15; }
.arm-panel h2 { margin: 0; }
.hint { color: var(--ink-dim); font-size: var(--text-sm); }
.arm-fields {
  display: grid; grid-template-columns: max-content 1fr;
  gap: var(--s-2) var(--s-4); align-items: center; margin: 0;
}
.arm-fields, .arm-fields > * { box-sizing: border-box; min-width: 0; max-width: 100%; }
.arm-fields label, .arm-meter-label { color: var(--ink-dim); font-size: var(--text-sm); }
.arm-fields select, .arm-fields input { box-sizing: border-box; width: 100%; min-width: 0; margin: 0; }
.arm-fields input { padding: var(--s-2) var(--s-3); }
.arm-fields .arm-inline-info { grid-column: 1 / -1; }
/* Display-name is OPTIONAL — de-emphasize by ordering its label + input LAST in
   the arm fields (below recording quality). Both share order:1 so they stay a
   paired row; every other field keeps the default order:0 in source order. */
.arm-fields label[for="session-name"], .arm-fields #session-name { order: 1; }

/* Live mic level meter (green-room). Ember accent fill + a peak-hold marker. */
.mic-meter {
  position: relative; height: 10px; width: 100%;
  background: color-mix(in srgb, #fff 6%, transparent);
  border: 1px solid var(--line); border-radius: var(--r-chip); overflow: hidden;
}
.mic-meter-fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  background: var(--grad-ember); border-radius: var(--r-chip);
  transition: width 80ms linear;
}
.mic-meter-peak {
  position: absolute; top: 0; bottom: 0; left: 0; width: 2px;
  background: var(--ink); opacity: .8; transition: left 120ms linear;
}
.arm-meter-label { align-self: center; }

.arm-disk {
  margin: 0; font-size: var(--text-xs); color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
/* The storage line's whole thesis is that it gets LOUDER as headroom falls —
   the old code went silent at zero. renderRecordingStorage stamps the tone, so
   the tone has to be visible: without these rules "Browser storage is FULL — a
   recording started now can stop at any moment" rendered in --ink-faint, the
   faintest text on the screen, pixel-identical to the calm state it replaced. */
.arm-disk[data-storage-tone="warn"] { color: var(--warn); }
.arm-disk[data-storage-tone="danger"] {
  color: var(--danger); font-weight: 600; font-size: var(--text-sm);
}
/* The way OUT of the ceiling sentence: the storage inventory, where the takes
   occupying that space can be seen, copied to disk, and removed one at a time by
   hand. It inherits the tone colour so it stays part of the same warning rather
   than reading as unrelated chrome. */
.arm-disk-manage {
  display: inline-block; margin-left: .4em; padding: 2px 0;
  color: inherit; text-decoration: underline; text-underline-offset: 2px;
}
.arm-disk-manage:hover, .arm-disk-manage:focus-visible { color: var(--ink); }
/* The guest's UNANSWERED save-folder offer. The row lives inside the collapsed
   "Recording storage" disclosure alongside the mic, camera and quality pickers —
   the one control that removes the recording ceiling, styled exactly like the
   settings it sits between. studio.js unfolds the disclosure for a folderless
   guest; this makes the row itself read as an offer rather than a preference. */
.save-row[data-folder-offer="open"] {
  border-left: 3px solid var(--warn); padding-left: var(--s-2);
}
.save-row[data-folder-offer="open"] .save-loc-label { color: var(--warn); }
/* Capability-refused: the same row, stated as a fact, never as an alarm — there
   is nothing this guest can press, so red would only be noise. */
.save-row[data-folder-offer="unavailable"] .save-loc-label { color: var(--ink-dim); }
/* The GUEST's persistent storage bar (lobby + recording screens). #folder-guard
   is host-only, so before this a guest had no folder control anywhere off the arm
   screen — including at the moment the 95% toast told them to use one. Sits in
   the same header slot and stays a sentence plus a button: it gates nothing. */
.guest-storage {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin: 0 0 var(--s-2); padding: var(--s-2) var(--s-3);
  border: 1px solid var(--warn); border-radius: 8px;
  background: color-mix(in srgb, var(--warn) 8%, transparent);
}
.guest-storage-text { flex: 1 1 18rem; font-size: var(--text-sm); color: var(--ink); }
.guest-storage-fix { flex: 0 0 auto; min-height: 44px; }
/* The bar now states this DEVICE's real remaining minutes rather than a constant,
   so it can be reporting anything from "about 3 hours" to "under a minute". Let
   the border carry that difference: at ten minutes or less the offer is no longer
   a suggestion. Colour only — the sentence says the number either way, and the
   bar still gates nothing. */
.guest-storage[data-tone="ok"] {
  border-color: var(--line);
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}
.guest-storage[data-tone="danger"] {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 10%, transparent);
}
/* This device's own join-time network line (rendered above .arm-disk). It reads
   as a hint but must stay legible — every warning ends with the "recording still
   works" promise, so the line stays informational, never alarm-red. */
.arm-net { margin: 0 0 var(--s-1); max-width: 560px; color: var(--ink-dim); }
.arm-save {
  display: block; align-items: normal; margin: 0; padding: 0;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--stage-1); overflow: clip;
}
.arm-save-head { color: var(--ink); font-weight: 650; font-size: var(--text-sm); margin: 0; }
.arm-save-body {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-3); border-top: 1px solid var(--line);
}
.save-file-lbl { color: var(--ink-faint); font-size: var(--text-xs); margin: 0; }
#folder-label-lbl { color: var(--ink-dim); font-size: var(--text-sm); margin: 0; }
.save-row { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.save-loc-label { color: var(--ink-faint); font-size: var(--text-sm); }

.drive-vault {
  margin-top: var(--s-3);
  padding: var(--s-3);
  border: 1px solid color-mix(in srgb, var(--line) 76%, var(--accent) 24%);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--stage-1) 92%, var(--accent) 8%);
}
.drive-vault-title { margin: 0 0 var(--s-1); color: var(--ink); font-weight: 700; }
.drive-vault-status { margin: 0; color: var(--ink-faint); font-size: var(--text-sm); }
.drive-vault-actions { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-2); }
.drive-vault[data-phase="connected"] {
  border-color: color-mix(in srgb, var(--ok) 58%, var(--line));
}
.drive-vault[data-phase="needs-attention"],
.drive-vault[data-phase="validation-cooldown"],
.drive-vault[data-phase="error"] {
  border-color: color-mix(in srgb, var(--warn) 60%, var(--line));
}
.arm-enter { width: 100%; min-height: 48px; font-size: var(--text-lg); margin: 0; }
.arm-enter-bar {
  position: relative; z-index: 4; flex: 0 0 auto;
  width: 100%; min-width: 0; margin-inline: auto;
}

/* The green room is a viewport shell. Preview and Enter never leave the viewport;
   the long capture/settings column owns the only scroll region. */
body[data-screen="arm"] .studio-main {
  box-sizing: border-box; height: calc(100vh - var(--studio-header-height, 64px));
  height: calc(100dvh - var(--studio-header-height, 64px));
  max-height: calc(100vh - var(--studio-header-height, 64px));
  max-height: calc(100dvh - var(--studio-header-height, 64px));
  padding-block: var(--s-3); overflow: hidden;
}
body[data-screen="arm"] .studio-columns,
body[data-screen="arm"] .studio-screens,
body[data-screen="arm"] #arm-screen,
body[data-screen="arm"] .arm,
body[data-screen="arm"] .arm-lobby {
  box-sizing: border-box; width: 100%; max-width: 100%; min-width: 0; min-height: 0; height: 100%;
}
body[data-screen="arm"] .studio-screens { display: flex; flex-direction: column; }
body[data-screen="arm"] #folder-guard:not([hidden]) {
  flex: 0 0 auto; max-height: min(42vh, 360px); max-height: min(42dvh, 360px); overflow: auto;
}
body[data-screen="arm"] #arm-screen { flex: 1 1 auto; }
body[data-screen="arm"] .arm-lobby {
  grid-template-rows: auto minmax(0, 1fr); align-items: stretch; gap: var(--s-3);
}
body[data-screen="arm"] .arm-preview {
  align-self: start; width: 100%; max-width: min(100%, 50vh);
  max-width: min(100%, 50dvh); max-height: 100%; margin-inline: auto;
}
body[data-screen="arm"] .arm-preview-foot {
  max-width: min(100%, 50vh); max-width: min(100%, 50dvh);
}
body[data-screen="arm"] .arm-enter-bar {
  max-width: min(100%, 50vh); max-width: min(100%, 50dvh);
}
body[data-screen="arm"] .arm-panel { height: 100%; max-height: 100%; }
.arm-settings-scroll > * { flex: 0 0 auto; }
.arm-settings-scroll > *, .cap-hud-mount { min-width: 0; max-width: 100%; }
.cap-hud-mount { overflow-x: hidden; }

/* Two columns are allowed only when the content rectangle leaves at least 560px
   for the preview beside the 400px settings panel and gap. */
@media (min-width: 1040px) {
  body[data-screen="arm"] .arm-lobby {
    grid-template-columns: minmax(560px, 1fr) minmax(320px, 400px);
    grid-template-rows: minmax(0, 1fr); gap: var(--s-5);
  }
  body[data-screen="arm"] .arm-preview-column {
    position: sticky; top: 0; align-self: start; width: 100%; max-height: 100%;
  }
  body[data-screen="arm"] .arm-preview,
  body[data-screen="arm"] .arm-preview-foot,
  body[data-screen="arm"] .arm-enter-bar {
    width: 100%; max-width: none;
  }
  body[data-screen="arm"] .arm-preview {
    max-height: min(64vh, 640px); max-height: min(64dvh, 640px);
    margin-inline: 0;
  }
}
/* Android landscape has enough horizontal room for the same two-pane flow, but
   not enough height to spend half the viewport stacking preview above settings. */
@media (min-width: 640px) and (max-width: 1039px) and (max-height: 620px) {
  body[data-screen="arm"] .arm-lobby {
    grid-template-columns: minmax(270px, 1fr) minmax(280px, 400px);
    grid-template-rows: minmax(0, 1fr); gap: var(--s-3);
  }
  body[data-screen="arm"] .arm-preview-column {
    align-self: start; width: 100%; max-height: 100%;
  }
  body[data-screen="arm"] .arm-preview,
  body[data-screen="arm"] .arm-preview-foot,
  body[data-screen="arm"] .arm-enter-bar {
    width: 100%; max-width: none; margin-inline: 0;
  }
  body[data-screen="arm"] .arm-preview { max-height: calc(100dvh - var(--studio-header-height, 64px) - 84px); }
}
@media (max-width: 1039px) {
  body.studio .studio-main { padding-inline: clamp(var(--s-3), 4vw, var(--s-5)); }
}
@media (max-height: 560px) {
  body[data-screen="arm"] .studio-main { padding-block: var(--s-2); }
  body[data-screen="arm"] .arm-lobby { gap: var(--s-2); }
  body[data-screen="arm"] .arm-preview-column { gap: var(--s-1); }
}
@media (max-width: 560px) {
  .arm-fields { grid-template-columns: 1fr; }
  .arm-fields label, .arm-meter-label { margin-bottom: calc(var(--s-1) * -1); }
  /* Keep the kicker and title on the same baseline on phones too. A previous
     column override made this heading appear shifted and pushed setup controls. */
  .arm-panel-head { align-items: baseline; flex-direction: row; justify-content: flex-start; }
  .arm-panel-head .kicker { font-size: 10px; }
  .arm-info-disclosure > summary, .arm-save > summary, .qr-card > summary { min-height: 44px; }
}

/* ── REC liveness pill (top-center of the stage, recording only) ──────────── */
.rec-live {
  display: none; align-items: center; gap: var(--s-2);
  background: var(--stage-2); border: 1px solid var(--line);
  border-radius: var(--r-chip); padding: 6px 14px; box-shadow: var(--shadow-card);
}
body[data-screen="recording"] .rec-live { display: inline-flex; }
.rec-live-dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--rec);
  box-shadow: 0 0 0 4px var(--rec-ring); animation: chip-pulse 1s ease-in-out infinite;
}
.rec-live-label { font-weight: 800; letter-spacing: .06em; color: var(--rec); font-size: var(--text-xs); }
.rec-live-time { font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 700; font-size: var(--text-sm); }

/* ── Tile grid — the stage floor ──────────────────────────────────────────── */
.tile-grid {
  display: grid; gap: var(--s-4);
  grid-template-columns: 1fr; width: 100%;
  max-width: 860px; margin-inline: auto; justify-content: center;
}
.tile-grid[data-count="1"] { max-width: 560px; }
.tile-grid[data-count="2"] { grid-template-columns: repeat(2, 1fr); max-width: 820px; }
.tile-grid[data-count="3"] { grid-template-columns: repeat(3, 1fr); }
.tile-grid[data-count="4"] { grid-template-columns: repeat(2, 1fr); max-width: 760px; }
/* 5 → three across the top, two centered below (6-col base, each tile spans 2). */
.tile-grid[data-count="5"] { grid-template-columns: repeat(6, 1fr); }
.tile-grid[data-count="5"] > * { grid-column: span 2; }
.tile-grid[data-count="5"] > *:nth-child(4) { grid-column: 2 / span 2; }
.tile-grid[data-count="5"] > *:nth-child(5) { grid-column: 4 / span 2; }
@media (max-width: 760px) {
  .tile-grid[data-count] { grid-template-columns: 1fr; }
  .tile-grid[data-count="5"] > * { grid-column: auto; }
}

.tile {
  position: relative; aspect-ratio: 16 / 9;
  background: var(--stage-2); border: 1px solid var(--line);
  border-radius: var(--r-tile); overflow: hidden; box-shadow: var(--shadow-tile);
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
.tile-self:hover { transform: translateY(-2px); box-shadow: var(--shadow-pop); }
.tile video {
  width: 100%; height: 100%; object-fit: cover;
  background: #000; display: block; /* letterbox, not a themed surface */
}
.tile-recording {
  border-color: var(--rec);
  box-shadow: inset 0 0 0 2px var(--rec), 0 0 0 3px var(--rec-ring), var(--shadow-tile);
}

/* Name chip bottom-left (low glass pill); badges bottom-right. */
.tile-overlay {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--s-2); padding: var(--s-2); background: none; pointer-events: none;
}
.tile-name {
  color: #fff; font-size: var(--text-sm); font-weight: 600;
  background: rgba(0, 0, 0, .5); backdrop-filter: blur(6px);
  border-radius: var(--r-chip); padding: 3px 10px; max-width: 68%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tile-chip {
  font-size: var(--text-xs); font-weight: 700; padding: 2px 8px;
  border-radius: var(--r-chip); white-space: nowrap;
  background: var(--stage-3); color: var(--ink-dim); border: 1px solid var(--line);
}
/* Semantic rec-state chips — shared by tiles and the participants panel. Defined
   AFTER the base .tile-chip/.pp-chip so they win on equal specificity. */
.chip-idle { background: var(--stage-3); color: var(--ink-dim); border: 1px solid var(--line); }
.chip-countdown { background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-line); animation: chip-pulse 1s ease-in-out infinite; }
.chip-recording { background: var(--rec); color: var(--on-record); border: 1px solid var(--rec); }
.chip-stopped { background: var(--stage-3); color: var(--ink-faint); border: 1px solid var(--line); }
/* ‼ NOT A STATE A DEVICE REPORTS — the state the room infers when it can no longer
   ask (see REC_CHIP in session-ui.js). It must not read as REC and it must not read
   as calm: a warning face, on both the tile and the People panel row. */
.chip-unknown { background: color-mix(in srgb, var(--warn) 12%, var(--stage-3)); color: var(--warn); border: 1px dashed color-mix(in srgb, var(--warn) 55%, transparent); }
@keyframes chip-pulse { 50% { opacity: 0.45; } }

.tile-meter { position: absolute; left: 0; right: 0; top: 0; height: 4px; background: transparent; }
.tile-meter-fill { display: block; height: 100%; width: 0; background: var(--primary); transition: width 0.08s linear; }

.tile-conn {
  position: absolute; top: var(--s-2); right: var(--s-2);
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--ink-faint); box-shadow: 0 0 0 2px var(--stage-2);
}
.tile-conn.peer-connected { background: var(--ok); }
.tile-conn.peer-connecting { background: var(--primary); animation: chip-pulse 1s ease-in-out infinite; }
.tile-conn.peer-failed { background: var(--rec); }
.tile-conn.peer-closed { background: var(--ink-faint); }

.tile-badges { display: inline-flex; align-items: center; gap: var(--s-1); }
.tile-muted {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  color: var(--on-accent); background: var(--accent); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
.tile-muted svg { display: block; }

.tile-xfer {
  font-size: var(--text-xs); font-weight: 700; padding: 2px 8px;
  border-radius: var(--r-chip); white-space: nowrap;
  color: var(--ink); background: var(--stage-2); border: 1px solid var(--accent-line);
}
.tile-xfer.xfer-ok { border-color: var(--line); color: var(--ok); }

.tile-camoff {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: var(--stage-2);
}
.tile-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22%; min-width: 44px; max-width: 96px; aspect-ratio: 1;
  border-radius: 50%; background: var(--grad-ember); color: var(--on-accent);
  font-weight: 700; font-size: var(--text-xl); text-transform: uppercase;
}

/* Per-peer LOCAL volume control (remote tiles only). */
.tile-vol {
  position: absolute; top: var(--s-2); left: var(--s-2);
  display: flex; align-items: center; gap: var(--s-1);
  padding: var(--s-1) var(--s-2); border-radius: var(--r-chip);
  background: rgba(0, 0, 0, 0.45); opacity: 0; transition: opacity 0.15s ease;
}
.tile:hover .tile-vol, .tile:focus-within .tile-vol { opacity: 1; }
/* Touch devices have no hover — the per-peer volume/mute control would be
   invisible and untappable. Keep it always visible there so it works on phones. */
@media (hover: none) {
  .tile-vol { opacity: 1; }
}
.vol-mute {
  display: inline-flex; align-items: center; justify-content: center; padding: 0;
  width: 22px; height: 22px; background: transparent; border: none; color: #fff; cursor: pointer;
}
.vol-mute:hover { color: var(--accent); background: transparent; }
.vol-mute.is-muted { color: var(--accent); }
.vol-mute svg { display: block; }
.vol-slider { width: 80px; margin: 0; accent-color: var(--accent); }

/* ── Floating control bar ─────────────────────────────────────────────────── */
.controls {
  position: fixed; left: 50%; transform: translateX(-50%);
  /* Lift clear of the home indicator / notch on phones so the bar isn't cut off. */
  bottom: max(var(--s-5), env(safe-area-inset-bottom));
  box-sizing: border-box;
  width: max-content; max-width: calc(100% - var(--s-4));
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--s-3);
  background: var(--stage-1); border: 1px solid var(--line-strong);
  border-radius: var(--r-control); padding: var(--s-2) var(--s-3);
  padding-bottom: max(var(--s-2), env(safe-area-inset-bottom));
  box-shadow: var(--shadow-bar); backdrop-filter: blur(8px); z-index: 40;
}

/* Circular icon buttons. */
.io-btn {
  display: none; align-items: center; justify-content: center;
  width: 48px; height: 48px; padding: 0; border-radius: 50%;
  background: var(--stage-2); color: var(--ink-dim); border: 1px solid var(--line);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
body[data-screen="lobby"] .io-btn,
body[data-screen="recording"] .io-btn { display: inline-flex; }
.io-btn:hover { background: var(--stage-3); color: var(--ink); }
.io-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.io-btn .io-icon { display: inline-flex; align-items: center; }
.io-btn .io-off { display: none; }
.io-btn .io-label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.io-btn.is-off { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }
.io-btn.is-off:hover { background: var(--accent-soft); }
.io-btn.is-off .io-on { display: none; }
.io-btn.is-off .io-off { display: inline-flex; }
/* A dead control still has to read as a control (moment-btn set this precedent);
   the WHY always lives on the title, never in silence. */
.io-btn:disabled { opacity: .45; cursor: not-allowed; }
.io-btn:disabled:hover { background: var(--stage-2); color: var(--ink-dim); }

/* PHONE: this bar was ALREADY over budget before "+ camera" / "+ screen" — mic,
   camera, captions and flag are 4×48px + 3 gaps + the Record hero (~130px) + padding
   ≈ 394px against a 375px viewport, and a fixed 50%-translated bar clips off BOTH
   ends with no way to scroll to what fell off. Six circles would be ~514px. So on a
   phone the row wraps instead: the icons take the first line, Record/Stop keeps a
   line of its own (it is the one control that must never be the thing that fell off),
   and the bar is capped to the viewport. Targets stay ≥44px. The two fixed overlays
   that float just above the bar are lifted to clear the taller stack. */
@media (max-width: 620px) {
  .controls {
    flex-wrap: wrap; justify-content: center;
    /* `width` is load-bearing, not decoration: the bar is position:fixed with
       left:50%, so its shrink-to-fit "available width" is only HALF the viewport —
       leave it auto and a wrapping bar collapses to ~188px and four stacked rows.
       max-content sizes it to the row it wants, capped at the viewport. The cap is a
       PERCENT, not 100vw: for a fixed box a percentage resolves against the initial
       containing block, so it excludes the scrollbar that 100vw includes. And
       box-sizing must be spelled out: .controls computes to content-box here, so an
       unqualified max-width caps the CONTENT and the 12px padding + 1px border still
       push 26px past it — which is exactly how far it hung off the screen.) */
    width: max-content; max-width: calc(100% - var(--s-4));
    gap: var(--s-2);
  }
  .io-btn { width: 44px; height: 44px; }
}

/* Record — the hero, resting slightly larger than its siblings. */
.record-btn, .stop-btn, .guest-wait { display: none; }
body.is-host[data-screen="lobby"] .record-btn { display: inline-flex; }
body:not(.is-host)[data-screen="lobby"] .guest-wait { display: inline-flex; }
body[data-screen="recording"] .stop-btn { display: inline-flex; }
.record-btn {
  align-items: center; gap: var(--s-2);
  height: 52px; padding: 0 var(--s-5); border: none; border-radius: var(--r-btn);
  background: var(--grad-ember); color: var(--on-accent); font-size: var(--text-base); font-weight: 700;
  box-shadow: var(--shadow-accent); transform: scale(1.02);
  transition: filter var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.record-btn:hover { background: var(--grad-ember); filter: brightness(1.06); transform: scale(1.02) translateY(-1px); }
.record-btn:active { transform: scale(.99); }
.record-btn:focus-visible { outline: none; box-shadow: var(--focus-ring), var(--shadow-accent); }
.rec-dot { width: 12px; height: 12px; border-radius: 50%; background: #fff; display: inline-block; }
.stop-btn {
  align-items: center; gap: var(--s-2);
  height: 52px; padding: 0 var(--s-5); border: none; border-radius: var(--r-btn);
  background: var(--rec); color: var(--on-record); font-size: var(--text-base); font-weight: 700;
  box-shadow: 0 6px 22px color-mix(in srgb, var(--rec) 40%, transparent);
}
.stop-btn::before { content: ""; width: 12px; height: 12px; border-radius: 3px; background: #fff; display: inline-block; }
.stop-btn:hover { background: var(--rec); filter: brightness(1.06); }
.stop-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.guest-wait {
  align-items: center; color: var(--ink-dim); font-size: var(--text-sm);
  background: var(--stage-2); border: 1px solid var(--line);
  border-radius: var(--r-chip); padding: 8px 16px; margin: 0;
}

/* ── Self-guest + dev test-sink banners ───────────────────────────────────── */
.self-guest-banner {
  margin: var(--s-2) auto 0; max-width: 42rem; padding: var(--s-2) var(--s-4);
  text-align: center; font-size: var(--text-sm); color: var(--ink);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: var(--r-card);
}
.dev-testsink-banner {
  /* Informational only — it must never eat a click meant for UI beneath it
     (it sat over the editor-mode bar and blocked Back to Studio, #68). */
  pointer-events: none;
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  padding: 4px 10px; text-align: center; font-size: var(--text-sm); font-weight: 700;
  color: var(--on-accent); background: var(--accent);
}

/* ── HARD FOLDER GUARD banner (host) ──────────────────────────────────────── */
.folder-guard {
  max-width: 1180px; margin: 0 auto var(--s-2); padding: 0; overflow: clip;
  border-radius: var(--r-card); border: 1px solid var(--line); background: var(--stage-2);
}
.folder-guard-details,
.folder-guard-details[open] {
  display: block; margin: 0; padding: 0; overflow: visible;
  border-radius: inherit; background: transparent;
}
.folder-guard-summary {
  box-sizing: border-box; display: flex; align-items: center; gap: var(--s-2);
  min-width: 0; min-height: 40px; margin: 0; padding: var(--s-2) var(--s-3);
  color: var(--ink); background: transparent; cursor: pointer; list-style: none;
  font-size: var(--text-sm); font-weight: 700; line-height: 1.2;
}
.folder-guard-details[open] > .folder-guard-summary { margin: 0; }
.folder-guard-summary::-webkit-details-marker { display: none; }
.folder-guard-summary::marker { content: ""; }
.folder-guard-summary:hover, .folder-guard-summary:focus { text-decoration: none; }
.folder-guard-summary:focus-visible { outline: none; box-shadow: inset var(--focus-ring); }
.folder-guard-state {
  width: 9px; height: 9px; flex: 0 0 auto; border-radius: 50%;
  background: var(--ink-faint); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink-faint) 16%, transparent);
}
.folder-guard-summary-text {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.folder-guard-chevron {
  flex: 0 0 auto; color: var(--ink-faint); transition: transform 140ms ease;
}
.folder-guard-details[open] .folder-guard-chevron { transform: rotate(180deg); }
.folder-guard-panel {
  display: grid; gap: var(--s-3); margin: 0; padding: var(--s-3);
  border-top: 1px solid var(--line); background: color-mix(in srgb, var(--stage-1) 58%, transparent);
}
.folder-guard-text { margin: 0; color: var(--ink-dim); font-size: var(--text-sm); line-height: 1.45; }
.folder-guard-path-row {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 3px; min-width: 0;
  padding: var(--s-2) var(--s-3); border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--stage-1);
}
.folder-guard-path-label {
  color: var(--ink-faint); font-size: var(--text-xs); font-weight: 750;
  letter-spacing: .055em; text-transform: uppercase;
}
.folder-guard-path {
  display: block; min-width: 0; padding: 0; color: var(--ink); background: transparent;
  font-size: var(--text-sm); overflow-wrap: anywhere; word-break: break-word;
}
.folder-guard-path-note { color: var(--ink-faint); font-size: var(--text-xs); line-height: 1.35; }
.folder-guard-actions { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.folder-guard-actions > button {
  min-height: 40px; margin: 0; padding: var(--s-2) var(--s-3); font-size: var(--text-sm);
}
.folder-guard.is-ok {
  border-color: color-mix(in srgb, var(--ok) 55%, transparent);
  background: color-mix(in srgb, var(--ok) 10%, var(--stage-2));
}
.folder-guard.is-ok .folder-guard-state { background: var(--ok); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 18%, transparent); }
.folder-guard.is-warn {
  border-color: color-mix(in srgb, var(--warn) 60%, transparent);
  background: color-mix(in srgb, var(--warn) 14%, var(--stage-2));
}
.folder-guard.is-warn .folder-guard-state { background: var(--warn); box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 18%, transparent); }
.folder-guard.is-blocked {
  border-color: color-mix(in srgb, var(--danger) 65%, transparent);
  background: color-mix(in srgb, var(--danger) 15%, var(--stage-2));
}
.folder-guard.is-blocked .folder-guard-state { background: var(--danger); box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 18%, transparent); }
.folder-guard.is-blocked .folder-guard-summary-text,
.folder-guard.is-warn .folder-guard-summary-text { font-weight: 750; }
.folder-guard-hatch {
  display: flex; align-items: flex-start; gap: var(--s-2);
  margin: 0; font-size: var(--text-xs); color: var(--ink-dim); cursor: pointer;
}
.folder-guard-hatch input { margin-top: 2px; flex: 0 0 auto; }
.folder-guard-recover { align-self: flex-start; }
@media (pointer: coarse) {
  .folder-guard-summary, .folder-guard-actions > button { min-height: 44px; }
}

/* ── Summary: process-feedback + recovery panel ───────────────────────────── */
.summary-recovery {
  margin: var(--s-4) 0; padding: var(--s-4);
  border-radius: var(--r-card); border: 1px solid var(--line); background: var(--stage-2);
  display: flex; flex-direction: column; gap: var(--s-3);
}
.summary-recovery.is-blocked {
  border-color: color-mix(in srgb, var(--danger) 65%, transparent);
  background: color-mix(in srgb, var(--danger) 15%, var(--stage-2));
}
.summary-recovery.is-warn {
  border-color: color-mix(in srgb, var(--warn) 60%, transparent);
  background: color-mix(in srgb, var(--warn) 14%, var(--stage-2));
}
.summary-recovery-msg { margin: 0; font-size: var(--text-sm); color: var(--ink); }
.summary-recovery-btn { align-self: flex-start; }

.recording-repair-progress {
  width: min(100%, 34rem); display: grid; grid-template-columns: minmax(7rem, 12rem) 1fr;
  align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-3);
  border: 1px solid var(--line); border-radius: var(--r-control); background: var(--stage-1);
  color: var(--ink-dim); font-size: var(--text-xs); line-height: 1.35;
}
.recording-repair-progress progress { width: 100%; height: .65rem; accent-color: var(--accent); }
.recording-repair-progress[data-phase="complete"] {
  border-color: color-mix(in srgb, var(--ok) 55%, transparent); color: var(--ok);
}
.recording-repair-progress[data-phase="failed"] {
  border-color: color-mix(in srgb, var(--danger) 55%, transparent); color: var(--danger);
}
@media (max-width: 620px) {
  .recording-repair-progress { grid-template-columns: 1fr; }
}

/* ── Countdown overlay ────────────────────────────────────────────────────── */
.countdown-overlay {
  position: fixed; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(10, 10, 12, .72); backdrop-filter: blur(8px); z-index: 50;
}
.countdown-num {
  display: flex; align-items: center; justify-content: center;
  width: 15rem; height: 15rem; border-radius: 50%;
  border: 2px solid var(--accent-line);
  font-size: 8rem; font-weight: 800; line-height: 1; color: var(--ink);
  text-shadow: 0 0 24px color-mix(in srgb, var(--accent) 60%, transparent);
  box-shadow: 0 0 60px color-mix(in srgb, var(--accent) 38%, transparent);
  animation: cd-tick 1s var(--ease-out) infinite;
}
@keyframes cd-tick { 0% { transform: scale(1.12); opacity: .5; } 30% { transform: scale(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .countdown-num { animation: none; } }

/* ── Summary — "recording complete" card ──────────────────────────────────── */
.summary { max-width: 640px; margin-inline: auto; }
#summary-title { display: flex; align-items: center; gap: var(--s-3); }
#summary-title::before {
  content: "✓"; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--grad-ember); color: var(--on-accent); font-size: var(--text-lg); font-weight: 800;
  box-shadow: var(--shadow-accent);
}
body[data-post="collecting"] #summary-title::before {
  content: "…"; background: var(--stage-3); color: var(--warn); border: 1px solid var(--line); box-shadow: none;
}
body[data-post="recovery-required"] #summary-title::before {
  content: "!"; background: color-mix(in srgb, var(--danger) 18%, var(--stage-2)); color: var(--danger); box-shadow: none;
}
.summary-stats {
  display: grid; grid-template-columns: max-content 1fr; align-items: center;
  gap: 0 var(--s-5);
  background: var(--stage-2); border: 1px solid var(--line);
  border-radius: var(--r-card); padding: var(--s-2) var(--s-5); box-shadow: var(--shadow-card);
}
.summary-stats dt, .summary-stats dd { margin: 0; padding: var(--s-3) 0; border-bottom: 1px solid var(--line); }
.summary-stats dt { color: var(--ink-dim); font-size: var(--text-sm); }
.summary-stats dd { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; }
.summary-stats dt:nth-last-of-type(1), .summary-stats dd:nth-last-of-type(1) { border-bottom: none; }
.stat-status {
  display: inline-block; font-size: var(--text-xs); font-weight: 700;
  padding: 2px 10px; border-radius: var(--r-chip);
  background: var(--stage-3); color: var(--ink-dim); border: 1px solid var(--line);
}
.stat-status.is-verified { background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.stat-status.is-uploading { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.stat-status.is-failed { background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.summary-warn { color: var(--accent); font-size: var(--text-sm); }

.summary-primary { display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap; margin: var(--s-5) 0 var(--s-3); }
.summary-editor-primary { text-decoration: none; font-size: var(--text-lg); font-weight: 700; padding: var(--s-4) var(--s-8); }
/* #33 — "Rejoin the session". The one caller of this full-page surface is a guest
   who reopened their invite link with an undelivered take; once that take has
   landed and the session is still live, getting back into the call is THE action,
   so it takes the whole row above the editor link instead of sitting beside it. */
.summary-enter-room {
  flex: 1 1 100%; justify-content: center; text-align: center;
  font-size: var(--text-lg); font-weight: 700; padding: var(--s-4) var(--s-8); min-height: 44px;
}
.summary-editor-primary.is-waiting { opacity: .72; cursor: wait; }
.summary-editor-wait { flex: 1 1 100%; margin: 0; color: var(--ink-dim); font-size: var(--text-sm); }
.summary-newtake { text-decoration: none; }
/* "What you get" — discoverability line under Open-in-editor: names the render
   outputs so the export flow is visible without opening the session folder. */
.summary-whatyouget {
  flex: 1 1 100%; margin: 0; color: var(--ink-dim); font-size: var(--text-sm); line-height: 1.5;
}
.summary-whatyouget strong { color: var(--ink); font-weight: 600; }
.summary-save-note { color: var(--ink-dim); font-size: var(--text-sm); margin: var(--s-2) 0; }
.summary-download { margin-bottom: var(--s-2); }
.summary-actions {
  display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap;
  margin-top: var(--s-3); padding-top: var(--s-3); border-top: 1px solid var(--line);
}
.summary-home { display: inline-block; color: var(--ink-dim); }

/* Multi-take list — compact sub-card. */
.takes-list-wrap {
  max-width: 640px; margin-bottom: var(--s-5);
  background: var(--stage-2); border: 1px solid var(--line);
  border-radius: var(--r-card); padding: var(--s-3) var(--s-4);
}
.takes-list-title { color: var(--ink-dim); font-size: var(--text-sm); font-weight: 600; margin: 0 0 var(--s-2); }
.takes-list { list-style: none; margin: 0; padding: 0; }
.takes-list li { padding: var(--s-2); border-radius: var(--r-sm); color: var(--ink-dim); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.takes-list li.is-current { background: var(--stage-3); color: var(--ink); font-weight: 600; }
.takes-current-tag { color: var(--ink-faint); font-weight: 400; }

/* ── Transfer status (summary) — sub-cards ────────────────────────────────── */
.summary-transfer { max-width: 640px; margin-top: var(--s-5); }
.xfer-status {
  background: var(--stage-2); border: 1px solid var(--line);
  border-left: 3px solid var(--accent); border-radius: var(--r-card);
  padding: var(--s-4) var(--s-5);
}
.xfer-status p { margin: 0 0 var(--s-2); color: var(--ink); }
.xfer-status p:last-child { margin-bottom: 0; }
.xfer-head { color: var(--ink-dim); font-size: var(--text-sm); font-weight: 600; }
.xfer-done { color: var(--ok); font-weight: 600; }
/* Stalled/terminal transfer rows (camera + screen lists, guest terminal line):
   caution amber — the row's wording carries the verdict, the color the salience. */
.xfer-warn { color: var(--warn) !important; font-weight: 600; }
.xfer-list { margin: 0; padding-left: var(--s-5); color: var(--ink); }
.xfer-list li { margin: var(--s-1) 0; font-variant-numeric: tabular-nums; }
.xfer-route { color: var(--ink-dim) !important; font-size: var(--text-sm); }
.xfer-meter { display: block; width: 100%; height: 10px; margin: var(--s-2) 0 var(--s-3); accent-color: var(--ok); }
.xfer-inflight { font-variant-numeric: tabular-nums; }
.xfer-audio-priority { color: var(--warn) !important; font-weight: 600; }
.xfer-ready { margin-top: var(--s-3) !important; }

/* ── Participants panel ───────────────────────────────────────────────────── */
.participants-panel { display: none; }
body[data-screen="lobby"] .participants-panel,
body[data-screen="recording"] .participants-panel,
body[data-screen="summary"] .participants-panel { display: block; }
.participants-panel.pp {
  flex: 0 0 300px; position: sticky; top: var(--s-5);
  background: var(--stage-1); border: 1px solid var(--line);
  border-radius: var(--r-card); box-shadow: var(--shadow-card); overflow: hidden;
}
.pp-header {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  padding: var(--s-2) var(--s-4); background: var(--stage-2); border-bottom: 1px solid var(--line);
}
.pp-heading { display: inline-flex; align-items: center; gap: var(--s-2); }
.pp-title { font-weight: 600; color: var(--ink); font-size: var(--text-sm); }
.pp-count {
  font-size: var(--text-xs); font-weight: 700; color: var(--ink-dim);
  background: var(--stage-3); border: 1px solid var(--line);
  border-radius: var(--r-chip); padding: 1px 8px; font-variant-numeric: tabular-nums;
}
.pp-toggle { padding: 0 var(--s-2); line-height: 1.6; font-size: var(--text-sm); }
.pp-body { padding: 0 var(--s-4) var(--s-2); }
.pp-collapsed .pp-body { display: none; }

.pp-nag {
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: var(--r-sm); padding: var(--s-3); margin-top: var(--s-3);
}
.pp-nag-text { margin: 0 0 var(--s-2); font-size: var(--text-sm); color: var(--ink); }
.pp-nag-btn { font-size: var(--text-sm); }

.pp-row { display: flex; gap: var(--s-2); padding: var(--s-3) 0; border-bottom: 1px solid var(--line); }
.pp-row:last-child { border-bottom: none; }
.pp-main { flex: 1 1 auto; min-width: 0; }

.pp-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--ink-faint); flex: 0 0 auto; margin-top: 5px; }
.pp-dot.peer-connected { background: var(--ok); }
.pp-dot.peer-connecting { background: var(--primary); animation: chip-pulse 1s ease-in-out infinite; }
.pp-dot.peer-failed { background: var(--rec); }
.pp-dot.peer-closed { background: var(--ink-faint); }

.pp-l1 { display: flex; align-items: center; gap: var(--s-1); }
.pp-name { font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.pp-chip {
  font-size: var(--text-xs); font-weight: 700; padding: 1px 8px; border-radius: var(--r-chip);
  white-space: nowrap; background: var(--stage-3); color: var(--ink-dim); border: 1px solid var(--line);
}
.pp-role.is-host { background: var(--grad-ember); color: var(--on-accent); border: none; }
/* Waiting room — opened the link, has not pressed Enter studio. Deliberately
   quiet: this row is a heads-up that somebody is coming, not a participant. */
.pp-role.is-waiting { background: var(--stage-3); color: var(--ink-dim); border: 1px dashed var(--line); }
.pp-is-waiting { opacity: .72; }
.pp-dot.peer-waiting { background: var(--ink-dim); opacity: .55; }
/* "Audio only" — no camera at all, as distinct from a camera that is switched
   off. The two look identical as icons, so the roster spells this one out. */
.pp-chip.pp-audio-only { background: rgba(0, 0, 0, .35); border-color: var(--accent-line); }
.pp-chip.pp-audio-only[hidden] { display: none; }

.pp-l2 { display: flex; align-items: center; gap: var(--s-2); margin-top: 3px; }
.pp-io { display: inline-flex; align-items: center; justify-content: center; color: var(--ink-dim); }
.pp-io.is-off { color: var(--accent); }
.pp-io svg { display: block; }
.pp-save { font-size: var(--text-xs); color: var(--ink-dim); margin-left: auto; }
.pp-save.is-ok { color: var(--ok); font-weight: 600; }

/* Join-time connectivity verdict line (§4): warn = caution amber (unconfirmed),
   bad = the red the UI already uses for a pair that cannot connect. */
.pp-net { margin: var(--s-1) 0 0; font-size: var(--text-xs); color: var(--ink-dim); }
.pp-net.is-warn { color: var(--warn); }
.pp-net.is-bad { color: var(--danger); font-weight: 600; }

/* Control-plane readiness (fleet finding #1): whether a RECORD COMMAND can
   reach this person at all. Deliberately louder than the delivery verdict above
   — a person who can't receive the command loses the whole take, not just the
   fast delivery path. A leading dot echoes the row's live dot so the two facts
   read as siblings rather than one contradicting the other. */
.pp-ctrl {
  margin: var(--s-1) 0 0; font-size: var(--text-xs); color: var(--ink-dim);
  display: flex; align-items: center; gap: 6px;
}
.pp-ctrl::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}
.pp-ctrl.is-ok { color: var(--ok); }
.pp-ctrl.is-warn { color: var(--warn); font-weight: 600; }
.pp-ctrl.is-warn::before { animation: chip-pulse 1s ease-in-out infinite; }
.pp-ctrl.is-bad { color: var(--danger); font-weight: 700; }

/* The room-level "who can't receive a take yet" banner, above the roster. */
.pp-readiness {
  margin: var(--s-3) 0 0; padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm); font-size: var(--text-sm); line-height: 1.4;
  border: 1px solid color-mix(in srgb, var(--warn) 55%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, var(--stage-2));
  color: var(--ink);
}
.pp-readiness[data-level="bad"] {
  border-color: color-mix(in srgb, var(--danger) 55%, transparent);
  background: color-mix(in srgb, var(--danger) 12%, var(--stage-2));
}
.pp-readiness[hidden] { display: none; }

.pp-xfer {
  margin-top: var(--s-2); padding: 7px 8px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: color-mix(in srgb, var(--stage-2) 82%, transparent);
}
.pp-xfer.is-done { border-color: color-mix(in srgb, var(--ok) 40%, var(--line)); }
.pp-xfer.is-warn { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
.pp-xhead { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-2); }
.pp-xtitle { min-width: 0; color: var(--ink); font-size: var(--text-xs); font-weight: 750; }
.pp-xpct { flex: 0 0 auto; color: var(--primary); font-size: var(--text-xs); font-weight: 800; font-variant-numeric: tabular-nums; }
.pp-xpct.is-done { color: var(--ok); }
.pp-bar { height: 6px; border-radius: var(--r-chip); background: color-mix(in srgb, #fff 6%, transparent); overflow: hidden; }
.pp-xhead + .pp-bar { margin-top: 5px; }
.pp-bar-fill { display: block; height: 100%; width: 0; background: var(--grad-ember); transition: width 0.2s ease; }
.pp-bar.is-done .pp-bar-fill { background: var(--ok); }
.pp-bar.is-stalled .pp-bar-fill { background: var(--ink-faint); }
.pp-xlabel { display: block; font-size: var(--text-xs); color: var(--ink-dim); margin-top: 4px; font-variant-numeric: tabular-nums; }
.pp-xlabel.is-done { color: var(--ok); font-weight: 600; }
.pp-xlabel.is-warn { color: var(--accent); }
.pp-xmetrics { display: flex; flex-wrap: wrap; gap: 3px 10px; margin-top: 4px; color: var(--ink-faint); font-size: 10px; font-variant-numeric: tabular-nums; }
.pp-xmetric { white-space: nowrap; }
.pp-xamount { color: var(--ink-dim); }
.pp-xspeed::before { content: 'Speed '; }

@media (max-width: 900px) {
  .studio-columns { flex-direction: column; }
  .participants-panel.pp { position: static; flex-basis: auto; width: 100%; }
}

/* ── Toasts ───────────────────────────────────────────────────────────────── */
.toasts {
  position: fixed; bottom: var(--s-5); right: var(--s-5);
  display: flex; flex-direction: column; gap: var(--s-2);
  z-index: 100; max-width: min(90vw, 360px);
}
.toast {
  background: var(--stage-2); border: 1px solid var(--line);
  border-left: 3px solid var(--primary); border-radius: var(--r-card);
  padding: var(--s-3) var(--s-4); color: var(--ink); font-size: var(--text-sm);
  box-shadow: var(--shadow-pop); opacity: 0; transform: translateY(8px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
.toast-show { opacity: 1; transform: translateY(0); }
.toast-success { border-left-color: var(--ok); }
.toast-error { border-left-color: var(--danger); }

/* Build stamp (auto-bumped by tools/bump-build.mjs on each deploy) */
.build-stamp {
  position: fixed; right: 10px; bottom: 8px; font-size: 12px; opacity: 0.95;
  color: #fff; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
  pointer-events: none; user-select: none; z-index: 50;
}
