/* Kiosk layout — tuned for a large portrait/landscape touchscreen. */

.stage { position: relative; z-index: 1; height: 100%; width: 100%; overflow: hidden; }

/* ---------- brand ---------- */
.brand {
  position: absolute; top: 42px; left: 38px; z-index: 6;
  display: flex; flex-direction: column; line-height: 1;
}
/* Width is matched to the tagline below it by fitLogo() in kiosk.js. */
.brand-logo { width: 172px; height: auto; display: block; opacity: 0.94; }
.brand-sub { margin-top: 10px; font-size: clamp(11px, 1.3vmin, 15px); letter-spacing: 4px; text-transform: uppercase; color: var(--accent-soft); white-space: nowrap; }

/* Back button — shown once she's engaged, sits where the logo was. */
.back-btn {
  position: absolute; top: 38px; left: 38px; z-index: 8;
  display: inline-flex; align-items: center; justify-content: center;
  width: clamp(46px, 6vmin, 64px); height: clamp(46px, 6vmin, 64px);
  border-radius: 50%; cursor: pointer;
  background: var(--glass); border: 1px solid var(--glass-brd); color: var(--lilac);
  backdrop-filter: blur(12px);
  opacity: 0; transform: translateX(-12px); pointer-events: none;
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease), background 0.3s var(--ease), color 0.3s var(--ease);
}
.back-btn svg { width: clamp(20px, 2.6vmin, 28px); height: clamp(20px, 2.6vmin, 28px); }
.back-btn:active { background: var(--accent); color: #2a1206; border-color: transparent; }
.stage.engaged .back-btn { opacity: 1; transform: none; pointer-events: auto; }
/* The brand steps aside for the back button whenever she's engaged. */
.stage.engaged .brand { opacity: 0; pointer-events: none; transition: opacity 0.4s var(--ease); }

/* ---------- character ---------- */
.character-zone {
  position: absolute; z-index: 2;
  left: 50%; bottom: 0;
  transform: translateX(-50%);
  height: 82vh; width: 46vh; max-width: 620px;
  display: flex; align-items: flex-end; justify-content: center;
  transition: left 1.05s var(--ease), transform 1.05s var(--ease),
              height 0.8s var(--ease), top 1.05s var(--ease), bottom 0.8s var(--ease);
  --speak: 0; --listen: 0;
}
.stage.engaged .character-zone {
  left: 23%;
  transform: translateX(-50%);
}
.character {
  position: relative; z-index: 3;
  height: 100%; aspect-ratio: 887 / 1774;
  filter: drop-shadow(0 30px 44px rgba(0,0,0,0.55));
  transform-origin: 50% 92%;
  animation: breathe 6.5s ease-in-out infinite;
  will-change: transform;
}
.stage.engaged .character { animation: breathe 5.5s ease-in-out infinite; }

/* Layered pose images crossfade between Klaire's expressions. */
.pose {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; object-position: bottom center;
  opacity: 0; transition: opacity 0.55s var(--ease); pointer-events: none;
}
.pose-idle { opacity: 1; }
.stage[data-state="thinking"] .pose-idle,
.stage[data-state="speaking"] .pose-idle,
.stage.delight .pose-idle { opacity: 0; }
.stage[data-state="thinking"] .pose-thinking { opacity: 1; }
.stage[data-state="speaking"] .pose-talking { opacity: 1; }
.stage.delight .pose-laughing { opacity: 1; }

@keyframes breathe {
  0%, 100% { transform: translateY(0) scale(1); }
  50% { transform: translateY(-1.1%) scale(1.006); }
}

/* speaking pulse driven by --speak (0..1) */
.character { transform: translateY(calc(var(--speak) * -0.6%)) scale(calc(1 + var(--speak) * 0.014)); }

.aura {
  position: absolute; z-index: 1; bottom: 6%; left: 50%;
  width: 118%; height: 62%;
  transform: translateX(-50%) scale(calc(1 + var(--speak) * 0.16 + var(--listen) * 0.1));
  background: radial-gradient(ellipse at center,
     rgba(154,108,255, calc(0.42 + var(--speak) * 0.4)) 0%,
     rgba(124,77,188,0.2) 42%, transparent 68%);
  filter: blur(26px);
  opacity: calc(0.55 + var(--speak) * 0.45);
  transition: opacity 0.12s linear;
  pointer-events: none;
}
.pedestal {
  position: absolute; z-index: 1; bottom: 2%; left: 50%;
  width: 96%; height: 40px; transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(255,138,61,0.28), transparent 70%);
  filter: blur(10px);
}

