/* Cloud Interpreter
   Visual direction: a modern interpreter's desk in daylight. Warm paper
   chassis, white cards, and the two parties colour-coded — amber and teal —
   like the two sides of a table. The accents are darkened until they hold
   WCAG contrast as body text on white, because they ARE body text here: every
   utterance is set in its speaker's colour. IBM Plex is the body face because
   it actually ships Cyrillic, Greek, Arabic, and Devanagari — the app needs
   them. */

:root {
  --chassis: #f5f4ef;   /* the page: warm paper, not clinical white */
  --panel:   #ffffff;   /* cards */
  --panel-2: #efede6;   /* hover / pressed */
  --inset:   #eceae2;   /* recessed panels: settings, meter, composers */
  --rule:    #e2dfd6;   /* hairlines */
  --bone:    #23272e;   /* ink (name kept — every rule references it) */
  --dim:     #6c737e;
  --ch-a:    #a2660d;   /* amber, dark enough to be small text on white */
  --ch-b:    #0d7386;   /* teal, likewise */
  --flag:    #bb4331;
  --good:    #2e8a58;

  --sans: "IBM Plex Sans", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, monospace;
  --display: "Space Grotesk", var(--sans);

  /* One radius scale and one shadow, everywhere. Mixed corner sizes are the
     fastest way for a UI to feel assembled rather than designed. */
  --r: 10px;
  --r-s: 7px;
  --shadow: 0 1px 3px rgb(35 30 15 / 0.07);
}

/* Interactive surfaces move a little. Everything, consistently. */
button, select, input, summary, .tab, .chip {
  transition: background-color 140ms ease, color 140ms ease, border-color 140ms ease, opacity 140ms ease;
}

* { box-sizing: border-box; }

/* The hidden attribute must always win, even over display:grid/flex below. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--chassis);
  color: var(--bone);
  font-family: var(--sans);
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
}

/* Flex, not a fixed grid template: sections (meter, settings, account) come
   and go with [hidden], and the tape must always be the part that flexes.
   The width limit lives on the interpret pane, not here — the admin tables
   want the full desk. */
body {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

#shell {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* ---------- one console, two panes ---------- */

.pane { display: none; }

/* The interpreter is a fixed frame with a scrolling tape in the middle. */
.pane.on[data-pane="interpret"] {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  width: 100%;
  max-width: 900px;
  margin-inline: auto;
}

/* The admin console is a long document; it scrolls as a whole. */
.pane.on[data-pane="admin"] {
  display: block;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.tabs {
  display: flex;
  gap: 3px;
  flex: 1;
  flex-wrap: wrap;
  min-width: 0;
}

.tab {
  font: 500 11.5px/1 var(--mono);
  letter-spacing: 0.04em;
  padding: 8px 10px;
  border: 1px solid transparent;
  border-radius: 3px;
  background: none;
  color: var(--dim);
  cursor: pointer;
  white-space: nowrap;
}

.tab:hover { color: var(--bone); }
.tab.on { color: var(--bone); background: var(--panel); border-color: var(--rule); }

/* ---------- the customer's view ---------- */

/* Signed in as a customer, the app is a conversation, not a console. One tab
   would be a tab bar with one tab; the specialty chip and Fast/Accurate are
   automatic decisions; the Session panel is an operator's drawer. What stays:
   speech on/off, Set up (names, gender, voice), the account drawer when
   billing is on, and the conversation itself. */
.lite .tabs,
.lite #context-chip,
.lite #mode,
.lite #settings-toggle { display: none; }

/* ---------- rack header ---------- */

/* Wraps because the controls grew: context, speech, mode, session, account. The
   body clips its overflow, so a header that cannot wrap loses a button off the
   right edge rather than showing a scrollbar. */
.rack {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 12px;
  padding: 14px 16px 12px;
  border-bottom: 1px solid var(--rule);
}

.rack h1 {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.02em;
}

.rack h1 span {
  font-weight: 500;
  color: var(--dim);
  margin-left: 2px;
}

.rack-controls { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; min-width: 0; align-items: center; }

/* Clerk's user button, sized to sit with the chips. */
#clerk-user { display: flex; align-items: center; min-width: 28px; }

/* Clerk mounts its own card here; give it room and let it centre itself. */
#clerk-signin { display: flex; justify-content: center; min-height: 360px; }
#clerk-signin:empty::after {
  content: "Loading sign-in…";
  font: 400 12px var(--mono);
  color: var(--dim);
  align-self: center;
}

.chip {
  font: 500 11.5px/1 var(--mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--bone);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--r-s);
  padding: 8px 11px;
  cursor: pointer;
}

