:root {
  --bg: #14161a;
  --panel: #1d2026;
  --line: #2c313a;
  --text: #e7e9ee;
  --dim: #949cab;
  --faint: #6b7382;
  --me: #4a9eff;
  --them: #ffb02e;
  --bad: #ff5b5b;
  --good: #3ddc84;
  /* A whole paragraph in the signal green is hard to read, so translated text
     gets a softened version of it: unmistakably green, still comfortable. */
  --translated: #8fe0b4;
  --tailored: #a78bfa;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 14px 20px 20px;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.55 system-ui, -apple-system, "Segoe UI", sans-serif;
}

a { color: inherit; }
.hidden { display: none !important; }
.dim { color: var(--dim); font-size: 12px; }
.empty { color: var(--dim); }

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

.topbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  max-width: 1320px;
  margin: 0 auto 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

.brand { font-size: 15px; font-weight: 700; text-decoration: none; white-space: nowrap; }

.title-input {
  flex: 1;
  min-width: 0;
  font-size: 21px;
  font-weight: 600;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 7px;
  padding: 5px 8px;
  color: var(--text);
}

.title-input:hover:not(:disabled) { border-color: var(--line); }
.title-input:focus { border-color: var(--me); outline: none; background: #12141a; }
.title-input:disabled { opacity: 1; color: var(--faint); }

.banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  border-radius: 9px;
  padding: 11px 14px;
  margin: 0 auto 14px;
  max-width: 1320px;
  font-size: 13.5px;
  border: 1px solid var(--bad);
  background: rgba(255, 91, 91, 0.12);
}

.banner-text { flex: 1; min-width: 0; }

.banner-close {
  flex: 0 0 auto;
  background: none;
  border: 0;
  color: inherit;
  opacity: 0.6;
  font-size: 18px;
  line-height: 1;
  padding: 0 2px;
  cursor: pointer;
}

.banner-close:hover { opacity: 1; }

.banner-info { border-color: var(--me); background: rgba(74, 158, 255, 0.12); }

/* ------------------------------------------------------------------ layout */

.layout {
  display: grid;
  grid-template-columns: 270px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
  max-width: 1320px;
  margin-inline: auto;
}

/* Collapsed: the history takes the whole page. The sidebar is removed from the
   grid rather than merely hidden, so nothing keeps its column open. */
.layout.sidebar-hidden { grid-template-columns: minmax(0, 1fr); }
.layout.sidebar-hidden .sidebar { display: none; }

.icon-toggle {
  flex: 0 0 auto;
  padding: 6px 10px;
  font-size: 14px;
  line-height: 1;
  color: var(--dim);
}

.icon-toggle.on { color: var(--me); border-color: var(--me); }

.sidebar {
  position: sticky;
  top: 14px;
  max-height: calc(100vh - 28px);
  overflow-y: auto;
  font-size: 13px;
}

.side-block {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px;
}

/* ------------------------------------------------------------------ inputs */

input[type="text"], textarea, select {
  background: #12141a;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  padding: 7px 9px;
  font: inherit;
  width: 100%;
}

textarea { resize: vertical; line-height: 1.45; font-size: 12.5px; }
select { cursor: pointer; }

input:disabled { opacity: 0.55; }

button {
  background: #23272f;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  padding: 7px 12px;
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
  white-space: nowrap;
}

