/* CleoListen-TutSpeaks demo UI.
   Dark by default because this gets demoed on projectors and in dim rooms.
   Arabic is the primary content language, so transcript text is direction-aware
   rather than forced left-to-right. */

:root {
  color-scheme: dark;
  --bg: #0e1116;
  --panel: #161b23;
  --panel-2: #1d232d;
  --line: #262d38;
  --text: #e6edf3;
  --muted: #8b98a8;
  --accent: #d4a24a;      /* gold, for Tut */
  --accent-2: #4a9fd4;    /* lapis, for Cleo */
  --ok: #3fb950;
  --warn: #d29922;
  --bad: #f85149;
  --radius: 12px;
  --mono: ui-monospace, "Cascadia Code", "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  min-height: 100vh;
}

/* ------------------------------------------------------------ header */
.bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, #141a22, #0e1116);
}
.brand { display: flex; align-items: center; gap: 14px; }
.glyph { font-size: 30px; color: var(--accent); line-height: 1; }
.bar h1 { margin: 0; font-size: 17px; font-weight: 650; letter-spacing: .2px; }
.sep { color: var(--muted); margin: 0 2px; }
.tagline { margin: 2px 0 0; font-size: 12.5px; color: var(--muted); }

.status { display: flex; gap: 8px; }
.pill {
  font: 600 11px/1 var(--mono);
  letter-spacing: .5px;
  padding: 6px 10px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--muted);
}
.pill.ok   { color: var(--ok);   border-color: #1c3d24; background: #10281a; }
.pill.bad  { color: var(--bad);  border-color: #47242a; background: #2a1618; }
.pill.warn { color: var(--warn); border-color: #453718; background: #2a2113; }

/* The server pill is the one pill you can click: it opens the dialog that
   says which gateway this page is driving. */
.pill-button { cursor: pointer; font-family: var(--mono); }
.pill-button:hover { border-color: var(--accent-2); color: var(--text); }

/* ----------------------------------------------------- server dialog */
.server-dialog {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel); color: var(--text);
  padding: 20px 22px; max-width: 440px; width: calc(100% - 32px);
}
.server-dialog::backdrop { background: rgba(6, 9, 13, .68); }
.server-dialog h2 { margin: 0 0 6px; font-size: 16px; }
.server-dialog label {
  display: block; margin: 14px 0 6px;
  font-size: 12px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: .5px;
}
.server-dialog input {
  width: 100%; padding: 9px 11px; border-radius: 8px;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--line); font: inherit; font-size: 13px;
}
.server-dialog .hint { margin: 6px 0 0; }
.server-dialog .row.end { justify-content: flex-end; margin-top: 18px; }
.server-dialog code {
  font-family: var(--mono); font-size: 12px; color: var(--accent);
}
button.ghost.primary {
  border-color: #2f4a63; background: #1b2e3f; color: #cfe6f7;
}
.server-note:empty { display: none; }
.server-note {
  margin: 14px 0 0; padding: 8px 10px; border-radius: 8px;
  background: #2a1618; border: 1px solid #47242a; color: var(--bad);
  font-size: 12.5px;
}

/* -------------------------------------------------------------- grid */
main {
  display: grid;
  /* The inspector is a reading column, not a sidebar: a prompt or a retrieved
     record has to be legible in it without horizontal scrolling. */
  grid-template-columns: 290px minmax(0, 1fr) minmax(360px, 420px);
  gap: 16px;
  padding: 16px 20px 28px;
  align-items: start;
}
@media (max-width: 1400px) {
  main { grid-template-columns: 270px minmax(0, 1fr) minmax(330px, 380px); }
}
@media (max-width: 1100px) { main { grid-template-columns: 1fr; } }
/* Above that breakpoint the three columns become independently scrolling
   panes rather than one long page; see "app shell" at the end of the file. */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
}
.panel h2 {
  margin: 0 0 10px; font-size: 12px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .8px; color: var(--muted);
}
.panel-head { display: flex; align-items: center; justify-content: space-between; }
.panel-head h2 { margin: 0; }