.chip:hover { background: var(--panel-2); }
.chip[data-mode="accurate"] { color: var(--chassis); background: var(--ch-a); border-color: var(--ch-a); }
.chip.danger { color: var(--flag); }

/* Speech off is a state you must be able to read across the room, because the
   symptom of forgetting it is silence — which looks exactly like a failure. */
.chip[data-speech="off"] { color: var(--dim); border-style: dashed; }

/* The detected specialty. A read-out that happens to be clickable, so it is
   quieter than the controls beside it — and quieter still with nothing to say. */
.chip.context {
  max-width: 26ch;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--ch-b);
  border-color: color-mix(in srgb, var(--ch-b) 45%, var(--rule));
}

.chip.context::before {
  content: "◆ ";
  color: var(--ch-b);
}

.chip.context.idle {
  color: var(--dim);
  border-color: var(--rule);
}

.chip.context.idle::before { content: "◇ "; color: var(--dim); }

.chip.context.pinned {
  color: var(--chassis);
  background: var(--ch-b);
  border-color: var(--ch-b);
}

.chip.context.pinned::before { content: "▣ "; color: var(--chassis); }
.chip:focus-visible, select:focus-visible, input:focus-visible, .paddle:focus-visible {
  outline: 2px solid var(--ch-b);
  outline-offset: 2px;
}

/* ---------- session settings ---------- */

.settings {
  padding: 14px 16px;
  border-bottom: 1px solid var(--rule);
  background: var(--inset);
  max-height: 46vh;
  overflow-y: auto;
}

/* Each section folds. Only Subject matter opens by default — it is the one an
   operator reaches for mid-call; the rest are set once and then in the way. */
.settings .fold {
  border: 0;
  padding: 0;
  margin: 0 0 10px;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 10px;
}

.settings .fold:last-of-type { border-bottom: 0; }

.settings .fold > summary {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--dim);
  padding: 4px 0;
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 7px;
}

.settings .fold > summary::-webkit-details-marker { display: none; }

/* A caret that turns, so the fold state is readable at a glance. */
.settings .fold > summary::before {
  content: "▸";
  color: var(--rule);
  transition: transform 120ms ease;
}

.settings .fold[open] > summary { color: var(--bone); }
.settings .fold[open] > summary::before { transform: rotate(90deg); color: var(--ch-b); }
.settings .fold > summary:hover { color: var(--bone); }
.settings .fold > *:not(summary) { margin-top: 9px; }

.context-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.context-row select {
  flex: 1 1 260px;
  min-width: 0;
  font: 400 14px/1 var(--sans);
  color: var(--bone);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 9px 10px;
}

.context-state {
  font: 400 12.5px/1.4 var(--sans);
  color: var(--dim);
}

.settings label {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 14px;
  cursor: pointer;
}

.settings input[type="checkbox"] { accent-color: var(--ch-b); width: 16px; height: 16px; }

.hint {
  margin: 9px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--dim);
  max-width: 62ch;
}

.settings-actions { display: flex; gap: 8px; }

/* ---------- channel strips ---------- */

.channels {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-bottom: 1px solid var(--rule);
}

.channel {
  padding: 11px 13px 13px;
  display: grid;
  gap: 7px;
  border-left: 3px solid var(--side);
}

.channel[data-side="a"] { --side: var(--ch-a); }
.channel[data-side="b"] { --side: var(--ch-b); border-left-width: 3px; }