/* Gold glow that blooms from the centre of the background while Klaire speaks.
   Intensity + size track her voice amplitude (--speak, set on the stage). */
.speak-glow {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0; mix-blend-mode: screen;
  background: radial-gradient(52% 48% at 50% 46%,
     rgba(255, 194, 82, calc(0.34 + var(--speak, 0) * 0.6)) 0%,
     rgba(255, 150, 40, calc(0.16 + var(--speak, 0) * 0.34)) 40%,
     transparent 72%);
  transform: scale(calc(0.9 + var(--speak, 0) * 0.26));
  transition: opacity 0.55s var(--ease), transform 0.12s ease-out;
}
.stage[data-state="speaking"] .speak-glow { opacity: 1; }

/* Thinking is signalled by the cooling, pulsing ambient background (see
   base.css, body.is-thinking) — the old bouncing-dots indicator is retired. */
.thinking { display: none !important; }

/* ---------- greeting + rotating prompt buttons ---------- */
.speech {
  position: absolute; z-index: 5; left: 52px; right: 214px; bottom: 150px;
  transition: opacity 0.5s var(--ease), transform 0.6s var(--ease);
}
.speech-line {
  font-family: var(--font-display);
  font-size: clamp(24px, 3.2vw, 44px); font-weight: 700; line-height: 1.14;
  letter-spacing: -0.2px; color: var(--ink); margin-bottom: clamp(12px, 1.8vmin, 24px);
  text-wrap: balance;
}
.prompts { display: flex; flex-direction: column; align-items: flex-start; gap: clamp(8px, 1.2vmin, 15px); }
.prompt-btn {
  display: inline-flex; align-items: center; gap: 12px; width: auto; max-width: 100%; text-align: left;
  padding: clamp(12px, 1.9vmin, 22px) clamp(16px, 2.3vmin, 28px);
  border-radius: 18px; cursor: pointer;
  background: rgba(201, 182, 242, 0.10); border: 1px solid var(--glass-brd);
  color: var(--lilac); font-family: inherit; font-weight: 600;
  font-size: clamp(15px, 2.05vmin, 23px); backdrop-filter: blur(12px);
  box-shadow: 0 10px 30px -18px rgba(0, 0, 0, 0.7);
  transition: opacity 0.95s var(--ease), transform 0.35s var(--ease),
              background 0.3s var(--ease), border-color 0.3s var(--ease);
}
.prompt-btn svg { width: clamp(18px, 2.5vmin, 28px); height: clamp(18px, 2.5vmin, 28px);
  color: var(--accent-soft); flex: 0 0 auto; transition: color 0.3s var(--ease); }
.prompt-btn:hover, .prompt-btn:active {
  background: var(--accent); color: #2a1206; border-color: transparent; transform: translateY(-2px);
}
.prompt-btn:hover svg, .prompt-btn:active svg { color: #2a1206; }
.prompt-btn.fading { opacity: 0; }   /* slow cross-fade as prompts rotate */
.speech.hide { opacity: 0; transform: translateY(10px); pointer-events: none; }

/* ---------- transcript ---------- */
.transcript {
  position: absolute; z-index: 5; right: 214px; top: 12%; bottom: 150px;
  width: min(36vw, 520px);
  overflow-y: auto; overflow-x: hidden;
  display: flex; flex-direction: column; gap: 14px;
  padding: 8px 6px 8px 2px;
  opacity: 0; pointer-events: none;
  transition: opacity 0.6s var(--ease);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 8%, #000 92%, transparent);
}
.stage.engaged .transcript { opacity: 1; pointer-events: auto; }
/* Keep the transcript stacked cleanly above the input bar / card. */
.stage.kbmode .transcript { bottom: 128px; }
.stage.card-open .transcript { bottom: calc(44vh + 28px); }
.stage.kbmode.card-open .transcript { bottom: calc(44vh + 104px); }
.transcript::-webkit-scrollbar { width: 6px; }
.transcript::-webkit-scrollbar-thumb { background: rgba(201,182,242,0.25); border-radius: 999px; }

.bubble {
  max-width: 88%; padding: 11px 15px; border-radius: 18px; font-size: 15px; line-height: 1.42;
  animation: rise 0.5s var(--ease) both;
}
.bubble.user {
  align-self: flex-end; background: linear-gradient(135deg, var(--purple), var(--purple-bright));
  color: #fff; border-bottom-right-radius: 6px; box-shadow: 0 10px 26px -10px rgba(124,77,188,0.7);
}
.bubble.klaire {
  align-self: flex-start; background: rgba(28, 15, 52, 0.88); border: 1px solid var(--glass-brd);
  color: var(--lilac); border-bottom-left-radius: 6px; backdrop-filter: blur(20px);
  box-shadow: 0 10px 30px -16px rgba(0, 0, 0, 0.75);
}
.bubble.voice {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 10px;
  background: rgba(201,182,242,0.08); border: 1px solid var(--glass-brd); color: var(--ink-dim);
  font-size: 15px; padding: 10px 15px;
}
.bubble.voice .spk { color: var(--accent-soft); }
.bubble.voice button {
  background: none; border: none; color: var(--lavender); cursor: pointer; font-size: 13px;
  text-decoration: underline; padding: 0;
}
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }

/* ---------- right controls ---------- */
.controls {
  position: absolute; z-index: 7; right: 46px; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: center; gap: clamp(16px, 2.6vmin, 34px);
}
.mic-btn {
  position: relative; width: clamp(96px, 14vmin, 176px); height: clamp(96px, 14vmin, 176px);
  border-radius: 50%; border: none; cursor: pointer;
  background: radial-gradient(circle at 35% 30%, var(--purple-bright), var(--purple) 60%, #4a2a86);
  color: #fff; box-shadow: 0 18px 44px -12px rgba(124,77,188,0.85), inset 0 2px 6px rgba(255,255,255,0.25);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.mic-btn:active { transform: scale(0.95); }
.mic-ico { width: clamp(34px, 5vmin, 60px); height: clamp(34px, 5vmin, 60px); fill: currentColor; }
.mic-label { font-size: clamp(13px, 1.6vmin, 19px); font-weight: 700; letter-spacing: 0.5px; }
.mic-ring {
  position: absolute; inset: -6px; border-radius: 50%; border: 3px solid var(--accent);
  opacity: 0; transform: scale(1);
}
.stage[data-state="listening"] .mic-btn {
  background: radial-gradient(circle at 35% 30%, var(--accent-soft), var(--accent) 65%, #d9631f);
  box-shadow: 0 0 0 calc(6px + var(--listen, 0) * 26px) rgba(255,138,61,0.18),
              0 18px 44px -10px rgba(255,138,61,0.7);
}
.stage[data-state="listening"] .mic-ring { animation: ripple 1.6s ease-out infinite; }
@keyframes ripple { 0%{opacity:.7;transform:scale(1)} 100%{opacity:0;transform:scale(1.5)} }

.key-btn {
  width: clamp(64px, 9.6vmin, 120px); height: clamp(64px, 9.6vmin, 120px);
  border-radius: 24%; cursor: pointer;
  background: var(--glass); border: 1px solid var(--glass-brd); color: var(--lavender);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  backdrop-filter: blur(12px);
  transition: transform 0.3s var(--ease), background 0.3s var(--ease), color 0.3s var(--ease);
}
.key-btn svg { width: clamp(26px, 3.8vmin, 44px); height: clamp(26px, 3.8vmin, 44px); }
.key-btn span { font-size: clamp(11px, 1.35vmin, 16px); font-weight: 700; letter-spacing: 0.5px; }
.key-btn:active { transform: scale(0.94); }
.stage.kbmode .key-btn { background: var(--accent); color: #2a1206; border-color: transparent; }

/* ---------- keyboard bar ---------- */
.keybar {
  position: absolute; z-index: 8; left: 50%; bottom: -120px; transform: translateX(-50%);
  width: min(760px, 80vw); display: flex; gap: 12px; align-items: center;
  padding: 12px; border-radius: 26px; background: var(--glass); border: 1px solid var(--glass-brd);
  backdrop-filter: blur(18px); box-shadow: var(--shadow);
  opacity: 0; transition: bottom 0.6s var(--ease), opacity 0.5s var(--ease);
}
.stage.kbmode .keybar { bottom: 34px; opacity: 1; }
.stage.kbmode.card-open .keybar { bottom: calc(44vh + 22px); }
.keybar input {
  flex: 1; background: transparent; border: none; outline: none; color: var(--ink);
  font-size: clamp(15px, 2.3vmin, 18px); font-family: inherit; padding: 12px 14px;
}
.keybar input::placeholder { color: var(--ink-faint); }
.send {
  width: 56px; height: 56px; border-radius: 18px; border: none; cursor: pointer; color: #2a1206;
  background: linear-gradient(135deg, var(--accent-soft), var(--accent));
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.25s var(--ease);
}
.send svg { width: 26px; height: 26px; }
.send:active { transform: scale(0.9); }

/* ---------- info card ---------- */
.card-dock {
  position: absolute; z-index: 9; left: 50%; bottom: 0; transform: translate(-50%, 110%);
  width: min(1080px, 92vw); height: 44vh; max-height: 520px;
  overflow: hidden;
  background: linear-gradient(160deg, rgba(42,21,80,0.92), rgba(20,10,36,0.94));
  border: 1px solid var(--glass-brd); border-bottom: none;
  border-radius: 30px 30px 0 0; box-shadow: var(--shadow); backdrop-filter: blur(22px);
  transition: transform 0.72s var(--ease);
}
.stage.card-open .card-dock { transform: translate(-50%, 0); }
.card-close {
  position: absolute; top: 16px; right: 18px; z-index: 4; width: 46px; height: 46px; border-radius: 50%;
  background: rgba(20,10,36,0.5); border: 1px solid var(--glass-brd); color: var(--ink);
  font-size: 26px; cursor: pointer; line-height: 1; backdrop-filter: blur(6px);
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
}
.card-close:hover, .card-close:active { background: var(--accent); color: #2a1206; transform: scale(1.05); }
/* Swipe-down handle (portrait sheet). */
.card-grab {
  display: none; position: absolute; top: 10px; left: 50%; transform: translateX(-50%); z-index: 4;
  width: 52px; height: 5px; border-radius: 999px; background: rgba(201,182,242,0.4);
}
/* The dock holds two swappable views; the mode class picks which is visible. */
.card-deck, .card-detail { position: absolute; inset: 0; }
.card-dock.mode-deck .card-detail { display: none; }
.card-dock.mode-detail .card-deck { display: none; }

/* ---- detail view (the full single card) ---- */
.card-detail { display: flex; }

/* ---- deck view (grid of summary tiles) ---- */
.card-deck { display: flex; flex-direction: column; padding: 26px 30px 20px; }
.deck-head { font-family: var(--font-display); font-weight: 700; color: var(--ink);
  font-size: clamp(18px, 2vw, 24px); margin: 0 0 16px; padding-right: 56px; }
.deck-grid { flex: 1; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; padding-right: 4px; }
.deck-grid::-webkit-scrollbar { width: 6px; }
.deck-grid::-webkit-scrollbar-thumb { background: rgba(201,182,242,0.25); border-radius: 999px; }
.deck-card {
  display: flex; align-items: center; gap: 16px; width: 100%; text-align: left; cursor: pointer;
  padding: 12px; border-radius: 18px; flex: 0 0 auto;
  background: rgba(201,182,242,0.07); border: 1px solid var(--glass-brd); color: var(--lilac);
  transition: transform 0.25s var(--ease), background 0.25s var(--ease), border-color 0.25s var(--ease);
}
.deck-card:hover, .deck-card:active { transform: translateX(4px); background: rgba(201,182,242,0.14); border-color: var(--purple-bright); }
.deck-thumb { flex: 0 0 auto; width: clamp(64px, 9vmin, 96px); height: clamp(64px, 9vmin, 96px);
  border-radius: 12px; overflow: hidden; background: var(--plum); position: relative; }
.deck-thumb img { width: 100%; height: 100%; object-fit: cover; object-position: center 28%; }
.deck-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.deck-kicker { font-size: 10.5px; letter-spacing: 2.5px; text-transform: uppercase; color: var(--accent-soft); font-weight: 700; }
.deck-title { font-family: var(--font-display); font-size: clamp(16px, 2.1vmin, 21px); font-weight: 700; color: var(--ink); line-height: 1.15; margin: 0; }
.deck-sum { font-size: clamp(12.5px, 1.7vmin, 15px); line-height: 1.4; color: var(--ink-dim);
  margin: 0; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.deck-arrow { flex: 0 0 auto; width: 22px; height: 22px; color: var(--lavender); opacity: 0.7; }

/* Back-to-results button on an expanded card. */
.detail-back {
  position: absolute; top: 16px; left: 18px; z-index: 4;
  display: none; align-items: center; gap: 4px; cursor: pointer;
  padding: 9px 16px; border-radius: 999px; font-family: inherit; font-weight: 700; font-size: 14px;
  background: rgba(20,10,36,0.5); border: 1px solid var(--glass-brd); color: var(--ink); backdrop-filter: blur(6px);
}
.card-dock.has-deck.mode-detail .detail-back { display: inline-flex; }

.card-media { flex: 0 0 42%; overflow: hidden; position: relative; background: var(--bg-1); }
/* Blurred fill of the same image so the CONTAINED (uncropped) image has no
   empty bars — nothing on the card gets cut, faces included. */
.card-media::before {
  content: ""; position: absolute; inset: -8%; z-index: 0;
  background-image: var(--card-bg, none); background-size: cover; background-position: center;
  filter: blur(30px) brightness(0.5) saturate(1.15);
}
.card-media img { position: relative; z-index: 1; width: 100%; height: 100%; object-fit: contain; animation: kenburns 12s ease-out both; }
.card-media::after { content: ""; position: absolute; inset: 0; z-index: 2; background: linear-gradient(90deg, transparent 62%, rgba(20,10,36,0.85)); }
@keyframes kenburns { from { transform: scale(1.08); } to { transform: scale(1); } }
.card-body { flex: 1; padding: 40px 46px; overflow-y: auto; display: flex; flex-direction: column; }
.card-body::-webkit-scrollbar { width: 6px; }
.card-body::-webkit-scrollbar-thumb { background: rgba(201,182,242,0.25); border-radius: 999px; }
.card-kicker { font-size: 12px; letter-spacing: 3px; text-transform: uppercase; color: var(--accent-soft); font-weight: 700; }
.card-title { font-family: var(--font-display); font-size: clamp(28px, 3vw, 40px); font-weight: 700; margin: 10px 0 16px; line-height: 1.1; letter-spacing: -0.2px; }
.card-text { font-size: clamp(14px, 1.6vw, 16px); line-height: 1.55; color: var(--lilac); white-space: pre-line; }
.card-related { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }
.card-link { margin-top: 20px; color: var(--accent-soft); font-weight: 600; text-decoration: none; font-size: 15px; }
.card-link:hover { text-decoration: underline; }

/* ---------- QR — vertical, top-right, sized to tuck in beside the chat.
   Same size in idle and while chatting (stays visible throughout). ---------- */
.qr-dock {
  position: absolute; z-index: 6; top: 22px; right: 20px; left: auto; bottom: auto;
  display: flex; flex-direction: column; align-items: center; gap: 9px; text-align: center;
  width: calc(clamp(72px, 9.6vmin, 120px) + 20px);
  padding: 10px; border-radius: 18px;
  background: var(--glass); border: 1px solid var(--glass-brd); backdrop-filter: blur(16px);
  box-shadow: 0 14px 36px -18px rgba(0,0,0,0.7);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
.qr-frame { width: clamp(72px, 9.6vmin, 120px); height: clamp(72px, 9.6vmin, 120px); border-radius: 12px; background: #fff; padding: 6px; }
.qr-frame img { width: 100%; height: 100%; display: block; }
.qr-copy { display: flex; flex-direction: column; gap: 2px; align-items: center; }
.qr-copy strong { font-family: var(--font-display); font-size: clamp(12px, 1.5vmin, 16px); font-weight: 700; color: var(--ink); line-height: 1.15; }
.qr-copy span { font-size: clamp(10px, 1.2vmin, 13px); color: var(--ink-dim); line-height: 1.25; }

/* auto-reset countdown ring (bottom-right) */
.idle-timer {
  position: absolute; z-index: 30; right: 26px; bottom: 26px;
  width: clamp(50px, 7.4vmin, 78px); height: clamp(50px, 7.4vmin, 78px);
  display: grid; place-items: center;
  opacity: 0; transform: scale(0.85); pointer-events: none;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}
.idle-timer.show { opacity: 1; transform: none; }
.idle-timer svg { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.it-track { fill: rgba(20, 10, 36, 0.7); stroke: var(--glass-brd); stroke-width: 2; }
.it-prog {
  fill: none; stroke: var(--accent); stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 100; stroke-dashoffset: 0; transition: stroke-dashoffset 1s linear;
}
.idle-timer.urgent .it-prog { stroke: #ff5a5a; }
.it-num { position: relative; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(19px, 3vmin, 32px); color: var(--ink); }

/* listening veil */
.listen-veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: 0;
  background: radial-gradient(60% 60% at 26% 60%, rgba(255,138,61,0.10), transparent 70%);
  transition: opacity 0.5s var(--ease);
}
.stage[data-state="listening"] .listen-veil { opacity: 1; }

/* =====================  PORTRAIT KIOSK  ===================== */
@media (max-aspect-ratio: 3/4) {
  /* Large, near life-size character standing on the floor glow, positioned a
     touch left of centre to leave a clear right-hand control rail. */
  .character-zone {
    height: 86vh; bottom: 0; top: auto; left: 41%;
  }
  /* When chatting she simply slides to the left — SAME size, not resized —
     freeing the right side for the conversation. */
  .stage.engaged .character-zone {
    height: 86vh; bottom: 0; top: auto; left: 18%;
  }
  .stage.engaged .brand { opacity: 0; transition: opacity 0.5s var(--ease); }
  /* With a card open she shrinks a little and rises to stay visible above it. */
  .stage.card-open .character-zone { height: 42vh; bottom: calc(52vh - 5vh); left: 20%; }

  /* Controls sit RIGHT-MIDDLE (inherited base rail). When a card is up they lift
     to just above it, so voice/type follow-ups stay one tap away. */
  .controls { right: clamp(20px, 2.8vmin, 40px); }
  .stage.card-open .controls { top: auto; bottom: calc(52vh + 18px); transform: none; }
  /* In keyboard mode the input bar is the follow-up affordance, so hide the rail. */
  .stage.kbmode.card-open .controls { opacity: 0; pointer-events: none; }

  /* Prompts span nearly the full width at the bottom (control rail is mid-right,
     QR sits below). */
  .speech {
    left: 28px; right: 28px; max-width: none; bottom: 188px; top: auto;
  }
  .speech-line { text-shadow: 0 2px 16px rgba(10, 4, 22, 0.75); }

  /* Transcript: a tall block that starts near the top edge and runs down to a
     third from the bottom. Its right edge is kept LEFT of the control rail so
     the bubbles never sit under Talk/Type. The top fade is trimmed so upper
     bubbles reach close to the top. */
  /* Wide chat that slightly overlaps the character on the left. Its right edge
     stays clear of the Talk/Type rail (which is mid-right in this state). Starts
     near the top edge with only a whisper of a top fade. */
  .transcript {
    left: 30%; right: clamp(124px, 19vmin, 224px); width: auto; top: 2%; bottom: 33%;
    -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 1.5%, #000 96%, transparent);
    mask-image: linear-gradient(180deg, transparent 0, #000 1.5%, #000 96%, transparent);
  }
  /* Card open — keep the SAME left/right as the no-card chat so the alignment
     never shifts, and run the chat DOWN to just above the card. In voice it
     passes to the LEFT of the lifted control rail (its right edge already clears
     it). This MUST override the base landscape rules. */
  .stage.card-open .transcript { top: 2%; bottom: calc(52vh + 16px); }
  /* Keyboard: the input bar spans full width above the card, so stop above it. */
  .stage.kbmode.card-open .transcript { top: 2%; bottom: calc(52vh + 100px); }
  .bubble { max-width: 100%; font-size: clamp(13px, 2.7vmin, 16px); }

  /* QR keeps the compact top-right position from the base (visible throughout). */
  .qr-dock { top: 20px; right: 18px; }

  /* Keyboard bar: full-width along the bottom (the control rail is mid-right,
     so nothing here needs to dodge it). */
  .keybar {
    width: auto; left: 24px; right: 24px; transform: none; bottom: 40px;
  }
  .stage.kbmode .keybar { bottom: 40px; }
  .stage.kbmode.card-open .keybar { bottom: calc(52vh + 16px); }

  /* Card: full-width sheet, image stacked on top, with a swipe-down handle. */
  .card-dock {
    width: 100vw; height: 52vh; max-height: none;
    border-radius: 28px 28px 0 0;
  }
  .card-grab { display: block; }
  .card-detail { flex-direction: column; }
  .card-media { flex: 0 0 34%; }
  .card-media::after { background: linear-gradient(0deg, rgba(20,10,36,0.92), transparent 55%); }
  .card-body { padding: 26px 30px; }
  .card-title { font-size: clamp(26px, 6vw, 34px); }
  .card-deck { padding: 24px 22px 18px; }
  .deck-head { font-size: clamp(17px, 4.8vw, 22px); }
}
