/* ui.css — iPhone frame, screen layout, swipe UI, pause overlay,
   tier toggle. Adapted from owl_creek; scene/animation rules stripped. */

* { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0;
  height: 100%;
  background: #111;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: #f5f5f5;
  overscroll-behavior: none;
  user-select: none;
  -webkit-user-select: none;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
}

.iphone {
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.frame {
  position: relative;
  width: 100%; height: 100%;
  background: #000;
  overflow: hidden;
}

/* iPhone 15 Pro logical viewport = 393x852 (aspect 393:852 ≈ 1:2.168).
   Dev-frame matches that 1:1; on a normal page the iphone div is auto-
   sized to fit while preserving the same aspect ratio (see below). */
body.dev-frame .iphone {
  width: min(393px, 100vw);
  height: min(852px, 100vh);
}
body.dev-frame .frame {
  border-radius: 47px;          /* iPhone 15 Pro corner radius */
  box-shadow: 0 0 0 6px #1a1a1a, 0 20px 60px #000a;
}

/* Default (non-dev) view: lock the visible frame to iPhone-15-Pro
   393:852 aspect ratio, scaling to the largest size that fits the
   current viewport. Prevents the player from stretching to the full
   window on wide monitors. */
body:not(.dev-frame) .iphone {
  width: min(100vw, calc(100vh * 393 / 852));
  height: min(100vh, calc(100vw * 852 / 393));
}
/* Pill geometry — also drives the top-fade-mask below. Tweak these and
   both the pill and the fade rebalance together. */
:root {
  --pill-top: 12px;
  --pill-height: 32px;
  --fade-height: calc(var(--pill-height) * 1.5);
}

.dynamic-island {
  position: absolute;
  top: var(--pill-top); left: 50%;
  transform: translateX(-50%);
  width: 110px; height: var(--pill-height);
  background: #000;
  border-radius: 20px;
  /* Sits ABOVE the top-fade-mask (z-index 20) so the tier-indicator
     letter remains readable inside the otherwise-solid black band. */
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: 14px;
}

/* Black mask + fade. Solid from y=0 through the bottom of the pill
   (so the pill is entirely inside the black region and invisible);
   then a linear-gradient down to fully transparent over `fade-height`.
   Sits above the pill in z-order so scrolling text disappears into
   black underneath the bezel area, never clipping at a hard line. */
.top-fade-mask {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: calc(var(--pill-top) + var(--pill-height) + var(--fade-height));
  background: linear-gradient(
    to bottom,
    #000 0,
    #000 calc(var(--pill-top) + var(--pill-height)),
    transparent 100%
  );
  pointer-events: none;
  z-index: 20;
}
.tier-indicator {
  font-size: 13px;
  font-weight: 700;
  color: #e8c070;
  letter-spacing: 1px;
}

.screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: #0a0a10;
  touch-action: pan-x;
}

/* Text area = top ~66% of screen. Holds chapter label + a stack of
   speaker segments. `position: relative` anchors the scroll container;
   `overflow: hidden` clips during normal display, but app.js can
   programmatically translate `.card-segments` to scroll long content
   into view as audio plays.

   padding-top clears the entire top-fade-mask region (pill + fade)
   plus a small breathing gap, so the chapter label and first visible
   line render fully below the gradient on initial paint. As content
   scrolls upward, lines pass back UNDER the fade and dissolve into
   black instead of clipping at a hard edge. */
.text-area {
  position: relative;
  flex: 0 0 66%;
  padding:
    calc(var(--pill-top) + var(--pill-height) + var(--fade-height) + 8px + env(safe-area-inset-top))
    calc(22px + env(safe-area-inset-right))
    12px
    calc(22px + env(safe-area-inset-left));
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.chapter-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: #8a8a98;
  margin-bottom: 10px;
  flex: 0 0 auto;
}

/* Scroll container — gets translated by app.js when audio progresses
   past the visible midpoint of an overflowing card. */
.card-segments {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  transform: translateY(0);
  transition: transform .6s ease-out;
  will-change: transform;
}

/* One segment per speaker (or one segment per pure-narration block).
   Order inside a segment matches the user's requested layout:
   body → speaker-label → dotted separator (except after the last). */
