/*
  KAL Assist test page. One file, no preprocessor.

  Tokens first, in both themes; everything below reads a token and never a
  literal colour. The tier chips are the one place with seven colours of their
  own — muted, and re-tuned for dark so `law` is still recognisably `law`.
*/
:root {
  --bg: #f4f5f3;
  --surface: #ffffff;
  --surface-2: #eef0ee;
  --ink: #1b1f23;
  --muted: #5f6770;
  --line: #d9dde1;
  --line-strong: #b9c0c7;
  --accent: #0f6e68;
  --accent-ink: #ffffff;
  --you: #e4eeec;
  --danger: #b3261e;
  --danger-bg: #fbeeed;
  --ok: #1f7a4d;
  --code-bg: #eef0ee;

  --chip-law-bg: #dfe6f5;    --chip-law-fg: #2d3f78;
  --chip-nqs-bg: #e8e1f4;    --chip-nqs-fg: #52367e;
  --chip-award-bg: #f4e9d4;  --chip-award-fg: #7a4f0d;
  --chip-guidance-bg: #d9efee; --chip-guidance-fg: #0f5e59;
  --chip-kal_policy-bg: #f6e0e5; --chip-kal_policy-fg: #8a2f46;
  --chip-kal_help-bg: #dfefdd;   --chip-kal_help-fg: #2b6431;
  --chip-vendor_help-bg: #e6e8ea; --chip-vendor_help-fg: #4a535c;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --radius: 10px;
  --col: 780px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141719;
    --surface: #1c2024;
    --surface-2: #23282d;
    --ink: #e7eaed;
    --muted: #9aa3ac;
    --line: #2b3238;
    --line-strong: #3d464e;
    --accent: #5cc4b9;
    --accent-ink: #0e1a19;
    --you: #22302e;
    --danger: #ff8a80;
    --danger-bg: #3a1f1d;
    --ok: #6fcf97;
    --code-bg: #23282d;

    --chip-law-bg: #26304d;    --chip-law-fg: #b9c6f2;
    --chip-nqs-bg: #33294a;    --chip-nqs-fg: #cdbdf0;
    --chip-award-bg: #3f3320;  --chip-award-fg: #ecc98a;
    --chip-guidance-bg: #1d3634; --chip-guidance-fg: #9fdcd5;
    --chip-kal_policy-bg: #3e262d; --chip-kal_policy-fg: #f0b3c1;
    --chip-kal_help-bg: #223a25;   --chip-kal_help-fg: #a9dcae;
    --chip-vendor_help-bg: #2b3137; --chip-vendor_help-fg: #b7bec5;
  }
}

* { box-sizing: border-box; }

/*
  ★ `hidden` MUST WIN. The browser's own `[hidden] { display: none }` is a
  user-agent rule, and every author rule below beats it — `.thread-wrap` sets
  `flex`, `.composer` sets `flex`, `.topbar-facts` sets `flex`. Without this the
  signed-out page draws the whole signed-in chrome (a scope chip, a corpus count
  and a Sign out button) over the login card, which is exactly what it did the
  first time it was screenshotted. Everything the page shows or hides — the two
  halves, the warm-up strip, the db chip — is toggled with `el.hidden`, so this
  one line is what makes all of it work.
*/
[hidden] { display: none !important; }

html, body { margin: 0; height: 100%; }

