:root {
  --bg: #0d1014;
  --panel: #151a21;
  --line: #232b35;
  --fg: #e7edf5;
  --dim: #8895a6;
  --white: #ffffff;
  --yellow: #f5c451;
  --accent: #4fd1c5;
  --warn: #f57b7b;
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }

body {
  margin: 0;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--fg);
  overflow: hidden;
}

/* --- visibility matrix ------------------------------------------------------
   Mode and engine are body classes; everything conditional hangs off them so
   the markup can carry both layouts at once and switching is class-only. */
body.mode-oneway .twoway-only { display: none !important; }
body.mode-twoway .oneway-only { display: none !important; }
body.engine-fish .openai-only { display: none !important; }
body.engine-openai .fish-only { display: none !important; }

/* Advanced content is present but hidden until asked for. */
.adv-only { display: none !important; }
body.advanced-open .adv-only { display: revert !important; }
body.advanced-open .pills.adv-only { display: flex !important; }
body.advanced-open .row.adv-only { display: flex !important; }
body.advanced-open.engine-openai .adv-only.fish-only,
body.advanced-open.engine-openai .fish-only { display: none !important; }
body.advanced-open #advanced { border-top: 1px solid var(--line); padding-top: 12px; }

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

header {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  align-items: center;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
  flex: none;
}

h1 { font-size: 15px; font-weight: 600; margin: 0 auto 0 0; letter-spacing: 0.01em; }
h1 a { color: inherit; text-decoration: none; display: inline-flex; align-items: center; gap: 9px; }
h1 a:hover { color: var(--accent); }
h1 .logo { height: 22px; width: auto; display: block; }

/* Operator tools (engine switch, Advanced) render only with ?admin=true. */
body:not(.admin) .admin-only { display: none !important; }

.seg { display: inline-flex; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.seg button {
  background: transparent;
  color: var(--dim);
  border: 0;
  padding: 6px 12px;
  font-size: 12px;
  cursor: pointer;
}
.seg button + button { border-left: 1px solid var(--line); }
.seg button.on { background: var(--panel); color: var(--fg); }
.seg button .short { display: none; }

.pills { display: flex; gap: 8px; flex-wrap: wrap; }
.pill {
  font-size: 12px;
  color: var(--dim);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 10px;
  font-variant-numeric: tabular-nums;
}
.pill b { color: var(--accent); font-weight: 600; }
.pill.warn b { color: var(--warn); }

.status { font-size: 12px; color: var(--dim); }
.status.err { color: var(--warn); }
header > .status { margin-left: auto; }

/* --- one-way (v1 layout) ---------------------------------------------------- */

#oneway-main { flex: 1; display: flex; flex-direction: column; gap: 1px; background: var(--line); min-height: 0; }

/* All rows implicit so minmax(0,1fr) applies in both the side-by-side and the
   stacked layout — a plain 1fr row has an auto minimum and a long transcript
   would push the pane past the footer instead of scrolling inside it. */
.panes { display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: minmax(0, 1fr); gap: 1px; flex: 1; min-height: 0; }
@media (max-width: 760px) { .panes { grid-template-columns: 1fr; } }

.pane, .log { background: var(--bg); padding: 16px 20px; overflow-y: auto; min-height: 0; }
.log { max-height: 200px; flex: none; }

h2 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--dim);
  margin: 0 0 12px;
  font-weight: 600;
}
h2 small { text-transform: none; letter-spacing: 0; font-weight: 400; margin-left: 8px; }


.text { font-size: 22px; line-height: 1.5; white-space: pre-wrap; }
.text .final { color: var(--fg); }
.text .partial { color: var(--dim); }
.text .white { color: var(--white); }
.text .yellow { color: var(--yellow); }
.text p { margin: 0 0 14px; }
.text p.old { opacity: 0.45; font-size: 18px; }

#flushlog { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--dim); }
#flushlog div { padding: 2px 0; }
#flushlog .reason { color: var(--accent); display: inline-block; min-width: 84px; }
#flushlog .reason.deadline { color: var(--yellow); }
#flushlog .reason.length { color: var(--warn); }
#flushlog .reason.pending { color: var(--yellow); }
#flushlog .reason.repair,
#flushlog .reason.retracted { color: var(--warn); }

/* --- conversation ------------------------------------------------------------
   Two halves and a strip, filling the viewport. The top half is rotated 180°
   as a whole (bar, hints, selects included) so the person across the table
   reads their side right-side-up. Rotation does not change scroll mechanics:
   scrollTop = scrollHeight still shows the newest row, and the paint lands
   nearest that reader's edge of the phone — chat order for both people. */

#twoway-main { flex: 1; display: grid; grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr); min-height: 0; }

.half { display: flex; flex-direction: column; min-height: 0; padding: 0 16px; }
.flip { transform: rotate(180deg); }

/* The rotation is for a phone or tablet lying flat between two people. On a
   desktop both people face the same screen, so everything reads one way up.
   Hover + fine pointer is the "this machine has a mouse" test — touch
   devices (no hover, coarse pointer) keep the flip. */