.channel-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.tag {
  font: 500 10px/1 var(--mono);
  letter-spacing: 0.12em;
  color: var(--side);
}

.role {
  font-size: 12px;
  color: var(--dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Who this channel is. Typed once, then it labels the paddle, the transcript
   column, the composer and the export — so nobody has to remember that the
   patient is "B". Never persisted: the next appointment is a different person. */
.party-name {
  width: 100%;
  font: 500 14px/1.15 var(--sans);
  color: var(--bone);
  background: var(--chassis);
  border: 1px solid var(--rule);
  border-left: 2px solid var(--side);
  border-radius: 3px;
  padding: 8px 10px;
}

.party-name::placeholder { font-weight: 400; color: var(--dim); }
.party-name:hover { border-color: color-mix(in srgb, var(--side) 40%, var(--rule)); border-left-color: var(--side); }

.channel select {
  width: 100%;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--bone);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 7px 8px;
  appearance: none;
}

.channel select:disabled { opacity: 0.45; }
.channel-opts { display: grid; grid-template-columns: 1fr auto; gap: 6px; }
.channel-opts select:last-child { font-family: var(--mono); font-size: 11px; }
.channel .voice { font-size: 11.5px; color: var(--dim); font-family: var(--mono); }

/* ---------- microphone check ---------- */

.mic-check { display: flex; align-items: center; gap: 10px; }

.mic-strip {
  flex: 1;
  height: 6px;
  min-width: 0;
  background: var(--chassis);
  border: 1px solid var(--rule);
  border-radius: 3px;
  overflow: hidden;
}

.mic-strip i {
  display: block;
  width: 0;
  height: 100%;
  background: var(--ch-b);
  transition: width 70ms linear;
}

#mic-report.error { color: var(--flag); }

/* The capture trace. Monospaced and scrollable — it is evidence, meant to be
   read line by line or screenshotted, not styled. */
.mic-log {
  margin: 9px 0 0;
  padding: 9px 10px;
  max-height: 190px;
  overflow: auto;
  background: var(--chassis);
  border: 1px solid var(--rule);
  border-radius: 3px;
  font: 400 11px/1.55 var(--mono);
  color: var(--dim);
  white-space: pre;
}

/* ---------- the pair bar ---------- */

/* Who speaks what, stated once and always visible. The transcript below is a
   single thread, so this is where the two languages live. */
.pairbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex: none;
  background: linear-gradient(180deg, #fbfaf5, var(--chassis));
  border-bottom: 1px solid var(--rule);
  padding: 9px 16px;
}

.pair-side {
  display: flex;
  align-items: baseline;
  gap: 7px;
  min-width: 0;
}

.pair-side::before {
  content: "";
  flex: none;
  width: 12px;
  height: 2px;
  background: var(--side);
  transform: translateY(-3px);
}

.pair-side[data-side="a"] { --side: var(--ch-a); }
.pair-side[data-side="b"] { --side: var(--ch-b); }

.pair-side b {
  font: 500 11.5px/1.2 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--side);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The language belongs in the always-visible bar: it is the one setting that
   has to be reachable at any moment, and it also states the direction. */
.pair-lang {
  min-width: 0;
  max-width: 15ch;
  font: 400 12px/1 var(--sans);
  color: var(--dim);
  background: none;
  border: 0;
  border-bottom: 1px dashed var(--rule);
  border-radius: 0;
  padding: 2px 0;
  cursor: pointer;
  appearance: none;
  text-overflow: ellipsis;
}

.pair-lang:hover { color: var(--bone); border-bottom-color: var(--side); }
.pair-lang:disabled { opacity: 0.5; cursor: not-allowed; }

/* Opens the strips below. Named for what it does, not for a gear icon. */
.setup-toggle {
  margin-left: auto;
  flex: none;
  font: 500 10.5px/1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--dim);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 6px 9px;
  cursor: pointer;
}

.setup-toggle:hover { color: var(--bone); background: var(--panel-2); }
.setup-toggle.on { color: var(--chassis); background: var(--ch-b); border-color: var(--ch-b); }

