/* =====================================================================
   app.css — product/page components for the talking-head, conversation,
   dashboard, summary and session-log pages.

   Colors come from tokens.css via var(--…); shared base components
   (reset, html/body, form controls, buttons, badges, role badge, modal,
   toast, scrollbar) live in base.css. Both sheets load before this one,
   so light and dark themes flow automatically.
   ===================================================================== */

/* ── Header ────────────────────────────────────────────────── */
.header {
  height: 56px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 28px;
  gap: 16px;
}
.header-brand { display: flex; flex-direction: column; gap: 2px; margin-right: 4px; }
.header-logo {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 4px;
  text-transform: uppercase;
  color: var(--primary);
  text-decoration: none;
  line-height: 1;
}
.header-title { font-size: 14px; font-weight: 500; color: var(--text-muted); }
.header-spacer { flex: 1; }
.back-link { font-size: 11px; color: var(--subtle); text-decoration: none; transition: color 0.15s; line-height: 1; }
.back-link:hover { color: var(--text-muted); }

/* ── Nav links ─────────────────────────────────────────────── */
.nav-link {
  font-size: 13px;
  color: var(--muted);
  text-decoration: none;
  padding: 4px 8px;
  border-radius: 4px;
  transition: color 0.15s;
}
.nav-link:hover { color: var(--text); }
.nav-link.active { color: var(--text); }

/* ── User pill ─────────────────────────────────────────────── */
.user-pill { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--text-muted); }
.header-user-label { font-size: 12px; color: var(--muted); margin-left: 12px; }

/* ── Container ─────────────────────────────────────────────── */
.container { max-width: 1000px; margin: 0 auto; padding: 40px 28px; }
.container-wide { max-width: 1100px; margin: 0 auto; padding: 48px 28px; }

/* ── Page headings ─────────────────────────────────────────── */
.page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 28px; gap: 12px; flex-wrap: wrap; }
.page-header-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.page-title { font-size: 22px; font-weight: 700; color: var(--text); margin-bottom: 8px; }
.page-subtitle { font-size: 14px; color: var(--muted); margin-bottom: 40px; }
.page-subtitle.compact { margin-bottom: 0; }

/* ── Card grid ─────────────────────────────────────────────── */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
  gap: 20px;
}
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 28px;
  text-decoration: none;
  color: inherit;
  display: block;
  transition: border-color 0.15s, box-shadow 0.15s, transform 0.1s;
  cursor: pointer;
}
.card:hover {
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary), 0 8px 32px rgba(250,70,22,0.15);
  transform: translateY(-2px);
}
.card.disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
/* A tinted tile behind the card's Material Icon. */
.card-icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-bottom: 16px;
  border-radius: 10px;
  background: var(--tintaccent-bg);
  color: var(--tintaccent-fg);
  font-size: 28px;
}
.card-icon .material-icons { font-size: 24px; }
.card-title { font-size: 16px; font-weight: 600; color: var(--text); margin-bottom: 6px; }
.card-desc { font-size: 13px; color: var(--muted); line-height: 1.5; }
.card-badge {
  display: inline-block;
  margin-top: 14px;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.card-badge.admin-only { background: var(--warn-bg); border: 1px solid var(--warn-bd); color: var(--warn-fg); }
.card-badge.coming-soon { background: var(--neutral-bg); border: 1px solid var(--neutral-bd); color: var(--neutral-fg); }

/* ── Form inputs ───────────────────────────────────────────── */
/* ── Video studio (generate-video page) ────────────────────── */
.studio-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}
.studio-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 24px;
}
.studio-panel-title { margin: 6px 0 20px; font-size: 20px; font-weight: 800; letter-spacing: -0.01em; color: var(--text); }
/* The selected character's face beside the picker, so it's clear who will speak. */
.studio-character-row { display: flex; align-items: center; gap: 12px; }
.studio-character-row .studio-character-image {
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--border);
  background: var(--surface-sunken);
}
.studio-character-row .ui-field { flex: 1 1 auto; min-width: 0; }
.studio-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.studio-status { font-size: 13px; color: var(--muted); }
.studio-status.error { color: var(--danger); }
/* Square, like the generated video, but never taller than ~520px. */
.studio-preview {
  position: relative;
  width: min(100%, 520px);
  margin-inline: auto;
  aspect-ratio: 1 / 1;
  background: var(--surface-sunken);
  border: 1px dashed var(--border);
  border-radius: 12px;
  overflow: hidden;
  display: grid;
  place-items: center;
  margin-bottom: 16px;
}
.studio-video { width: 100%; height: 100%; object-fit: contain; background: #000; }
.studio-empty {
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 16px;
  color: var(--muted);
  font-size: 14px;
  text-align: center;
}
.studio-empty .material-icons { font-size: 40px; color: var(--tintaccent-fg); }
@media (max-width: 760px) {
  .studio-grid { grid-template-columns: 1fr; }
}

.form-group { margin-bottom: 18px; }
.form-label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}
.form-label-row label { margin-bottom: 0; }
label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
  margin-bottom: 6px;
}
.form-hint { font-size: 11px; color: var(--subtle); margin-top: 4px; }

/* ── Table ─────────────────────────────────────────────────── */
.hidden { display: none !important; }
.table-wrap { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; overflow-x: auto; overflow-y: hidden; }
table { width: 100%; border-collapse: collapse; }
.character-table { min-width: 980px; table-layout: fixed; }
.character-table th:nth-child(1),
.character-table td:nth-child(1) { width: 22%; }
.character-table th:nth-child(2),
.character-table td:nth-child(2) { width: 15%; }
.character-table th:nth-child(3),
.character-table td:nth-child(3) { width: 7%; }
.character-table th:nth-child(5),
.character-table td:nth-child(5) { width: 17%; }
.character-table th:nth-child(6),
.character-table td:nth-child(6) { width: 9%; }
.character-table th:nth-child(8),
.character-table td:nth-child(8) { width: 150px; }
thead { background: var(--bg); }
th {
  padding: 11px 16px;
  text-align: left;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--subtle);
  border-bottom: 1px solid var(--border);
}
td { padding: 12px 16px; font-size: 13px; border-bottom: 1px solid var(--border); vertical-align: middle; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: var(--surface2); }
.empty-row td { text-align: center; color: var(--subtle); padding: 40px; }

/* Per-row "Actions ▾" dropdown — groups a row's actions behind one toggle
   instead of a row of buttons. Same component/class names as .row-menu in
   styles.css; repeated here so pages on the app.css design system (which
   don't load styles.css) can use it too.
   The menu is `position: fixed` (top/left set by JS from the toggle's
   bounding rect when opened) rather than absolute — table rows live inside
   .table-wrap, which clips vertical overflow for its horizontal-scroll-on-
   phones behavior, and an absolutely positioned menu is clipped by that. A
   fixed-position element's containing block is the viewport, so it escapes
   that clipping regardless of DOM nesting. */
