/* =========================================================================
   Telescoping Video RPG — design system v2 ("Cinema black")
   Near-black canvas, Inter throughout, video as hero.
   Derived from the Claude-design v2 dark spec, with our app-specific
   component classes (.timeline-clip, .pick-card, etc.) re-themed.
   ========================================================================= */

:root {
  /* === Canvas / surfaces ===
     v1's --paper/--ink names are preserved so existing inline styles in the
     templates cascade automatically. The values are now a dark UI. */
  --paper:        #0b0b0e;
  --paper-warm:   #14141a;
  --paper-deep:   #1c1c24;
  --paper-edge:   rgba(255, 255, 255, 0.08);
  --paper-stain:  rgba(255, 255, 255, 0.18);

  /* === Type / ink ===  "ink" is now near-white on the dark canvas. */
  --ink:          #f4f4f7;
  --ink-soft:     #c5c5cf;
  --ink-muted:    #8a8a96;
  --ink-faint:    #56565f;

  /* === Accents — saturated cinema palette ===
     Single hot signal (oxblood) used sparingly: REC, LIVE, primary CTA. */
  --oxblood:      #ff4438;
  --oxblood-deep: #d72c20;
  --moss:         #3dd68c;
  --amber:        #ffb84a;
  --bruise:       #8a7dff;

  /* === Type system === */
  --font-display: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-sans:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* === Elevation === */
  --shadow-card:  0 1px 0 rgba(0, 0, 0, 0.4),
                  0 2px 8px rgba(0, 0, 0, 0.25),
                  0 24px 60px -30px rgba(0, 0, 0, 0.7);
  --shadow-lift:  0 4px 12px rgba(0, 0, 0, 0.35),
                  0 28px 80px -20px rgba(0, 0, 0, 0.8);
  --shadow-glow:  0 0 0 1px rgba(255, 68, 56, 0.4),
                  0 12px 40px -8px rgba(255, 68, 56, 0.35);

  /* === Legacy compatibility aliases ===
     Older templates (authoring) reference these var names — map them onto
     the v2 system so those pages stay coherent without being touched. */
  --bg:       var(--paper);
  --panel:    var(--paper-warm);
  --panel-2:  var(--paper-deep);
  --border:   var(--paper-edge);
  --text:     var(--ink);
  --muted:    var(--ink-muted);
  --accent:   var(--oxblood);
  --warn:     var(--amber);
  --good:     var(--moss);
  --bad:      var(--oxblood);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  font-family: var(--font-sans);
  color: var(--ink);
  background: var(--paper);
  font-size: 16px;
  line-height: 1.5;
  min-height: 100vh;
  font-feature-settings: "cv11", "ss01", "ss02";
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* main is a transparent passthrough — each page owns its own width. */
main { display: block; min-height: 100vh; }

/* === Subtle canvas: soft warm/cool gradient, no noise overlay === */
.paper-bg {
  position: relative;
  background: var(--paper);
  background-image:
    radial-gradient(ellipse 80% 50% at 20% -10%, rgba(255, 68, 56, 0.06), transparent 60%),
    radial-gradient(ellipse 60% 50% at 100% 100%, rgba(138, 125, 255, 0.04), transparent 60%);
}
.paper-bg::before { content: none; }
.paper-bg > * { position: relative; z-index: 1; }

/* === Typography ===
   No serifs anywhere. Big headings get tight tracking + 600 weight. */
.display { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.025em; }
.serif   { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.02em; font-style: normal !important; }
.mono    { font-family: var(--font-mono); font-feature-settings: "ss02"; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.025em;
  margin: 0 0 12px 0;
  color: var(--ink);
}
h1 { font-size: 32px; }
h2 { font-size: 24px; }
h3 { font-size: 19px; }
h4 { font-size: 17px; }
p  { margin: 0 0 12px 0; }

/* Sober links — underlined ink, not a hot accent. Oxblood is reserved
   for REC/LIVE/primary CTA so it stays meaningful. */
a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.28);
  text-underline-offset: 2px;
}
a:hover { text-decoration-color: var(--ink); }

/* Kill leftover italic transcript / quote styling — v2 has no italics
   anywhere. Catches both `font-style:italic` and `font-style: italic`
   spacings in inline style attributes. */
[style*="italic"] {
  font-style: normal !important;
  font-family: var(--font-sans) !important;
}
em { font-style: normal; }

code {
  font-family: var(--font-mono);
  font-size: 0.85em;
  background: var(--paper-deep);
  padding: 1px 5px;
  border-radius: 4px;
}

/* === Eyebrow labels === */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--ink-muted);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.eyebrow::before {
  content: "";
  display: inline-block;
  width: 12px;
  height: 1px;
  background: currentColor;
  opacity: 0.6;
}
.eyebrow.plain::before { display: none; }

/* === Buttons — pill, tech-product feel === */
button, .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.005em;
  padding: 11px 18px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  cursor: pointer;
  border-radius: 999px;
  text-decoration: none;
  min-height: 42px;
  transition: transform 0.08s ease, background 0.12s, color 0.12s, border-color 0.12s;
  box-shadow: none;
}
button:hover, .btn:hover { background: #fff; border-color: #fff; color: #000; transform: translateY(-1px); text-decoration: none; }
button:active, .btn:active { transform: translateY(0); }
button.secondary, .btn.secondary {
  background: transparent;
  color: var(--ink);
  border-color: rgba(255, 255, 255, 0.18);
}
button.secondary:hover, .btn.secondary:hover {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.3);
  color: var(--ink);
}
button.ghost, .btn.ghost {
  background: transparent;
  color: var(--ink-soft);
  border-color: transparent;
}
button.ghost:hover, .btn.ghost:hover {
  background: rgba(255, 255, 255, 0.06);
  color: var(--ink);
}
button.danger, .btn.danger, button.bad, .btn.bad {
  background: var(--oxblood);
  border-color: var(--oxblood);
  color: #fff;
}
button.danger:hover, .btn.danger:hover, button.bad:hover, .btn.bad:hover {
  background: var(--oxblood-deep);
  border-color: var(--oxblood-deep);
  color: #fff;
}
button.warn, .btn.warn { background: var(--amber); border-color: var(--amber); color: #000; }
button:disabled, .btn:disabled { opacity: 0.35; cursor: not-allowed; transform: none; }

/* === Chips / tags — pill === */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 3px 9px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.03);
  border-radius: 999px;
  white-space: nowrap;
  vertical-align: middle;
}
.chip.solid { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.chip.good  { color: var(--moss);   border-color: rgba(61, 214, 140, 0.4); background: rgba(61, 214, 140, 0.08); }
.chip.warn  { color: var(--amber);  border-color: rgba(255, 184, 74, 0.4); background: rgba(255, 184, 74, 0.08); }
.chip.bad   { color: var(--oxblood); border-color: rgba(255, 68, 56, 0.4); background: rgba(255, 68, 56, 0.08); }
.chip.live  { color: #fff; background: var(--oxblood); border-color: var(--oxblood); }

/* === Live dot === */
.live-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  background: currentColor;
  border-radius: 50%;
  animation: pulse 1.6s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.85); }
}

/* === Cards & panels === */
.card, .panel {
  background: var(--paper-warm);
  border: 1px solid var(--paper-edge);
  border-radius: 14px;
  box-shadow: var(--shadow-card);
}
.panel { padding: 22px; margin-bottom: 20px; }
.panel-2 {
  background: var(--paper-deep);
  border: 1px solid var(--paper-edge);
  border-radius: 8px;
  padding: 12px 14px;
}

/* === Ornamental divider === */
.rule { display: flex; align-items: center; gap: 12px; color: var(--ink-faint); }
.rule::before, .rule::after { content: ""; flex: 1; height: 1px; background: currentColor; opacity: 0.4; }

/* === Form controls === */
input[type="text"], input[type="email"], input[type="number"],
input[type="password"], select, textarea {
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--paper-edge);
  border-radius: 8px;
  padding: 11px 13px;
  width: 100%;
  outline: none;
  transition: border-color 0.12s, box-shadow 0.12s, background 0.12s;
}
textarea { font-family: var(--font-sans); resize: vertical; }
input:focus, select:focus, textarea:focus {
  border-color: rgba(255, 255, 255, 0.4);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.06);
}
input::placeholder, textarea::placeholder { color: var(--ink-faint); }
label {
  display: block;
  margin: 14px 0 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* === Scrollbar === */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 6px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.2); background-clip: padding-box; }

/* === Layout helpers === */
.row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.col { display: flex; flex-direction: column; }
.muted   { color: var(--ink-muted); }
.faint   { color: var(--ink-faint); }
.tabular { font-variant-numeric: tabular-nums; }

.container        { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
.container-narrow { max-width: 920px;  margin: 0 auto; padding: 0 32px; }
.phone-wrap       { max-width: 460px;  margin: 0 auto; padding: 28px 18px 90px; }

/* Desktop-first host console: keep a min-width so the 3-column layout
   doesn't crumble; the page scrolls horizontally below it. */
.desktop-surface { min-width: 1200px; }

/* Multi-column grids used on the marketing / library surfaces. Pulled into
   a class so the @media block below can collapse them on phones — inline
   `grid-template-columns` styles outrank @media and can't be overridden. */
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr;     gap: 16px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }

/* Sidebar layout (scenario detail: scrollable content + sticky "Create
   session" card on the right). At desktop width the aside sticks at top:24px
   so the CTA stays in view while reading lore. */
.grid-sidebar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 48px;
  align-items: start;
}

/* Scene-arc row on scenario detail: [SCENE NN/T+XX | title + question | duration].
   Inline grid moved to a class so the mobile @media can re-stack it without
   fighting inline-style specificity. */
.scene-row {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) 64px;
  gap: 20px;
  padding: 18px 0;
  border-bottom: 1px solid var(--paper-edge);
  align-items: baseline;
}

/* ─────────────────────── Mobile breakpoint ────────────────────────
   The site renders desktop-first; this block is the only place that
   adjusts layout for narrow viewports. Player surfaces (join/play) use
   `.phone-wrap` which is already mobile-shaped — this block targets the
   rest (homepage, scenario library, host console, /me) so a phone
   visitor doesn't see crushed 3-column grids and an oversized hero. */