/* Either direction is interpreted into the other side's language; this says so
   and lets the operator exchange them without touching two dropdowns. */
.swap {
  flex: none;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  font: 500 13px/1 var(--mono);
  color: var(--dim);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
}

.swap:hover { color: var(--bone); background: var(--panel-2); }
.swap:disabled { opacity: 0.4; cursor: not-allowed; }

/* ---------- the tape: signature element ---------- */

.tape {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 20px 16px 8px;
  scroll-behavior: smooth;
}

.empty {
  position: relative;
  margin: 9vh auto 0;
  max-width: 40ch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  text-align: center;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--dim);
  padding: 10px 0;
}

.empty-mark {
  font-size: 15px;
  letter-spacing: 6px;
  color: var(--rule);
}

.empty-mark b:first-child { color: var(--ch-a); }
.empty-mark b:last-child { color: var(--ch-b); }
.empty-mark b { font-weight: 400; }

.empty > b {
  font: 600 15px/1.3 var(--display);
  color: var(--bone);
}

/* One row per turn, in time order — but split down the middle, because the two
   halves belong to different people. What was said sits in the speaker's
   column; the interpretation sits in the listener's, which is the side they
   actually read. So each party watches their own column and sees only their own
   language, while the row keeps the pair together and the sequence intact. */
.turn {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 14px;
  margin-bottom: 12px;
  animation: rise 260ms ease-out;
}

.turn[data-side="a"] { --side: var(--ch-a); --other: var(--ch-b); }
.turn[data-side="b"] { --side: var(--ch-b); --other: var(--ch-a); }

/* The speaker's half tracks whoever is talking, so a turn from Party B mirrors:
   said on the right, heard on the left. Nothing moves but the column. */
.turn[data-side="a"] .said  { grid-column: 1; }
.turn[data-side="a"] .heard { grid-column: 2; }
.turn[data-side="b"] .said  { grid-column: 2; }
.turn[data-side="b"] .heard { grid-column: 1; }

.said, .heard {
  padding: 10px 13px 11px;
  background: var(--panel);
  border: 1px solid color-mix(in srgb, var(--rule) 72%, transparent);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  min-width: 0;
}

.said  { border-left: 3px solid var(--side); }
/* The interpretation carries the listener's colour: it is theirs to read. */
.heard { border-left: 3px solid var(--other); }

@keyframes rise {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.meta {
  display: flex;
  align-items: baseline;
  gap: 7px;
  flex-wrap: wrap;
  font: 400 10px/1.4 var(--mono);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 7px;
}

.said .from { color: var(--side); font-weight: 500; }
.heard .to { color: var(--other); font-weight: 500; }
.heard .arrow { color: var(--rule); }
.meta .lang { color: var(--dim); text-transform: none; letter-spacing: 0.02em; }
.meta .when { margin-left: auto; font-variant-numeric: tabular-nums; }

/* what was actually said, in the speaker's own language */
.floor {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--side);
  margin: 0;
  word-wrap: break-word;
}

.floor.interim { opacity: 0.55; font-style: italic; }

/* the interpretation — the payload, and what gets spoken aloud */
.relay {
  font-size: 16.5px;
  line-height: 1.5;
  margin: 0;
  word-wrap: break-word;
}

.relay.pending { color: var(--dim); animation: breathe 1.2s ease-in-out infinite; }

@keyframes breathe {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 0.9; }
}

/* words light up as the voice reaches them */
.relay w { transition: color 90ms linear; }
.relay w.lit { color: var(--other); }

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 8px;
}

.badge {
  font: 400 10.5px/1.35 var(--mono);
  color: var(--dim);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 4px 6px;
  text-align: left;
}

.badge.warn { color: var(--flag); border-color: color-mix(in srgb, var(--flag) 45%, var(--rule)); }
.badge.addr { color: var(--bone); border-color: var(--rule); white-space: pre-line; }
a.badge.addr { text-decoration: none; cursor: pointer; }
a.badge.addr:hover { border-color: var(--ch-b); color: var(--ch-b); }

/* ---------- status line ---------- */