.row-menu { position: relative; display: inline-block; }
/* A narrow actions column would otherwise wrap "Actions ▾" onto two lines. */
.row-menu-toggle { white-space: nowrap; }
.row-menu-dropdown {
  display: none; position: fixed; z-index: 200;
  background: var(--surface2); border: 1px solid var(--border); border-radius: 8px;
  min-width: 150px; padding: 4px 0; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.row-menu-dropdown.open { display: block; }
.row-menu-item {
  display: block; width: 100%; text-align: left; padding: 8px 14px;
  background: none; border: none; color: var(--text); font-size: 13px; cursor: pointer;
  text-decoration: none; font-family: inherit;
}
.row-menu-item:hover, .row-menu-item:focus-visible { background: var(--surface); color: var(--primary); outline: none; }
.row-menu-item-danger { color: var(--danger); }
.row-menu-item-danger:hover, .row-menu-item-danger:focus-visible { background: var(--danger); color: #fff; }
.row-menu-item:disabled { color: var(--muted); cursor: not-allowed; opacity: 0.5; }
.row-menu-item:disabled:hover, .row-menu-item:disabled:focus-visible { background: none; color: var(--muted); }

/* Users table: a 6-column grid that must scroll horizontally inside its
   .table-wrap on phones rather than squashing. */
.users-table { min-width: 720px; }
.cell-email { color: var(--text-muted); }
.cell-meta { color: var(--muted); font-size: 12px; }

/* ── Talking Head Home ─────────────────────────────────────── */
.talking-head-page { max-width: none; padding: 48px 28px; }

/* ── Conversation stage progress ────────────────────────────────
   Slim two-line timeline INSIDE the call card (top strip): current stage
   name with a pulsing dot, a continuous time-based track (past filled, live
   edge glowing), elapsed time, and a subtle "up next" hint. Driven by
   talking-head.js. No outer box — it sits flush on the card's surface with a
   divider below. */
.stage-progress {
  /* A size container: the bar stacks based on its own width (see below). */
  container-type: inline-size;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, color-mix(in srgb, var(--surface2) 60%, transparent), transparent);
}
/* Outer two-column layout: [dot + name + range] | [track + description]. */
.stage-progress-cols {
  display: flex;
  align-items: stretch;
  gap: 16px;
}
.stage-current {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  /* Don't shrink: the long description would otherwise squeeze the name down
     to a few letters. The label's own max-width bounds this column. */
  flex: 0 0 auto;
}
.stage-current-heading {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.stage-current-dot {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 0 rgba(250, 70, 22, 0.45);
  animation: stage-dot-pulse 2s ease-in-out infinite;
}
@keyframes stage-dot-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(250, 70, 22, 0.45); }
  50%      { box-shadow: 0 0 0 6px rgba(250, 70, 22, 0); }
}
.stage-current-label {
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 320px;
}
.stage-current-range {
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
  opacity: 0.9;
}
/* Right column: progress bar on top, description below it. */
.stage-track-col {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
}
/* The continuous track: a rounded groove with a gradient fill that moves
   smoothly with the clock, plus ticks at each stage boundary. */
.stage-track {
  width: 100%;
  min-width: 0;
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  overflow: visible;
  cursor: crosshair;
}
/* Two-tone fill: the completed (past) portion is a calm solid accent; the last
   ~10% at the live leading edge is a brighter gradient with a glow, so "old"
   vs "now" reads at a glance. */
.track-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  height: 100%;
  border-radius: 999px;
  /* left 90% = settled past; right 10% = live edge */
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--primary) 78%, var(--surface)) 0%,
      var(--primary) calc(100% - 10%),
      var(--accent) calc(100% - 4%),
      #fc997d 100%);
  transition: width 0.1s linear;
  box-shadow: 0 0 8px rgba(250, 70, 22, 0.35);
}
/* A small bright cap at the very leading edge of the fill. */
.track-fill::after {
  content: "";
  position: absolute;
  top: -1px;
  right: -1px;
  bottom: -1px;
  width: 5px;
  border-radius: 999px;
  background: #fec4b4;
  box-shadow: 0 0 8px 1px rgba(252, 153, 125, 0.9);
}
.track-tick {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  border-radius: 1px;
  background: color-mix(in srgb, var(--text) 22%, transparent);
  pointer-events: none;
}
/* Hover tooltip: a small floating card showing the stage under the cursor. */
.stage-tooltip {
  position: fixed;
  z-index: 1000;
  pointer-events: none;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  white-space: nowrap;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.15s ease, transform 0.15s ease;
}
.stage-tooltip.visible {
  opacity: 1;
  transform: translateY(0);
}
.stage-tooltip small {
  display: block;
  font-weight: 400;
  color: var(--muted);
  white-space: normal;
  max-width: 260px;
  margin-top: 2px;
}
.stage-current-desc {
  font-size: 12px;
  color: var(--muted);
  line-height: 1.4;
  /* Full description, no clipping — it may wrap to a second line. */
  overflow: visible;
  white-space: normal;
}
/* Expands the description where the stacked layout clamps it. talking-head.js
   shows it only while the text is actually cut off. */
.stage-desc-toggle {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin: -8px -10px -8px auto;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
}
.stage-desc-toggle[hidden] { display: none; }
.stage-desc-toggle:hover { color: var(--text); }
.stage-desc-toggle:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.stage-desc-toggle .material-icons {
  font-size: 20px;
  transition: transform 0.15s ease;
}
.stage-desc-toggle[aria-expanded="true"] .material-icons { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .stage-desc-toggle .material-icons { transition: none; }
}
/* End-of-stage cue: when the current stage is nearly done, the fill's leading
   edge pulses to signal the transition to the next stage. */
.stage-track.stage-ending .track-fill {
  animation: stage-edge-pulse 1s ease-in-out infinite;
}
.stage-track.stage-ending .track-fill::after {
  animation: stage-edge-glow 1s ease-in-out infinite;
}
@keyframes stage-edge-pulse {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.45); }
}
@keyframes stage-edge-glow {
  0%, 100% { box-shadow: 0 0 6px 1px rgba(252, 153, 125, 0.7); }
  50%      { box-shadow: 0 0 14px 3px rgba(252, 153, 125, 1); }
}
/* Slimmer in the fixed call-screen layout so the avatar keeps its height. */
body.call-screen .stage-progress {
  padding: 8px 14px;
}
body.call-screen .stage-current-label { font-size: 13px; }
body.call-screen .stage-track { height: 6px; }
@media (max-width: 640px) {
  .stage-progress-cols { gap: 10px; }
  .stage-current-label { font-size: 12.5px; }
}
/* Too narrow for two columns (phones, portrait tablets, narrow desktop
   windows): stack the name with its time range flowing after it, then the
   full-width track, then the description clamped to two lines behind the
   caret toggle. */