/* ---------------------------------------------------------- controls */
.mic-block {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 12px 14px;
  align-items: center;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 16px;
}
.mic {
  width: 64px; height: 64px; border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--muted);
  cursor: pointer;
  display: grid; place-items: center;
  transition: background .18s, color .18s, box-shadow .18s, transform .1s;
}
.mic svg { width: 26px; height: 26px; fill: none; stroke: currentColor;
           stroke-width: 1.8; stroke-linecap: round; }
.mic:hover { background: #222a35; color: var(--text); }
.mic:active { transform: scale(.96); }
.mic.live {
  background: #1b3345; color: var(--accent-2); border-color: #2a5878;
  box-shadow: 0 0 0 4px rgba(74,159,212,.12);
}
/* Pulses only while the endpointer has actually latched onto speech, so it
   reports real VAD state rather than just "the mic is open". */
.mic.hearing { animation: pulse 1.1s ease-in-out infinite; }
@keyframes pulse {
  0%,100% { box-shadow: 0 0 0 4px rgba(74,159,212,.12); }
  50%     { box-shadow: 0 0 0 11px rgba(74,159,212,.05); }
}

.mic-meta { min-width: 0; }
.mic-state { font-size: 13px; color: var(--muted); margin-bottom: 8px; }
.meter { height: 5px; border-radius: 3px; background: var(--panel-2); overflow: hidden; }
#meter-fill {
  height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  transition: width .06s linear;
}
.mic-block .ghost { grid-column: 1 / -1; }

.field { margin-bottom: 16px; }
.field > label {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 12px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: .5px;
  margin-bottom: 7px;
}
.val { font: 500 12px/1 var(--mono); color: var(--accent); text-transform: none; }
.hint { margin: 6px 0 0; font-size: 11.5px; color: var(--muted); }

select, input[type="text"] {
  width: 100%; padding: 9px 10px;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--line); border-radius: 8px;
  font: inherit; font-size: 14px;
}
select:focus, input:focus { outline: 2px solid var(--accent-2); outline-offset: -1px; }

input[type="range"] { width: 100%; accent-color: var(--accent); }

.row { display: flex; gap: 8px; }
.row input { flex: 1; min-width: 0; }

.tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.tag {
  font-size: 11.5px; padding: 3px 9px; border-radius: 999px;
  background: #22303d; color: #9dc6e3; border: 1px solid #2b3d4d;
}