.status {
  min-height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2px 16px;
  font: 400 11.5px/1.5 var(--mono);
  color: var(--dim);
  text-align: center;
}

.status:not(:empty) {
  width: fit-content;
  max-width: min(92%, 68ch);
  margin-inline: auto;
  padding: 5px 13px;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 999px;
  box-shadow: var(--shadow);
}

.status.error:not(:empty) {
  color: var(--flag);
  background: color-mix(in srgb, var(--flag) 9%, var(--panel));
  border-color: color-mix(in srgb, var(--flag) 45%, var(--rule));
}

.status.error { color: var(--flag); }

/* ---------- typed fallback ---------- */

/* One composer per lane, in the same two columns as the paddles below. The old
   single field needed an "A → B" toggle, which meant every typed turn carried a
   chance of being attributed to the wrong person. Two fields cannot be wrong. */
.type-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 8px 16px;
  border-top: 1px solid var(--rule);
  background: var(--inset);
}

.composer {
  display: flex;
  gap: 6px;
  min-width: 0;
}

.composer[data-side="a"] { --side: var(--ch-a); }
.composer[data-side="b"] { --side: var(--ch-b); }

.composer input {
  flex: 1;
  min-width: 0;
  font-family: var(--sans);
  font-size: 14px;
  color: var(--bone);
  background: var(--chassis);
  border: 1px solid var(--rule);
  border-left: 2px solid var(--side);
  border-radius: var(--r-s);
  padding: 9px 11px;
}

.composer input:focus-visible { outline-color: var(--side); }

.composer input::placeholder { color: var(--dim); }

.send {
  flex: none;
  width: 36px;
  font: 400 15px/1 var(--mono);
  color: var(--dim);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--r-s);
  cursor: pointer;
}

.send:hover { color: var(--side); border-color: color-mix(in srgb, var(--side) 55%, var(--rule)); }

/* Channel B's composer is closed during practice — the partner speaks for it. */
.composer input:disabled { opacity: 0.4; cursor: not-allowed; }
.composer input:disabled ~ .send { opacity: 0.4; pointer-events: none; }

/* ---------- push-to-talk paddles ---------- */

.paddles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--rule);
  border-top: 1px solid var(--rule);
  padding-bottom: env(safe-area-inset-bottom);
}

.paddle {
  position: relative;
  overflow: hidden;
  border: 0;
  background: var(--panel);
  color: var(--bone);
  padding: 20px 12px;
  min-height: 76px;
  font-family: var(--sans);
  font-size: 13px;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: none;
}

.paddle[data-side="a"] { --side: var(--ch-a); }
.paddle[data-side="b"] { --side: var(--ch-b); }

/* Each button carries its person's colour along the top — the same edge the
   transcript cards use, so the mapping never has to be explained. */
.paddle::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--side);
  opacity: 0.45;
  transition: opacity 140ms ease;
}

.paddle:active:not(:disabled) { background: var(--panel-2); }
.paddle.live::before { opacity: 1; }

/* The name is the button. In a room you press the person, not the channel. */
.paddle-label {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  min-width: 0;
}

.paddle-label b {
  max-width: 100%;
  font-size: 15px;
  font-weight: 600;
  color: var(--side);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.paddle-label i {
  font: 400 10px/1 var(--mono);
  font-style: normal;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--dim);
}

.paddle.live { background: color-mix(in srgb, var(--side) 7%, var(--panel-2)); }
.paddle:disabled { opacity: 0.4; cursor: not-allowed; }

/* live mic amplitude fills the paddle from the bottom */
.vu {
  position: absolute;
  inset: 0;
  display: block;
  pointer-events: none;
}

.vu i {
  position: absolute;
  inset: auto 0 0 0;
  display: block;
  height: 0;
  background: var(--side);
  opacity: 0.16;
  transition: height 70ms linear;
}

/* ---------- narrow screens ---------- */