@container (max-width: 800px) {
  .stage-progress-cols { flex-direction: column; gap: 6px; }
  .stage-current { align-items: flex-start; }
  .stage-current-dot { margin-top: 5px; }
  .stage-current-heading { display: block; }
  .stage-current-label { white-space: normal; max-width: none; }
  .stage-current-desc {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
  }
  .stage-progress.is-desc-expanded .stage-current-desc {
    display: block;
    -webkit-line-clamp: none;
    line-clamp: none;
  }
}

.call-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.28);
  overflow: hidden;
  min-height: 0;
}
/* The conversation is a fixed-height app screen at every size: the card fills
   the space left under the header and never grows past it, so the page itself
   never scrolls — each panel scrolls internally instead. The page padding
   shrinks on short or narrow windows so the call keeps the room. */
body.call-screen {
  display: flex;
  flex-direction: column;
  height: 100%;
  height: 100dvh;   /* phones: follow the visible viewport as browser chrome shows/hides */
  overflow: hidden;
}
.call-screen .talking-head-page {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  /* As a column-flex item, .container-wide's `margin: 0 auto` would beat
     align-self:stretch and shrink-to-fit the page. Width 100% resolves those
     auto margins to 0 so the card keeps the full width. */
  width: 100%;
  padding: clamp(12px, 4vh, 48px) clamp(12px, 2.5vw, 28px);
}
.call-screen .call-card {
  flex: 1 1 auto;
  min-height: 0;
}
.call-main {
  /* Three columns: call session | supervisor monitor | tool rail. All three
     stretch to the card height, so each scrolls internally instead of growing
     the page. The monitor narrows on mid-size windows to leave the video room. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(240px, 26vw, 300px) auto;
  gap: 0;
  align-items: stretch;
  height: 100%;
  min-height: 0;
}
/* Study condition: the risk monitor can be blinded. Its column stays, empty,
   so the video keeps the same size and framing as in the other conditions
   (a wider frame would crop the avatar tighter). The tool rail is pinned to
   the last column so it doesn't slide into the empty one. */
.call-main.supervisor-hidden .tool-box { grid-column: 3; }
.call-session {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}
.call-videos {
  /* The stage area between the stage bar and the call controls. It is a size
     container, so the two tiles inside can be sized from its width and
     height. flex: 1 1 0 + min-height: 0 lets it shrink so the controls row
     below it always stays visible. */
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
  container-type: size;
}
/* Two square tiles side by side — the character's portrait and the user's
   camera — each as large as the stage allows. */
.call-stage {
  --tile-gap: 16px;
  --tile-size: min(calc((100cqw - var(--tile-gap)) / 2), 100cqh);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--tile-gap);
}
.call-tile,
.video-shell,
.camera-shell {
  position: relative;
  min-width: 0;
}
.video-shell,
.camera-shell {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.avatar-tile,
.user-tile {
  width: var(--tile-size);
  height: var(--tile-size);
}
.avatar-tile .video-shell,
.user-tile .camera-shell {
  width: 100%;
  height: 100%;
}
/* Speaking feedback, the same on both tiles: a breathing green outline while
   that side is actually speaking — the character while its reply plays (the
   #avatar-visualizer.active state), the user while the voice detector hears
   them (#user-visualizer.active), not merely while the mic is switched on. */
.avatar-tile .video-shell:has(#avatar-visualizer.active),
.user-tile .camera-shell:has(#user-visualizer.active) {
  border-color: var(--ok-fg);
  animation: speaking-breathe 1.6s ease-in-out infinite;
}
@keyframes speaking-breathe {
  0%, 100% { box-shadow: 0 0 0 2px var(--ok-fg); }
  50%      { box-shadow: 0 0 0 5px var(--ok-fg), 0 0 18px var(--ok-fg); }
}
@media (prefers-reduced-motion: reduce) {
  .avatar-tile .video-shell:has(#avatar-visualizer.active),
  .user-tile .camera-shell:has(#user-visualizer.active) {
    animation: none;
    box-shadow: 0 0 0 3px var(--ok-fg);
  }
}
.camera-shell video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The portrait crops to the square from slightly above centre, where the
   face usually sits. It stays transparent until decoded, so it never flashes
   in at the wrong size. */
.avatar-image {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.avatar-image.ready { opacity: 1; }
/* Stand-in when the portrait cannot load: the character's initials. */
.avatar-fallback {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface2);
  color: var(--text-muted);
  font-size: clamp(32px, 8vw, 88px);
  font-weight: 700;
  letter-spacing: 0.04em;
}
/* Boot overlay: opaque cover while the session assembles. Sits above the
   header (z-index) and fades out once talking-head.js marks every step done. */
.conv-loading {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  transition: opacity 0.25s ease;
}
.conv-loading.is-hidden {
  opacity: 0;
  pointer-events: none;
}
.conv-loading-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  padding: 32px 40px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 8px 30px rgba(24, 34, 52, 0.08);
}
.conv-loading-card h2 {
  font-size: 17px;
  color: var(--text);
}
.conv-loading-steps {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 240px;
}
.conv-loading-steps li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--text-muted);
}
.conv-loading-steps li .material-icons {
  font-size: 19px;
  color: var(--border);
}
.conv-loading-steps li.is-active { color: var(--text); }
.conv-loading-steps li.is-active .material-icons {
  color: var(--primary);
  animation: conv-step-pulse 1.2s ease-in-out infinite;
}
.conv-loading-steps li.is-done .material-icons { color: var(--success); }
.conv-loading-steps li.is-error { color: var(--danger); }
.conv-loading-steps li.is-error .material-icons { color: var(--danger); }
@keyframes conv-step-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
  .conv-loading { transition: none; }
  .conv-loading-steps li.is-active .material-icons { animation: none; }
}

/* ── Call reminder toast (study mode) ──────────────────────────
   Timed nudges during an interaction call (e.g. "5 minutes left, wrap up").
   Deliberately louder than the standard corner .toast (base.css): bigger,
   top-right so it doesn't sit under the call controls along the bottom, and
   paired with a chime in talking-head.js — like a video-call app's
   "meeting ending soon" nudge, since the point is to interrupt an ongoing
   call rather than blend into the corner. */