button.ghost {
  padding: 8px 12px; border-radius: 8px;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--line); font: inherit; font-size: 13px;
  cursor: pointer; transition: background .15s;
}
button.ghost:hover:not(:disabled) { background: #252d3a; }
button.ghost:disabled { opacity: .4; cursor: not-allowed; }
button.ghost.small { padding: 6px 10px; font-size: 12px; }
#preview-btn { margin-top: 8px; width: 100%; }

details summary {
  cursor: pointer; font-size: 12px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: .5px;
}
.commands { list-style: none; margin: 10px 0 0; padding: 0; }
.commands li {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid var(--line); font-size: 13px;
}
.commands li:last-child { border-bottom: 0; }
.commands .ar { direction: rtl; color: var(--accent); }
.commands .en { color: var(--muted); font-size: 12px; }

/* -------------------------------------------------------- transcript */
.transcript-panel { display: flex; flex-direction: column; min-height: 460px; }
.transcript {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; margin-top: 12px;
  display: flex; flex-direction: column; gap: 10px;
  max-height: 60vh;   /* a cap only the stacked layout needs */
}
.empty { color: var(--muted); font-size: 13.5px; margin: auto; text-align: center; }

.turn {
  border-radius: 10px; padding: 10px 13px;
  border: 1px solid var(--line); background: var(--panel-2);
  animation: rise .18s ease-out;
}
@keyframes rise { from { opacity: 0; transform: translateY(4px); } }
.turn .who {
  font: 600 10.5px/1 var(--mono); letter-spacing: .8px;
  text-transform: uppercase; margin-bottom: 5px;
}
.turn.user { border-left: 3px solid var(--accent-2); }
.turn.user .who { color: var(--accent-2); }
.turn.bot { border-left: 3px solid var(--accent); }
.turn.bot .who { color: var(--accent); }
.turn.note { border-left: 3px solid var(--muted); }
.turn.note .who, .turn.note .text { color: var(--muted); font-size: 13px; }
.turn .text { font-size: 15.5px; line-height: 1.65; }
.turn .meta { margin-top: 6px; font: 11px/1 var(--mono); color: var(--muted); }

.partial {
  margin-top: 10px; padding: 9px 12px; min-height: 20px;
  border-radius: 8px; border: 1px dashed var(--line);
  color: var(--muted); font-size: 14px; font-style: italic;
}
.partial:empty { display: none; }

/* ----------------------------------------------------------- metrics */
.metrics { margin: 0 0 18px; }
.metrics > div {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--line);
}
.metrics > div:last-child { border-bottom: 0; }
.metrics dt { font-size: 12.5px; color: var(--muted); }
.metrics dd { margin: 0; font: 600 13px/1 var(--mono); color: var(--text); }
.metrics.small dd { font-size: 12px; }
.metrics dd.good { color: var(--ok); }
.metrics dd.mid  { color: var(--warn); }
.metrics dd.slow { color: var(--bad); }