@media (max-width: 640px) {
  /* The header holds a brand, six tabs and five chips. On a phone the tabs
     scroll in their lane instead of wrapping the header into three rows. */
  .rack { padding: 10px 12px 8px; gap: 8px 10px; }
  .rack h1 { font-size: 15px; }
  .tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .tabs::-webkit-scrollbar { display: none; }
  .chip { padding: 7px 8px; font-size: 10.5px; }
  .chip.context { max-width: 13ch; }

  .pairbar { padding: 7px 10px; gap: 8px; }
  .pair-lang { max-width: 11ch; }
  .setup-toggle { padding: 6px 8px; }

  .channels { grid-template-columns: 1fr; }
  .channel + .channel { border-top: 1px solid var(--rule); }

  .turn { grid-template-columns: 1fr; gap: 6px; }
  .turn .said, .turn .heard { grid-column: 1; }
  .relay { font-size: 15px; }

  .type-row { padding: 8px 10px; gap: 6px; }
  .composer { gap: 4px; }
  /* 16px stops iOS zooming the whole page when a field is focused. */
  .composer input { font-size: 16px; padding: 8px 10px; }
  .party-name { font-size: 16px; }
  .send { width: 34px; }

  .paddle { min-height: 68px; padding: 16px 10px; }
  .paddle-label b { font-size: 14px; }
  .paddle-label i { font-size: 9px; letter-spacing: 0.05em; }

  .settings, .account { max-height: 62vh; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  .tape { scroll-behavior: auto; }
}

/* Short viewports: the fixed sections (header, channels, type row, paddles)
   can exceed the screen. Let the page scroll instead of clipping the paddles,
   and never let the transcript collapse to nothing. */
@media (max-height: 480px), (max-width: 480px) and (max-height: 620px) {
  body { overflow-y: auto; }
  .tape { min-height: 96px; }
}

/* operator-side "send this to the Accuracy Lab" control */
.badge.fix {
  font-family: var(--mono);
  background: none;
  color: var(--dim);
  border: 1px dashed var(--rule);
  cursor: pointer;
}

.badge.fix:hover:not(:disabled) { color: var(--flag); border-color: var(--flag); border-style: solid; }

/* Replay. Sized for a thumb, because on a phone it is the control that works
   when the browser refuses to play the audio on its own. */
.badge.play {
  font-family: var(--mono);
  color: var(--ch-b);
  background: none;
  border: 1px solid color-mix(in srgb, var(--ch-b) 45%, var(--rule));
  padding: 6px 10px;
  cursor: pointer;
}

.badge.play:hover { color: var(--chassis); background: var(--ch-b); }
.badge.fix:disabled { cursor: default; opacity: 0.6; }

/* ---------- practice mode ---------- */

.practice-row { display: flex; gap: 8px; flex-wrap: wrap; }

.practice-row select {
  flex: 1 1 150px;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--bone);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 8px;
  appearance: none;
}

.practice-row select:disabled { opacity: 0.5; }
.chip.on { background: var(--ch-b); border-color: var(--ch-b); color: var(--chassis); }