#call-reminder-container {
  position: fixed;
  top: 24px;
  right: 24px;
  z-index: 250;
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 420px;
  pointer-events: none;
}
.call-reminder-toast {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 18px 22px;
  border-radius: 14px;
  border: 1px solid var(--info-bd);
  background: var(--info-bg);
  color: var(--info-fg);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
  opacity: 0;
  transform: translate(24px, -12px);
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.call-reminder-toast.is-visible { opacity: 1; transform: translate(0, 0); }
.call-reminder-toast .material-icons { font-size: 26px; flex: 0 0 auto; margin-top: 1px; }
.call-reminder-toast.success { border-color: var(--ok-bd); background: var(--ok-bg); color: var(--ok-fg); }
.call-reminder-toast.warning { border-color: var(--warn-bd); background: var(--warn-bg); color: var(--warn-fg); }
.call-reminder-toast.error   { border-color: var(--err-bd); background: var(--err-bg); color: var(--err-fg); }
@media (max-width: 640px) {
  #call-reminder-container { top: 12px; right: 12px; left: 12px; max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
  .call-reminder-toast { transition: none; }
}

/* Autoplay recovery: shown when the browser refused to play a reply until the
   user taps. */
.unmute-chip {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(24, 34, 52, 0.18);
}
.unmute-chip .material-icons { font-size: 18px; color: var(--danger); }
.unmute-chip:hover { background: var(--surface2); }

/* Shown until the character's portrait has loaded. */
.avatar-connecting {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  background: var(--bg);
  color: var(--text-muted);
  font-size: 14px;
  z-index: 1;
}

.camera-shell video {
  transform: scaleX(-1);
}
.camera-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  background: var(--bg);
  font-size: 14px;
}
/* Name badge sits bottom-left and hugs its content, so on phones the
   bottom-right picture-in-picture never overlaps it. */
.tile-caption {
  position: absolute;
  z-index: 3;
  left: 18px;
  bottom: 18px;
  max-width: calc(100% - 36px);
  padding: 11px 16px;
  border-radius: 8px;
  background: rgba(220, 55, 9, 0.55);
  color: #fff;
}
.tile-caption strong,
.tile-caption span {
  display: block;
}
.tile-caption strong { font-size: 16px; }
.tile-caption span { font-size: 12px; opacity: 0.9; margin-top: 2px; }
/* The user's badge is dark, so the two tiles are told apart at a glance. */
.user-caption { background: rgba(15, 23, 42, 0.62); }
.user-caption .caption-status-row { min-width: 0; }
.user-caption #speech-state {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.caption-status-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
}
.caption-status-row span {
  margin-top: 0;
}
.caption-visualizer {
  /* Hidden unless the speaker (user or avatar) is actively talking. */
  display: none;
  align-items: center;
  gap: 4px;
  height: 14px;
  margin-top: 0;
}
.caption-visualizer.active {
  display: flex;
}
.caption-visualizer i {
  display: block;
  width: 4px;
  height: 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.85);
  opacity: 0.35;
  transform: scaleY(0.35);
  transform-origin: center;
  transition: transform 80ms linear, opacity 80ms linear;
}
.caption-visualizer.active i {
  animation: captionPulse 620ms ease-in-out infinite;
}
.caption-visualizer.active i:nth-child(2) { animation-delay: 80ms; }
.caption-visualizer.active i:nth-child(3) { animation-delay: 160ms; }
.caption-visualizer.active i:nth-child(4) { animation-delay: 240ms; }
@keyframes captionPulse {
  0%, 100% { transform: scaleY(0.35); opacity: 0.35; }
  50% { transform: scaleY(1.25); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  /* Keep the visualizer as a static "talking" indicator, but don't pulse. */
  .caption-visualizer.active i { animation: none; }
}
.call-controls {
  /* mic | camera | timer (centred in the free space) | end call, on one row.
     A size container, so the controls tighten based on the row's own width —
     the same whether it sits under a narrow desktop column or across a phone. */
  container-type: inline-size;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: clamp(10px, 2.2vh, 20px) clamp(12px, 2vw, 22px);
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.round-control {
  min-width: 74px;
  height: 48px;
  border: 0;
  border-radius: 12px;
  background: var(--bg);
  color: var(--text-muted);
  font-weight: 700;
  cursor: pointer;
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
}
.round-control.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.call-timer {
  margin-inline: auto;
  min-width: 84px;
  padding: 13px 18px;
  border-radius: 12px;
  background: var(--tintaccent-bg);
  color: var(--tintaccent-fg);
  font-weight: 800;
  text-align: center;
}
.end-call-btn {
  flex: 0 0 auto;
  border: 0;
  border-radius: 12px;
  background: var(--danger);
  color: #fff;
  padding: 0 22px;
  height: 48px;
  font-weight: 800;
  white-space: nowrap;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
/* Tighten the row as it narrows. The End Call text goes once there's no room
   for it beside an hours-long timer (hh:mm:ss); the button keeps its
   aria-label. */
@container (max-width: 480px) {
  .call-controls .round-control { min-width: 48px; }
  .call-controls .call-timer { min-width: 0; padding: 10px; }
  .call-controls .end-call-btn { padding: 0 12px; }
}
@container (max-width: 324px) {
  .call-controls .end-call-label { display: none; }
}
@container (max-width: 250px) {
  .call-controls .round-control { min-width: 44px; }
  .call-controls .call-timer { padding: 8px 6px; font-size: 13px; }
  .call-controls .end-call-btn { padding: 0 10px; }
}
.status-detail {
  display: none;
  margin: 0 22px 22px;
  min-height: 38px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--muted);
  font-size: 13px;
  line-height: 1.4;
  padding: 10px 12px;
}
/* ── Supervisor panel (live in-call risk monitor + coaching) ── */
/* An always-visible column of cards on a shaded background; position:
   relative anchors the loading overlay. */
.supervisor-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  min-height: 0;
  padding: 12px;
  border-left: 1px solid var(--border);
  background: var(--surface-sunken);
  overflow: hidden;
}
/* Loading overlay shown until the first analysis returns. */
.supervisor-loading {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 16px;
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: 13px;
  text-align: center;
}
.supervisor-loading[hidden] { display: none; }
.supervisor-loading p { margin: 0; }
.supervisor-block {
  flex: 0 0 auto;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
}
.supervisor-block--grow {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* The heading stays on one line; a long badge drops below it instead. */
.supervisor-block-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px 8px;
  margin-bottom: 10px;
}
.supervisor-block-head h2 {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
  color: var(--text-muted);
}
.supervisor-block-head h2 .material-icons { font-size: 17px; color: var(--indigo); }
/* Status chips (risk level, last-message verdict). */
.sup-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface2);
  color: var(--text-muted);
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
}
.sup-badge--none,
.sup-badge--unknown { background: var(--neutral-bg); border-color: var(--neutral-bd); color: var(--neutral-fg); }
.sup-badge--clear   { background: var(--ok-bg); border-color: var(--ok-bd); color: var(--ok-fg); }
.sup-badge--low     { background: var(--warn-bg); border-color: var(--warn-bd); color: var(--warn-fg); }
.sup-badge--mid     { background: var(--mid-bg); border-color: var(--mid-bd); color: var(--mid-fg); }
.sup-badge--high,
.sup-badge--flag    { background: var(--err-bg); border-color: var(--err-bd); color: var(--err-fg); }
.sup-meter {
  height: 8px;
  border-radius: 999px;
  background: var(--surface2);
  overflow: hidden;
}
.sup-meter-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  transition: width 0.25s ease, background-color 0.25s ease;
}
/* Severity escalates by number of flagged patient statements: 1+ light yellow,
   3+ orange, 5+ red. */
