:root {
  --bg: #0a0c13;
  --panel: #121622;
  --panel-2: #171c2b;
  --line: #242c40;
  --text: #e7ebf5;
  --muted: #8d97b0;
  --accent: #7aa2ff;
  --ok: #56d6a8;
  --warn: #eeb65e;
  --violet: #a88cff;
  --off: #64708c;
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--text);
  font: 15px/1.55 ui-sans-serif, -apple-system, "Segoe UI", Roboto, Inter, system-ui, sans-serif; }

.stage { display: grid; grid-template-columns: minmax(300px, 460px) minmax(340px, 1fr);
  gap: 20px; max-width: 1180px; margin: 0 auto; padding: 22px 16px; align-content: start; }
@media (max-width: 880px) { .stage { grid-template-columns: 1fr; } }

/* ---------- face ---------- */
.face-panel { background: var(--panel); border: 1px solid var(--line); border-radius: 18px;
  padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.face-wrap { position: relative; border-radius: 14px; overflow: hidden; background: #0b0d15; }
#face { display: block; width: 100%; aspect-ratio: 640 / 796; max-width: 100%; }

.status { position: absolute; left: 12px; top: 12px; font-size: 11px; font-weight: 600;
  letter-spacing: .07em; text-transform: uppercase; padding: 5px 11px; border-radius: 999px;
  background: rgba(10,12,19,.72); border: 1px solid rgba(231,235,245,.2); color: #c3cadd;
  backdrop-filter: blur(6px); }
.status[data-state="listening"] { color: var(--ok); border-color: rgba(86,214,168,.5); }
.status[data-state="thinking"]  { color: var(--warn); border-color: rgba(238,182,94,.5); }
.status[data-state="speaking"]  { color: var(--violet); border-color: rgba(168,140,255,.5); }

.caption { position: absolute; left: 0; right: 0; bottom: 0; padding: 14px 16px 16px;
  background: linear-gradient(to top, rgba(6,8,14,.94) 38%, rgba(6,8,14,0));
  font-size: 15px; line-height: 1.45; min-height: 0; }
.caption:empty { display: none; }

.face-controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between; }
.badges { display: flex; flex-wrap: wrap; gap: 6px; }
.badge { font-size: 11px; padding: 4px 9px; border-radius: 999px; border: 1px solid var(--line);
  color: var(--muted); background: #0f1320; max-width: 190px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.badge--ok { color: var(--ok); border-color: rgba(86,214,168,.35); }
.badge--off { color: var(--off); }

/* ---------- chat / script ---------- */
.chat-panel { background: var(--panel); border: 1px solid var(--line); border-radius: 18px;
  padding: 18px; display: flex; flex-direction: column; gap: 14px; min-height: 480px; }
.chat-head h1 { margin: 0; font-size: 19px; letter-spacing: -.01em; }
.chat-head .sub { margin: 4px 0 0; color: var(--muted); font-size: 13px; }

.modes, .seg { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.seg { gap: 0; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.seg-btn { font: inherit; font-size: 13px; font-weight: 600; padding: 8px 13px; cursor: pointer;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--muted); border-radius: 10px; }
.seg .seg-btn { border: 0; border-radius: 0; }
.seg-btn.is-on { background: #1e2a4d; color: var(--text); border-color: #2c3d6b; }
.seg-btn:hover:not(.is-on) { color: var(--text); }

.run-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.run-title { font-weight: 600; font-size: 14px; }
.run-count { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }

.beats { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px;
  flex: 1; max-height: 40vh; overflow-y: auto; }
.beat { border-left: 2px solid var(--line); padding: 6px 0 6px 11px; opacity: .45; }
.beat.is-done { opacity: .55; border-left-color: var(--off); }
.beat.is-now { opacity: 1; border-left-color: var(--violet); }
.beat q { display: block; color: var(--muted); font-size: 13px; font-style: italic; quotes: none; }
.beat p { margin: 3px 0 0; font-size: 13.5px; }
.beat .flag { display: inline-block; margin-top: 4px; font-size: 11px; color: var(--warn); }

.transcript { flex: 1; min-height: 180px; max-height: 40vh; overflow-y: auto; background: #0d1120;
  border: 1px solid var(--line); border-radius: 12px; padding: 12px; display: flex;
  flex-direction: column; gap: 10px; }
.line { display: grid; grid-template-columns: 62px 1fr; gap: 10px; align-items: start; }
.line .who { color: var(--muted); font-size: 12px; padding-top: 2px; }
.line--you .who { color: var(--accent); }
.line--companion .who { color: var(--violet); }
.line--system { grid-template-columns: 1fr; color: var(--warn); font-size: 13px; }
.line[data-partial="1"] .what { opacity: .55; font-style: italic; }
.what { white-space: pre-wrap; word-break: break-word; }

/* ---------- controls ---------- */
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.row--sub { justify-content: space-between; margin-top: auto; }
.input { flex: 1 1 160px; min-width: 0; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: #0d1120; color: var(--text); font: inherit; }
.btn { border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  padding: 10px 14px; border-radius: 10px; font: inherit; font-weight: 600; cursor: pointer; }
.btn:hover:not(:disabled) { background: #1d2437; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn--go { background: #1e2a4d; border-color: #2c3d6b; }
.btn--ghost { background: transparent; }
.btn--mic { display: inline-flex; align-items: center; gap: 8px; }
.btn--mic .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--off); }
.btn--mic.is-live .dot { background: var(--ok); animation: pulse 1.3s infinite; }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .3 } }
@media (prefers-reduced-motion: reduce) { .btn--mic.is-live .dot { animation: none } }
kbd { font: inherit; font-size: 11px; padding: 1px 5px; border-radius: 4px;
  border: 1px solid var(--line); background: #0d1120; color: var(--muted); }
.rate { display: inline-flex; align-items: center; gap: 8px; color: var(--muted); font-size: 12px; }
.rate input { width: 110px; accent-color: var(--accent); }
.rate output { min-width: 42px; text-align: right; font-variant-numeric: tabular-nums; }
.input:focus-visible, .btn:focus-visible, .seg-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.keys { display: none; }

/* ---------- presenter view: everything else gets out of the way ---------- */
body.presenting { background: #05070c; overflow: hidden; }
body.presenting .stage { display: block; max-width: none; margin: 0; padding: 0; height: 100%; }
body.presenting .chat-panel { display: none; }
body.presenting .face-panel { border: 0; border-radius: 0; padding: 0; height: 100%;
  background: #05070c; gap: 0; }
body.presenting .face-controls { display: none; }
/* The portrait keeps its own aspect and the caption sits BELOW it, so nothing
   ever covers her mouth, which is the one thing the room came to watch. */
body.presenting .face-wrap { border-radius: 0; height: 100%; background: #05070c;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(12px, 2.4vh, 30px); padding: clamp(10px, 2vh, 26px) 0; }
body.presenting #face { flex: 0 0 auto; height: min(56vh, 70vw); width: auto;
  max-width: 92vw; aspect-ratio: 640 / 796; }
body.presenting .status { top: clamp(10px, 2vh, 24px); left: 50%; transform: translateX(-50%); }
body.presenting .caption { position: static; flex: 0 1 auto; background: none; padding: 0;
  font-size: clamp(20px, 2.1vw, 34px); line-height: 1.32; text-align: center;
  text-wrap: balance; width: min(92vw, 46ch); max-height: 32vh; overflow: hidden; }
body.presenting .keys { display: flex; gap: 16px; position: fixed; right: 16px; bottom: 14px;
  font-size: 11px; color: #3c4560; }
body.presenting .keys kbd { border-color: #222a3d; background: #0a0f1a; color: #5a668a; }

/* A landscape phone or a short projector: shrink the face, keep the words. */
@media (max-height: 620px) {
  body.presenting #face { height: min(48vh, 52vw); }
  body.presenting .caption { font-size: clamp(16px, 1.9vw, 24px); width: min(94vw, 52ch); }
}

/* --------------------------------------------------------------------------
   The 3D face. It sits in the same slot as the canvas and only one of the two
   is ever visible, so every layout rule that framed the canvas keeps working.
   The background is ours, not the renderer's: the WebGL canvas is transparent,
   which means a soft studio wash costs nothing to draw.
   -------------------------------------------------------------------------- */
.face-3d {
  position: relative;
  width: 100%;
  aspect-ratio: 640 / 796;
  border-radius: inherit;
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 18%, #3c4658 0%, #222836 55%, #171b24 100%);
}
.face-3d[hidden] { display: none; }
#face[hidden] { display: none; }
.face-3d canvas { display: block; width: 100% !important; height: 100% !important; }

body.presenting .face-3d {
  flex: 0 0 auto;
  height: min(56vh, 70vw);
  width: auto;
  max-width: 92vw;
  aspect-ratio: 640 / 796;
}

/* ==========================================================================
   Booth mode: a tablet in a stranger's hands, mirrored onto a projector.

   Two readers at once. One is holding the thing at arm's length; the other is
   across a hall looking at a wall. Type sized in vmin lands somewhere both can
   read, because it scales with the screen rather than with a guess about how
   far away the screen is.
   ========================================================================== */

/* Nothing here should feel like a web page: no text selection on a drag, no
   grey flash under a fingertip, no rubber-band scroll behind the demo. */
body.booth,
body.booth .face-wrap,
body.booth .booth-bar button {
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}
body.booth { overscroll-behavior: none; touch-action: manipulation; }
body.booth .face-wrap { cursor: pointer; touch-action: pan-y; }
body.booth .keys { display: none; }

/* The bar sits over the bottom of the screen and is the only thing to press.
   56px is the smallest target a standing adult hits reliably; these are more. */
.booth-bar {
  position: fixed;
  left: 50%;
  bottom: max(18px, env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px;
  border-radius: 999px;
  background: rgba(12, 16, 26, 0.72);
  border: 1px solid #1d2435;
  backdrop-filter: blur(10px);
  z-index: 40;
}
.booth-bar[hidden] { display: none; }
.booth-bar button {
  min-width: 72px;
  min-height: 60px;
  padding: 0 22px;
  border: 0;
  border-radius: 999px;
  background: #182033;
  color: #cdd6ea;
  font: inherit;
  font-size: 20px;
  line-height: 1;
}
.booth-bar button[data-act="back"],
.booth-bar button[data-act="next"] { font-size: 34px; padding-bottom: 4px; }
.booth-bar button:active { background: #24314f; }

/* Portrait: face on top, words beneath. The tablet's natural way up. */
body.presenting.is-portrait .face-wrap { flex-direction: column; }
body.presenting.is-portrait #face,
body.presenting.is-portrait .face-3d { height: min(52vh, 88vw); }
body.presenting.is-portrait .caption {
  font-size: clamp(19px, 3.4vmin, 40px);
  width: min(92vw, 30ch);
  max-height: 34vh;
}

/* Landscape: the face would eat the height, so put the words beside it. */
body.presenting.is-landscape .face-wrap {
  flex-direction: row;
  gap: clamp(18px, 4vw, 60px);
  padding: clamp(10px, 3vh, 34px) clamp(16px, 4vw, 64px);
}
body.presenting.is-landscape #face,
body.presenting.is-landscape .face-3d {
  height: min(82vh, 46vw);
  width: auto;
  max-width: 46vw;
}
body.presenting.is-landscape .caption {
  font-size: clamp(18px, 2.6vmin, 38px);
  width: min(46vw, 34ch);
  max-height: 76vh;
  text-align: left;
}

/* Leave room for the control bar so it never sits on top of the words. */
body.booth.presenting .caption { padding-bottom: clamp(56px, 11vh, 96px); }

/* A tablet held in portrait is tall and narrow; the face should not shrink to
   fit a caption that could simply wrap more. */
@media (orientation: portrait) and (min-width: 700px) {
  body.presenting.is-portrait #face,
  body.presenting.is-portrait .face-3d { height: min(56vh, 76vw); }
}

/* In presenter view the face should not read as a photograph pinned to a wall.
   Drop the panel's own wash, put a soft one on the whole screen, and let her
   sit in it with no visible edge. Matters most on a projector, where a hard
   rectangle of slightly-lighter grey is the first thing the room notices. */
body.presenting {
  background:
    radial-gradient(120% 80% at 50% 26%, #1b2231 0%, #0b0e16 58%, #05070c 100%);
}
body.presenting .face-panel,
body.presenting .face-wrap { background: transparent; }
/* The 3D face keeps its backdrop. Making it transparent was a mistake: her
   clothes are dark, the stage is dark, and she came out looking like a head
   floating in a void. A person needs something to stand in front of. */
body.presenting .face-3d {
  background:
    radial-gradient(75% 55% at 50% 96%, rgba(0,0,0,.45) 0%, rgba(0,0,0,0) 60%),
    radial-gradient(110% 80% at 50% 22%, #4a5468 0%, #2b3244 52%, #1a1f2c 100%);
  box-shadow: inset 0 0 120px rgba(0,0,0,.55);
}

/* And give her more of the screen. A booth visitor is looking at a face, not
   at a layout. */
body.presenting.is-landscape #face,
body.presenting.is-landscape .face-3d { height: min(88vh, 56vw); max-width: 56vw; }
body.presenting.is-landscape .caption { width: min(40vw, 32ch); }

/* ==========================================================================
   Kiosk mode. She waits to be asked, and the one thing to press is enormous,
   because it is pressed by strangers who are standing up, holding a coffee,
   and have never seen this before.
   ========================================================================== */
.kiosk-ui {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 18px 16px max(18px, env(safe-area-inset-bottom, 0px));
  background: linear-gradient(to top, rgba(6,8,14,.95) 55%, rgba(6,8,14,0));
  z-index: 30;
}
.kiosk-ui[hidden] { display: none; }

.kiosk-scope {
  margin: 0;
  max-width: 44ch;
  text-align: center;
  color: var(--muted);
  font-size: clamp(12px, 1.6vmin, 17px);
  line-height: 1.4;
  text-wrap: balance;
}

.kiosk-talk {
  font: inherit;
  font-weight: 600;
  font-size: clamp(17px, 2.4vmin, 26px);
  min-height: 68px;
  padding: 0 clamp(26px, 5vw, 56px);
  border: 1px solid #2c3d6b;
  border-radius: 999px;
  background: #1e2a4d;
  color: var(--text);
  cursor: pointer;
}
.kiosk-talk:active { background: #27356090; }
.kiosk-talk.is-live {
  background: #16402f;
  border-color: rgba(86,214,168,.55);
  color: var(--ok);
  animation: kiosk-pulse 1.4s ease-in-out infinite;
}
@keyframes kiosk-pulse { 0%,100% { box-shadow: 0 0 0 0 rgba(86,214,168,.35) } 50% { box-shadow: 0 0 0 14px rgba(86,214,168,0) } }
@media (prefers-reduced-motion: reduce) { .kiosk-talk.is-live { animation: none } }

.kiosk-hint { margin: 0; min-height: 1.2em; color: var(--warn); font-size: clamp(12px, 1.6vmin, 16px); }
.kiosk-hint:empty { display: none; }

/* In presenter view the caption has to get out of the way of the controls. */
body.is-kiosk.presenting .caption { padding-bottom: clamp(140px, 22vh, 210px); }
body.is-kiosk.presenting .booth-bar { display: none; }
/* Tapping her face advances the scripted run. In kiosk mode there is no run to
   advance, and a stray tap must not do anything at all. */
body.is-kiosk .face-wrap { cursor: default; }

/* Her, filmed. Same slot as the other three faces; only one is ever visible. */
.face-film {
  position: relative;
  width: 100%;
  aspect-ratio: 640 / 796;
  border-radius: inherit;
  overflow: hidden;
  background: #11141c;
}
.face-film[hidden] { display: none; }
.face-film video { display: block; width: 100%; height: 100%; object-fit: cover; }
body.presenting .face-film {
  flex: 0 0 auto; height: min(56vh, 70vw); width: auto; max-width: 92vw; aspect-ratio: 640 / 796;
}
body.presenting.is-landscape .face-film { height: min(88vh, 56vw); max-width: 56vw; }
body.presenting.is-portrait .face-film { height: min(52vh, 88vw); }