/*
  ── THE PAGE DOES NOT SCROLL. THE THREAD DOES. ────────────────────────────
  `body` is a full-height flex column and is the only element with
  `overflow: hidden`; the top bar, the warm-up strip and the composer are
  fixed-size children of it, and `.thread-wrap` is the one flexible child that
  scrolls. `min-height: 0` on that child is the whole trick — a flex item's
  default `min-height: auto` refuses to shrink below its content, so without it
  the column grows to the height of the answer and the composer walks off the
  bottom of the window. `position: sticky` used to do this job and cannot: a
  long answer still pushed the document taller than the viewport, so the reader
  scrolled the PAGE and the answer's own top scrolled away above the bar.
*/
body {
  font: 15px/1.55 var(--font);
  color: var(--ink);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

a { color: var(--accent); }
a:hover { text-decoration-thickness: 2px; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ── Top bar ─────────────────────────────────────────────────────────────── */
.topbar {
  flex: none;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: 8px 20px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px 20px;
  flex-wrap: wrap;
  font-size: 13px;
}
.topbar-brand { display: flex; align-items: baseline; gap: 10px; }
.brand { font-weight: 650; letter-spacing: 0.01em; font-size: 14px; }
.brand-note { color: var(--muted); }
.version { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.topbar-facts { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 18px; color: var(--muted); }
.fact { white-space: nowrap; }
.fact strong { color: var(--ink); font-weight: 600; }
.fact-db { color: var(--danger); font-weight: 600; }
/*
  "signed in as Nat Smith · head office staff · all centres". It is the first
  fact in the bar and the only one with a background, because it is the one that
  answers "whose answers am I looking at?" — a person reading somebody else's
  scoped answers and not noticing is the failure this chip exists to prevent.
*/
.fact-who {
  background: var(--you);
  border-radius: 999px;
  padding: 3px 10px;
  white-space: normal;
}
.fact-who strong { font-weight: 600; }

/* ── Sign in ─────────────────────────────────────────────────────────────── */
/*
  The whole page until /api/me answers 200. A single centred card: there is one
  thing to do here and no navigation to offer.
*/
.signin-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 10vh 20px 32px;
}
.signin {
  width: 100%;
  max-width: 400px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 26px 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.signin-title { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }
.signin-note { margin: -8px 0 2px; color: var(--muted); font-size: 14px; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field-label { font-size: 13px; font-weight: 600; color: var(--muted); }
.signin input {
  font: inherit; color: var(--ink); background: var(--bg);
  border: 1px solid var(--line-strong); border-radius: 8px; padding: 9px 11px;
  width: 100%;
}
.signin input:focus {
  border-color: var(--accent); outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.signin input:disabled { opacity: 0.6; }
.signin-button { width: 100%; padding: 10px 18px; }
.signin-foot { margin: 2px 0 0; font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.signin .inline-error { margin: 0; }

/* ── Warm-up banner ──────────────────────────────────────────────────────── */
/*
  One slim strip under the top bar, shown only while the vector cache is still
  loading. Accent-tinted rather than red: nothing is wrong, the server is simply
  not ready yet — and it says how far along it is, because the whole reason this
  exists is that a silent four-minute start looks identical to a hang.
*/
.warmup {
  flex: none;
  padding: 8px 20px;
  font-size: 13px;
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
}
.warmup-inner { max-width: var(--col); margin: 0 auto; display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.warmup strong { font-weight: 650; }
.warmup .warmup-note { color: var(--muted); }
.warmup .secs { font-family: var(--mono); }

/* ── Acting as a centre director (T15b) ──────────────────────────────────── */
/*
  Amber, thin, and directly under the top bar: the one thing a tester must not
  forget is that the answers below are scoped to ONE centre and are not what
  head office would normally see. Same shape as the warm-up strip, different
  colour, because it means something entirely different.
*/
.acting-strip {
  flex: none;
  padding: 7px 20px;
  font-size: 13px;
  color: var(--chip-award-fg);
  background: var(--chip-award-bg);
  border-bottom: 1px solid color-mix(in srgb, var(--chip-award-fg) 35%, var(--line));
}
.acting-strip strong { font-weight: 650; }

/* The "View as" select, and the acting half of the who-am-I chip. */
.fact-viewas { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.viewas-label { color: var(--muted); }
#viewas {
  font: inherit; font-size: 13px; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: 6px; padding: 3px 6px;
  max-width: 270px;
}
.fact-who .acting { color: var(--chip-award-fg); font-weight: 600; }
.stop-acting { margin-left: 6px; }

/* ── The chat rail ───────────────────────────────────────────────────────── */
/*
  ★ THE WORKSPACE IS THE FLEX ROW; `.mainpane` IS THE OLD COLUMN.
  `body` still owns the height and still does not scroll — the rail and the
  thread each scroll inside themselves. `min-width: 0` on the main pane is the
  same trick `min-height: 0` plays vertically: without it a wide answer would
  refuse to shrink and push the rail off the left edge.
*/
.workspace { flex: 1 1 auto; min-height: 0; display: flex; }
.mainpane {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.rail {
  flex: none;
  width: 260px;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--line);
}
.rail-head { flex: none; padding: 12px 12px 8px; }
.rail-new {
  width: 100%;
  font: inherit; font-size: 13.5px; font-weight: 600;
  color: var(--ink); background: var(--bg);
  border: 1px solid var(--line-strong); border-radius: 8px;
  padding: 8px 12px; cursor: pointer; text-align: left;
}
.rail-new:hover { border-color: var(--accent); color: var(--accent); }
.rail-new::before { content: "+"; margin-right: 8px; color: var(--muted); font-weight: 700; }
.rail-new:hover::before { color: var(--accent); }

.rail-list {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  list-style: none; margin: 0; padding: 0 8px 16px;
}
.rail-empty { margin: 0; padding: 4px 14px; color: var(--muted); font-size: 13px; }

/* One chat. The pencil is only in the flow on hover/focus, never in the tab order twice. */
.rail-row {
  display: flex; align-items: flex-start; gap: 2px;
  border-radius: 8px; margin-bottom: 2px;
}
.rail-row:hover { background: var(--surface-2); }
.rail-row.current { background: var(--you); }
.rail-open {
  flex: 1 1 auto; min-width: 0;
  font: inherit; text-align: left; color: inherit; background: none; border: 0;
  padding: 7px 8px; cursor: pointer; border-radius: 8px;
}
.rail-title {
  display: block;
  font-size: 13.5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rail-row.current .rail-title { font-weight: 650; }
.rail-meta {
  display: block; margin-top: 2px;
  font-size: 11.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rail-tag {
  display: inline-block; margin-left: 5px; padding: 0 5px; border-radius: 999px;
  font-family: var(--mono); font-size: 10px; line-height: 15px;
  background: var(--chip-award-bg); color: var(--chip-award-fg);
}
.rail-rename {
  flex: none; align-self: center;
  font: inherit; font-size: 12px; line-height: 1;
  color: var(--muted); background: none; border: 0; border-radius: 6px;
  padding: 6px 8px; cursor: pointer; visibility: hidden;
}
.rail-row:hover .rail-rename, .rail-row:focus-within .rail-rename { visibility: visible; }
.rail-rename:hover { color: var(--accent); }
.rail-edit {
  flex: 1 1 auto; min-width: 0; margin: 4px 6px;
  font: inherit; font-size: 13.5px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--accent); border-radius: 6px; padding: 5px 7px;
}

/* The drawer's backdrop. Only ever visible under 900 px — see the media query. */
.rail-scrim { display: none; }

/* "asked while acting as director at CAN", above a reopened conversation. */
.thread-banner {
  margin: 0; align-self: stretch;
  font-size: 12.5px; color: var(--chip-award-fg);
  background: var(--chip-award-bg);
  border-radius: 999px; padding: 4px 12px;
}

/* ── The conversation ────────────────────────────────────────────────────── */
/* ★ The ONLY scrolling region of the main pane. See the note on body above. */
.thread-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 24px 20px 32px;
}
.thread { max-width: var(--col); margin: 0 auto; display: flex; flex-direction: column; gap: 18px; }

.intro { margin: 8vh 0 0; }
.intro-title { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 8px; }
.intro-text { color: var(--muted); margin: 0; max-width: 56ch; }

.turn-you {
  align-self: flex-end;
  max-width: 78%;
  background: var(--you);
  border-radius: var(--radius) var(--radius) 3px var(--radius);
  padding: 10px 14px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.turn-answer {
  align-self: stretch;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px 12px;
  /*
    `scrollIntoView({ block: "start" })` aligns the card's border box with the
    top of the scrollport and ignores the scrollport's own padding, so without
    this the newest answer arrives welded to the underside of the top bar. This
    is the gap it lands with — a scroll offset, not a margin, so it changes
    nothing about how the card sits when the reader scrolls past it.
  */
  scroll-margin-top: 18px;
}
.turn-answer.refused { border-left: 3px solid var(--danger); }

.turn-wait {
  align-self: flex-start;
  color: var(--muted);
  font-size: 14px;
  padding: 6px 2px;
}
.turn-wait .secs { font-family: var(--mono); color: var(--ink); }

.turn-error {
  align-self: stretch;
  color: var(--danger);
  background: var(--danger-bg);
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
  border-radius: var(--radius);
  padding: 10px 14px;
  overflow-wrap: anywhere;
}

/* Rendered markdown */
.md > :first-child { margin-top: 0; }
.md > :last-child { margin-bottom: 0; }
.md p { margin: 0 0 10px; }
.md h1, .md h2, .md h3, .md h4, .md h5, .md h6 { margin: 14px 0 6px; line-height: 1.3; }
.md h1 { font-size: 19px; } .md h2 { font-size: 17px; } .md h3 { font-size: 16px; }
.md h4, .md h5, .md h6 { font-size: 15px; }
.md ul, .md ol { margin: 0 0 10px; padding-left: 22px; }
.md li { margin: 3px 0; }
.md code { font-family: var(--mono); font-size: 0.9em; background: var(--code-bg); padding: 1px 5px; border-radius: 4px; }
.md pre { background: var(--code-bg); padding: 10px 12px; border-radius: 6px; overflow-x: auto; margin: 0 0 10px; }
.md pre code { background: none; padding: 0; font-size: 13px; }
.md .cite { font-size: 0.72em; color: var(--accent); font-weight: 600; vertical-align: super; line-height: 0; margin: 0 1px; }
.md a { overflow-wrap: anywhere; }
/*
  Every link on this page opens a new tab, so every link says so. A glyph rather
  than an icon font or an SVG: this page has no external asset and is not about
  to acquire one for 2 kB of arrow. `aria-hidden` in app.js keeps it out of the
  accessible name, which is the link text and nothing else.
*/
.new-tab { font-size: 0.78em; margin-left: 0.15em; opacity: 0.75; text-decoration: none; }

.answer-note { margin: 10px 0 0; font-size: 13.5px; color: var(--muted); }
.answer-note strong { color: var(--ink); font-weight: 600; }

/* ── Sources ledger — the signature block ────────────────────────────────── */
.block { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 8px; }
.block-title {
  margin: 0 0 4px; font-size: 11.5px; font-weight: 650; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}
.sources { list-style: none; margin: 0; padding: 0; }
/*
  A source row must WRAP, never widen the column. Every track that can hold a
  long string is `minmax(0, …)` and every box inside it carries `min-width: 0`,
  because a grid or flex item defaults to `min-width: auto` — it refuses to
  shrink below its longest unbreakable word, and one 90-character heading path
  is enough to push the whole answer card off the right edge of the window.
*/
.source {
  display: grid;
  grid-template-columns: 2.2em auto minmax(0, 1fr) auto;
  gap: 6px 10px;
  align-items: baseline;
  padding: 7px 0;
  border-bottom: 1px dashed var(--line);
  font-size: 14px;
  min-width: 0;
}
.source:last-child { border-bottom: 0; }
.source-n { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.chip {
  display: inline-block; font-family: var(--mono); font-size: 11px; line-height: 1;
  padding: 4px 7px; border-radius: 999px; letter-spacing: 0.02em; white-space: nowrap;
  background: var(--surface-2); color: var(--muted);
}
.chip-law { background: var(--chip-law-bg); color: var(--chip-law-fg); }
.chip-nqs { background: var(--chip-nqs-bg); color: var(--chip-nqs-fg); }
.chip-award { background: var(--chip-award-bg); color: var(--chip-award-fg); }
.chip-guidance { background: var(--chip-guidance-bg); color: var(--chip-guidance-fg); }
.chip-kal_policy { background: var(--chip-kal_policy-bg); color: var(--chip-kal_policy-fg); }
.chip-kal_help { background: var(--chip-kal_help-bg); color: var(--chip-kal_help-fg); }
.chip-vendor_help { background: var(--chip-vendor_help-bg); color: var(--chip-vendor_help-fg); }

.source-body { min-width: 0; overflow-wrap: anywhere; }
.source-title { font-weight: 600; }
/*
  The heading path — "Procedure › Reporting an incident › What the educator does".
  Truncated to one line with an ellipsis rather than wrapped, because it is the
  ADDRESS of the extract and not something anybody reads in full; the whole
  string is on the element as `title`, so hovering shows it.
*/
.source-ref {
  color: var(--muted);
  display: inline-block;
  max-width: 100%;
  vertical-align: bottom;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.source-ref::before { content: " · "; }
.source-meta { display: block; font-size: 12.5px; color: var(--muted); margin-top: 1px; overflow-wrap: anywhere; }
.source-meta a { color: var(--accent); }
.source-meta .dot { margin: 0 5px; }
.source-meta .asat, .source-ref { white-space: nowrap; }
.source-claim { display: block; font-size: 13px; color: var(--muted); margin-top: 2px; }
.verified { font-weight: 700; font-size: 14px; cursor: help; justify-self: end; }
.verified.yes { color: var(--ok); }
.verified.no { color: var(--danger); }

/* Conflicts */
.conflicts { margin: 0; padding: 0; list-style: none; }
.conflict { padding: 6px 10px; border-left: 3px solid var(--chip-kal_policy-fg); background: var(--surface-2); border-radius: 0 6px 6px 0; margin: 4px 0; font-size: 14px; }
.conflict b { font-family: var(--mono); font-size: 12.5px; font-weight: 600; }

/* Tool trace */
.trace summary { cursor: pointer; list-style: none; display: inline-flex; gap: 8px; align-items: baseline; }
.trace summary::-webkit-details-marker { display: none; }
.trace summary::before { content: "▸"; color: var(--muted); font-size: 11px; }
.trace[open] summary::before { content: "▾"; }
.trace .count { font-family: var(--mono); font-size: 11px; color: var(--muted); }
.trace-table { width: 100%; border-collapse: collapse; margin-top: 6px; font-size: 13px; }
.trace-table th { text-align: left; font-weight: 600; color: var(--muted); font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase; padding: 4px 8px 4px 0; border-bottom: 1px solid var(--line); }
.trace-table td { padding: 5px 8px 5px 0; vertical-align: top; border-bottom: 1px solid var(--line); }
.trace-table tr:last-child td { border-bottom: 0; }
.trace-table code { font-family: var(--mono); font-size: 12px; white-space: pre-wrap; overflow-wrap: anywhere; }
.trace-table .num { font-family: var(--mono); font-size: 12px; white-space: nowrap; }
.trace-table .ok { color: var(--ok); font-weight: 600; }
.trace-table .err { color: var(--danger); font-weight: 600; }
.trace-wrap { overflow-x: auto; }
.trace-none { color: var(--muted); font-size: 13px; margin: 4px 0 0; }

/* Footer verdict line */
.meta {
  margin-top: 12px; padding-top: 8px; border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 12px; color: var(--muted);
  overflow-wrap: anywhere;
}
.meta .g-verified { color: var(--ok); }
.meta .g-partial { color: var(--chip-award-fg); }
.meta .g-not_found { color: var(--danger); }

/* ── Composer ────────────────────────────────────────────────────────────── */
.composer {
  flex: none;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding: 12px 20px 10px;
}
.composer-inner { max-width: var(--col); margin: 0 auto; }
.ask-form { display: flex; flex-direction: column; gap: 8px; }
textarea {
  width: 100%; resize: vertical; min-height: 56px; max-height: 40vh;
  font: inherit; color: var(--ink); background: var(--bg);
  border: 1px solid var(--line-strong); border-radius: 8px; padding: 10px 12px;
}
textarea:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); }
textarea:disabled { opacity: 0.6; }
.ask-actions { display: flex; align-items: center; gap: 14px; }
.thread-note { flex: 1; font-family: var(--mono); font-size: 12px; color: var(--muted); }
.link-button { background: none; border: 0; padding: 0; font: inherit; font-size: 13.5px; color: var(--accent); cursor: pointer; text-decoration: underline; }
/*
  The drawer button exists only where the rail is a drawer. Two rules decide
  that: `hidden` (app.js, signed out) and this `display` (app.css, wide window).
  The attribute wins when it is set — `[hidden]` above is `!important` — so the
  two can never disagree into a button that opens a rail already on screen.
*/
.chats-button {
  display: none;
  font: inherit; font-size: 13px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--line-strong); border-radius: 8px; padding: 4px 10px;
  cursor: pointer; margin-right: 4px;
}
.ask-button {
  font: inherit; font-weight: 600; color: var(--accent-ink); background: var(--accent);
  border: 0; border-radius: 8px; padding: 8px 18px; cursor: pointer; min-width: 84px;
}
.ask-button:disabled { opacity: 0.55; cursor: default; }
.composer-hint { margin: 8px 0 0; font-size: 12px; color: var(--muted); }
.inline-error { color: var(--danger); margin: 0 0 8px; font-size: 14px; }

/* ── Below 900: the rail becomes a drawer ────────────────────────────────── */
/*
  Under 900 px a 260 px column would leave the answer about 400 px wide on a
  laptop and nothing at all on a phone, so the rail slides in over the
  conversation instead, with a scrim that closes it. It is the SAME markup and
  the same list — only the layout changes — so nothing about the rail's
  behaviour has two implementations to keep in step.
*/
@media (max-width: 899px) {
  .chats-button { display: inline-block; }
  .rail {
    position: fixed; z-index: 20; top: 0; bottom: 0; left: 0;
    width: 282px; max-width: 86vw;
    transform: translateX(-100%);
    transition: transform 160ms ease-out;
    box-shadow: 0 0 0 rgba(0, 0, 0, 0);
    padding-top: 6px;
  }
  .rail.open { transform: translateX(0); box-shadow: 6px 0 24px rgba(0, 0, 0, 0.22); }
  .rail-scrim {
    display: block;
    position: fixed; z-index: 15; inset: 0;
    background: rgba(0, 0, 0, 0.38);
  }
  .rail-rename { visibility: visible; }
}

/* ── Narrow (420) ───────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  .topbar { flex-direction: column; align-items: flex-start; gap: 4px; padding: 8px 14px; }
  .topbar-facts { gap: 2px 14px; }
  .thread-wrap { padding: 16px 12px 24px; }
  .turn-you { max-width: 92%; }
  .turn-answer { padding: 14px 14px 10px; }
  /* [n] chip …………… ✓ on the first row, the body on the second. */
  .source { grid-template-columns: 2em auto minmax(0, 1fr) auto; gap: 4px 8px; }
  .source-body { grid-column: 1 / -1; grid-row: 2; }
  /* Narrow enough that an ellipsis would hide most of the path — wrap instead. */
  .source-ref { white-space: normal; overflow: visible; text-overflow: clip; display: inline; }
  .verified { grid-column: 4; grid-row: 1; }
  .composer { padding: 10px 12px 8px; }
  .composer-hint { display: none; }
  .signin-wrap { padding: 6vh 12px 24px; }
  .signin { padding: 20px 18px 18px; }
  .acting-strip { padding: 7px 14px; }
  .fact-viewas { width: 100%; }
  #viewas { max-width: 100%; flex: 1 1 auto; }
}