.sup-meter-fill.tier-none { background: transparent; }
.sup-meter-fill.tier-low  { background: var(--tier-low); }
.sup-meter-fill.tier-mid  { background: var(--tier-mid); }
.sup-meter-fill.tier-high { background: var(--danger); }
/* Count line doubles as the expand/collapse control for the flagged list. */
.sup-flagged-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  margin-top: 8px;
  padding: 6px 2px;
  border: none;
  border-radius: 8px;
  background: none;
  cursor: pointer;
  color: var(--text-muted);
  font: inherit;
  font-size: 13px;
  text-align: left;
}
.sup-flagged-toggle:hover { color: var(--text); }
.sup-flagged-toggle:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.sup-flagged-toggle strong { color: var(--text); }
.sup-flagged-caret {
  font-size: 20px;
  transition: transform 0.15s ease;
}
.sup-flagged-toggle[aria-expanded="true"] .sup-flagged-caret {
  transform: rotate(180deg);
}
.sup-last-message {
  margin: 0;
  max-height: 132px;
  overflow-y: auto;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--surface2);
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}
.sup-flagged {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  max-height: 200px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.sup-flagged[hidden] { display: none; }
.sup-flagged-item {
  padding: 8px 10px;
  border: 1px solid var(--err-bd);
  border-left: 3px solid var(--danger);
  border-radius: 10px;
  background: var(--err-bg);
  color: var(--err-fg);
  font-size: 12.5px;
  line-height: 1.45;
}
/* Cue-type tag on a flagged statement: covert = warning tint (veiled sign),
   overt = danger tint (explicit statement). */
.sup-cue-tag {
  display: inline-block;
  margin-right: 6px;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid var(--warn-bd);
  background: var(--warn-bg);
  color: var(--warn-fg);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}
.sup-cue-tag--overt {
  border-color: var(--err-bd);
  background: var(--surface);
  color: var(--danger);
}
.sup-flagged-empty,
.sup-suggestion-empty {
  margin: 0;
  padding: 12px;
  border: 1px dashed var(--border);
  border-radius: 10px;
  font-size: 12.5px;
  color: var(--muted);
}
.sup-suggestions {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  min-height: 0;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.sup-suggestion-guidance {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}
/* Example phrasings: quote cards the counselor could say next. */
.sup-suggestion-examples {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.sup-suggestion-examples li {
  position: relative;
  padding: 9px 12px 9px 30px;
  border: 1px solid var(--tintaccent-bd);
  border-radius: 10px;
  background: var(--tintaccent-bg);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text);
}
.sup-suggestion-examples li::before {
  content: '\201C';
  position: absolute;
  left: 11px;
  top: 6px;
  color: var(--indigo);
  font-weight: 800;
  font-size: 18px;
  line-height: 1;
}

/* ── Tool rail + tool popovers ────────────────────────────────────
   A narrow icon rail on the far right of the call. Each button opens its tool
   in a popover anchored beside it (positioned by JS). More tools slot straight
   into the rail without any layout changes. */
.tool-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  padding: 12px 10px;
  border-left: 1px solid var(--border);
  background: var(--surface-sunken);
  min-height: 0;
  overflow: hidden;
}
.tool-btn {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background-color 0.15s;
}
.tool-btn:hover { color: var(--indigo); border-color: var(--indigo); }
.tool-btn.active {
  background: var(--indigo);
  border-color: var(--indigo);
  color: #fff;
}
.tool-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.tool-btn .material-icons { font-size: 20px; }

/* Fixed so the call card's overflow:hidden can't clip it; JS sets top/left. */
.tool-popover {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  width: 360px;
  max-width: calc(100vw - 24px);
  /* Fixed (not max-) height so every tool popover is the same size regardless of
     how much content it holds; each body scrolls or stretches to fill it. */
  height: min(70vh, 580px);
  max-height: calc(100vh - 24px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.24);
  overflow: hidden;
}
.tool-popover[hidden] { display: none; }
.tool-popover-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex: 0 0 auto;
  padding: 12px 12px 12px 16px;
  border-bottom: 1px solid var(--border);
}
.tool-popover-head h2 {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: 15px;
  font-weight: 800;
  color: var(--text);
}
/* Tinted icon tile beside the panel title. */
.tool-popover-icon {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: var(--tintaccent-bg);
  color: var(--tintaccent-fg);
}
.tool-popover-icon .material-icons { font-size: 18px; }
.tool-popover-close {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}
.tool-popover-close:hover { border-color: var(--indigo); color: var(--indigo); }
.tool-popover-close:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.tool-popover-close .material-icons { font-size: 18px; }
.tool-popover-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
/* Conversation log: a shaded chat area under a one-line session note. */
#tool-panel-log .tool-popover-body { background: var(--surface-sunken); }
.tool-popover-subtitle {
  margin: 0;
  flex: 0 0 auto;
  padding: 9px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}
#tool-panel-log .conversation-log { padding: 14px 16px; }