@media (hover: hover) and (pointer: fine) {
  .flip { transform: none; }
}

.half-bar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 4px 4px;
  flex: none;
}
.half-name { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--dim); font-weight: 600; }
.ear { font-size: 11px; color: var(--dim); font-variant-numeric: tabular-nums; }
.ear b { color: var(--accent); font-weight: 600; }

.stream { flex: 1; overflow-y: auto; min-height: 0; padding: 4px; }
.stream p { margin: 0 0 10px; }
.stream p.old { opacity: 0.45; }

/* Incoming translation: the thing this half's reader is here for. */
.stream p.in { font-size: 26px; line-height: 1.35; }
.stream .white { color: var(--white); }
.stream .yellow { color: var(--yellow); }

/* The reader's own words, as the pipeline heard them — small and dim, a
   receipt rather than content. The chip is the only clue when language
   detection routes a turn the wrong way, so it stays legible at arm's length. */
.stream p.own { font-size: 14px; line-height: 1.4; color: var(--dim); }
.stream p.own.partial { opacity: 0.7; }

.chip {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 1px 6px;
  margin-right: 6px;
  border-radius: 5px;
  vertical-align: 2px;
  color: hsl(var(--chip-h, 180) 55% 70%);
  background: hsl(var(--chip-h, 180) 45% 60% / 0.14);
  border: 1px solid hsl(var(--chip-h, 180) 45% 60% / 0.35);
}

/* --- center strip ----------------------------------------------------------- */

.strip {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 10px;
  align-items: center;
  padding: 8px 12px;
  background: var(--panel);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.side-ctl { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.side-ctl select { width: 100%; min-width: 0; }
.side-ctl .hint { font-size: 10px; color: var(--dim); min-height: 12px; }

.strip-mid { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.strip-status { font-size: 10px; max-width: 110px; text-align: center; }

.swap { font-size: 10px; padding: 3px 8px; align-self: center; }
.swap.swapped { color: var(--accent); border-color: var(--accent); }

/* THE control. A filled dot reads the same from both sides of the table. */
.mic.big {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  padding: 0;
  font-size: 0;
  position: relative;
}
.mic.big::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #07231f;
}
.mic.big.live::after { border-radius: 4px; background: #2a0d0d; }

/* --- footer (one-way controls) ---------------------------------------------- */

footer {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
  padding: 14px 20px;
  border-top: 1px solid var(--line);
  background: var(--panel);
  flex: none;
}
footer .row { display: flex; flex-wrap: wrap; gap: 14px 18px; align-items: flex-end; }
footer .row > .status { margin-left: auto; align-self: center; }
footer label { font-size: 11px; color: var(--dim); display: flex; flex-direction: column; gap: 4px; }
footer output { color: var(--fg); font-variant-numeric: tabular-nums; }
footer .note { font-size: 11px; color: var(--dim); align-self: center; }

select, input[type="range"] { background: var(--bg); color: var(--fg); border: 1px solid var(--line); border-radius: 6px; padding: 5px 6px; font-size: 12px; }
select:disabled { opacity: 0.5; }
input[type="range"] { padding: 0; width: 140px; }

.mic {
  background: var(--accent);
  color: #07231f;
  border: 0;
  border-radius: 8px;
  padding: 10px 18px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.mic.live { background: var(--warn); color: #2a0d0d; }

.ghost {
  background: transparent;
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 11px;
  cursor: pointer;
}
.ghost:hover { color: var(--accent); border-color: var(--accent); }

.balance { display: flex; flex-direction: column; gap: 2px; min-width: 300px; flex: 1; max-width: 460px; }
.balance-head {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--dim);
  text-transform: lowercase;
}
.balance-head output { color: var(--accent); font-size: 11px; }
.balance input[type=range] { width: 100%; }
.resolved {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px;
  color: var(--dim);
  min-height: 14px;
}

/* --- phone ------------------------------------------------------------------
   Conversation mode's real form factor. The header shrinks to one dense row,
   transcripts get the vertical space, and the strip controls stay clear of
   each other with two thumbs in play. */
@media (max-width: 640px) {
  header { padding: 8px 10px; gap: 6px 8px; }
  /* One row: logo left, mode switch right (the other switches are admin-only
     and usually absent). A non-empty status wraps to its own line below. */
  h1 { font-size: 13px; }
  header > .status { order: 1; flex: 1 1 100%; text-align: left; }
  header > .status:empty { display: none; }
  .seg button { padding: 5px 9px; font-size: 11px; }
  .seg button .full { display: none; }
  .seg button .short { display: inline; }

  .half { padding: 0 10px; }
  .stream p.in { font-size: 23px; }
  .strip { gap: 8px; padding: 8px; }
  .side-ctl select { font-size: 11px; padding: 5px 3px; }

  .pane, .log { padding: 12px; }
  footer { padding: 10px 12px; }
  .balance { min-width: 220px; }
}

/* No gratuitous animation anywhere; the one nicety respects the setting. */
@media (prefers-reduced-motion: no-preference) {
  .seg button, .ghost, .mic { transition: background-color 120ms, color 120ms, border-color 120ms; }
}