button:hover:not(:disabled) { border-color: #4a5261; }
button:disabled { opacity: 0.4; cursor: default; }
button.primary { background: var(--me); border-color: var(--me); color: #06121f; font-weight: 600; }
button.danger { color: var(--bad); }

.icon-button {
  background: transparent;
  border: 0;
  font-size: 22px;
  line-height: 1;
  padding: 0 4px;
  color: var(--dim);
}

.pill {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 20px;
  border: 1px solid var(--line);
  color: var(--dim);
  white-space: nowrap;
}

/* Sign out is a POST with a CSRF token, so it is a form rather than a link.
   The wrapper must not disturb the row it sits in. */
.signout {
  display: inline-flex;
  margin: 0;
}

.signout .pill {
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: 11px;
}


/* ------------------------------------------------------------------- modal */

.modal {
  position: fixed;
  inset: 0;
  background: rgba(8, 10, 13, 0.72);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 8vh 20px 20px;
  z-index: 20;
}

.modal-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 16px;
  width: 100%;
  max-width: 540px;
  max-height: 78vh;
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
}

.modal-head { display: flex; align-items: center; justify-content: space-between; }
.modal-head h2 { margin: 0; font-size: 15px; }

.new-conversation { display: flex; gap: 8px; }

.conversation-list { overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.conversation-list .empty { padding: 8px 2px; font-size: 13px; }

.conversation-row {
  display: flex;
  align-items: center;
  gap: 6px;
  border-radius: 8px;
  border-left: 2px solid transparent;
}

.conversation-link {
  display: block;
  flex: 1;
  min-width: 0;
  padding: 9px 10px;
  text-decoration: none;
}

.conversation-row:hover { background: #23272f; }
.conversation-row.active { background: #23272f; border-left-color: var(--me); }

.row-delete {
  background: transparent;
  border: 0;
  color: var(--faint);
  font-size: 17px;
  line-height: 1;
  padding: 4px 9px;
  border-radius: 6px;
  opacity: 0;
}

/* Duplicate sits beside delete and behaves the same way: hidden until the row
   is hovered, so a list of conversations stays a list rather than a toolbar. */
.row-duplicate {
  background: transparent;
  border: 0;
  color: var(--faint);
  font-size: 14px;
  line-height: 1;
  padding: 5px 7px;
  border-radius: 6px;
  opacity: 0;
}

.conversation-row:hover .row-delete,
.conversation-row:hover .row-duplicate { opacity: 1; }
.row-delete:hover { color: var(--bad); background: rgba(255, 91, 91, 0.12); }
.row-duplicate:hover { color: var(--me); background: rgba(74, 158, 255, 0.12); }
.row-delete:focus-visible,
.row-duplicate:focus-visible { opacity: 1; }

.conversation-title {
  display: block;
  font-weight: 600;
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.conversation-row.active .conversation-title { color: #fff; }
.conversation-meta { display: block; color: var(--faint); font-size: 11.5px; }

/* ---------------------------------------------------------------- controls */

.controls-block { display: flex; flex-direction: column; gap: 11px; }

/* Empty unless a flush failed, so it takes no room when all is well. */
.save-state:empty { display: none; }
.save-state { font-size: 11px; color: var(--bad); }

.release-button { align-self: flex-start; font-size: 11px; padding: 4px 9px; }

.meters { display: flex; flex-direction: column; gap: 7px; }
.meter-head { display: flex; justify-content: space-between; font-size: 11px; margin-bottom: 3px; }
.meter[data-lane="me"] .meter-head span:first-child { color: var(--me); font-weight: 600; }
.meter[data-lane="them"] .meter-head span:first-child { color: var(--them); font-weight: 600; }
.meter-source { color: var(--faint); }
.meter-track { height: 7px; background: #12141a; border-radius: 4px; overflow: hidden; }
.meter-fill { height: 100%; width: 0; border-radius: 4px; transition: width 60ms linear; }
.meter[data-lane="me"] .meter-fill { background: var(--me); }
.meter[data-lane="them"] .meter-fill { background: var(--them); }

.field { display: flex; flex-direction: column; gap: 4px; }
.field > span { font-size: 12px; font-weight: 600; }
.field small, .check small { color: var(--faint); font-size: 11px; line-height: 1.35; }

.check { display: grid; grid-template-columns: auto 1fr; gap: 1px 7px; align-items: center; font-size: 12.5px; }
.check small { grid-column: 2; }

.option-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.option-row .check { flex: 1; }
.option-select { width: auto; flex: 1; min-width: 0; font-size: 12.5px; padding: 5px 8px; }


/* --------------------------------------------------------- interview mode */

/* Same container as the interview block, but folded away: the microphone and
   its meters are set once and then only looked at when something is wrong. */
.panel-block {
  padding: 0 11px;
  margin: 2px -2px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.02);
}

.panel-block > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 9px 0;
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  list-style: none;
}

.panel-block > summary::-webkit-details-marker { display: none; }

/* A caret that turns, rather than the browser's default triangle. */
.panel-block > summary > span:first-child::before {
  content: '';
  display: inline-block;
  width: 0;
  height: 0;
  margin-right: 7px;
  vertical-align: 1px;
  border: 4px solid transparent;
  border-left-color: var(--dim);
  transition: transform 0.15s ease;
}

.panel-block[open] > summary > span:first-child::before {
  transform: rotate(90deg) translateX(-1px);
}

.panel-block > summary .dim { font-weight: 400; font-size: 11px; color: var(--faint); }
.panel-block > *:last-child { padding-bottom: 11px; }
.panel-block .field { margin-bottom: 10px; }

/* One container for every document row, interview or not, so they read as one
   list rather than as two groups that happen to look alike. */
.docs-block {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 11px;
  margin: 2px -2px;
  border: 1px solid rgba(74, 158, 255, 0.35);
  border-radius: 9px;
  background: rgba(74, 158, 255, 0.06);
}

.interview-rows { display: flex; flex-direction: column; gap: 10px; }

.doc-row { display: flex; align-items: center; gap: 8px; }
.doc-row button { flex: 1; text-align: left; }
.doc-row .dim { font-size: 11px; color: var(--faint); white-space: nowrap; }

/* A CV title can be long, and the button carries it. Truncate rather than let
   the sidebar widen or the label wrap onto three lines. */
.doc-button { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-button.cv-tailored { border-color: var(--tailored); color: var(--tailored); }

/* Red means the prompts would go out with this document too thin to be worth
   sending, which is the one thing worth noticing at a glance before an
   interview starts. */
.doc-button.thin {
  border-color: var(--bad);
  color: var(--bad);
  background: rgba(255, 91, 91, 0.08);
}

/* One dot, the same everywhere it appears: document rows and Diarize. */
.help-dot {
  flex: 0 0 auto;
  width: 19px;
  height: 19px;
  padding: 0;
  text-align: center;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--faint);
  font-size: 11px;
  line-height: 1;
  font-weight: 700;
}

/* `.doc-row button { flex: 1; text-align: left }` is more specific than the
   block above, so those two properties have to be won back by name. */
.doc-row .help-dot { flex: 0 0 auto; text-align: center; }

.help-dot:hover:not(:disabled) { color: var(--text); border-color: var(--dim); }

/* The switch sits at the end of the document's own row, so the button already
   names it and the switch carries no label of its own. */
.toggle {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: 0 0 auto;
  cursor: pointer;
  font-size: 12.5px;
}

.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }

.toggle-track {
  position: relative;
  flex: 0 0 auto;
  width: 32px;
  height: 18px;
  border-radius: 9px;
  background: #343a45;
  border: 1px solid var(--line);
  transition: background 0.15s ease;
}

.toggle-track::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--dim);
  transition: transform 0.15s ease, background 0.15s ease;
}

.toggle input:checked + .toggle-track { background: rgba(74, 158, 255, 0.55); border-color: var(--me); }
.toggle input:checked + .toggle-track::after { transform: translateX(14px); background: #fff; }
.toggle input:focus-visible + .toggle-track { outline: 2px solid var(--me); outline-offset: 2px; }
.toggle input:disabled + .toggle-track { opacity: 0.4; }

.brag-build-row { border-color: rgba(255, 176, 46, 0.4); background: rgba(255, 176, 46, 0.08); }
.brag-build-row button { flex: 0 0 auto; }
/* The tab strip is borrowed from the hints panel, where green means Help. Here
   it is just a tab, so it takes the neutral accent instead. */
/* The card already spaces its children, and .hints-tabs adds its own margin for
   the history panel, so it has to be beaten on specificity rather than order. */
.modal-card .brag-tabs { margin-bottom: 0; }
.brag-tabs .hints-tab.active { color: var(--me); border-color: rgba(74, 158, 255, 0.6); }

.brag-warning {
  margin: 0;
  padding: 9px 11px;
  border-radius: 8px;
  border: 1px solid rgba(255, 176, 46, 0.45);
  background: rgba(255, 176, 46, 0.09);
  color: var(--them);
  font-size: 12.5px;
  line-height: 1.45;
}

/* ------------------------------------------------- alerts and long waits */

/* Both open on top of another modal, so they sit above the rest of the stack
   rather than relying on document order. */
#busy-modal, #alert-modal { z-index: 30; }

.modal-narrow { max-width: 440px; }
.alert-body { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--dim); }
.modal-actions button.hidden { display: none !important; }

.busy { display: flex; align-items: flex-start; gap: 12px; }
.busy strong { display: block; font-size: 14px; }
.busy .dim { display: block; margin-top: 3px; font-size: 12px; line-height: 1.45; }

.spinner {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  border-radius: 50%;
  border: 2px solid rgba(74, 158, 255, 0.25);
  border-top-color: var(--me);
  animation: spin 0.9s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* An indeterminate bar: the wait is known to be long but not how long, so it
   shows movement rather than a percentage it would have to invent. */
.busy-bar {
  height: 3px;
  border-radius: 2px;
  background: #2a2f39;
  overflow: hidden;
}

.busy-bar span {
  display: block;
  width: 34%;
  height: 100%;
  border-radius: 2px;
  background: var(--me);
  animation: sweep 1.5s ease-in-out infinite;
}

@keyframes sweep {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(330%); }
}

.modal-tall { max-width: 820px; height: 80vh; }
.modal-tall textarea {
  flex: 1;
  min-height: 0;
  resize: none;
  font-size: 13.5px;
  line-height: 1.55;
}

.tailor-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px;
  border: 1px solid rgba(167, 139, 250, 0.4);
  background: rgba(167, 139, 250, 0.08);
  border-radius: 8px;
}

.tailor-row select { width: auto; flex: 1; min-width: 0; font-size: 12.5px; }
.preset-row { border-color: rgba(61, 220, 132, 0.4); background: rgba(61, 220, 132, 0.07); }
/* Each document's row is tinted by what it does: purple tailors, green starts
   from a preset, blue picks. */
.cv-row { border-color: rgba(74, 158, 255, 0.4); background: rgba(74, 158, 255, 0.07); }
.keyterms-row { border-color: rgba(255, 176, 46, 0.4); background: rgba(255, 176, 46, 0.08); }
.keyterms-row button { flex: 0 0 auto; }
.tailor-row .dim { font-size: 11px; white-space: nowrap; }

/* A session CV is not one of the library CVs, so it must not look like one.
   Only the closed control is tinted: options inherit the select's colour, so
   they have to be reset or the whole open dropdown turns purple. */
.cv-tailored {
  color: var(--tailored);
  border-color: var(--tailored);
  font-weight: 600;
}

.cv-tailored option {
  color: var(--text);
  font-weight: 400;
}

.option-tailored,
.cv-tailored option.option-tailored {
  color: var(--tailored);
  font-weight: 600;
}

.modal-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.modal-actions .dim { font-size: 11.5px; }
/* The hint spells out what the button is about to do, so it is the hint that
   wraps when it runs long, never the button that gets squeezed. */
.modal-actions button { padding: 8px 22px; flex: 0 0 auto; }

/* Lit = Flash, dark = Flash Lite. */
/* The bulb governs Help and nothing else, so it sits on the Help button rather
   than beside it. Small, because it is a secondary control on a primary one. */
.bulb {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin-left: 8px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  /* Against the blue Help button, not against the page. */
  color: rgba(6, 18, 31, 0.55);
  /* Unlit it is still a control, and without an edge it read as part of the
     Help label rather than as something separately pressable. */
  border: 1px solid var(--them);
  cursor: pointer;
  transition: color 120ms, background 120ms, box-shadow 120ms, border-color 120ms;
}

.bulb svg { width: 14px; height: 14px; fill: currentColor; }
.bulb:hover:not(.on) { color: rgba(6, 18, 31, 0.9); background: rgba(255, 176, 46, 0.25); }
.bulb:focus-visible { outline: 2px solid #06121f; outline-offset: 1px; }

.bulb.on {
  color: #1a1400;
  background: #ffd54a;
  border-color: #ffd54a;
  box-shadow: 0 0 9px rgba(255, 213, 74, 0.65);
}

/* inline-flex so the bulb sits on the text baseline row rather than below it */
.help-button {
  flex: 0 0 auto;
  padding: 7px 12px;
  font-size: 13px;
  display: inline-flex;
  align-items: center;
}


/* ----------------------------------------------------------------- history */

.hints {
  border: 1px solid rgba(61, 220, 132, 0.45);
  background: rgba(61, 220, 132, 0.08);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 14px;
}

.hints-error { border-color: var(--bad); background: rgba(255, 91, 91, 0.1); }

.hints-tabs { display: flex; align-items: center; gap: 6px; margin-bottom: 9px; }

.hints-tab {
  background: transparent;
  border: 1px solid transparent;
  color: var(--faint);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 10px;
  border-radius: 20px;
}

.hints-tab.has-result { color: var(--dim); }
.hints-tab.active { color: var(--good); border-color: rgba(61, 220, 132, 0.5); }
.hints[data-tab="advice"] .hints-tab.active { color: var(--me); border-color: rgba(74, 158, 255, 0.6); }

.hints-stamp {
  margin-left: auto;
  font-size: 11px;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}

/* Advice is a different kind of answer, so the box says so. */
.hints[data-tab="advice"] { border-color: rgba(74, 158, 255, 0.45); background: rgba(74, 158, 255, 0.08); }
.hints-error, .hints[data-tab="advice"].hints-error { border-color: var(--bad); background: rgba(255, 91, 91, 0.1); }
.hints-message { margin: 0; font-size: 13px; color: var(--dim); }
.hints ul { margin: 0; padding-left: 18px; }
.hints li { font-size: 16.5px; line-height: 1.5; color: #fff; margin-bottom: 3px; }

/* Placeholders before Help has been pressed, so the box keeps its height. */
.hints-idle { border-color: var(--line); background: rgba(255, 255, 255, 0.02); }
.hint-empty::after {
  content: '';
  display: inline-block;
  width: 42%;
  height: 1px;
  vertical-align: middle;
  background: rgba(255, 255, 255, 0.09);
}

.hints li.hint-empty { color: var(--faint); }

.history { min-width: 0; }
.live { display: flex; flex-direction: column; }

.live-block { padding: 9px 0; }
.live-block:not(.active) { display: none; }
.live-block[data-lane="me"] .turn-who { color: var(--me); }
.live-block[data-lane="them"] .turn-who { color: var(--them); }

.live-block .turn-text {
  font-size: 21px;
  line-height: 1.45;
  color: #fff;
}

.live-block .turn-translation { font-size: 21px; }
/* The original drops back in the live block exactly as it does in the history. */
.live-block .turn-original { font-size: 13px; }

.live-block .turn-text::after,
.live-block .turn-translation::after {
  content: '';
  display: inline-block;
  width: 7px;
  height: 17px;
  margin-left: 4px;
  vertical-align: -2px;
  background: var(--me);
  animation: blink 1.1s steps(2, start) infinite;
}

/* Only the half being read carries the caret. */
.live-block .turn-original::after { content: none; }

@keyframes blink { to { visibility: hidden; } }

.transcript { display: flex; flex-direction: column; }

.turn { padding: 9px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
.turn-head { display: flex; align-items: baseline; gap: 9px; margin-bottom: 2px; }

.turn-who { font-size: 11.5px; font-weight: 700; letter-spacing: 0.02em; }
.turn[data-lane="me"] .turn-who { color: var(--me); }
.turn[data-lane="them"] .turn-who { color: var(--them); }

.turn-time { font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums; }

.turn-delete {
  background: transparent;
  border: 0;
  color: var(--faint);
  font-size: 15px;
  line-height: 1;
  padding: 0 5px;
  border-radius: 4px;
  opacity: 0;
  transition: opacity 90ms;
}

.turn:hover .turn-delete { opacity: 1; }
.turn-delete:hover { color: var(--bad); background: rgba(255, 91, 91, 0.14); }
.turn-delete:focus-visible { opacity: 1; }

.turn-text {
  margin: 0;
  font-size: 15px;
  color: #b9c0cb;
  overflow-wrap: anywhere;
}

/* The newest portion is the one being read, so it gets the weight, unless a
   lane is mid-portion, in which case the live block is the current one. */
.turn-current .turn-text { font-size: 21px; line-height: 1.45; color: #fff; }
.turn-current .turn-who { font-size: 12.5px; }

.history.live-active .turn-current .turn-text { font-size: 15px; color: #b9c0cb; }
.history.live-active .turn-current .turn-who { font-size: 11.5px; }

.session-divider {
  color: var(--faint);
  font-size: 11px;
  text-align: center;
  margin: 12px 0;
  border-top: 1px dashed var(--line);
  padding-top: 8px;
}

.footer {
  color: var(--faint);
  font-size: 11.5px;
  margin-top: 22px;
  border-top: 1px solid var(--line);
  padding-top: 10px;
}

@media (max-width: 860px) {
  .layout { grid-template-columns: 1fr; }
  .sidebar { position: static; max-height: none; }
  .title-input { font-size: 17px; }
  .live-block .turn-text, .turn-current .turn-text { font-size: 18px; }
  .live-block .turn-translation, .turn-current .turn-translation { font-size: 18px; }
  .live-block .turn-original, .turn-current .turn-original { font-size: 13px; }
}

/* Phone capture: one lane carrying both voices. */
.meter[data-lane="room"] .meter-head span:first-child { color: var(--tailored); font-weight: 600; }
.meter[data-lane="room"] .meter-fill { background: var(--tailored); }
.option-row.phone-capture { opacity: 0.45; }
.turn[data-lane="room"] .turn-who { color: var(--tailored); }
.live-block[data-lane="room"] .turn-who { color: var(--tailored); }

.advice-button { flex: 0 0 auto; padding: 7px 14px; font-size: 13px; border-color: rgba(74, 158, 255, 0.55); color: var(--me); }
.advice-button:hover:not(:disabled) { border-color: var(--me); }



/* Advice picks its model when pressed, so the button opens a menu. */
.advice-wrap { position: relative; flex: 0 0 auto; }
.advice-menu {
  position: absolute;
  top: calc(100% + 5px);
  left: 0;
  z-index: 30;
  min-width: 148px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5);
}

.advice-menu button {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  background: transparent;
  border: 0;
  border-radius: 6px;
  padding: 7px 9px;
  text-align: left;
}

.advice-menu button:hover { background: #23272f; }
.advice-menu strong { font-size: 12.5px; font-weight: 600; }
.advice-menu span { margin-left: auto; font-size: 11px; color: var(--faint); }

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

.gate {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 80vh;
  padding: 20px;
}

.gate-card {
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  gap: 13px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 26px 24px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
}

.gate-card h1 { margin: 0; font-size: 19px; }
.gate-card .dim { margin: -8px 0 4px; }
.gate-card .primary { margin-top: 5px; padding: 9px; }

.gate-alt {
  margin: 14px 0 0;
  font-size: 13px;
  text-align: center;
}

.gate-alt .pill { margin-left: 6px; }

.gate-error {
  margin: 0;
  padding: 9px 11px;
  border-radius: 8px;
  border: 1px solid var(--bad);
  background: rgba(255, 91, 91, 0.12);
  font-size: 13px;
}

/* Turning translation on means the original is not the language being read, so
   the translation carries the weight and the original becomes the reference
   under it. Green rather than white keeps it distinguishable at a glance from
   a line that was never translated. */
.turn-translation {
  margin: 0;
  color: var(--translated);
  font-size: 15px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.turn-original {
  margin: 3px 0 0;
  padding-left: 9px;
  border-left: 2px solid var(--line);
  color: var(--faint);
  font-size: 12.5px;
  line-height: 1.5;
}

/* The newest portion is read from across the room, so both halves grow. */
.turn-current .turn-translation { font-size: 21px; line-height: 1.45; }
/* The "newest portion" rules above turn .turn-text white and large, and they
   outrank .turn-original on specificity, so the original is put back by name. */
.turn-current .turn-original { font-size: 13px; color: var(--faint); }
.history.live-active .turn-current .turn-translation { font-size: 15px; }
.history.live-active .turn-current .turn-original { font-size: 12.5px; color: var(--faint); }


/* The context editor borrows the tab strip; green means Help in the history,
   so here it takes the neutral accent instead. */
.modal-card .context-tabs { margin-bottom: 0; }
.context-tabs .hints-tab.active { color: var(--me); border-color: rgba(74, 158, 255, 0.6); }

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

.settings { max-width: 640px; margin-inline: auto; }
.settings-title { flex: 1; font-size: 15px; font-weight: 600; }
.settings-heading {
  margin: 0 0 4px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.settings-form { display: flex; flex-direction: column; gap: 20px; }
.setting { display: flex; flex-direction: column; gap: 6px; }
.setting-help { margin: 0; line-height: 1.5; }
.settings-actions { display: flex; align-items: center; gap: 12px; }

/* ------------------------------------------------------------------- home */

/* With no conversation open the list is the page, not a placeholder pointing
   at a modal. Same rows as the modal, just given room. */
.home { display: flex; flex-direction: column; gap: 14px; max-width: 620px; }
.home .conversation-list { gap: 3px; }
.home .conversation-row { border: 1px solid var(--line); }

/* --------------------------------------------------------------- lane dots */

/* The proof both halves are live without unfolding the Audio panel. Grey until
   that lane has actually carried sound, so a flat lane is visible at a glance. */
.lane-dots {
  display: flex;
  gap: 7px;
  margin: 7px 0 0;
  align-items: center;
}

.lane-dot { display: flex; align-items: center; }

.lane-dot i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #444;
  display: inline-block;
  transition: background 120ms linear;
}

.lane-dot.live i { background: var(--good); }
/* Carried sound once, but nothing recently: the lane may have died. */
.lane-dot.stale i { background: #e0a33e; }

/* --------------------------------------------------------------- talk time */

.talk-time {
  margin-top: 10px;
  padding-top: 9px;
  border-top: 1px solid var(--line);
  font-size: 11px;
}

.talk-bar {
  height: 4px;
  border-radius: 2px;
  background: #2a6df4;   /* the far end fills the remainder */
  overflow: hidden;
  margin-bottom: 4px;
}

/* Your share, drawn from the left. */
.talk-fill {
  height: 100%;
  background: var(--good);
  width: 0;
  transition: width 400ms linear;
}

.talk-time.talking-too-much .talk-fill { background: #e0a33e; }

/* ------------------------------------------------------------- write-ups */

.writeup-row { gap: 6px; }

.wide-card { max-width: 880px; }

.writeup-body {
  max-height: 60vh;
  overflow-y: auto;
  padding-right: 6px;
}

.writeup-section { margin-bottom: 18px; }

.writeup-section h3 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--dim);
  margin: 0 0 6px;
}

.writeup-section ul { margin: 0; padding-left: 18px; }
.writeup-section li { margin-bottom: 5px; line-height: 1.5; }
.writeup-section p { margin: 0; line-height: 1.6; }

.writeup-empty { color: var(--dim); font-style: italic; }

/* ------------------------------------------------------------ pre-flight */

.preflight-lanes { display: flex; flex-direction: column; gap: 14px; margin: 4px 0 16px; }

.preflight-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 12px;
  margin-bottom: 5px;
}

.preflight-tick { color: #444; font-size: 14px; }
.preflight-lane.ok .preflight-tick { color: var(--good); }
.preflight-lane.ok .preflight-head { color: var(--good); }

/* What the test tone proved about echo cancellation. Shown in the pre-flight
   only when it went wrong, and in the Audio panel either way. */
.echo-warning {
  font-size: 12px;
  line-height: 1.45;
  color: var(--bad);
  border-left: 2px solid var(--bad);
  padding-left: 9px;
  margin: 0 0 14px;
}

/* Hover for the working, click to copy it. */
.echo-status { font-size: 11px; margin-top: 8px; cursor: pointer; color: var(--dim); }
.echo-status.bad { color: var(--bad); }

/* ---------------------------------------------------------------- search */

.search-row { display: flex; gap: 8px; margin-bottom: 14px; }

.search-row input {
  flex: 1;
  padding: 7px 10px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--fg);
  font: inherit;
}

.search-results { margin-bottom: 18px; }

.search-hit {
  display: block;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
}

.search-hit:hover { background: var(--panel); }

.search-hit-meta {
  display: block;
  font-size: 11px;
  color: var(--dim);
  margin-bottom: 3px;
}

.search-hit-text { display: block; line-height: 1.5; }
/* snippet() marks the matched terms with << >>, swapped for these on render. */
.search-hit-text mark { background: rgba(61, 220, 132, 0.22); color: inherit; border-radius: 2px; }

/* ------------------------------------------------------------------ flags */

/* A moment marked during the call. Deliberately loud in the history: the whole
   point is to find it again afterwards. */
.turn.flagged { border-left: 2px solid #e0a33e; padding-left: 8px; }
.turn-flag {
  background: none;
  border: none;
  color: #444;
  cursor: pointer;
  font-size: 12px;
  padding: 0 4px;
}
.turn.flagged .turn-flag { color: #e0a33e; }
.turn-flag:hover { color: #e0a33e; }

/* Open questions answering "nothing" is the good outcome, so it reads as a
   clear result rather than as a failure or an empty waiting state. */
.hints-clear { color: var(--good); }

/* The two folded panels sit together as a pair, so the second needs a hairline
   of its own rather than reading as part of the first. */
.panel-block + .panel-block { margin-top: 8px; }

/* Inside the panel the option rows no longer sit against the sidebar edge. */
#options-block .option-row:first-of-type { margin-top: 10px; }

/* --------------------------------------------------------------- mode menu */

/* What a conversation is decides everything under it, so it sits at the top of
   the sidebar. Same shape as the Advice menu, but full width, because a sidebar
   control has the room and a truncated "Mode: Assisted meeting" reads badly. */
.mode-wrap { width: 100%; margin-bottom: 2px; }

.mode-button {
  width: 100%;
  justify-content: space-between;
  font-weight: 600;
}

/* The caret is drawn rather than typed, so the label can be set as plain text
   from one place without carrying markup with it. */
.mode-button::after { content: '\25BE'; margin-left: 8px; color: var(--faint); }

.mode-wrap .advice-menu { width: 100%; min-width: 0; }
.mode-wrap .advice-menu span { color: var(--faint); }

/* ---------------------------------------------------------- capture button */

/* One control for start, stop, what is happening and how long it has been
   happening. It changes colour rather than moving, so the thing you reach for
   mid-call is always in the same place. */
.capture-toggle {
  width: 100%;
  padding: 9px 12px;
  font-size: 13.5px;
  font-weight: 600;
  /* The elapsed time is inside the label, so the digits must not reflow it. */
  font-variant-numeric: tabular-nums;
}

/* Recording. Red because the only action it now offers is to stop. */
.capture-toggle.is-live {
  background: var(--bad);
  border-color: var(--bad);
  color: #2a0505;
}

/* Connecting or finishing: mid-flight, and not pressable either way. */
.capture-toggle.is-waiting {
  background: transparent;
  border-color: var(--them);
  color: var(--them);
  opacity: 1;
}

/* The three write-up rows read as document rows: one ?, one full-width button.
   Minutes and the debrief are never both visible, so the pair reads as one
   row that changes name with the mode. */
#prebrief-row .doc-button,
#minutes-row .doc-button,
#debrief-row .doc-button { flex: 1; text-align: left; }

/* Zero, one or two actions in the alert, so the container has to collapse. */
.alert-extra { display: contents; }

/* The two lists are a tab strip above the create form, not part of the card
   header, so they need a little air under them. */
.list-tabs { margin-bottom: 12px; }

/* In the create form the picker sits in a row with the title field and the
   create button, so it sizes to its content rather than filling the row the
   way the sidebar mode button does. */
.new-conversation .capture-wrap { width: auto; flex: 0 0 auto; margin-bottom: 0; }
.new-conversation .capture-wrap .mode-button { width: auto; }
.new-conversation .capture-wrap .advice-menu { min-width: 210px; width: auto; }

/* ---------------------------------------------------------------- checklist */

/* Beside the answers, not above them: it is glanced at while reading a hint. */
.hints { display: flex; gap: 16px; align-items: flex-start; }
.hints-main { flex: 1; min-width: 0; }

.checklist-panel {
  flex: 0 0 236px;
  border-left: 1px solid var(--line);
  padding-left: 14px;
  align-self: stretch;
}

.checklist-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--dim);
  margin-bottom: 8px;
}

.checklist-panel ul { list-style: none; margin: 0; padding: 0; }

.checklist-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 8px;
  font-size: 12px;
  line-height: 1.4;
}

/* Red, amber, green. The dot carries the state and the text stays readable at
   every one of them, so the colour is a signal rather than a legibility cost. */
.checklist-dot {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 4px;
  background: var(--bad);
}

.state-yellow .checklist-dot { background: var(--them); }
.state-green .checklist-dot { background: var(--good); }

.checklist-text { color: var(--dim); }
.state-yellow .checklist-text { color: var(--text); }
.state-green .checklist-text { color: var(--text); text-decoration: line-through; text-decoration-color: var(--good); }

/* --------------------------------------------------------------- bookmark */

/* Amber rather than blue: the three beside it each spend a model call, and this
   one only writes a flag. Same colour as the mark it leaves in the history. */
.bookmark-button {
  flex: 0 0 auto;
  padding: 7px 14px;
  font-size: 13px;
  border-color: rgba(255, 176, 46, 0.55);
  color: var(--them);
}

.bookmark-button:hover:not(:disabled) { border-color: var(--them); }

/* ----------------------------------------------------------------- wizard */

/* One scaffold with its parts shown per step, so the styling is of the parts
   rather than of eleven panels. The card is the tall editor's, because it is
   the same kind of screen: a box you read and change, with a row of controls
   that act on it. */

/* Sized to the step rather than to the tallest step: two choice cards do not
   need eighty per cent of the window.

   A step with a box keeps the tall editor's fixed 80vh, and for the reason that
   number is 80 rather than 90 — `.modal` reserves 8vh above the card and 20px
   below it, so anything taller pushes its own footer off the bottom of the
   screen. The box is the flex child that absorbs the difference, and it has to
   be able to shrink to nothing to do that: a `min-height` on it stops the card
   clamping and the buttons walk off the page again. */
#wizard-modal .modal-card { height: auto; max-height: 80vh; }
#wizard-modal.wizard-tall .modal-card { height: 80vh; }

/* Which steps this mode has. A step already reached can be clicked back to;
   one not yet reached cannot, because its own answer often decides whether the
   steps after it exist at all. */
.wizard-progress {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 4px;
}

.wizard-pill {
  padding: 3px 9px;
  font-size: 11.5px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--faint);
}

.wizard-pill.done { color: var(--dim); border-color: rgba(74, 158, 255, 0.35); }
.wizard-pill.current {
  color: var(--text);
  border-color: var(--me);
  background: rgba(74, 158, 255, 0.14);
}
.wizard-pill:disabled { cursor: default; opacity: 0.55; }
.wizard-pill:not(:disabled):hover { color: var(--text); border-color: var(--dim); }

/* The reason the step exists, not a restatement of its title. Long on purpose:
   this is where the trade-off behind each choice is explained, and it is the
   only place most of it is ever read. */
.wizard-note {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--dim);
}

/* A card each, laid out side by side when there is room. The detail is what
   makes the choice answerable, so it is part of the control rather than a
   tooltip on it. */
.wizard-choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  align-content: start;
  gap: 10px;
  overflow-y: auto;
}

.wizard-choice {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 13px;
  text-align: left;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  height: 100%;
  /* Buttons are nowrap everywhere else in this app, which is right for a label
     and wrong for a paragraph: without this the detail runs off the side and
     the dialog grows a horizontal scrollbar. */
  white-space: normal;
}

.wizard-choice strong { font-size: 14px; color: var(--text); }
.wizard-choice span { font-size: 12px; line-height: 1.5; color: var(--faint); }
.wizard-choice:hover { border-color: var(--dim); }
.wizard-choice.chosen {
  border-color: var(--me);
  background: rgba(74, 158, 255, 0.1);
}
.wizard-choice.chosen span { color: var(--dim); }

.wizard-switch { display: flex; align-items: center; gap: 9px; font-size: 12.5px; }

/* Three controls rather than one, so this step has its own row. */
.wizard-language { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; }
.wizard-language .field { flex: 1; min-width: 170px; }

.wizard-state { margin: 0; font-size: 12px; line-height: 1.45; min-height: 16px; }

/* Cancel is the destructive one and sits apart from the three that navigate,
   so it cannot be hit while reaching for Back. */
.wizard-actions { align-items: center; }
.wizard-spacer { flex: 1; }