/* Notes tool: label + auto-saving textarea that fills the popover. */
#tool-panel-notes .tool-popover-body { padding: 14px 16px; gap: 8px; }
.tool-notes-label {
  flex: 0 0 auto;
  margin: 0;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
/* Grows to fill whatever the popover's fixed height leaves after the label and
   status line; min-height:0 lets it fill exactly rather than forcing overflow. */
.tool-notes-input {
  flex: 1 1 auto;
  min-height: 0;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--surface);
  font-size: 14px;
  line-height: 1.55;
  resize: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.tool-notes-input:focus { border-color: var(--indigo); box-shadow: 0 0 0 3px var(--tintaccent-bg); }
.tool-notes-status {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0;
  flex: 0 0 auto;
  min-height: 18px;
  font-size: 12px;
  color: var(--muted);
}
.tool-notes-status.is-error { color: var(--danger); }

/* ── Risk Assessment (C-SSRS) tool panel ───────────────────────── */
/* Questions and outcomes are cards in a shaded, scrolling column; each
   follow-up question appears as the previous one is answered. */
.risk-assessment-body {
  gap: 10px;
  padding: 12px;
  overflow-y: auto;
  background: var(--surface-sunken);
}
.risk-intro {
  margin: 0;
  flex: 0 0 auto;
  padding: 0 4px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}
.ra-hidden { display: none !important; }

/* Question card */
.ra-question {
  flex: 0 0 auto;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  animation: ra-slide-in 0.18s ease;
}
@keyframes ra-slide-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.ra-q-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
/* The question number as a small round tile. */
.ra-q-num {
  display: grid;
  place-items: center;
  min-width: 26px;
  height: 26px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--tintaccent-bg);
  color: var(--tintaccent-fg);
  font-size: 11.5px;
  font-weight: 800;
}
/* Severity chips */
.ra-q-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
}
.ra-badge-yellow { background: var(--warn-bg); color: var(--warn-fg); border: 1px solid var(--warn-bd); }
.ra-badge-orange { background: var(--mid-bg);  color: var(--mid-fg);  border: 1px solid var(--mid-bd); }
.ra-badge-red    { background: var(--err-bg);  color: var(--err-fg);  border: 1px solid var(--err-bd); }
.ra-badge-green  { background: var(--ok-bg);   color: var(--ok-fg);   border: 1px solid var(--ok-bd); }

.ra-q-text {
  margin: 0 0 12px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text);
}
.ra-btn-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.ra-btn {
  flex: 1;
  min-height: 36px;
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.12s, border-color 0.12s, color 0.12s;
}
.ra-btn:hover { border-color: var(--indigo); color: var(--indigo); }
.ra-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Answered-state highlight: Yes is a risk signal (red), No is clear (green). */
.ra-btn-yes.ra-answered-yes {
  background: var(--err-bg); color: var(--err-fg); border-color: var(--err-bd);
}
.ra-btn-no.ra-answered-no {
  background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-bd);
}

/* Outcome cards */
.ra-outcome {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  flex: 0 0 auto;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  animation: ra-slide-in 0.18s ease;
}
.ra-outcome-icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 10px;
}
.ra-outcome-icon .material-icons { font-size: 20px; }
.ra-outcome strong {
  display: block;
  margin-bottom: 3px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text);
}
.ra-outcome p {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* Footer: save status and Reset, pinned to the bottom of the panel. */
.ra-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex: 0 0 auto;
  margin: auto -12px -12px;
  padding: 10px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface);
  position: sticky;
  bottom: 0;
}
.ra-save-status {
  flex: 1;
  margin: 0;
  font-size: 12px;
  color: var(--muted);
}
.ra-save-status.is-error { color: var(--danger); }
.ra-reset-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 32px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}
.ra-reset-btn:hover { border-color: var(--indigo); color: var(--indigo); }
.ra-reset-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.ra-reset-btn .material-icons { font-size: 16px; }

/* Per-question clear button: dim until the question has an answer. */
.ra-btn-clear {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid transparent;
  border-radius: 50%;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  opacity: 0.35;
  transition: background-color 0.12s, color 0.12s, border-color 0.12s, opacity 0.12s;
}
.ra-btn-clear .material-icons { font-size: 18px; }
.ra-btn-clear:disabled { cursor: default; pointer-events: none; }
.ra-btn-clear.ra-clear-active {
  opacity: 1;
  border-color: var(--border);
  background: var(--surface);
}
.ra-btn-clear.ra-clear-active:hover {
  border-color: var(--err-bd);
  background: var(--err-bg);
  color: var(--err-fg);
}
.ra-btn-clear:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.conversation-log {
  flex: 1;
  height: 0;
  min-height: 0;
  max-height: 100%;
  overflow-y: auto;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.conversation-empty {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
  padding: 12px;
  border: 1px dashed var(--border);
  border-radius: 8px;
}
.conversation-message {
  max-width: 92%;
  padding: 8px 11px;
  /* Rounded chat-bubble shape; the per-role tail corner is squared off below. */
  border-radius: 16px;
  border: 1px solid transparent;
  background: var(--bg);
  color: var(--text);
  font-size: 12px;
  line-height: 1.45;
}
/* Speaker and time on one line above a message (debrief transcript, study
   flow viewer, session log). */
.transcript-turn-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.transcript-turn-head time {
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
/* On the blue outgoing bubble the muted grey timestamp is unreadable. */
.conversation-message.user .transcript-turn-head time { color: var(--msg-out-label); }
.conversation-message strong {
  display: block;
  color: var(--text-muted);
  font-size: 11px;
  margin-bottom: 4px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.conversation-message.user {
  align-self: flex-end;
  background: var(--msg-out-bg);
  color: var(--msg-out-fg);
  border-bottom-right-radius: 5px;
}
.conversation-message.user strong {
  color: var(--msg-out-label);
}
/* The user's words while they are still speaking (live speech-to-text): a
   dashed, faded bubble that becomes a normal one when the turn is sent. */
.conversation-message.is-interim {
  opacity: 0.75;
  border: 1px dashed var(--msg-out-label);
  font-style: italic;
}
.conversation-message.avatar {
  align-self: flex-start;
  background: var(--msg-in-bg);
  border-bottom-left-radius: 5px;
}
.conversation-message.system {
  align-self: center;
  background: var(--err-bg);
  border-color: var(--err-bd);
  color: var(--err-fg);
  max-width: 100%;
  text-align: center;
}
.conversation-message.system strong {
  color: var(--danger);
}
.status-pill {
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-muted);
  background: var(--surface);
  font-size: 12px;
  font-weight: 700;
  padding: 5px 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.status-pill.generating { color: var(--info-fg); border-color: var(--info-bd); background: var(--info-bg); }
.status-pill.listening { color: var(--info-fg); border-color: var(--info-bd); background: var(--info-bg); }
.status-pill.queued { color: var(--tintaccent-fg); border-color: var(--tintaccent-bd); background: var(--tintaccent-bg); }
.status-pill.done { color: var(--ok-fg); border-color: var(--ok-bd); background: var(--ok-bg); }
.status-pill.error { color: var(--err-fg); border-color: var(--err-bd); background: var(--err-bg); }

/* ── Shared empty state ──────────────────────────────────────── */
.muted-text {
  color: var(--muted);
  font-size: 12px;
}
.dashboard-empty {
  grid-column: 1 / -1;
  width: 100%;
  border: 1px dashed var(--border);
  border-radius: 10px;
  color: var(--muted);
  background: var(--surface-sunken);
  padding: 28px;
  text-align: center;
  font-size: 13px;
}

/* ── Summary loading overlay ─────────────────────────────────
   Used by the debrief page and the call-end overlay on the conversation
   page; .summary-spinner is also the characters modal's loading spinner.
   The debrief page's own layout lives in summary.css. */
.summary-modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  background: rgba(5, 8, 16, 0.72);
  backdrop-filter: blur(6px);
  padding: 20px;
}
.summary-modal-box {
  width: min(420px, 100%);
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-sunken);
  padding: 28px;
  text-align: center;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
}
.summary-modal-box h2 {
  color: var(--text);
  font-size: 20px;
  margin: 14px 0 8px;
}
.summary-modal-box p {
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.5;
}
.summary-spinner {
  width: 42px;
  height: 42px;
  margin: 0 auto;
  border: 4px solid rgba(251, 113, 75, 0.22);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: summary-spin 0.9s linear infinite;
}
@keyframes summary-spin {
  to { transform: rotate(360deg); }
}
.character-modal-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.85fr);
  gap: 22px;
  align-items: start;
}
.character-modal-main,
.character-modal-side {
  min-width: 0;
}
.character-form-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}
.character-generation-panel {
  margin-bottom: 18px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-sunken);
  padding: 14px;
}
/* The boxed fields under a section label (voice, image, scripted cue)
   share one panel look. */