@media (max-width: 720px) {
  .container        { padding: 0 16px; }
  .container-narrow { padding: 0 16px; }
  .grid-3           { grid-template-columns: 1fr; gap: 14px; }
  .grid-2           { grid-template-columns: 1fr; gap: 14px; }
  /* Stats grid: 4-col at desktop, 2×2 on mobile (numbers read better in pairs
     than stacked 4-tall). */
  .grid-4           { grid-template-columns: 1fr 1fr; gap: 10px; }
  .grid-sidebar     { grid-template-columns: 1fr; gap: 32px; }
  /* The aside's sticky position only makes sense beside the content. Once
     stacked it IS the whole page width and sticky becomes confusing.
     `order: -1` lifts it above the main content div so the "Start a session"
     CTA sits right under the hero — players reading on a phone shouldn't
     have to scroll past the world/roles/arc to find the button. */
  .grid-sidebar > aside { position: static !important; order: -1; }
  /* Arc rows: drop the 3-column grid and let each cell own its own line.
     Title gets full width (no more 125px-wide crushed column on iPhone)
     and duration falls below in mono. */
  .scene-row        { grid-template-columns: 1fr; gap: 6px; padding: 14px 0; }
  .scene-row > :last-child { text-align: left !important; }
  /* Hero headline overflows at 54px+ on a 393px iPhone — clamp it. */
  .display-hero     { font-size: 36px !important; line-height: 1.08; }
  /* Header nav bar has a right-aligned eyebrow label (e.g. "My account",
     "Sign in") that clashes with the fixed auth widget at top-right.
     Hide it — the page heading below gives context on mobile. */
  .nav-eyebrow      { display: none; }
}

/* === Brand mark === */
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-sans); font-size: 20px; font-weight: 600;
  color: var(--ink); text-decoration: none; letter-spacing: -0.02em;
}
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 28px; height: 28px;
  background: var(--ink); color: var(--paper);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 13.5px; font-weight: 700;
  border-radius: 6px;
}

/* =========================================================================
   Cinematic cover plates — used by the scenario library card hero on the
   landing page (.stripe-art.mood-breach etc.). Renders as a moody gradient
   + vignette + film grain instead of the v1 diagonal-stripe placeholder.
   ========================================================================= */
.stripe-art {
  position: relative;
  overflow: hidden;
  background: #07070a;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  border: 1px solid var(--paper-edge);
  border-radius: 10px;
}
.stripe-art::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 45% 60% at 50% 70%, rgba(0, 0, 0, 0.8), transparent 60%),
    radial-gradient(ellipse 60% 80% at 50% 0%, rgba(255, 255, 255, 0.06), transparent 60%);
  pointer-events: none;
}
.stripe-art::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.18;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}
.stripe-art .stripe-label {
  position: relative;
  z-index: 2;
  margin: 16px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.8);
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(6px);
  padding: 5px 9px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
}