.log {
  margin-top: 6px; max-height: 45vh; overflow-y: auto;
  font: 11px/1.6 var(--mono); color: var(--muted);
  border-top: 1px solid var(--line); padding-top: 10px;
}
.log div { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.log .err { color: var(--bad); }

/* ======================================================================
   Live pipeline strip
   Between a question and its answer there is a second or two of silence.
   Filling it with the stage that is actually running is the difference
   between a system that looks alive and one that looks hung.
   ====================================================================== */
.stage-strip {
  list-style: none; display: flex; flex-wrap: wrap; gap: 6px;
  margin: 12px 0 0; padding: 0;
}
.stage-chip {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--panel-2);
  font: 600 11px/1 var(--mono); letter-spacing: .3px;
  color: var(--muted); white-space: nowrap;
  transition: color .15s, border-color .15s, background .15s;
}
.stage-chip .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--line); flex: none;
}
.stage-chip .ms { font-size: 10px; opacity: .8; }
.stage-chip.done { color: #9fb2c6; }
.stage-chip.done .dot { background: var(--ok); }
.stage-chip.active {
  color: var(--accent); border-color: #4a3a1b; background: #241d10;
}
.stage-chip.active .dot { background: var(--accent); animation: blip .9s infinite; }
.stage-chip.bad { color: var(--bad); border-color: #47242a; }
.stage-chip.bad .dot { background: var(--bad); }
.stage-chip.skipped { opacity: .45; }
@keyframes blip { 50% { opacity: .25; } }

/* ======================================================================
   Inspector: tabs
   ====================================================================== */
.inspector { display: flex; flex-direction: column; padding: 0; min-height: 520px; }
.tabs {
  display: flex; gap: 2px; padding: 8px 8px 0;
  border-bottom: 1px solid var(--line);
}
.tab {
  flex: 1; padding: 9px 6px; border: 0; border-bottom: 2px solid transparent;
  background: transparent; color: var(--muted); cursor: pointer;
  font: 600 11.5px/1 system-ui, sans-serif; letter-spacing: .4px;
  text-transform: uppercase; border-radius: 6px 6px 0 0;
}
.tab:hover { color: var(--text); background: var(--panel-2); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.tab .count {
  display: inline-block; min-width: 16px; padding: 1px 5px; margin-left: 3px;
  border-radius: 999px; background: var(--panel-2); color: var(--muted);
  font: 600 10px/1.4 var(--mono);
}
.tab.active .count { background: #2c2415; color: var(--accent); }

/* No `overflow: hidden` here: it clipped whatever a tab rendered taller than
   its box, and clipped content cannot be scrolled to. Each tab either scrolls
   as a whole or hands its scrollbar to the one list that fills it. */
.tab-panel { display: none; padding: 14px 14px 16px; min-height: 0; }
.tab-panel.active { display: block; }
.tab-hint { margin: 0 0 10px; font-size: 11.5px; line-height: 1.55; color: var(--muted); }
.tab-head { display: flex; flex-direction: column; gap: 8px; }
.tab-actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 10px;
}
.check {
  display: flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--muted); cursor: pointer;
}
.check input { accent-color: var(--accent); }

/* ======================================================================
   Activity: one card per turn, one row per step
   ====================================================================== */
.trace-list { max-height: 72vh; overflow-y: auto; display: flex;
              flex-direction: column; gap: 10px; }

.trace-turn {
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel-2); overflow: hidden;
  animation: rise .18s ease-out;
  /* The list is a flex column, so a card would otherwise be squeezed to fit
     the space left over instead of overflowing it — and `overflow: hidden`
     above removes the automatic minimum size that normally prevents that, so
     the card silently crops its own steps and the list never gains a
     scrollbar. Keep every card at its natural height and let the list scroll. */
  flex: none;
}
.trace-turn.live { border-color: #4a3a1b; }

.trace-turn > summary {
  list-style: none; cursor: pointer; padding: 10px 12px;
  display: flex; flex-direction: column; gap: 4px;
}
.trace-turn > summary::-webkit-details-marker { display: none; }
.trace-turn-top {
  display: flex; align-items: center; gap: 8px;
  font: 600 11px/1 var(--mono); color: var(--muted);
}
.trace-turn-top .n { color: var(--accent); }
.trace-turn-top .spacer { flex: 1; }
.trace-turn-top .total { color: var(--text); }
.trace-turn-q {
  font-size: 13px; color: var(--text); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.trace-turn-q.pending { color: var(--muted); font-style: italic; }

.trace-steps { border-top: 1px solid var(--line); }

/* A step: a header row that is always visible, detail that unfolds. */
.step { border-bottom: 1px solid var(--line); }
.step:last-child { border-bottom: 0; }
.step-head {
  width: 100%; display: grid;
  grid-template-columns: 14px minmax(0, 1fr) auto;
  gap: 8px; align-items: start;
  padding: 8px 12px; border: 0; background: transparent;
  color: inherit; text-align: left; cursor: pointer; font: inherit;
}
.step-head:hover, .step.open .step-head { background: #1f2630; }

.step-dot {
  width: 9px; height: 9px; margin-top: 4px; border-radius: 50%;
  background: var(--muted); flex: none;
}
.step.ok      .step-dot { background: var(--ok); }
.step.running .step-dot { background: var(--accent); animation: blip .9s infinite; }
.step.warn    .step-dot { background: var(--warn); }
.step.error   .step-dot { background: var(--bad); }
.step.skipped .step-dot { background: var(--line); }

.step-label { font-size: 12.5px; font-weight: 600; color: var(--text); }
.step.skipped .step-label { color: var(--muted); font-weight: 500; }
.step-summary {
  margin-top: 2px; font-size: 11.5px; line-height: 1.5; color: var(--muted);
  overflow-wrap: anywhere;
}
.step-stage {
  display: inline-block; margin-right: 6px; padding: 1px 6px;
  border-radius: 4px; font: 600 9.5px/1.6 var(--mono);
  text-transform: uppercase; letter-spacing: .5px;
  background: #232c38; color: #8fa6bd;
}
.step-stage.knowledge { background: #14301f; color: #63c98a; }
.step-stage.prompt    { background: #2a2413; color: #d2b061; }
.step-stage.llm       { background: #2a1b33; color: #c08ce0; }
.step-stage.asr       { background: #16293a; color: #6cb3e8; }
.step-stage.tts       { background: #33220f; color: #e0a45c; }
.step-stage.capture   { background: #202833; color: #93a6ba; }
.step-stage.done      { background: #1a2b1f; color: #7fc08f; }
.step-stage.agent     { background: #2b2233; color: #b79ad4; }

.step-ms { font: 600 11px/1.5 var(--mono); color: var(--muted); text-align: right; }
.step-ms .at { display: block; font-size: 9.5px; opacity: .7; font-weight: 400; }

/* The waterfall: where this step sat inside the turn. */
.step-bar { grid-column: 2 / -1; height: 3px; border-radius: 2px;
            background: #222a35; position: relative; margin-top: 6px; }
.step-bar i {
  position: absolute; top: 0; bottom: 0; border-radius: 2px;
  background: var(--accent-2); min-width: 2px;
}
.step-detail { padding: 2px 12px 12px; display: none; }
.step.open .step-detail { display: block; }
.step.flash { animation: flash 1.2s ease-out; }
@keyframes flash { from { background: #2a2413; } to { background: transparent; } }

/* ======================================================================
   Step detail: the evidence
   ====================================================================== */
.kv { display: grid; grid-template-columns: auto 1fr; gap: 3px 10px;
      font-size: 11.5px; margin: 0 0 10px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; font-family: var(--mono); font-size: 11px;
         overflow-wrap: anywhere; }

.detail-title {
  margin: 12px 0 6px; font: 600 10px/1 var(--mono); letter-spacing: .7px;
  text-transform: uppercase; color: var(--muted);
}
.detail-title:first-child { margin-top: 2px; }

pre.blob {
  margin: 0; padding: 9px 11px; max-height: 340px; overflow: auto;
  /* Wheel inside a text panel scrolls the panel, not the list behind it. */
  overscroll-behavior: contain;
  background: #11161d; border: 1px solid var(--line); border-radius: 8px;
  font: 11.5px/1.65 var(--mono); color: #c9d6e2;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
/* Arabic in a monospace face at 11px is unreadable; the text panels that
   actually hold Arabic get a larger size and more leading. */
pre.blob.rtl { font-size: 13px; line-height: 1.85;
               font-family: system-ui, "Segoe UI", sans-serif; }

.chips { display: flex; flex-wrap: wrap; gap: 4px; margin: 0 0 8px; }
.chip {
  padding: 2px 8px; border-radius: 999px; font: 500 11px/1.7 var(--mono);
  background: #22303d; color: #9dc6e3; border: 1px solid #2b3d4d;
}
.chip.muted { background: #232a33; color: var(--muted); border-color: var(--line); }

/* A retrieved record. */
.card {
  border: 1px solid var(--line); border-radius: 8px; margin-bottom: 8px;
  background: #151b23; overflow: hidden;
}
.card.sent { border-color: #24512f; }
.card-head {
  width: 100%; display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  background: transparent; border: 0; color: inherit; cursor: pointer;
  font: inherit; text-align: left;
}
.card-head:hover { background: #1b222c; }
.card-title { flex: 1; min-width: 0; font-size: 12.5px; }
.card-score {
  font: 600 11px/1 var(--mono); color: var(--accent);
  padding: 3px 7px; border-radius: 5px; background: #2a2413;
}
.card-score.zero { color: var(--muted); background: #232a33; }
.card-why { padding: 0 10px 8px; }
.card-body { display: none; padding: 0 10px 10px; }
.card.open .card-body { display: block; }

.msg { margin-bottom: 8px; }
.msg-head {
  display: flex; align-items: center; gap: 8px; margin-bottom: 4px;
  font: 600 10px/1 var(--mono); letter-spacing: .6px; text-transform: uppercase;
}
.msg-role { padding: 2px 7px; border-radius: 4px; background: #232c38; color: #8fa6bd; }
.msg-role.system { background: #2a2413; color: #d2b061; }
.msg-role.user { background: #16293a; color: #6cb3e8; }
.msg-role.assistant { background: #2a1b33; color: #c08ce0; }
.msg-chars { color: var(--muted); font-weight: 400; }

.detail-actions { display: flex; gap: 6px; margin-top: 10px; }
.detail-actions button { flex: 1; }

.banner {
  padding: 8px 10px; border-radius: 8px; margin-bottom: 10px;
  font-size: 11.5px; line-height: 1.5;
  border: 1px solid #453718; background: #241d10; color: #d9bf85;
}
.banner.bad { border-color: #47242a; background: #2a1618; color: #f0a6a2; }
.banner.good { border-color: #1c3d24; background: #10281a; color: #8fd5a3; }

/* ======================================================================
   Latency bars
   ====================================================================== */
.latency-bars { margin: 0 0 18px; }
.lat-row { margin-bottom: 8px; }
.lat-row .lab {
  display: flex; justify-content: space-between; font-size: 11px;
  color: var(--muted); margin-bottom: 3px;
}
.lat-row .lab b { font: 600 11px/1 var(--mono); color: var(--text); }
.lat-track { height: 6px; border-radius: 3px; background: var(--panel-2); overflow: hidden; }
.lat-track i { display: block; height: 100%; border-radius: 3px; background: var(--accent-2); }
.lat-row.asr .lat-track i   { background: #6cb3e8; }
.lat-row.agent .lat-track i { background: #c08ce0; }
.lat-row.tts .lat-track i   { background: #e0a45c; }

/* ======================================================================
   Data browser
   ====================================================================== */
.kb-result { margin: 10px 0; }
.kb-summary { margin: 4px 0 12px; }
.kb-entries { max-height: 46vh; overflow-y: auto; }
.kb-stats {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px;
  margin-bottom: 10px;
}
.kb-stat {
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel-2);
}
.kb-stat b { display: block; font: 600 15px/1.3 var(--mono); color: var(--accent); }
.kb-stat span { font-size: 10.5px; color: var(--muted); text-transform: uppercase;
                letter-spacing: .5px; }

/* ======================================================================
   Sources on a reply, and the conversation's own working indicator
   ====================================================================== */
.turn .sources { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; }
.source-chip {
  padding: 2px 8px; border-radius: 999px; cursor: pointer;
  font: 500 11px/1.7 var(--mono);
  background: #14301f; color: #63c98a; border: 1px solid #1f4b30;
}
.source-chip:hover { background: #1a3d28; }
.source-chip.ungrounded { background: #2a2113; color: #d2b061; border-color: #453718; }

.turn.working .text::after {
  content: ""; display: inline-block; width: 7px; height: 7px;
  margin-left: 6px; border-radius: 50%; background: var(--accent);
  animation: blip .9s infinite; vertical-align: middle;
}

/* ======================================================================
   What is answering, and how long the call has been open
   ====================================================================== */
.mode-banner { display: none; margin-top: 12px; }
.mode-banner.show { display: block; }
.mode-banner .head {
  display: flex; align-items: center; gap: 8px;
  font: 600 12px/1.4 system-ui, sans-serif;
}
.mode-banner .body { margin-top: 5px; font-size: 12px; line-height: 1.55; }
.mode-banner code {
  display: block; margin-top: 7px; padding: 7px 9px;
  border-radius: 6px; background: #11161d; border: 1px solid var(--line);
  font: 11.5px/1.6 var(--mono); color: #c9d6e2;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
/* Echo mode is a warning, not a status: it is the single most likely reason
   for "the model just repeats me". */
.mode-banner.echo {
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid #453718; background: #241d10; color: #e4cb96;
}
.mode-banner.echo .head { color: var(--warn); }
/* Conversation mode is a one-line reassurance and nothing more. */
.mode-banner.live {
  padding: 0; border: 0; background: none;
  font: 600 11px/1.5 var(--mono); color: var(--muted);
}
.mode-banner.live b { color: var(--ok); font-weight: 600; }
.mode-banner.live .sep { color: var(--line); margin: 0 6px; }

.call-meta {
  margin-top: 7px; font: 600 11px/1.4 var(--mono); color: var(--muted);
}
.call-meta.on { color: var(--accent-2); }

/* A statement of scope, not a fault: running without a catalog is a normal
   way to run, and amber here would read as something being broken. */
.banner.note {
  border-color: var(--line); background: var(--panel-2); color: var(--muted);
}

/* A worker being down stops everything, so it gets the loudest treatment the
   panel has. */
.mode-banner.down {
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid #47242a; background: #2a1618; color: #f0b3af;
}
.mode-banner.down .head { color: var(--bad); }

/* The code line inside a panel note, e.g. how to attach a catalog. */
.banner code, .tab-panel details code {
  display: block; margin-top: 7px; padding: 7px 9px;
  border-radius: 6px; background: #11161d; border: 1px solid var(--line);
  font: 11.5px/1.6 var(--mono); color: #c9d6e2;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.banner.note .head { color: var(--text); font: 600 12px/1.4 system-ui, sans-serif; }
.tab-panel details { margin: 10px 0; }
.tab-panel details .tab-hint { margin: 8px 0 0; }

/* ======================================================================
   App shell
   Three columns side by side is a dashboard, not an article. Scrolled as
   one page it breaks in a way that has no escape: the inspector's list is
   capped in viewport units, so the column ends up taller than the window,
   and a wheel over that list scrolls the list and then — once the list has
   bottomed out — nothing at all. The bottom of the panel is unreachable
   without moving the pointer off it.

   So above the breakpoint the page stops scrolling and each column is
   bounded by the window with a scrollbar of its own. Below it the columns
   stack and ordinary page scrolling is the right thing, so none of this
   applies. These rules live at the end of the file because they override
   earlier ones of equal specificity; a media query adds none.
   ====================================================================== */
@media not all and (max-width: 1100px) {
  body { height: 100%; display: flex; flex-direction: column; overflow: hidden; }
  main {
    flex: 1 1 auto; min-height: 0;
    grid-template-rows: minmax(0, 1fr);
    align-items: stretch;
  }

  /* Sized by the row, never by their contents: a long trace cannot push its
     column past the bottom of the window. `min-height: 0` is what lets a
     grid item shrink below its content in the first place. */
  .panel { min-height: 0; }
  .transcript-panel, .inspector { min-height: 0; }

  .controls { overflow-y: auto; overscroll-behavior: contain; }
  .transcript { max-height: none; overscroll-behavior: contain; }

  /* ------------------------------------------------------- inspector */
  .tabs { flex: none; }
  .tab-panel.active { flex: 1 1 auto; min-height: 0; }

  /* Activity and Log are a header plus one long list, so the list takes the
     leftover height and scrolls; the header stays put. */
  #panel-activity.active, #panel-log.active { display: flex; flex-direction: column; }
  .tab-head { flex: none; }
  .trace-list, #panel-log .log {
    flex: 1 1 auto; min-height: 0; max-height: none;
    /* Bottoming out here must not jolt anything behind it. */
    overscroll-behavior: contain;
  }

  /* Latency and Data are plain documents — search box, stats, records — with
     no single list to hand a scrollbar to, so the tab scrolls as a whole and
     the records give up their own scroller rather than nest a second one. */
  #panel-latency.active, #panel-data.active {
    overflow-y: auto; overscroll-behavior: contain;
  }
  .kb-entries { max-height: none; overflow: visible; }
}