/* a full-width note across the tape: scenario start, session end */
.marker {
  position: relative;
  margin: 6px auto 22px;
  max-width: 46ch;
  text-align: center;
  font: 400 11.5px/1.6 var(--mono);
  color: var(--dim);
  background: var(--chassis);
  padding: 8px 12px;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

/* the partner's turns are marked so a rehearsal can never be mistaken for a
   real session, in the room or in the exported transcript */
.turn.simulated .said .from::after {
  content: " · SIMULATED";
  color: var(--dim);
  font-weight: 400;
}

.turn.simulated .said, .turn.simulated .heard { border-left-style: dotted; }

body.practising .paddle[data-side="b"] { background: repeating-linear-gradient(135deg, var(--panel), var(--panel) 6px, var(--panel-2) 6px, var(--panel-2) 12px); }

/* ---------- account gate ---------- */

.gate {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: 20px;
  background: var(--chassis);
  overflow-y: auto;
}

.gate-card {
  width: 100%;
  max-width: 340px;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 26px 22px;
}

.gate-card h1 { margin: 0; font-family: var(--display); font-size: 19px; font-weight: 700; }
.gate-card h1 span { font-weight: 500; color: var(--dim); }
.gate-sub { margin: 4px 0 18px; font: 400 10.5px/1 var(--mono); letter-spacing: 0.09em; text-transform: uppercase; color: var(--dim); }

.gate-tabs { display: flex; gap: 4px; margin-bottom: 16px; }

.gate-tab {
  flex: 1;
  font: 500 11.5px/1 var(--mono);
  padding: 9px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: none;
  color: var(--dim);
  cursor: pointer;
}

.gate-tab.on { background: var(--panel-2); color: var(--bone); }

.gate-card label { display: block; margin-bottom: 13px; font-size: 12.5px; color: var(--dim); }

.gate-card input {
  width: 100%;
  margin-top: 5px;
  font-family: var(--sans);
  font-size: 15px;
  color: var(--bone);
  background: var(--chassis);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 10px;
}

.btn-wide {
  width: 100%;
  font: 500 12px/1 var(--mono);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 12px;
  border: 0;
  border-radius: 3px;
  background: var(--ch-b);
  color: var(--chassis);
  cursor: pointer;
}

.gate-error { margin: 12px 0 0; min-height: 18px; font-size: 13px; color: var(--flag); }

.rate-card { margin-top: 18px; border-top: 1px solid var(--rule); padding-top: 14px; }
.rate-card summary { font: 500 11px var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--dim); cursor: pointer; }
.rate-card table { width: 100%; margin-top: 10px; border-collapse: collapse; font-size: 13px; }
.rate-card td { padding: 4px 0; border-bottom: 1px solid var(--rule); }
.rate-card td:last-child { text-align: right; font-family: var(--mono); font-size: 12px; color: var(--ch-a); }

/* ---------- the meter ---------- */

.meter {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 16px;
  border-bottom: 1px solid var(--rule);
  background: var(--inset);
}

.meter-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--rule);
  flex: none;
}

.meter.live .meter-dot { background: var(--ch-b); animation: pulse 1.8s ease-in-out infinite; }
.meter.paused .meter-dot { background: var(--dim); animation: none; }
.meter.low .meter-dot { background: var(--flag); }

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

.meter-clock {
  font: 500 15px/1 var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--bone);
  flex: none;
}

.meter-cost {
  font: 600 17px/1 var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--ch-a);
  flex: none;
}

.meter.low .meter-cost { color: var(--flag); }

.meter-detail {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
  font: 400 10.5px/1.3 var(--mono);
  color: var(--dim);
  overflow: hidden;
}

.meter-detail span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.meter.low .meter-detail { color: var(--flag); }
.meter .chip { flex: none; }

@media (max-width: 400px) {
  .meter { gap: 8px; padding: 8px 12px; }
  .meter-cost { font-size: 15px; }
  .meter-detail { font-size: 9.5px; }
}

/* ---------- account drawer ---------- */

.account {
  padding: 16px;
  border-bottom: 1px solid var(--rule);
  background: var(--inset);
  max-height: 60vh;
  overflow-y: auto;
}

.account-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.account-label { display: block; font: 500 10px/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--dim); margin-bottom: 6px; }
.account-head b { font: 600 26px/1 var(--mono); font-variant-numeric: tabular-nums; color: var(--ch-b); }
.account-email { display: block; margin-top: 5px; font-size: 12px; color: var(--dim); }
.account-block { margin-bottom: 18px; }
.account-block:last-child { margin-bottom: 0; }

.topup-row { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }

.topup-row input {
  flex: 1 1 120px;
  font-family: var(--sans);
  font-size: 14px;
  color: var(--bone);
  background: var(--chassis);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 8px 10px;
}

.history-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 4px 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 13px;
  align-items: baseline;
}

.history-row:last-child { border-bottom: 0; }
.history-when { grid-column: 1 / -1; font: 400 10px var(--mono); color: var(--dim); }
.history-pair { color: var(--bone); }
.history-time { font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--dim); }
.history-cost { font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--ch-a); min-width: 62px; text-align: right; }