.voice-clone-box,
.character-upload-box,
.character-cue-box {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
  padding: 12px;
}
/* Custom cloned voice controls under the preset picker. */
.voice-clone-box {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.voice-clone-box audio { width: 100%; height: 36px; }
.voice-clone-box .form-hint { margin-top: 0; }
.voice-select-row { display: flex; align-items: center; gap: 8px; }
.voice-select-row select { flex: 1 1 auto; min-width: 0; }
/* Recording teleprompter: the reader follows the moving highlight so every
   clone is recorded at the same calm pace (the model mimics the clip's tempo). */
.voice-teleprompter {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-sunken);
  padding: 10px 12px;
}
.voice-teleprompter-hint { font-size: 11px; color: var(--muted); margin-bottom: 8px; }
.voice-teleprompter-text {
  max-height: 120px;
  overflow-y: auto;
  font-size: 15px;
  line-height: 1.9;
  color: var(--subtle);
}
.voice-teleprompter-text .tp-word { transition: color 0.1s, background 0.1s; padding: 1px 0; }
/* Karaoke fill: everything already read stays highlighted as one continuous
   band; the current word is just the brighter leading edge. */
.voice-teleprompter-text .tp-word.is-read,
.voice-teleprompter-text .tp-word.is-current {
  background: var(--primary);
  color: #fff;
}
.voice-teleprompter-text .tp-word.is-current { font-weight: 700; }

.voice-clone-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.voice-clone-row input[type="text"] { flex: 1 1 200px; min-width: 160px; }
/* <label> and <button> compute different heights from the same .btn-sm rules;
   flex-centering with a fixed height makes Upload/Record/Save sit level. */
.voice-clone-box .btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  line-height: 1;
  white-space: nowrap;
}
#f-voice-record-btn .material-icons { font-size: 15px; vertical-align: -3px; margin-right: 4px; }
#f-voice-record-btn.is-recording {
  color: var(--danger);
  border-color: var(--danger);
}
#f-voice-record-btn.is-recording .material-icons { animation: rec-pulse 1.2s ease-in-out infinite; }
@keyframes rec-pulse { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) {
  #f-voice-record-btn.is-recording .material-icons { animation: none; }
}

.character-generation-panel .form-group:last-child,
.character-modal-side .form-group:last-child {
  margin-bottom: 0;
}
.character-modal-side textarea {
  min-height: 260px;
}
.generated-sessions-panel {
  display: grid;
  gap: 10px;
  max-height: 360px;
  overflow-y: auto;
  padding-right: 4px;
}
.generated-sessions-empty {
  border: 1px dashed var(--border);
  border-radius: 8px;
  padding: 18px;
  color: var(--muted);
  font-size: 13px;
  text-align: center;
}
.generated-session-card {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  padding: 12px;
}
.generated-session-card h4 {
  margin: 0 0 8px;
  color: var(--text);
  font-size: 13px;
}
.generated-session-card p,
.generated-session-card div {
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.45;
  margin-top: 6px;
}
.generated-session-card strong {
  color: var(--text);
}
.session-edit-row {
  margin-top: 8px;
}
.session-edit-row label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-muted);
  margin-bottom: 4px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.session-edit-row .session-field {
  font-size: 12px;
  /* Override .character-modal-side textarea{min-height:260px} so each field
     sizes to its rows attribute instead of being 260px tall. */
  min-height: 0;
}
/* Scoped to the card so it outweighs .generated-session-card p, which would
   otherwise re-apply its 12px/margin-top:6px paragraph styling here. */
.generated-session-card .session-edit-hint {
  margin: 0 0 4px;
  color: var(--text-muted);
  font-size: 11px;
  line-height: 1.4;
}
.session-edit-actions {
  margin-top: 10px;
  display: flex;
  justify-content: flex-end;
}
.character-upload-box {
  display: grid;
  grid-template-columns: 112px minmax(0, 1fr);
  gap: 14px;
  align-items: center;
}
.character-cue-box {
  display: grid;
  gap: 10px;
}
.character-cue-box .form-hint { margin-top: 0; }
.character-upload-preview {
  position: relative;
  width: 112px;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-sunken);
}
.character-upload-preview img,
.character-upload-preview video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.character-upload-preview .material-icons {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  color: var(--primary);
  font-size: 42px;
}
.character-upload-actions {
  min-width: 0;
  display: grid;
  gap: 8px;
  justify-items: start;
}
.character-upload-actions input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.character-generation-loading {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(8, 11, 22, 0.72);
  backdrop-filter: blur(2px);
  border-radius: 12px;
}
.character-generation-loading.hidden { display: none !important; }
.character-generation-loading-box {
  width: min(420px, 100%);
  padding: 28px;
  text-align: center;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 20px 50px rgba(0,0,0,0.45);
}
.character-generation-loading-box h3 {
  margin: 16px 0 8px;
  color: var(--text);
  font-size: 18px;
}
.character-generation-loading-box p {
  margin: 0;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1.5;
}

/* ── Conversation: stacked layout (phones, and portrait tablets/windows) ──
   One column in reading order — stage bar, video, risk monitor, controls,
   tools — filling the screen with no page scroll. Portrait shapes stack even
   when wide (e.g. a portrait iPad), because side-by-side there leaves a tall,
   narrow video column that crops away most of the frame.
   KEEP IN SYNC with TOOL_SHEET_QUERY in public/js/tool-rail.js, which docks the
   tool popovers as bottom sheets under the same condition. */