.segment {
  display: flex;
  flex-direction: column;
}
.segment + .segment {
  margin-top: 6px;
}
.segment-body {
  font-size: clamp(15px, 4.2vw, 20px);
  line-height: 1.5;
  color: #f5f5f5;
  white-space: pre-line;
}
.segment-body em { color: #e8c070; font-style: italic; }
.segment-body q  { color: #e8c070; }
.segment-speaker {
  margin-top: 4px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: #e8c070;
  align-self: flex-end;       /* speaker name flush right under their text */
}
.segment-speaker.narrator-hidden {
  display: none;
}
/* Dotted yellow line between speaker groups. Only appears between
   segments (CSS adjacent-sibling selector). */
.segment + .segment::before {
  content: '';
  display: block;
  border-top: 1px dotted #e8c070;
  margin: 6px 0 8px;
  opacity: 0.7;
}

/* Password gate — pre-app overlay. Hidden when unlocked. */
.pw-gate {
  position: fixed; inset: 0;
  z-index: 9999;
  background: #0a0a10;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.pw-gate.hidden { display: none; }
.pw-card {
  width: 100%; max-width: 320px;
  text-align: center;
  display: flex; flex-direction: column; gap: 12px;
}
.pw-title {
  font-size: 28px; font-weight: 700;
  color: #f5f5f5; letter-spacing: 1px;
}
.pw-sub {
  font-size: 12px; color: #8a8a98;
  text-transform: uppercase; letter-spacing: 2px;
  margin-bottom: 8px;
}
.pw-input {
  font-size: 16px; padding: 12px 14px;
  border-radius: 10px; border: 1px solid #2a2a35;
  background: #15151c; color: #f5f5f5;
  outline: none;
}
.pw-input:focus { border-color: #e8c070; }
.pw-submit {
  font-size: 14px; font-weight: 600;
  padding: 12px; border: 0; border-radius: 10px;
  background: #e8c070; color: #0a0a10;
  cursor: pointer;
  text-transform: uppercase; letter-spacing: 1px;
}
.pw-submit:hover { background: #f0d488; }
.pw-err {
  font-size: 13px; color: #ef4444;
  min-height: 16px;
}

/* Section card — Act / Scene / stage direction. Centered, italic,
   distinct from speech segments. The dotted-line ::before is overridden
   to a solid short rule so a section visually starts a new beat. */
.segment.section {
  align-items: center;
  text-align: center;
  padding: 6px 0;
}
.segment.section .segment-body {
  font-size: clamp(13px, 3.4vw, 16px);
  color: #e8c070;
  letter-spacing: 0.4px;
  font-style: italic;
  line-height: 1.35;
}
.segment.section .segment-speaker { display: none; }
.segment + .segment.section::before {
  border-top: 2px solid #e8c070;
  border-style: solid;
  width: 28%;
  margin: 4px auto 8px;
  opacity: 0.5;
}
/* Act-level section (uppercase, larger). */
.segment.section.act {
  padding: 12px 0;
}
.segment.section.act .segment-body {
  font-size: clamp(18px, 4.6vw, 24px);
  text-transform: uppercase;
  letter-spacing: 2px;
  font-style: normal;
  font-weight: 700;
}

/* Per-clip karaoke highlight. A clip is one sentence (or comma-broken
   sub-sentence) when the card has per-clip audio attached. The active
   clip glows gold; played clips dim to gray; unplayed text stays at
   the normal body color so reading ahead is still natural. */
.clip            { transition: color .25s ease; color: inherit; }
.clip-played     { color: #8a8a98; }
.clip-active     { color: #ffe4b5; }

/* ── Scene placeholder ────────────────────────────────────────────
   Black region below the text area. No animation content yet — this
   is the slot where scene CSS / illustration would render. */
.animation-canvas {
  flex: 1 1 auto;
  position: relative;
  background: #000;
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .text-area, .card-segments { transition: none !important; animation: none !important; }
}

.progress {
  position: absolute;
  bottom: calc(8px + env(safe-area-inset-bottom)); left: 16px; right: 16px;
  height: 3px;
  background: #ffffff20;
  border-radius: 2px;
  overflow: hidden;
}
#progress-bar {
  height: 100%;
  width: 0%;
  background: #e8c070;
  transition: width .25s ease;
}

.splash {
  position: absolute; inset: 0;
  z-index: 100;
  background: #0a0a10;
  display: flex; align-items: center; justify-content: center;
  transition: opacity .5s ease;
}
.splash.hidden {
  opacity: 0;
  pointer-events: none;
}
.splash-inner {
  text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 16px;
}
.splash-title {
  font-size: 28px; font-weight: 600; line-height: 1.2;
  color: #f5f5f5;
}
.splash-author {
  font-size: 14px; color: #8a8a98;
  font-style: italic;
}
.splash-status {
  font-size: 13px; color: #8a8e9a;
  font-family: ui-monospace, monospace;
}
.splash-tap {
  margin-top: 12px; font-size: 15px; color: #e8c070;
  animation: pulse-tap 2s ease-in-out infinite;
}
@keyframes pulse-tap {
  0%,100% { opacity: .6; }
  50% { opacity: 1; }
}

/* Card transition — vertical (swipe up = next card) */
.text-area.swipe-out-up   { animation: swipeOutUp   .25s ease forwards; }
.text-area.swipe-out-down { animation: swipeOutDown .25s ease forwards; }
.text-area.swipe-in-down  { animation: swipeInDown  .25s ease forwards; }
.text-area.swipe-in-up    { animation: swipeInUp    .25s ease forwards; }

@keyframes swipeOutUp   { to { transform: translateY(-30%); opacity: 0; } }
@keyframes swipeOutDown { to { transform: translateY( 30%); opacity: 0; } }
@keyframes swipeInDown  { from { transform: translateY( 30%); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes swipeInUp    { from { transform: translateY(-30%); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

/* ═══════════════════════════════════════════════════
   PAUSE OVERLAY
   ═══════════════════════════════════════════════════ */
.pause-overlay {
  position: absolute; inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity .3s ease;
}
.pause-overlay.hidden {
  opacity: 0;
  pointer-events: none;
}
.pause-scrim {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, .72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.pause-content {
  position: relative;
  z-index: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  padding: 0 16px;
}

/* Transport buttons */
.transport {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 32px;
}
.transport-btn {
  background: rgba(255,255,255,.1);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .15s ease, transform .15s ease;
}
.transport-btn:active {
  transform: scale(.9);
  background: rgba(255,255,255,.2);
}
.transport-btn.play-btn {
  width: 72px; height: 72px;
  background: rgba(232, 192, 112, .25);
  border: 2px solid rgba(232, 192, 112, .5);
}
.transport-btn.play-btn:active {
  background: rgba(232, 192, 112, .4);
}
.transport-btn:not(.play-btn) {
  width: 48px; height: 48px;
}

.section-label {
  font-size: 12px;
  color: #8a8a98;
  letter-spacing: 1px;
  text-transform: uppercase;
  text-align: center;
}

/* ---------------------------------------------------------------- */
/* Autoplay (robot) button. Lives in the pause overlay, below the   */
/* prev/play/next transport row. When `.active`, glows gold + does  */
/* a subtle bob so you can tell from across the room it's running.  */
/* ---------------------------------------------------------------- */
.autoplay-btn {
  width: 56px; height: 56px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.06);
  color: #cfcfd6;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 6px auto 0;
  transition: background 180ms ease, border-color 180ms ease,
              box-shadow 220ms ease, transform 100ms ease;
}
.autoplay-btn:active   { transform: scale(0.92); }
.autoplay-btn:hover    { background: rgba(255, 255, 255, 0.10); }
.autoplay-btn svg      { fill: #cfcfd6; transition: fill 180ms ease; }
.autoplay-btn.active {
  background: rgba(232, 192, 112, 0.18);
  border-color: rgba(232, 192, 112, 0.65);
  box-shadow: 0 0 18px rgba(232, 192, 112, 0.55);
  animation: autoplay-bob 2.4s ease-in-out infinite;
}
.autoplay-btn.active svg { fill: #ffd97a; }
@keyframes autoplay-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2px); }
}

/* ---------------------------------------------------------------- */
/* Tier toggle (3-switch) — injected into the pause overlay by      */
/* app.js. Three pill-shaped buttons; tap switches the active tier  */
/* via the explicit linkage table in tier-switch.js.                */
/* ---------------------------------------------------------------- */
.tier-toggle {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: stretch;
  gap: 8px;
  margin: 12px auto 18px;
  padding: 6px;
  width: min(92%, 540px);
  background: rgba(20, 20, 28, 0.85);
  border: 1px solid rgba(232, 192, 112, 0.35);
  border-radius: 14px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}
.tier-btn {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 10px 8px;
  background: rgba(40, 40, 50, 0.6);
  color: #cfcfd6;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 10px;
  cursor: pointer;
  transition: background 180ms ease, color 180ms ease,
              border-color 180ms ease, transform 100ms ease;
  font-family: inherit;
}
.tier-btn:hover {
  background: rgba(60, 60, 75, 0.75);
  color: #fff;
}
.tier-btn:active {
  transform: scale(0.97);
}
.tier-btn .tier-letter {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: inherit;
}
.tier-btn .tier-name {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  opacity: 0.85;
}
.tier-btn .tier-count {
  font-size: 10px;
  opacity: 0.65;
  margin-top: 2px;
}
.tier-btn.active {
  background: linear-gradient(180deg, #4a3520 0%, #6b4a2a 100%);
  color: #ffe4b5;
  border-color: #e8c070;
  box-shadow: inset 0 -2px 0 rgba(232, 192, 112, 0.65),
              0 2px 8px rgba(232, 192, 112, 0.18);
}
.tier-btn.active .tier-letter { color: #ffd97a; }
.tier-btn.active .tier-name   { color: #ffe4b5; opacity: 1; }

/* Tiers with no audio in the current manifest (currently A — see
   CARDS_AUDIO.md §11) get a muted-speaker glyph + dimmed letter so the
   user knows a tier swap won't yield karaoke. */
.tier-btn.no-audio .tier-letter::after {
  content: ' \1F507';   /* speaker-with-cancellation-stroke */
  font-size: 0.6em;
  margin-left: 4px;
  opacity: 0.7;
}
.tier-btn.no-audio .tier-count {
  opacity: 0.8;
  font-style: italic;
}