/* Mood variants — pick one per scenario card via CoverArt(mood=…). */
.stripe-art.mood-breach {
  background:
    radial-gradient(ellipse 60% 80% at 30% 20%, rgba(60, 90, 130, 0.5), transparent 60%),
    linear-gradient(180deg, #0a1018 0%, #131b26 50%, #060810 100%);
}
.stripe-art.mood-warm {
  background:
    radial-gradient(ellipse 50% 70% at 60% 30%, rgba(255, 180, 80, 0.45), transparent 60%),
    linear-gradient(180deg, #1a1208 0%, #2a1d0c 60%, #0c0805 100%);
}
.stripe-art.mood-blood {
  background:
    radial-gradient(ellipse 60% 80% at 30% 70%, rgba(255, 68, 56, 0.3), transparent 60%),
    linear-gradient(180deg, #1a0608 0%, #2a0810 50%, #0a0204 100%);
}
.stripe-art.mood-moss {
  background:
    radial-gradient(ellipse 60% 80% at 70% 30%, rgba(80, 140, 90, 0.35), transparent 60%),
    linear-gradient(180deg, #08120a 0%, #131c12 50%, #060a06 100%);
}

/* === App component classes (re-themed for v2 dark) ===================== */

/* Card that is itself a link — lifts on hover, never underlines. */
a.card-link {
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: box-shadow 0.14s ease, transform 0.1s ease, border-color 0.12s;
}
a.card-link:hover {
  text-decoration: none;
  box-shadow: var(--shadow-lift);
  transform: translateY(-2px);
  border-color: rgba(255, 255, 255, 0.18);
}

/* Radio-card pickers — clickable cards backing a hidden radio input. */
.pick-card {
  display: block;
  position: relative;
  cursor: pointer;
  padding: 14px 16px;
  margin-bottom: 10px;
  background: rgba(255, 255, 255, 0.02);
  color: var(--ink);
  border: 1px solid var(--paper-edge);
  border-radius: 12px;
  font-family: var(--font-sans);
  font-size: 14px;
  text-transform: none;
  letter-spacing: normal;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.pick-card:last-child { margin-bottom: 0; }
.pick-card input { position: absolute; opacity: 0; width: 0; height: 0; }
.pick-card:hover { background: rgba(255, 255, 255, 0.05); border-color: rgba(255, 255, 255, 0.18); }
.pick-card:has(input:checked) {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.pick-card:has(input:checked):hover { background: #fff; }
.pick-card .pc-title { font-weight: 600; font-size: 14px; }
.pick-card .pc-sub {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  margin-top: 2px;
  opacity: 0.6;
}
.pick-card .pc-desc { font-size: 12.5px; margin-top: 4px; opacity: 0.78; line-height: 1.45; }

/* Role picker cards (join page). */
.character-card {
  display: block;
  background: var(--paper-warm);
  border: 1px solid var(--paper-edge);
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 10px;
  box-shadow: var(--shadow-card);
}
.character-card.taken { opacity: 0.55; }
.character-card strong { display: block; font-family: var(--font-sans); font-size: 17px; font-weight: 600; }

/* An open role: the WHOLE card is a submit button on the join form, so a player
   types their name once (above) and taps anywhere on a role to claim it. Reset
   the native <button> look so it reads as a card, with a clear tap affordance. */
button.character-pick {
  width: 100%;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
button.character-pick:hover,
button.character-pick:focus-visible {
  border-color: var(--oxblood);
  box-shadow: 0 0 0 2px rgba(123, 30, 30, 0.12);
  outline: none;
}
.claim-cta { display: inline-block; font-size: 12.5px; font-weight: 600; color: var(--oxblood); }

/* Shared "story so far" timeline clip. Vertical stack — big video on top,
   info below, fullscreen button to the side of the video. */
.timeline-clip {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 0;
  border-bottom: 1px solid var(--paper-edge);
}
.timeline-clip:last-child { border-bottom: none; }
.timeline-clip video {
  width: 100%; max-width: 320px;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  background: #06060a;
  border-radius: 10px;
  display: block;
  border: 1px solid var(--paper-edge);
}
.timeline-clip .info { min-width: 0; }
/* Element-fullscreen must letterbox, never crop. object-fit:cover (right for
   the inline 9/16 thumbnails) follows the element into fullscreen, where it
   crop-zooms a portrait clip to fill a landscape monitor — the "zoomed in"
   desktop bug. Fullscreen keeps the same framing the clip has inline / on a
   phone. */
video:fullscreen { object-fit: contain !important; background: #000; }
video:-webkit-full-screen { object-fit: contain !important; background: #000; }
.timeline-clip .fs-btn { width: 100%; max-width: 320px; }
.timeline-clip .placeholder {
  width: 100%; max-width: 320px;
  aspect-ratio: 9 / 16;
  background: #06060a;
  border-radius: 10px;
  border: 1px solid var(--paper-edge);
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-muted);
  font-family: var(--font-mono); font-size: 10.5px;
  text-transform: uppercase; letter-spacing: 0.14em;
  text-align: center; padding: 12px;
}

/* Countdown / prompt panel (player). */
.countdown {
  font-family: var(--font-display);
  font-size: 48px; font-weight: 600; text-align: center;
  margin: 16px 0; font-variant-numeric: tabular-nums;
}
.prompt-box {
  font-family: var(--font-sans);
  font-size: 16px; line-height: 1.6;
  padding: 18px;
  background: var(--paper-warm);
  border: 1px solid var(--paper-edge);
  border-left: 3px solid var(--oxblood);
  border-radius: 8px;
  margin-bottom: 14px;
  color: var(--ink);
}

/* Desktop browser-recording preview UI. On phones the record button just
   triggers a native <input type="file" capture> — none of this applies. */
.rec-wrap {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
  margin: 12px 0 14px;
}
.rec-wrap video {
  width: 100%; max-width: 320px;
  aspect-ratio: 9 / 16;
  background: #06060a;
  border-radius: 10px;
  object-fit: cover;
  border: 1px solid var(--paper-edge);
  /* Mirror the preview only — recorded stream is unaffected */
  transform: scaleX(-1);
}
.rec-wrap .rec-hint {
  margin: 0;
  font-size: 14px;
  text-align: center;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
/* Teleprompter: a compact copy of the story prompt that sits with the camera
   preview (and the review player), so the player can read their direction
   while performing instead of scrolling back up. */
.rec-wrap .rec-prompt {
  width: 100%; max-width: 320px;
  max-height: 132px; overflow-y: auto;
  font-size: 13px; line-height: 1.55;
  padding: 10px 12px;
  background: var(--paper-warm);
  border: 1px solid var(--paper-edge);
  border-left: 3px solid var(--oxblood);
  border-radius: 8px;
  white-space: pre-wrap;
  color: var(--ink);
}
/* Review step (watch your take before submitting): show the TRUE recording —
   no mirror (that's a preview-only affordance) and no crop (contain + the
   clip's own aspect, so what you approve is what uploads). */
.rec-wrap.review video {
  transform: none;
  object-fit: contain;
  aspect-ratio: auto;
  max-height: 52vh;
}
.rec-wrap .rec-btn-row {
  display: flex;
  gap: 10px;
  width: 100%;
  max-width: 320px;
}
.rec-wrap .rec-btn-row > * { flex: 1; }
.rec-dot {
  display: inline-block; width: 12px; height: 12px;
  background: var(--paper); border-radius: 50%;
}
.rec-square {
  display: inline-block; width: 12px; height: 12px;
  background: var(--paper); border-radius: 2px;
}

/* "or upload an existing video" fallback link under the desktop Record
   button. Override the global label styling (mono uppercase form-label
   look) since this is a content link, not a form label. */
.rec-fallback { margin-top: 14px; text-align: center; }
.rec-fallback .rec-fallback-link {
  display: inline-block;
  margin: 0;
  text-transform: none;
  letter-spacing: normal;
  font-family: var(--font-sans);
  font-size: 12.5px;
  color: var(--ink-muted);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.2);
}
.rec-fallback .rec-fallback-link:hover { color: var(--ink-soft); }

/* Record button + upload progress (player). */
.record-input { display: none; }
.record-button {
  display: flex; flex-direction: column; align-items: center;
  gap: 10px; padding: 22px; font-size: 16px; width: 100%;
  background: var(--oxblood); border-color: var(--oxblood); color: #fff;
  box-shadow: 0 4px 14px rgba(255, 68, 56, 0.30), 0 0 0 6px rgba(255, 68, 56, 0.09);
}
.record-button:hover { background: var(--oxblood-deep); border-color: var(--oxblood-deep); color: #fff; }
.upload-progress {
  width: 100%; height: 8px; margin-top: 10px;
  background: var(--paper-deep); border-radius: 4px; overflow: hidden;
}
.upload-progress > div {
  height: 100%; width: 0;
  background: var(--moss);
  transition: width 0.2s ease;
}

/* HUD stat block (host header). Lives on the dark page bg in v2 (no
   inverted bar), so values use --ink (near-white) and labels --ink-muted. */
.hud-stat { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.hud-stat .v {
  font-family: var(--font-display); font-size: 26px; font-weight: 600;
  color: var(--ink); font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.hud-stat .k {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
  color: var(--ink-muted); text-transform: uppercase;
}

/* === Cinematic video frame primitive (v2 new) =========================
   Optional richer thumbnail w/ HUD label, caption, play overlay. Not yet
   adopted by .timeline-clip — kept available for future use. */
.v-frame {
  position: relative;
  overflow: hidden;
  border-radius: 10px;
  background: #06060a;
  isolation: isolate;
}
.v-frame::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 50%, rgba(0, 0, 0, 0.45) 100%);
}
.v-frame .v-hud {
  position: absolute; z-index: 2;
  top: 10px; left: 10px;
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 8px;
  background: rgba(0, 0, 0, 0.45); backdrop-filter: blur(6px);
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.v-frame .v-caption {
  position: absolute; z-index: 2;
  left: 12px; right: 12px; bottom: 12px;
  font-size: 14.5px; font-weight: 500;
  color: rgba(255, 255, 255, 0.95);
  letter-spacing: -0.01em;
}
.v-frame .v-play {
  position: absolute; z-index: 3; inset: 0;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity 0.2s;
}
.v-frame:hover .v-play { opacity: 1; }
.v-frame .v-play > div {
  width: 56px; height: 56px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.95);
  color: #000;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; padding-left: 4px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}

/* === Selection === */
::selection { background: rgba(255, 68, 56, 0.35); color: #fff; }

/* ===== Threads App feed (vertical = story progress, horizontal = branches) ===== */
.vfeed { position:fixed; inset:0; z-index:60; background:#000;
  overflow-y:scroll; scroll-snap-type:y mandatory; -webkit-overflow-scrolling:touch; }
.vfeed::-webkit-scrollbar { display:none; }
.vslide { height:100dvh; scroll-snap-align:start; position:relative; }
.htrack { height:100%; display:flex; overflow-x:auto; scroll-snap-type:x mandatory; }
/* (no -webkit-overflow-scrolling: its legacy scroll layer is what composited the
   playing video over the rail on the 2-pane forked slide on iOS; momentum scroll
   is the default on modern iOS anyway.) */
.htrack::-webkit-scrollbar { display:none; }
.vpane { position:relative; flex:0 0 100%; width:100%; height:100%;
  scroll-snap-align:start; overflow:hidden; }
.vvid { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; background:#000; }
.ph-feed { position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  color:var(--ink-muted); font-size:14px; }
.grad { position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to top, rgba(0,0,0,.72) 0%, transparent 38%, transparent 82%, rgba(0,0,0,.42) 100%); }
.story-tag { position:absolute; left:14px; top:16px; z-index:3; color:#fff;
  font-family:var(--font-display); font-weight:600; font-size:14px;
  background:rgba(0,0,0,.4); padding:5px 11px; border-radius:999px; }
/* Feed icon system (design_handoff_icons): every <use> sprite consumer sets its
   presentation here — the symbols carry geometry only, so stroke width/colour
   theme per site. currentColor follows the element's `color`. */
.tk { display:block; fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round; }
.tk-tab { stroke-width:1.8; }

.frail { position:absolute; right:10px; bottom:92px; display:flex; flex-direction:column;
  gap:20px; align-items:center; z-index:3; }
.ficon { color:#fff; text-align:center; text-decoration:none; line-height:1;
  background:none; border:0; padding:0; cursor:pointer; font-family:inherit;
  display:flex; flex-direction:column; align-items:center; gap:4px; }
.ficon-i { width:30px; height:30px; filter:drop-shadow(0 1px 3px rgba(0,0,0,.55)); }
.ficon small { display:block; font-size:12px; font-weight:700; letter-spacing:-.01em; opacity:1; }
.ficon.fshare.shared small::after { content:" \2713"; }

/* Join — the ONE filled, prominent rail action: red disc + glow + gentle pulse. */
.fjoin { background:none; border:0; padding:0; cursor:pointer; font-family:inherit;
  display:flex; flex-direction:column; align-items:center; gap:5px; margin-top:2px;
  -webkit-appearance:none; appearance:none; -webkit-tap-highlight-color:transparent; }
.fjoin-circle { display:flex; align-items:center; justify-content:center;
  width:48px; height:48px; border-radius:50%; background:var(--oxblood); color:#fff;
  box-shadow:0 2px 12px rgba(255,68,56,.55), 0 0 0 3px rgba(255,255,255,.18);
  animation:joinPulse 2.4s ease-in-out infinite; }
.fjoin-i { width:26px; height:26px; }
.fjoin-label { font-size:13px; font-weight:800; color:#fff; letter-spacing:.02em;
  text-shadow:0 1px 3px rgba(0,0,0,.55); }
.fjoin:focus, .fjoin:active { outline:none; }
@keyframes joinPulse {
  0%,100% { box-shadow:0 2px 12px rgba(255,68,56,.55), 0 0 0 3px rgba(255,255,255,.18); }
  50%     { box-shadow:0 2px 16px rgba(255,68,56,.75), 0 0 0 6px rgba(255,255,255,.10); }
}
@media (prefers-reduced-motion: reduce) { .fjoin-circle { animation:none; } }
.fcap { position:absolute; left:14px; right:68px; bottom:30px; z-index:3; color:#fff;
  text-shadow:0 1px 4px rgba(0,0,0,.7); }
.ftitle { font-family:var(--font-display); font-weight:600; font-size:15px; }
.fwho { font-size:13px; opacity:.95; margin-top:2px; }
.ftx { font-size:12.5px; opacity:.85; margin-top:6px; }
.alt-follow { display:inline-block; margin-top:10px; color:#fff; background:rgba(255,68,56,.92);
  padding:7px 13px; border-radius:999px; font-size:12.5px; font-weight:600; text-decoration:none; }
/* Swipe-to-branch hint: a pill flush to the right edge (branch glyph + count +
   a chevron that gently nudges toward the hidden alternate). Tappable too. */
.branch-peek { position:absolute; right:0; top:42%; transform:translateY(-50%); z-index:4;
  display:flex; flex-direction:column; align-items:center; gap:2px; padding:9px 7px 9px 8px;
  border:0; cursor:pointer; color:#fff; background:rgba(0,0,0,.34); border-radius:16px 0 0 16px;
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  -webkit-appearance:none; appearance:none; -webkit-tap-highlight-color:transparent; }
.branch-peek .bp-icon { line-height:1; }
.branch-peek .bp-icon svg { display:block; width:16px; height:16px; }
.branch-peek .bp-count { font-size:12px; font-weight:700; line-height:1; }
.branch-peek .bp-chev { color:var(--amber); font-size:19px; line-height:.7; font-weight:700;
  animation: bp-nudge 1.5s ease-in-out infinite; }
@keyframes bp-nudge { 0%, 100% { transform: translateX(0); opacity:.55; }
  50% { transform: translateX(3px); opacity:1; } }
@media (prefers-reduced-motion: reduce) { .branch-peek .bp-chev { animation: none; opacity:.9; } }
.branch-back { position:absolute; left:8px; top:50%; transform:translateY(-50%); z-index:3;
  color:#fff; font-size:11px; opacity:.7; writing-mode:vertical-rl; }

/* Threads App — Phase 2 Join bottom-sheet (inside each main .vpane) */
.join-sheet { position:absolute; left:0; right:0; bottom:0; z-index:6;
  background:var(--paper-warm); border-top-left-radius:18px; border-top-right-radius:18px;
  padding:18px 16px calc(18px + env(safe-area-inset-bottom));
  transform:translateY(110%); transition:transform .22s ease; max-height:85%; overflow-y:auto;
  box-shadow:0 -8px 30px rgba(0,0,0,.5); }
.join-sheet.open { transform:translateY(0); }
.js-backdrop { position:absolute; inset:0; z-index:5; background:rgba(0,0,0,.45);
  opacity:0; pointer-events:none; transition:opacity .2s; }
.js-backdrop.open { opacity:1; pointer-events:auto; }
/* Sticky head so Close stays reachable while you scroll the recap + roles. */
.js-head { display:flex; justify-content:space-between; align-items:center;
  position:sticky; top:0; z-index:1; background:var(--paper-warm); padding-bottom:8px; }
.js-head strong { font-family:var(--font-display); font-size:16px; }
.js-close { background:none; border:0; color:var(--ink-muted); font-size:24px; line-height:1;
  padding:0 4px; cursor:pointer; min-height:0; }
.js-lede { color:var(--ink-muted); font-size:12.5px; margin:0 0 10px; }
.js-section { font-family:var(--font-display); font-weight:600; font-size:11px;
  text-transform:uppercase; letter-spacing:.05em; color:var(--ink-muted); margin:14px 0 8px; }
/* The story so far — the thread's beats in order, as a scrollable recap. */
.js-recap { display:flex; flex-direction:column; gap:11px; }
.js-recap-beat { border-left:2px solid var(--paper-edge); padding:1px 0 1px 11px; }
.js-recap-who { font-size:12px; font-weight:600; color:var(--ink); }
.js-recap-text { font-size:12.5px; color:var(--ink-soft); line-height:1.45; margin-top:2px; }
/* Role cards: name + blurb + a full-width "Record as …" CTA. */
.js-roles { display:flex; flex-direction:column; gap:10px; }
.js-role { display:block; padding:13px 14px; border:1px solid var(--paper-edge);
  border-radius:12px; background:var(--paper); color:var(--ink); text-decoration:none; }
.js-role:hover { border-color:var(--oxblood); }
.js-role-name { font-weight:600; font-size:15px; }
.js-role-desc { font-size:12px; color:var(--ink-muted); margin-top:3px; line-height:1.4;
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:3; overflow:hidden; }
.js-role-cta { display:block; margin-top:11px; text-align:center; padding:9px 12px;
  border-radius:9px; background:var(--oxblood); color:#fff; font-weight:600; font-size:13px; }

/* Threads App — bottom-tab nav + app pages (Phase 4 shell) */
.app-nav { position:fixed; left:0; right:0; bottom:0; z-index:70; height:54px;
  display:flex; background:rgba(11,11,14,.92); border-top:1px solid var(--paper-edge);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  padding-bottom:env(safe-area-inset-bottom); }
.anav { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:3px; color:#fff; opacity:.55; text-decoration:none; }
.anav svg { width:22px; height:22px; }
.anav .al { font-size:9px; letter-spacing:.02em; }
.anav.on { opacity:1; }
body.sheet-open .app-nav { display:none; }     /* hide nav while a join sheet is up */
.fcap { bottom:62px; }                          /* lift caption clear of the nav */

.app-page { padding:20px 16px calc(76px + env(safe-area-inset-bottom));
  max-width:680px; margin:0 auto; min-height:100vh; }
.app-page h1 { font-size:24px; margin:0 0 4px; }
.app-page .sub { color:var(--ink-muted); font-size:13px; margin:0 0 18px; }
.tcard-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:12px; }
.tcard { display:block; border:1px solid var(--paper-edge); border-radius:14px; overflow:hidden;
  background:var(--paper-warm); text-decoration:none; color:var(--ink); }
.tcard .thumb { aspect-ratio:9/16; background:#000; width:100%; object-fit:cover; display:block; }
.tcard .thumb-ph { aspect-ratio:9/16;
  background:linear-gradient(160deg,#1c1c24,#0b0b0e); display:flex;
  align-items:center; justify-content:center; color:var(--ink-faint); font-size:30px; }
.tcard .meta { padding:9px 11px; }
.tcard .meta .t { font-family:var(--font-display); font-weight:600; font-size:14px; line-height:1.2; }
.tcard .meta .r { color:var(--ink-muted); font-size:11.5px; margin-top:3px; }
.tcard .meta .n { color:var(--amber); font-size:10.5px; margin-top:4px; }
.feed-empty { text-align:center; color:var(--ink-muted); padding:54px 16px; }

/* Threads App — report affordance in the per-beat sheet (Phase 5) */
.js-report { margin-top:14px; padding-top:12px; border-top:1px solid var(--paper-edge); }
.js-report summary { list-style:none; cursor:pointer; color:var(--ink-muted); font-size:12px; }
.js-report summary::-webkit-details-marker { display:none; }
.js-report-form { display:flex; gap:8px; margin-top:8px; }
.js-report-form input { flex:1; font-size:12.5px; }
.js-report-form button { padding:6px 12px; font-size:12px; min-height:0; }
.js-report a { font-size:12.5px; display:inline-block; margin-top:8px; }

/* Desktop: the feed is phone-first (9:16). Instead of stretching it across the
   whole window, keep the black backdrop full-bleed and center the video +
   overlays as a phone-width column (TikTok/Reels-on-web pattern). The bottom
   nav centers to match. */
@media (min-width: 768px) {
  .vslide { display:flex; justify-content:center; }
  .htrack { width:min(440px, 100%); flex:0 0 auto; }
  .app-nav { left:50%; right:auto; transform:translateX(-50%); width:min(440px, 100vw);
    border-left:1px solid var(--paper-edge); border-right:1px solid var(--paper-edge); }
}

/* Start picker — richer story cards (synopsis + genre/length/roles) */
.story-list { display:flex; flex-direction:column; gap:12px; }
.story-card { display:flex; gap:13px; padding:14px; border:1px solid var(--paper-edge);
  border-radius:16px; background:var(--paper-warm); text-decoration:none; color:var(--ink);
  transition:border-color .15s; }
.story-card:hover, .story-card:active { border-color:var(--oxblood); }
.story-emoji { flex:0 0 auto; width:46px; height:46px; border-radius:12px; font-size:25px;
  display:flex; align-items:center; justify-content:center;
  background:linear-gradient(160deg,#1c1c24,#0b0b0e); }
.story-body { min-width:0; }
.story-title { font-family:var(--font-display); font-weight:600; font-size:17px; line-height:1.15; }
.story-syn { font-size:13px; line-height:1.45; color:var(--ink-soft); margin:5px 0 9px;
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:5; overflow:hidden; }
.story-meta { display:flex; flex-wrap:wrap; align-items:center; gap:9px;
  font-size:11.5px; color:var(--ink-muted); }
.story-genre { text-transform:uppercase; letter-spacing:.04em; color:var(--amber);
  font-weight:600; font-size:10.5px; }
.story-go { color:var(--oxblood); font-weight:600; margin-left:auto; white-space:nowrap; }

/* Feed rail — creator avatar (links to the beat author's profile, /app/u/{id}) */
.fauthor { margin-bottom:4px; }
.favatar { display:flex; align-items:center; justify-content:center; width:42px; height:42px;
  border-radius:50%; background:var(--oxblood); color:#fff; font-size:18px; font-weight:700;
  font-family:var(--font-display); }
.fauthor small { max-width:54px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* Rail buttons are <button>s — reset native iOS chrome so tapping doesn't flash
   a white oval / focus ring behind the glyph. */
.frail button.ficon { -webkit-appearance: none; appearance: none;
  -webkit-tap-highlight-color: transparent; }
.frail button.ficon:focus, .frail button.ficon:active { outline: none; background: none; }

/* Feed rail — like: an inline SVG heart, white outline → filled oxblood on .on.
   CSS does the fill so a tap never re-renders a glyph (no iOS tofu/oval). */
.flike-i { display:block; width:30px; height:30px; margin:0 auto;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.55)); }
.flike-i path { fill: none; stroke: #fff; stroke-width: 2; }
.flike.on .flike-i path { fill: var(--oxblood); stroke: var(--oxblood); }

/* Rail must stay legible over BRIGHT videos: a single soft drop-shadow (a heavy
   double shadow blobbed a dark halo behind the hollow heart — the "odd look"). */
.frail .ficon { text-shadow: 0 1px 3px rgba(0,0,0,.85); }
.favatar { box-shadow: 0 1px 6px rgba(0,0,0,.55); text-shadow: none; }

/* iOS Safari: on the 2-pane (forked) slide the playing inline <video> composites
   ABOVE these absolutely-positioned overlays, hiding the whole rail/caption.
   Promoting each overlay to its own layer forces it back on top. */
.frail, .fcap, .story-tag, .branch-peek, .grad { transform: translateZ(0); }

/* Top-right cluster (design handoff) — credits pill + mute button, glass style. */
.feed-topright { position:fixed; z-index:65; display:flex; align-items:center; gap:8px;
  top:calc(env(safe-area-inset-top, 0px) + 14px); right:14px; }
/* Mute toggle — 34px glass circle; feed.js swaps the speaker sprite on tap. */
.mute-toggle { display:flex; align-items:center; justify-content:center;
  width:34px; height:34px; border-radius:50%; border:1px solid rgba(255,255,255,.18);
  cursor:pointer; background:rgba(0,0,0,.35); color:#fff; padding:0;
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  -webkit-appearance:none; appearance:none; -webkit-tap-highlight-color:transparent; }
.mute-i { width:18px; height:18px; }
.mute-toggle:active { background:rgba(0,0,0,.55); }

/* "Tap for sound" cue — shown only when the browser forced a muted autoplay
   fallback; floats just above the bottom nav, pulses, dismissed on first tap. */
.sound-hint { position:fixed; left:50%; bottom:calc(env(safe-area-inset-bottom, 0px) + 70px);
  z-index:66; border:0; cursor:pointer; border-radius:999px; padding:9px 16px;
  background:rgba(0,0,0,.62); color:#fff; font-size:14px; font-weight:600;
  -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px);
  box-shadow:0 2px 12px rgba(0,0,0,.4);
  opacity:0; pointer-events:none; transform:translateX(-50%);
  transition:opacity .25s ease; }
.sound-hint.show { opacity:1; pointer-events:auto; animation:soundpulse 1.6s ease-in-out infinite; }
@keyframes soundpulse {
  0%,100% { transform:translateX(-50%) scale(1); }
  50%     { transform:translateX(-50%) scale(1.06); }
}
@media (prefers-reduced-motion: reduce) { .sound-hint.show { animation:none; } }

/* Account tab — web-push opt-in card */
.app-notify { display:flex; align-items:center; justify-content:space-between; gap:14px;
  padding:14px; border:1px solid var(--paper-edge); border-radius:14px;
  background:var(--paper-warm); margin-bottom:18px; }
.app-notify .an-title { font-family:var(--font-display); font-weight:600; font-size:14px; }
.app-notify .an-help { color:var(--ink-muted); font-size:12px; margin:4px 0 0; line-height:1.4; }
.app-notify .btn { white-space:nowrap; flex:0 0 auto; min-height:0; padding:9px 16px; }

/* Comments — shared bottom sheet (z-index above the nav; centered on desktop) */
.cmt-backdrop { position:fixed; inset:0; z-index:75; background:rgba(0,0,0,.5);
  opacity:0; pointer-events:none; transition:opacity .2s; }
.cmt-backdrop.open { opacity:1; pointer-events:auto; }
.cmt-sheet { position:fixed; left:0; right:0; bottom:0; z-index:80;
  max-width:440px; margin:0 auto; height:70vh; max-height:560px;
  display:flex; flex-direction:column; background:var(--paper); color:var(--ink);
  border-radius:16px 16px 0 0; transform:translateY(100%); transition:transform .25s ease;
  padding-bottom:env(safe-area-inset-bottom); }
.cmt-sheet.open { transform:translateY(0); }
.cmt-head { display:flex; align-items:center; justify-content:space-between;
  padding:14px 16px; border-bottom:1px solid var(--paper-edge);
  font-family:var(--font-display); font-weight:600; }
.cmt-close { background:none; border:0; color:var(--ink-muted); font-size:24px;
  line-height:1; cursor:pointer; }
.cmt-list { flex:1; overflow-y:auto; padding:12px 16px; display:flex;
  flex-direction:column; gap:12px; }
.cmt { font-size:13.5px; line-height:1.4; display:flex; align-items:baseline; gap:8px; }
.cmt-body { flex:1; min-width:0; }
.cmt-who { font-weight:600; margin-right:6px; }
.cmt-text { color:var(--ink-soft); }
/* Per-comment report flag — dim until hover/tap; becomes "Reported" on success. */
.cmt-report { flex:0 0 auto; background:none; border:0; padding:0 2px; cursor:pointer;
  color:var(--ink-faint); font-size:13px; line-height:1; opacity:.55; font-family:inherit; }
.cmt-report:hover { opacity:1; color:var(--ink-muted); }
.cmt-report.done { opacity:1; color:var(--ink-muted); font-size:11px; cursor:default; }
.cmt-empty { color:var(--ink-muted); font-size:13px; text-align:center; padding:24px 0; }
.cmt-compose { display:flex; gap:8px; padding:10px 12px; border-top:1px solid var(--paper-edge); }
.cmt-compose input { flex:1; min-width:0; font-size:14px; padding:9px 12px; border-radius:8px;
  border:1px solid var(--paper-edge); background:var(--paper-warm); color:var(--ink); }
.cmt-compose button { padding:9px 16px; font-size:13px; font-weight:600; white-space:nowrap;
  border:0; border-radius:8px; background:var(--oxblood); color:#fff; cursor:pointer; }

/* Shared Join sheet — half-height, NO backdrop, so the thread video keeps playing
   above it (swipe up there to watch the story). Reuses .js-role* for the cards. */
.joinx { position:fixed; left:0; right:0; bottom:0; z-index:80; max-width:440px; margin:0 auto;
  height:54vh; max-height:540px; display:flex; flex-direction:column;
  background:var(--paper-warm); border-radius:18px 18px 0 0;
  transform:translateY(110%); transition:transform .25s ease;
  box-shadow:0 -8px 30px rgba(0,0,0,.55); padding-bottom:env(safe-area-inset-bottom); }
.joinx.open { transform:translateY(0); }
.joinx-head { display:flex; justify-content:space-between; align-items:center;
  padding:14px 16px; border-bottom:1px solid var(--paper-edge); }
.joinx-head strong { font-family:var(--font-display); font-size:16px; }
.joinx-close { background:none; border:0; color:var(--ink-muted); font-size:24px;
  line-height:1; cursor:pointer; }
.joinx-body { flex:1; overflow-y:auto; padding:14px 16px calc(14px + env(safe-area-inset-bottom)); }

/* Token credits — Account card, feed chip, join "can't afford" note */
.credits-card { display:flex; align-items:center; gap:14px; padding:14px 16px;
  border:1px solid var(--paper-edge); border-radius:14px; background:var(--paper-warm);
  margin-bottom:18px; }
.credits-bal { font-family:var(--font-display); font-weight:700; font-size:26px;
  display:flex; align-items:center; gap:6px; white-space:nowrap; }
.credits-coin { font-size:21px; }
.credits-title { font-family:var(--font-display); font-weight:600; font-size:14px; }
.credits-help { color:var(--ink-muted); font-size:12px; margin:3px 0 0; line-height:1.4; }
/* Feed credits pill — glass chip in the top-right cluster, amber spark + count. */
.credits-chip { display:inline-flex; align-items:center; gap:5px; height:34px; padding:0 12px;
  border-radius:999px; text-decoration:none; background:rgba(0,0,0,.35); color:#fff;
  font-size:13.5px; font-weight:700; border:1px solid rgba(255,255,255,.18);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px); }
.credits-i { width:17px; height:17px; color:var(--amber); }
.js-nocredits { background:rgba(255,68,56,.12); border:1px solid var(--oxblood);
  color:var(--ink); font-size:12.5px; line-height:1.4; padding:10px 12px;
  border-radius:10px; margin:0 0 12px; }

/* ============================================================================
   First-run onboarding (design_handoff_onboarding). Slice 1: the Welcome
   first-touch screen + feed coachmarks. Reuses the existing --paper/--ink/
   --oxblood/--amber tokens; no new colors. See app_welcome.html + app_feed.html.
   ========================================================================== */
.ob-welcome {
  position: fixed; inset: 0; overflow: hidden;
  display: flex; flex-direction: column; background: var(--paper);
}
/* Cinematic neon plate standing in for video (OB_LOOKS.neon). */
.ob-welcome-bg {
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(circle at 72% 26%, rgba(255, 90, 180, 0.40), transparent 42%),
    radial-gradient(circle at 20% 78%, rgba(70, 200, 255, 0.30), transparent 45%),
    linear-gradient(180deg, #0a0618 0%, #1c0f33 48%, #06040c 100%);
}
.ob-welcome-bg::after { /* legibility scrim */
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.45) 0%, transparent 24%, transparent 50%, rgba(0,0,0,0.55) 100%);
}
.ob-welcome-inner {
  position: relative; z-index: 2; flex: 1;
  display: flex; flex-direction: column; padding: 0 22px;
}
.ob-welcome-top { flex: 0 0 auto; padding-top: 78px; text-align: center; }
.ob-wordmark {
  font-family: var(--font-sans); font-size: 30px; font-weight: 700;
  letter-spacing: -0.03em; color: #fff;
}
.ob-star { color: var(--amber); }
.ob-tagline {
  margin: 10px auto 0; max-width: 256px; font-size: 16px; line-height: 1.4;
  color: rgba(255, 255, 255, 0.78);
}
.ob-spacer { flex: 1; }
.ob-paths { display: flex; flex-direction: column; gap: 12px; padding-bottom: 8px; }
.ob-path {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 16px 18px; border-radius: 16px; color: #fff; text-decoration: none;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  font-family: var(--font-sans);
}
.ob-path-primary   { background: rgba(255, 68, 56, 0.16); border: 1px solid rgba(255, 68, 56, 0.5); }
.ob-path-secondary { background: rgba(255, 255, 255, 0.10); border: 1px solid rgba(255, 255, 255, 0.24); }
.ob-path-glyph { font-size: 22px; line-height: 1; }
.ob-path-text { flex: 1; text-align: left; min-width: 0; }
.ob-path-title { display: block; font-size: 18px; font-weight: 700; letter-spacing: -0.02em; }
.ob-path-sub { display: block; font-size: 13px; line-height: 1.4; color: rgba(255, 255, 255, 0.65); margin-top: 3px; }
.ob-path-arrow { opacity: 0.5; font-size: 18px; }
.ob-browse {
  display: block; text-align: center; background: none; border: none;
  color: rgba(255, 255, 255, 0.42); text-decoration: none; cursor: pointer;
  padding: 16px 0 calc(20px + env(safe-area-inset-bottom, 0px));
  font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase;
}

/* Desktop welcome (design_handoff_desktop): ONE markup, two layouts. These are
   the MOBILE base rules for the new wrappers (video full-bleed behind content);
   the ≥900px block below switches to a constrained two-column panel with the
   video CONTAINED in a 9:16 plate — so desktop never stretches the phone layout. */
.ob-welcome-panel { position: relative; z-index: 2; flex: 1; display: flex;
  flex-direction: column; min-height: 0; }
.ob-welcome-stage { position: absolute; inset: 0; z-index: 0; }
/* Taps fall through the content's empty areas to the video's sound button below. */
.ob-welcome-inner { pointer-events: none; }
.ob-welcome-inner .ob-path, .ob-welcome-inner .ob-browse { pointer-events: auto; }
/* Double-class selectors so these beat the base `.ob-nowplaying` display rule,
   which sits LATER in the file (source order would otherwise override us). */
.ob-nowplaying.ob-np-overlay { display: none; }   /* mobile uses the in-flow pill */

@media (min-width: 900px) {
  .ob-welcome { align-items: center; justify-content: center; }
  /* ambient backdrop — dimmed neon plate (~50%) under a radial vignette */
  .ob-welcome-bg {
    background:
      linear-gradient(rgba(11, 11, 14, 0.5), rgba(11, 11, 14, 0.5)),
      radial-gradient(circle at 72% 26%, rgba(255, 90, 180, 0.40), transparent 42%),
      radial-gradient(circle at 20% 78%, rgba(70, 200, 255, 0.30), transparent 45%),
      linear-gradient(180deg, #0a0618 0%, #1c0f33 48%, #06040c 100%);
  }
  .ob-welcome-bg::after {
    background: radial-gradient(ellipse 70% 60% at 50% 45%, transparent 30%, rgba(11, 11, 14, 0.92) 100%);
  }
  .ob-welcome-panel { flex: 0 1 auto; flex-direction: row; align-items: center;
    gap: 56px; max-width: 880px; width: 100%; padding: 0 48px; }
  .ob-welcome-inner { flex: 1 1 auto; max-width: 440px; padding: 0; pointer-events: auto; }
  .ob-welcome-top { padding-top: 0; text-align: left; }
  .ob-wordmark { font-size: 40px; }
  .ob-tagline { margin: 12px 0 0; max-width: 360px; font-size: 17px; line-height: 1.5; }
  .ob-spacer { display: none; }
  .ob-nowplaying.ob-np-flow { display: none; }   /* the pill moves into the plate */
  .ob-paths { margin-top: 32px; padding-bottom: 0; }
  .ob-browse { text-align: left; padding: 26px 0 0; }
  /* right column — the real video, CONTAINED in a 9:16 plate */
  .ob-welcome-stage { position: relative; inset: auto; z-index: 2; flex: 0 0 auto;
    height: min(540px, calc(100dvh - 160px)); aspect-ratio: 9 / 16;
    border-radius: 16px; overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: var(--shadow-lift); }
  .ob-nowplaying.ob-np-overlay { display: inline-flex; align-items: center; gap: 6px;
    position: absolute; left: 50%; transform: translateX(-50%); bottom: 14px;
    margin: 0; z-index: 2; white-space: nowrap; padding: 5px 11px; border-radius: 999px;
    background: rgba(0, 0, 0, 0.45); border: 1px solid rgba(255, 255, 255, 0.14);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    font-size: 10px; letter-spacing: 0.14em; }
}

/* Feed coachmarks — one-time first-run swipe hints (handoff §3.2). */
.ob-coach {
  position: fixed; inset: 0; z-index: 60; cursor: pointer;
  background: rgba(0, 0, 0, 0.45);
  display: flex; align-items: center; justify-content: center;
}
.ob-coach[hidden] { display: none; }
.ob-coach-inner {
  text-align: center; color: #fff; font-family: var(--font-sans);
  font-size: 17px; font-weight: 600; letter-spacing: -0.01em; padding: 0 24px;
  animation: obFloat 1.6s ease-in-out infinite;
}
.ob-coach-arrow { font-size: 30px; margin-bottom: 6px; }
.ob-coach-hint {
  font-family: var(--font-mono); font-size: 11px; font-weight: 400;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6); margin-top: 12px;
}
@keyframes obFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }

/* ============================================================================
   Processing-wait centerpiece (onboarding slice 2). The rich beat_record.html
   "filming your beat" state + done/raw-fallback outcomes. Reuses .card/.btn/
   .chip/.eyebrow; tokens only. See beat_record.html + design_handoff_onboarding.
   ========================================================================== */
.ob-wait-status, .ob-wait-card, .ob-wait-how, .ob-wait-done, .ob-wait-fallback { margin-bottom: 12px; }
.ob-wait-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ob-wait-h { font-size: 16px; font-weight: 700; letter-spacing: -0.02em; }
.ob-wait-pct { font-size: 13px; color: var(--ink-muted); }
.ob-wait-bar { height: 6px; background: var(--paper-deep); border-radius: 3px; overflow: hidden; margin: 12px 0 8px; }
.ob-wait-bar-fill { height: 100%; background: linear-gradient(90deg, var(--oxblood), var(--amber)); border-radius: 3px; transition: width 0.5s ease; }
.ob-wait-stage { font-size: 13px; color: var(--ink-soft); }
.ob-wait-notify {
  margin-top: 14px; width: 100%; display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 10px; cursor: pointer; text-align: left;
  background: rgba(255, 255, 255, 0.03); border: 1px solid var(--paper-edge);
  color: var(--ink); font-family: var(--font-sans);
}
.ob-wait-notify.on { background: rgba(61, 214, 140, 0.08); border-color: rgba(61, 214, 140, 0.3); }
.ob-wait-notify-ico { font-size: 16px; }
.ob-wait-notify-txt { flex: 1; }
.ob-wait-notify-head { display: block; font-size: 13.5px; font-weight: 600; }
.ob-wait-notify-sub { display: block; font-size: 11.5px; color: var(--ink-muted); }
.ob-wait-toggle {
  width: 38px; height: 22px; border-radius: 999px; flex: 0 0 auto; position: relative;
  background: var(--paper-deep); border: 1px solid var(--paper-edge); transition: background 0.2s;
}
.ob-wait-notify.on .ob-wait-toggle { background: var(--moss); }
.ob-wait-knob { position: absolute; top: 1px; left: 1px; width: 18px; height: 18px; border-radius: 50%; background: #fff; transition: left 0.2s; }
.ob-wait-notify.on .ob-wait-knob { left: 17px; }
.ob-wait-card-h { font-size: 15px; font-weight: 700; letter-spacing: -0.02em; }
.ob-wait-muted { font-size: 10.5px; color: var(--ink-muted); }
.ob-wait-desc { margin: 6px 0 10px; font-size: 13px; line-height: 1.45; color: var(--ink-soft); }
.ob-credit-chip {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  font-size: 11px; font-weight: 600; letter-spacing: 0.04em; color: var(--amber);
  background: rgba(255, 184, 74, 0.12); border: 1px solid rgba(255, 184, 74, 0.32);
  border-radius: 999px; padding: 2px 8px;
}
.ob-wait-btn { width: 100%; padding: 11px; font-size: 14.5px; }
/* "While you wait" carousel */
.ob-wait-carousel { display: flex; gap: 9px; overflow-x: auto; padding-bottom: 2px; margin: 10px -2px 0; }
.ob-wait-thumb {
  flex: 0 0 auto; width: 92px; position: relative; aspect-ratio: 9 / 16;
  border-radius: 9px; overflow: hidden; border: 1px solid var(--paper-edge); display: block;
}
.ob-wait-thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: var(--paper-deep); }
.ob-wait-thumb::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, transparent 48%, rgba(0,0,0,0.72) 100%); }
.ob-wait-thumb-meta { position: absolute; left: 6px; right: 6px; bottom: 6px; z-index: 2; }
.ob-wait-thumb-title { display: block; font-size: 11px; font-weight: 700; color: #fff; letter-spacing: -0.01em; line-height: 1.1; text-shadow: 0 1px 4px rgba(0,0,0,0.7); }
.ob-wait-thumb-sub { display: block; font-size: 8.5px; color: rgba(255,255,255,0.8); letter-spacing: 0.06em; margin-top: 1px; }
/* "How Telescope works" */
.ob-wait-how { padding: 0 !important; overflow: hidden; }
.ob-wait-how-head { width: 100%; display: flex; align-items: center; justify-content: space-between; padding: 14px; background: none; border: none; cursor: pointer; color: var(--ink); font-family: var(--font-sans); }
.ob-wait-how-caret { opacity: 0.5; transition: transform 0.2s; }
.ob-wait-how-body { padding: 0 14px 14px; display: flex; flex-direction: column; gap: 12px; }
.ob-wait-how-body[hidden] { display: none; }
.ob-wait-how-row { display: flex; gap: 11px; }
.ob-wait-how-k { font-size: 10.5px; color: var(--amber); letter-spacing: 0.1em; text-transform: uppercase; width: 64px; flex: 0 0 auto; padding-top: 2px; }
.ob-wait-how-v { font-size: 13px; line-height: 1.5; color: var(--ink-soft); }
/* outcome cards */
.ob-wait-done { text-align: center; background: linear-gradient(180deg, rgba(61,214,140,0.10), rgba(61,214,140,0.02)); border-color: rgba(61,214,140,0.3); }
.ob-wait-done-emoji { font-size: 30px; margin-bottom: 6px; }
.ob-wait-done-h { font-size: 22px; font-weight: 700; letter-spacing: -0.025em; }
.ob-wait-fallback { background: linear-gradient(180deg, rgba(255,184,74,0.10), rgba(255,184,74,0.02)); border-color: rgba(255,184,74,0.3); }
.ob-wait-done-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.ob-wait-done-actions .btn { display: inline-flex; align-items: center; justify-content: center; }
.ob-wait-done-row { display: flex; gap: 8px; }
.ob-wait-done-row .btn { flex: 1; }

/* "Who can join?" privacy picker (onboarding slice 3) — thread_roles.html. */
.ob-privacy { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.ob-privacy-opt {
  text-align: left; padding: 11px 13px; border-radius: 11px; cursor: pointer;
  background: transparent; border: 1.5px solid var(--paper-edge);
  color: var(--ink); font-family: var(--font-sans);
}
.ob-privacy-opt.on { background: rgba(255, 255, 255, 0.06); border-color: var(--ink); }
.ob-privacy-glyph { font-size: 17px; margin-bottom: 4px; }
.ob-privacy-title { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }
.ob-privacy-sub { font-size: 9.5px; letter-spacing: 0.06em; color: var(--ink-muted); text-transform: uppercase; margin-top: 2px; }
.ob-privacy-help { font-size: 10.5px; letter-spacing: 0.04em; color: var(--ink-muted); margin: 8px 2px 0; line-height: 1.5; }

/* ============================================================================
   Start-a-thread flow, brought to spec (onboarding §3.3). Step 1 = scenario
   grid (app_start.html), step 2 = role picker (thread_roles.html). Tokens only.
   ========================================================================== */
.ob-start { max-width: 560px; margin: 0 auto; padding: 60px 16px calc(88px + env(safe-area-inset-bottom, 0px)); }
.ob-start-head { margin-bottom: 18px; }
.ob-start-title { font-family: var(--font-sans); font-size: 27px; font-weight: 700; letter-spacing: -0.025em; margin: 6px 0 4px; }
.ob-start-sub { margin: 0; color: var(--ink-muted); font-size: 14px; line-height: 1.5; }
.ob-sc-list { display: flex; flex-direction: column; gap: 12px; }
.ob-sc-card {
  display: flex; gap: 14px; padding: 10px; border-radius: 14px; color: var(--ink);
  background: var(--paper-warm); border: 1px solid var(--paper-edge); text-decoration: none;
}
.ob-sc-card:active { background: var(--paper-deep); }
.ob-sc-thumb {
  position: relative; flex: 0 0 auto; width: 74px; aspect-ratio: 9 / 16;
  border-radius: 9px; overflow: hidden; display: flex; align-items: center; justify-content: center;
}
.ob-sc-emoji { font-size: 26px; filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.6)); }
.ob-sc-body { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 5px; }
.ob-sc-titlerow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ob-sc-name { font-size: 17px; font-weight: 700; letter-spacing: -0.02em; }
.ob-sc-syn {
  font-size: 13px; line-height: 1.45; color: var(--ink-soft);
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ob-sc-meta { font-size: 10.5px; letter-spacing: 0.08em; color: var(--ink-muted); text-transform: uppercase; }
/* Cinematic plate gradients (stand in for per-scenario video), cycled by index. */
.ob-plate-0 { background: radial-gradient(circle at 72% 26%, rgba(255, 90, 180, 0.40), transparent 46%), linear-gradient(180deg, #0a0618, #1c0f33 50%, #06040c); }
.ob-plate-1 { background: radial-gradient(circle at 50% 22%, rgba(180, 220, 255, 0.30), transparent 50%), linear-gradient(180deg, #0a0e12, #16242f 50%, #060809); }
.ob-plate-2 { background: radial-gradient(ellipse 60% 30% at 50% 64%, rgba(255, 184, 74, 0.28), transparent 70%), linear-gradient(180deg, #060b14, #0c1422 48%, #02060c); }
.ob-plate-3 { background: radial-gradient(circle at 30% 42%, rgba(255, 170, 60, 0.40), transparent 56%), linear-gradient(180deg, #0c0703, #1c100a 52%, #08050a); }
.ob-plate-4 { background: radial-gradient(circle at 50% 44%, rgba(255, 80, 70, 0.40), transparent 52%), linear-gradient(180deg, #0b0204, #1a0408 50%, #050102); }

/* Step 2: role picker — fixed-height column, internal scroll, pinned footer. */
.ob-role { display: flex; flex-direction: column; height: 100dvh; }
.ob-role-head { padding: 56px 16px 12px; flex: 0 0 auto; }
.ob-back { display: inline-block; color: var(--ink-muted); text-decoration: none; font-size: 12px; letter-spacing: 0.06em; margin-bottom: 8px; }
.ob-role-title { font-family: var(--font-sans); font-size: 24px; font-weight: 700; letter-spacing: -0.025em; line-height: 1.1; margin: 0; }
.ob-role-lede { margin: 8px 0 0; color: var(--ink-soft); font-size: 13px; line-height: 1.5; }
.ob-role-signin { flex: 0 0 auto; margin: 0 16px 8px; padding: 11px 13px; border-radius: 10px; border: 1px solid rgba(255, 184, 74, 0.4); background: rgba(255, 184, 74, 0.06); font-size: 13px; line-height: 1.55; }
.ob-role-scroll { flex: 1; overflow-y: auto; padding: 4px 16px 16px; }
.ob-role-list { display: flex; flex-direction: column; gap: 10px; }
.ob-role-card {
  width: 100%; text-align: left; padding: 13px 15px; border-radius: 12px; cursor: pointer;
  background: var(--paper-warm); border: 1.5px solid var(--paper-edge); color: var(--ink); font-family: var(--font-sans);
}
.ob-role-card.on { background: rgba(255, 68, 56, 0.08); border-color: var(--oxblood); }
.ob-role-titlerow { display: flex; align-items: center; gap: 9px; margin-bottom: 4px; }
.ob-role-name { font-size: 16px; font-weight: 700; letter-spacing: -0.015em; }
.ob-role-check { display: none; margin-left: auto; }
.ob-role-card.on .ob-role-check { display: inline-flex; }
.ob-role-desc { display: block; font-size: 12.5px; line-height: 1.5; color: var(--ink-soft); }
.ob-privacy-wrap { margin-top: 18px; }
.ob-role-footer { flex: 0 0 auto; padding: 12px 16px calc(14px + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--paper-edge); background: var(--paper); }
.ob-role-submit { width: 100%; padding: 14px; font-size: 16px; }
.ob-role-submit:disabled { opacity: 0.5; cursor: default; }

/* Global button styling defaults these to flex; the card-style buttons must
   stack their contents (title row above description / glyph above labels). */
.ob-role-card, .ob-privacy-opt { display: block; }

/* Welcome preview video — the busiest thread plays behind first-touch. */
.ob-welcome-vid { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; object-fit: cover; background: #000; }
.ob-welcome-scrim { position: absolute; inset: 0; z-index: 1; background: linear-gradient(180deg, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.12) 26%, rgba(0,0,0,0.35) 58%, rgba(0,0,0,0.88) 100%); }
.ob-nowplaying { display: inline-flex; align-items: center; gap: 7px; align-self: center; color: rgba(255,255,255,0.80); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 12px; }
.ob-np-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--oxblood); box-shadow: 0 0 8px var(--oxblood); }

/* Welcome preview tap-to-unmute button (autoplay must be muted). */
.ob-welcome-sound {
  position: absolute; top: 14px; left: 14px; z-index: 3;
  width: 38px; height: 38px; border-radius: 50%; cursor: pointer;
  background: rgba(0, 0, 0, 0.45); border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff; font-size: 16px; line-height: 1;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  display: flex; align-items: center; justify-content: center;
}

/* Wait-page sign-in gate (anonymous draft, before paid processing). */
.ob-wait-gate { margin-bottom: 12px; text-align: center; background: linear-gradient(180deg, rgba(255,68,56,0.12), rgba(255,68,56,0.03)); border-color: rgba(255,68,56,0.35); }

/* Regenerate / Direct — the "what would you like to change?" hint field on the
   beat done view + compare page. (styles.css ?v bumped to 37) */
.ob-regen-hint {
  width: 100%; box-sizing: border-box; resize: vertical; min-height: 44px;
  padding: 9px 11px; border-radius: 9px; border: 1px solid var(--paper-edge);
  background: var(--paper); color: var(--ink); font: inherit; font-size: 14px;
  line-height: 1.4;
}
.ob-regen-hint:focus { outline: none; border-color: var(--oxblood); }
.ob-regen-hint:disabled { opacity: .5; }

/* ============================================================================
   Desktop shell (design_handoff_desktop 2) — one breakpoint at 900px.
   Below: mobile layouts untouched (tab bar, full-bleed feed). At ≥900px:
   left sidebar (wordmark / nav / credits card), contained 9:16 feed player
   with the action rail BESIDE it + chevrons + ↑/↓ keys, 460px hairline
   wizard/wait columns, wider Browse grid. Source order: this block sits after
   the 768px Reels-on-web block on purpose — same specificity, later wins.
   ========================================================================== */

/* Sidebar-only elements — hidden on the mobile tab bar. */
.anav-brand, .anav-spacer, .anav-credits { display:none; }
.feed-chevrons { display:none; }

@media (min-width: 900px) {
  /* — shell: the bottom tab bar becomes a left sidebar — */
  .app-nav { left:0; right:auto; top:0; bottom:0; transform:none; width:210px; height:auto;
    flex-direction:column; align-items:stretch; gap:2px; padding:18px 12px;
    background:var(--paper); border-top:0; border-left:0;
    border-right:1px solid var(--paper-edge); }
  body.sheet-open .app-nav { display:flex; }   /* sheets never hide the sidebar */
  .anav-brand { display:block; font-family:var(--font-sans); font-size:19px; font-weight:700;
    letter-spacing:-0.03em; color:var(--ink); padding:4px 10px 18px; }
  .anav { flex:0 0 auto; flex-direction:row; justify-content:flex-start; gap:12px;
    padding:10px; border-radius:10px; border:1px solid transparent;
    opacity:1; color:var(--ink-muted); }
  .anav svg { width:20px; height:20px; }
  .anav .al { font-size:14.5px; font-weight:600; letter-spacing:normal; }
  .anav.on { background:var(--paper-warm); border-color:var(--paper-edge); color:var(--ink); }
  .anav-start { color:var(--ink-muted); }      /* one hot action per screen — not the nav */
  .anav-start.on { color:var(--ink); }
  .anav-spacer { display:block; flex:1; }
  .anav-credits { display:flex; align-items:center; gap:9px; padding:11px 12px;
    border:1px solid var(--paper-edge); border-radius:12px; background:var(--paper-warm);
    color:var(--ink); text-decoration:none; }
  .anav-credits b { font-size:14px; font-weight:700; }
  .anav-credits .mono { font-size:9.5px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--ink-muted); margin-left:auto; }
  /* content clears the sidebar (routes without the nav are unaffected) */
  body:has(.app-nav) main { margin-left:210px; }
  .vfeed { left:210px; background:#050507; }

  /* — feed: centered, CONTAINED 9:16 player (never full-bleed) — */
  .vslide { display:flex; align-items:center; justify-content:center; }
  .htrack { height:min(618px, calc(100dvh - 48px)); aspect-ratio:9/16; width:auto;
    flex:0 0 auto; border-radius:14px; box-shadow:var(--shadow-lift);
    border:1px solid var(--paper-edge); }
  .fcap { bottom:14px; }
  .feed-topright .credits-chip { display:none; }   /* the sidebar card owns credits */

  /* action rail — fixed BESIDE the frame, only for the in-view slide
     (feed.js toggles .in-view; the frame is centered in the content area whose
     midline is 50vw + 105px, half the 9:16 frame width is H * 0.28125) */
  .frail { display:none; }
  .vslide.in-view .frail { display:flex; right:auto; bottom:auto; position:fixed;
    left:calc(50vw + 105px + (min(618px, 100dvh - 48px) * 0.28125) + 26px);
    top:50%; transform:translateY(-50%); z-index:62; }
  .frail .ficon { text-shadow:none; color:var(--ink); }
  .frail .ficon small { color:var(--ink-soft); }
  .frail .ficon-i, .frail .flike-i { width:48px; height:48px; padding:13px;
    background:var(--paper-warm); border:1px solid var(--paper-edge); border-radius:50%;
    box-sizing:border-box; filter:none; }
  .fjoin-label { color:var(--ink); text-shadow:none; }

  /* prev/next chevrons, far right; ↑/↓ arrow keys mirror them (feed.js) */
  .feed-chevrons { display:flex; position:fixed; right:22px; top:50%;
    transform:translateY(-50%); flex-direction:column; gap:10px; z-index:65; }
  .feed-chevrons button { width:44px; height:44px; border-radius:50%;
    background:var(--paper-warm); border:1px solid var(--paper-edge); color:var(--ink);
    cursor:pointer; font-size:17px; display:flex; align-items:center; justify-content:center; }
  .feed-chevrons button:hover { background:var(--paper-deep, #1a1a20); }

  /* — wizard + wait: centered 460px sheet-over-stage columns — */
  .ob-start { max-width:460px; min-height:100vh;
    border-left:1px solid var(--paper-edge); border-right:1px solid var(--paper-edge); }
  .ob-role { max-width:460px; margin:0 auto;
    border-left:1px solid var(--paper-edge); border-right:1px solid var(--paper-edge); }
  .phone-wrap { min-height:100vh; padding-top:34px;
    border-left:1px solid var(--paper-edge); border-right:1px solid var(--paper-edge); }

  /* — Browse grid + profile column — */
  .app-page { max-width:720px; }
  .app-page-wide { max-width:1120px; }
  .app-page-wide .tcard-grid { grid-template-columns:repeat(auto-fill, minmax(200px, 1fr));
    gap:18px; }
}

/* ============================================================================
   Story page (/app/story/{root}) — the campaign home base (handoff §3).
   Mobile: stacked column. ≥900px: player+timeline left, meta/cast right.
   ========================================================================== */
.sp-page { max-width:1040px; }
.sp-cols { display:flex; flex-direction:column; gap:22px; }
.sp-player { position:relative; border-radius:14px; overflow:hidden;
  border:1px solid var(--paper-edge); box-shadow:var(--shadow-lift);
  background:#000; aspect-ratio:9/16; max-height:min(562px, 68vh); margin:0 auto; }
.sp-player video { width:100%; height:100%; object-fit:cover; display:block; }
.sp-player-tag { position:absolute; top:10px; left:12px; z-index:2; font-size:10px;
  letter-spacing:.1em; text-transform:uppercase; color:rgba(255,255,255,.85);
  text-shadow:0 1px 3px rgba(0,0,0,.6); pointer-events:none; }
.sp-timeline { display:flex; gap:7px; margin-top:12px; overflow-x:auto;
  padding-bottom:4px; justify-content:center; }
.sp-timeline::-webkit-scrollbar { display:none; }
.sp-thumb { position:relative; flex:0 0 auto; width:54px; aspect-ratio:9/16;
  border-radius:7px; overflow:hidden; cursor:pointer; padding:0; background:#111;
  border:1px solid var(--paper-edge); -webkit-tap-highlight-color:transparent; }
.sp-thumb img { width:100%; height:100%; object-fit:cover; display:block; }
.sp-thumb.on { border:2px solid var(--ink); }
.sp-thumb-n { position:absolute; top:3px; left:5px; z-index:2; font-size:8.5px;
  color:rgba(255,255,255,.85); text-shadow:0 1px 2px rgba(0,0,0,.7); }
.sp-thumb-open { display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:3px; text-decoration:none;
  border:1.5px dashed rgba(255,255,255,.35); background:transparent; }
.sp-open-plus { color:var(--oxblood); font-size:17px; font-weight:700; line-height:1; }
.sp-open-label { font-size:8px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--ink-muted); }
.sp-thumb-end { display:flex; align-items:center; justify-content:center;
  color:var(--amber); font-size:17px; border:1px solid rgba(255,184,74,.35);
  cursor:default; }
.sp-meta { display:flex; flex-direction:column; gap:14px; min-width:0; }
.sp-title { font-family:var(--font-sans); font-size:30px; font-weight:700;
  letter-spacing:-.03em; line-height:1.05; margin:0; }
.sp-stats { font-size:11px; color:var(--ink-muted); letter-spacing:.06em; }
.sp-cta { display:block; text-align:center; padding:15px; font-size:16px;
  font-weight:700; border-radius:999px; background:var(--oxblood); color:#fff;
  text-decoration:none; border:0; cursor:pointer; width:100%;
  font-family:var(--font-sans); }
.sp-cta:hover { background:var(--oxblood-deep); }
.sp-cta-secondary { display:block; text-align:center; padding:12px; font-size:13.5px;
  font-weight:600; border-radius:999px; border:1px solid var(--paper-edge);
  color:var(--ink-soft); text-decoration:none; }
.sp-film-pending { padding:12px 14px; border-radius:12px; font-size:13px;
  line-height:1.5; color:var(--ink-soft); background:rgba(255,184,74,.07);
  border:1px solid rgba(255,184,74,.3); }
.sp-section { margin:6px 0 -6px; }
.sp-cast { display:flex; flex-direction:column; gap:7px; }
.sp-cast-row { display:flex; align-items:center; gap:11px; padding:9px 12px;
  border-radius:10px; background:var(--paper-warm); border:1px solid var(--paper-edge); }
.sp-cast-open { background:transparent; border:1.5px dashed var(--paper-edge); }
.sp-cast-avatar { display:inline-flex; align-items:center; justify-content:center;
  width:30px; height:30px; border-radius:50%; flex:0 0 auto; font-size:12.5px;
  font-weight:700; color:#fff; background:var(--paper-deep, #1a1a20);
  border:1px solid rgba(255,255,255,.2); }
.sp-cast-open .sp-cast-avatar { background:transparent; color:var(--ink-faint);
  border:1.5px dashed var(--paper-edge); }
.sp-cast-body { flex:1; min-width:0; display:flex; flex-direction:column; }
.sp-cast-name { font-size:13.5px; font-weight:600; }
.sp-cast-name a { color:var(--ink); text-decoration:none; }
.sp-cast-open .sp-cast-name { color:var(--ink-muted); }
.sp-cast-role { font-size:9.5px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--ink-muted); }
.sp-claim { flex:0 0 auto; padding:5px 12px; font-size:12.5px; font-weight:600;
  border-radius:8px; border:1px solid var(--paper-edge); color:var(--ink);
  text-decoration:none; }
.sp-claim:hover { border-color:var(--oxblood); }
.sp-watchlink { font-size:11px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--ink-muted); text-decoration:none; margin-top:4px; }

@media (min-width: 900px) {
  .sp-cols { flex-direction:row; gap:26px; align-items:flex-start; }
  .sp-left { flex:0 0 auto; }
  .sp-player { height:min(562px, calc(100dvh - 220px)); max-height:none;
    aspect-ratio:9/16; margin:0; }
  .sp-timeline { justify-content:flex-start; }
  .sp-meta { flex:1; max-width:460px; }
}

/* Feed story-tag is now a LINK to the story page — keep its pill look. */
a.story-tag { text-decoration:none; }
.story-tag .st-arrow { opacity:.6; margin-left:4px; }

/* Story page — host card ("You started this story", handoff §3: host is a
   state, not a mode). Amber accent; 3-up action grid. */
.sp-host { padding:14px; border-radius:12px;
  border:1px solid rgba(255,184,74,.3);
  background:linear-gradient(180deg, rgba(255,184,74,.06), rgba(255,184,74,.01)); }
.sp-host-eyebrow { color:var(--amber); margin-bottom:10px; }
.sp-host-note { margin:0 0 10px; font-size:12.5px; color:var(--ink-soft); }
.sp-host-grid { display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; }
.sp-host-form { margin:0; display:contents; }
.sp-host-btn { display:flex; flex-direction:column; align-items:center; gap:6px;
  padding:10px 4px; border-radius:10px; cursor:pointer; width:100%;
  background:rgba(255,255,255,.03); border:1px solid var(--paper-edge);
  color:var(--ink); font-family:var(--font-sans); font-size:16px; line-height:1; }
.sp-host-btn span { font-size:11.5px; font-weight:600; }
.sp-host-btn:hover { border-color:rgba(255,184,74,.45); }

/* ── Earn toast (credit flywheel, made felt) ─────────────────────────────
   One-shot pill that slides down over the feed when credits were earned since
   the user last looked ("+5 ✦ — someone continued your story!"). Rendered by
   app_feed.html only on /app (the For You landing); tap to dismiss. */
.earn-toast {
  position: fixed; top: 14px; left: 50%;
  transform: translate(-50%, -64px); opacity: 0;
  display: flex; align-items: center; gap: 9px;
  padding: 9px 16px; border-radius: 999px;
  background: rgba(16, 16, 20, 0.92);
  border: 1px solid rgba(255, 184, 74, 0.55);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  z-index: 60; cursor: pointer;
  transition: transform 0.35s ease, opacity 0.35s ease;
  pointer-events: none;
}
.earn-toast.on { transform: translate(-50%, 0); opacity: 1; pointer-events: auto; }
.earn-toast-amt {
  font-family: var(--font-mono, monospace); font-weight: 700;
  font-size: 14px; color: var(--amber, #ffb84a); white-space: nowrap;
}
.earn-toast-line { font-size: 12.5px; color: rgba(255, 255, 255, 0.85); }

/* Account — recent credit activity (the ledger behind the balance). */
.ledger { margin: 10px 0 4px; border: 1px solid var(--paper-edge); border-radius: 10px; overflow: hidden; }
.ledger-row {
  display: flex; align-items: baseline; gap: 10px;
  padding: 8px 12px; font-size: 12.5px;
  border-bottom: 1px solid var(--paper-edge);
}
.ledger-row:last-child { border-bottom: none; }
.ledger-delta { min-width: 46px; text-align: right; color: var(--ink-muted); font-size: 12px; }
.ledger-delta.up { color: var(--amber, #ffb84a); }
.ledger-label { flex: 1; color: var(--ink); }
.ledger-when { color: var(--ink-muted); font-size: 10.5px; }

/* Role picker — full story pitch up top (new-thread flow) + role register line.
   Descriptions stay COMPLETE (writer's words, never clamped) but compact. */
.ob-role-story { margin: 0 0 12px; padding: 12px 14px; border-radius: 12px;
  background: var(--paper-warm); border: 1px solid var(--paper-edge); }
.ob-role-story-desc { margin: 0; font-size: 13px; line-height: 1.55;
  color: var(--ink-soft); }
.ob-role-story-meta { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 9px;
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-muted); }
.ob-role-register { display: block; margin: 1px 0 4px; font-size: 10px;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--amber); }