@media (max-width: 767px), (orientation: portrait) and (max-width: 1024px) {
  .call-screen .talking-head-page { padding: 0; }
  .call-screen .call-card {
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }
  .call-main,
  .call-main.supervisor-hidden {
    --monitor-h: clamp(150px, 32dvh, 300px);
    grid-template-columns: minmax(0, 1fr) auto;
    /* An absent stage bar (a study condition) leaves an empty auto row of zero
       height. The tool rail stays a full-height column on the right, as on
       wider screens. */
    grid-template-rows: auto minmax(140px, 1fr) auto auto;
    grid-template-areas:
      "stage    tools"
      "video    tools"
      "monitor  tools"
      "controls tools";
  }
  /* With the risk monitor blinded (a study condition), its row keeps the
     monitor's height and is left empty, so the video has the same size and
     framing as when the monitor is shown, instead of stretching tall and
     cropping the avatar to a close-up. */
  .call-main.supervisor-hidden { grid-template-rows: auto minmax(140px, 1fr) var(--monitor-h) auto; }
  .call-main.supervisor-hidden .tool-box { grid-area: tools; }
  /* The session column's children join the grid directly, so the monitor can
     sit between the video and the controls. */
  .call-session { display: contents; }
  .stage-progress { grid-area: stage; }
  .call-videos { grid-area: video; padding: 8px; }
  /* Shares the row with the tool rail, so it runs narrow on phones. */
  .call-controls { grid-area: controls; gap: 8px; }
  /* Always on screen when the study condition shows it (never hidden behind a
     button). A FIXED height, not a capped one: as flagged statements and
     suggestions arrive the monitor scrolls inside instead of growing, so the
     video above keeps the same size for the whole call. */
  .supervisor-panel {
    grid-area: monitor;
    height: var(--monitor-h);
    overflow-y: auto;
    border-left: 0;
    border-top: 1px solid var(--border);
  }
  .supervisor-block--grow { flex: 0 0 auto; }
  .tool-box {
    grid-area: tools;
    padding: 10px 6px;
  }
  .tool-btn { width: 44px; height: 44px; }
  /* One square portrait, as large as fits, with the user's camera as a small
     square picture-in-picture in its corner. The stage is itself a size
     container, so the picture-in-picture is sized from it (and the
     character's name badge stops short of it). The custom property is only
     substituted where used, so its cq units resolve against the stage. */
  .call-stage {
    position: relative;
    display: block;
    width: min(100cqw, 100cqh);
    height: min(100cqw, 100cqh);
    container-type: size;
    --pip: clamp(72px, 32cqw, 170px);
  }
  .avatar-tile {
    width: 100%;
    height: 100%;
  }
  .user-tile {
    position: absolute;
    right: 10px;
    bottom: 10px;
    z-index: 4;
    width: var(--pip);
    height: var(--pip);
  }
  .user-tile .camera-shell {
    border-color: var(--primary);
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
  }
  .user-tile .camera-placeholder { font-size: 11px; }
  .tile-caption {
    left: 10px;
    bottom: 10px;
    padding: 6px 10px;
    max-width: calc(100cqw - var(--pip) - 30px);
  }
  .tile-caption strong { font-size: 14px; }
  /* The small picture-in-picture's caption takes two compact lines ("You",
     then the status and speech bars) so the status is not cut off. */
  .user-caption {
    left: 6px;
    right: 6px;
    bottom: 6px;
    max-width: none;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    padding: 4px 7px;
    border-radius: 6px;
  }
  .user-caption strong { font-size: 11px; }
  .user-caption span { font-size: 10px; margin-top: 0; }
  .user-caption .caption-status-row { width: 100%; gap: 4px; margin-top: 0; }
  .user-caption .caption-visualizer { gap: 2px; height: 10px; }
  .user-caption .caption-visualizer i { width: 3px; height: 8px; }
  /* Tool popovers dock as sheets over the strip between the video and the
     call controls (tool-rail.js sets their top/left/width/height from the
     layout), so the video and the controls stay visible. Without those
     measurements they fall back to a short sheet along the bottom. */
  .tool-popover {
    top: auto;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    max-width: none;
    height: min(45dvh, 420px);
    max-height: none;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -12px 32px rgba(15, 23, 42, 0.18);
  }
}

/* Short windows (landscape phones, small laptop windows): trim vertical chrome
   so the video keeps its height. */
@media (max-height: 560px) {
  .call-screen .talking-head-page { padding-block: 8px; }
  .call-videos { padding: 8px; }
  body.call-screen .stage-progress { padding: 4px 12px; }
  .stage-current-desc { display: none; }
  .tool-box { gap: 6px; padding: 8px 6px; }
  .tool-btn { width: 36px; height: 36px; }
}

@media (max-width: 900px) {
  .conversation-log {
    max-height: 320px;
  }
  .character-form-grid {
    grid-template-columns: 1fr;
  }
  .character-modal-layout {
    grid-template-columns: 1fr;
  }
  .character-modal-side textarea {
    min-height: 280px;
  }
  .character-upload-box {
    grid-template-columns: 1fr;
  }
}

/* ── Modal extensions ──────────────────────────────────────────
   Base .modal / .modal-box / .modal-title live in base.css; these are
   the product-specific wide layout, copy, actions and error banner. */
.modal-box.modal-box-wide {
  max-width: min(1180px, calc(100vw - 48px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}
.modal-copy {
  color: var(--text);
  font-size: 14px;
  line-height: 1.5;
}
.modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 24px; }
.error-banner {
  display: none;
  background: var(--err-bg);
  border: 1px solid var(--err-bd);
  color: var(--err-fg);
  border-radius: 6px;
  padding: 8px 12px;
  font-size: 12px;
  margin-bottom: 16px;
}
.error-banner.visible { display: block; }

@media (max-width: 900px) {
  .modal-box.modal-box-wide {
    max-width: calc(100vw - 24px);
    max-height: calc(100vh - 24px);
    padding: 22px;
  }
}

/* ── Responsive: tablet & phone ──────────────────────────────────
   Desktop-first, but keep the app usable on touch: let the header wrap instead
   of overflowing, grow tap targets toward the ~44px guideline, and keep the
   in-call controls reachable. */
@media (max-width: 768px) {
  .header {
    height: auto;
    min-height: 56px;
    flex-wrap: wrap;
    padding: 8px 14px;
    row-gap: 6px;
  }
  .header-title { display: none; }

  /* Larger tap targets so fingers don't mis-hit adjacent controls. */
  .btn, .btn-sm, .round-control, .end-call-btn, .modal-close {
    min-height: 44px;
  }
}
