/* A refresh of app.css. Same class names, so adopting it is one line in base.html
   and rolling it back is the same line.

   Still one stylesheet, no build step and no CDN. What is different is mechanics
   rather than character: this is the same sober operator tool, with the five things
   that dated it fixed.

   1. TOKENS THAT SCALE. Spacing, radius and elevation are scales rather than
      hand-picked values. The old file had 6px on buttons, 8px on cards, 12px on
      bubbles and 999px on pills with no relationship between them, which reads as
      unfinished more reliably than any other single thing.

   2. ELEVATION INSTEAD OF BORDERS. Everything used to be 1px on a flat ground, so a
      stat tile, a card and a table row sat on one visual plane. Surfaces now lift;
      only interactive things keep an outline.

   3. DARK MODE IS A DESIGN, NOT AN INVERSION. Shadows do almost nothing on a dark
      ground, so elevation there is a *lighter surface* - the convention every dark
      UI uses and the old file ignored.

   4. AN OPEN TYPE SCALE. 15px body against a 1.4rem h1 left headings barely larger
      than text. 16px body, a real ratio, negative tracking on headings.

   5. MOTION, GUARDED. Nothing transitioned, so hovers snapped and a streaming answer
      gave no sign of being alive. Everything here is inside a
      prefers-reduced-motion guard.

   6. THEMES, AS FOURTEEN VALUES EACH. Colour is derived with color-mix() from a
      handful of seeds rather than listed as forty hex values, so a palette never
      declares a hover, a tint or a focus ring - it declares an accent and the states
      follow. `light-dark()` carries both schemes in one declaration, which is what
      makes a theme one block instead of three.

      **A theme is not only a palette.** It may also set the display face, the radius
      ramp and whether elevation exists at all, because a set of themes that varied
      only the accent turned out to be five versions of one design. Paper switches
      shadows off and takes a serif; Terminal goes monospace and square; Indigo is
      the app-shaped one. Three designs, which is what a choice is for.

      None of these is the house green: adopting any of them is a decision about
      brand as much as about design, which is why they are shown rather than
      applied. */

/* -- themes ---------------------------------------------------------------

   Every colour is declared once, as `light-dark(light, dark)`. The browser picks
   the side from `color-scheme`, so a theme is one block of fourteen values instead
   of a light block plus a dark block plus the media query that switches them - and
   forcing light or dark is a `color-scheme` change rather than a second palette.

   Everything else in the file is mixed from these with `color-mix()`, so a theme
   never lists a hover, a tint or a focus ring: change the accent and its own states
   follow. That is the whole reason the seeds are separated from the surfaces.

   `data-mode` on <html> overrides the system preference; absent, `light dark` means
   the system decides. `data-theme` selects the palette. -------------------------- */

:root[data-theme="paper"] {
  /* Paper. **A document, not an app.** The departure here is structural rather than
     chromatic: a serif for display, elevation switched off entirely, hairline rules
     instead of filled surfaces, and a near-square radius. Nothing floats, so the
     page reads as something printed and handed over rather than something running.

     That suits what this app mostly shows - prose, tables and an audit chain - and
     it is the one theme where a screenshot looks like evidence rather than software.

     The serif is a system stack: no download, no external request. */
  --display: Charter, "Bitstream Charter", "Iowan Old Style", Georgia,
             "Times New Roman", serif;
  --display-tracking: -.005em;
  --display-weight: 600;

  --accent:      light-dark(#7a2e1e, #e0a08a);
  --accent-ink:  light-dark(#ffffff, #1a0d08);
  --bg:          light-dark(#fbfaf7, #131211);
  --panel:       light-dark(#fffefc, #1a1918);
  --panel-2:     light-dark(#f6f4f0, #201f1d);
  --ink:         light-dark(#1c1a17, #eae7e1);
  --ink-soft:    light-dark(#544f47, #a29c92);
  --ink-faint:   light-dark(#837c71, #766f65);
  --line:        light-dark(#ddd8cf, #2b2926);
  --line-strong: light-dark(#b3aca0, #423f3a);
  --ok-seed:     light-dark(#3a5f2b, #9fc98a);
  --bad-seed:    light-dark(#8a2622, #e89b95);
  --warn-seed:   light-dark(#7a5510, #d9b878);

  /* No elevation at all. Paper does not hover. */
  --shade-1: transparent;
  --shade-2: transparent;
  --raised-line: var(--line);
  --r-sm: 2px;
  --r-md: 3px;
  --r-lg: 4px;
}

:root,
:root[data-theme="terminal"] {
  /* Terminal. **A console, and it does not pretend otherwise.** Monospace
     throughout - not just in code blocks - square corners, one-pixel hard borders,
     no shadows and no tint. The accent is a phosphor cyan, chosen because it is the
     one bright hue that collides with none of the three status colours: green is
     `ok`, red is `bad`, amber is `warn`, and an accent sharing any of them would
     make every page look like it needed attention.

     It stays recognisably a console in light mode rather than turning into a
     different theme: same square, same mono, same hard rules, on paper. */
  --sans: ui-monospace, "Cascadia Code", "JetBrains Mono", SFMono-Regular,
          Menlo, Consolas, monospace;
  --display: var(--sans);
  --display-tracking: -.01em;
  --display-weight: 700;

  --accent:      light-dark(#00666e, #3ad6e0);
  --accent-ink:  light-dark(#ffffff, #001518);
  --bg:          light-dark(#eef0ef, #07090a);
  --panel:       light-dark(#ffffff, #0d1113);
  --panel-2:     light-dark(#f4f6f5, #12171a);
  --ink:         light-dark(#0a0d0e, #cfe3e6);
  --ink-soft:    light-dark(#4e5a5c, #86a0a4);
  --ink-faint:   light-dark(#77878a, #5b7175);
  --line:        light-dark(#c3cccb, #1e2629);
  --line-strong: light-dark(#8b9998, #33454a);
  --ok-seed:     light-dark(#0f6b3f, #4fdc8f);
  --bad-seed:    light-dark(#a81f1f, #ff7b74);
  --warn-seed:   light-dark(#8a5c00, #ffc24d);

  --shade-1: transparent;
  --shade-2: transparent;
  --raised-line: var(--line-strong);
  --r-sm: 0px;
  --r-md: 0px;
  --r-lg: 0px;
  --r-full: 0px;
}

:root[data-theme="indigo"] {
  /* Indigo. Reads as a product rather than an internal tool - the most "modern" of
     the five in the sense people usually mean, and the furthest from the brand. */
  --accent:      light-dark(#4f46e5, #8b85f0);
  --accent-ink:  light-dark(#ffffff, #0b0a1f);
  --bg:          light-dark(#f6f6fb, #0e0e16);
  --panel:       light-dark(#ffffff, #171722);
  --panel-2:     light-dark(#fafaff, #1e1e2b);
  --ink:         light-dark(#15141f, #e9e8f2);
  --ink-soft:    light-dark(#5b5870, #9b98b0);
  --ink-faint:   light-dark(#8d8aa3, #6d6a82);
  --line:        light-dark(#e6e5f0, #272536);
  --line-strong: light-dark(#cecbe0, #3a3750);
  --ok-seed:     light-dark(#166f52, #5fd3aa);
  --bad-seed:    light-dark(#9b1f38, #f28598);
  --warn-seed:   light-dark(#8a5700, #e5b45c);
}

/* -- light or dark ---------------------------------------------------------

   `light dark` means the operating system decides, which is the whole position:
   every theme above carries both palettes, so light and dark is not a second choice
   to make - it is a preference a person already set once, somewhere every other
   application on their machine respects.

   `data-mode` stays as an override because a preview needs to show both without
   somebody changing a system setting to see the other. It is not a control the
   dashboard itself needs to offer. */

:root                      { color-scheme: light dark; }
:root[data-mode="light"]   { color-scheme: light; }
:root[data-mode="dark"]    { color-scheme: dark; }

/* -- everything else, derived --------------------------------------------- */

:root {
  /* One accent produces its own hover, tint, border and focus ring. */
  --accent-hover: color-mix(in oklab, var(--accent) 88%, light-dark(black, white));
  --accent-tint:  color-mix(in oklab, var(--accent) 10%, var(--panel));
  --accent-line:  color-mix(in oklab, var(--accent) 35%, var(--line));
  --ring:         color-mix(in oklab, var(--accent) 45%, transparent);

  --ok: var(--ok-seed);
  --bad: var(--bad-seed);
  --warn: var(--warn-seed);
  /* One percentage for both schemes: `--panel` is already light-dark, so the same
     mix lands as a pale tint on paper and a deep one on ink. A light-dark() here
     would be a type error - it resolves to a colour, never to a percentage. */
  --ok-bg:   color-mix(in oklab, var(--ok-seed) 12%, var(--panel));
  --bad-bg:  color-mix(in oklab, var(--bad-seed) 11%, var(--panel));
  --warn-bg: color-mix(in oklab, var(--warn-seed) 14%, var(--panel));

  /* A raised surface. On a light ground that is a shadow; on a dark one a shadow is
     nearly invisible, so elevation is carried by a border instead. Both are declared
     here so no component has to know which it got. */
  --raised-line: light-dark(transparent, var(--line));

  /* -- spacing. A 4px base, so gaps compose instead of being guessed. -- */
  --s1: .25rem;
  --s2: .5rem;
  --s3: .75rem;
  --s4: 1rem;
  --s5: 1.5rem;
  --s6: 2rem;
  --s7: 3rem;

  /* -- radius. One ramp, and every component picks from it. -- */
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-full: 999px;

  /* -- elevation. Two-layer shadows: a tight contact shadow and a soft ambient
        one. A single blurred shadow is what makes a card look like a sticker. -- */
  /* The geometry is shared; only the ink differs, so only the ink is light-dark.
     Dark shadows are heavier because a shadow on a dark ground barely reads - which
     is also why `--raised-line` exists to carry elevation there instead. */
  --shade-1: light-dark(rgb(16 21 26 / .05), rgb(0 0 0 / .40));
  --shade-2: light-dark(rgb(16 21 26 / .07), rgb(0 0 0 / .30));
  --e1: 0 1px 2px var(--shade-1), 0 1px 3px var(--shade-2);
  --e2: 0 2px 4px var(--shade-1), 0 4px 12px var(--shade-2);
  --e3: 0 4px 8px var(--shade-1), 0 12px 28px var(--shade-2);

  --mono: ui-monospace, "Cascadia Code", SFMono-Regular, Menlo, Consolas, monospace;
  /* Segoe UI Variable is the Windows 11 face and is a visible step up from Segoe
     UI. Listed ahead of it, with the old stack intact behind, so this costs no
     download and no external request - and a self-hosted Inter can slot in front
     later without touching anything else. */
  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Text",
          "Segoe UI", Roboto, "Helvetica Neue", sans-serif;

  /* Overridden by a theme that wants a different voice. Sans, tight, and heavy is
     the app default; Paper and Terminal both change all three. */
  --display: var(--sans);
  --display-tracking: -.02em;
  --display-weight: 640;

  --fast: 120ms;
  --slow: 220ms;
  --ease: cubic-bezier(.2, 0, .2, 1);
}

/* The whole page cross-fades when a theme is chosen, so switching reads as one
   change rather than as a flicker. */
@media (prefers-reduced-motion: no-preference) {
  body, .card, .stat, .grid, .bubble, .thread, .composer, .chat-thread {
    transition: background-color var(--slow) var(--ease),
                border-color var(--slow) var(--ease),
                color var(--slow) var(--ease);
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 400 16px/1.6 var(--sans);
  /* Optical sizing and kerning are free on a variable face and are the difference
     between "system font" and "typeset". */
  font-optical-sizing: auto;
  text-rendering: optimizeLegibility;
}

a { color: var(--accent); text-underline-offset: 2px; }
a:hover { color: var(--accent-hover); }

h1, h2, h3 {
  /* `--display` is its own token so a theme can change the voice of the page and
     not only its colour. Everything else inherits `--sans`. */
  font-family: var(--display);
  letter-spacing: var(--display-tracking);
  text-wrap: balance;
  font-weight: var(--display-weight);
}
h1 { font-size: 1.75rem; line-height: 1.25; margin: 0; }
h2 { font-size: 1.15rem; line-height: 1.35; margin: 0 0 var(--s3); }
p { text-wrap: pretty; }

/* Only where the pointer did not put it. A ring after a mouse click is the small
   thing that reads as an old page. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* -- chrome -------------------------------------------------------------- */

.bar {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--s4); padding: var(--s3) var(--s5);
  background: color-mix(in oklab, var(--panel) 85%, transparent);
  border-bottom: 1px solid var(--line);
  /* The bar floats over content that scrolls under it rather than being a slab. */
  backdrop-filter: saturate(180%) blur(12px);
  position: sticky; top: 0; z-index: 20;
}
.bar-left, .bar-right { display: flex; align-items: center; gap: var(--s4); }
.brand { font-weight: 680; letter-spacing: -.015em; }
.bar nav { display: flex; gap: var(--s1); }
.bar nav a {
  color: var(--ink-soft); text-decoration: none; font-weight: 500;
  padding: var(--s1) var(--s3); border-radius: var(--r-sm);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.bar nav a:hover { color: var(--ink); background: var(--bg); }
/* Where you are. Filled rather than merely coloured, because at this size a hue
   change alone is easy to miss between two entries. */
.bar nav a.here {
  color: var(--accent); background: var(--accent-tint); font-weight: 600;
}
.who { color: var(--ink-soft); font-size: .875rem; }

main { max-width: 1180px; margin: 0 auto; padding: var(--s5) var(--s5) var(--s7); }
main.centred { max-width: 400px; padding-top: 10vh; }

.page-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--s4); flex-wrap: wrap; margin-bottom: var(--s5);
}

/* -- surfaces ------------------------------------------------------------ */

.card {
  background: var(--panel);
  border: 1px solid var(--raised-line);
  border-radius: var(--r-lg);
  padding: var(--s5);
  margin-bottom: var(--s4);
  box-shadow: var(--e1);
}

.login { display: flex; flex-direction: column; gap: var(--s3); box-shadow: var(--e3); }
.login h1 { margin-bottom: var(--s1); }
.login button { margin-top: var(--s2); }

.notice {
  border-radius: var(--r-md); padding: var(--s3) var(--s4); margin-bottom: var(--s4);
  border: 1px solid transparent; font-size: .9375rem;
  /* A coloured rail carries the meaning at a glance; the tint alone is quieter
     than it needs to be at this contrast. */
  border-left-width: 3px;
}
.notice.ok   { background: var(--ok-bg);   color: var(--ok);   border-color: color-mix(in oklab, var(--ok) 30%, transparent);   border-left-color: var(--ok); }
.notice.bad  { background: var(--bad-bg);  color: var(--bad);  border-color: color-mix(in oklab, var(--bad) 30%, transparent);  border-left-color: var(--bad); }
.notice.warn { background: var(--warn-bg); color: var(--warn); border-color: color-mix(in oklab, var(--warn) 30%, transparent); border-left-color: var(--warn); }

.empty-note { color: var(--ink-soft); padding: var(--s6) 0; }

/* -- stats --------------------------------------------------------------- */

.stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--s3); margin-bottom: var(--s4);
}
.stat {
  background: var(--panel); border: 1px solid var(--raised-line);
  border-radius: var(--r-md); padding: var(--s4);
  display: flex; flex-direction: column; gap: var(--s1);
  box-shadow: var(--e1);
}
.stat-value {
  font-size: 1.625rem; font-weight: 660; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.stat-label {
  font-size: .75rem; color: var(--ink-faint); font-weight: 550;
  text-transform: uppercase; letter-spacing: .06em;
}
.stat.ok .stat-value { color: var(--ok); }
.stat.bad .stat-value { color: var(--bad); }

/* -- forms --------------------------------------------------------------- */

label { font-size: .875rem; color: var(--ink-soft); font-weight: 550; }

input[type=text], input[type=password], input:not([type]), select, textarea {
  width: 100%; padding: var(--s2) var(--s3);
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  font: inherit; font-size: .9375rem;
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
input:hover, select:hover, textarea:hover { border-color: var(--ink-faint); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  /* A ring drawn as a shadow rather than an outline, so it follows the radius. */
  box-shadow: 0 0 0 3px var(--ring);
}
textarea { font-family: inherit; resize: vertical; }

button {
  padding: var(--s2) var(--s4); border-radius: var(--r-sm); border: 1px solid transparent;
  background: var(--accent); color: var(--accent-ink);
  font: inherit; font-size: .9375rem; font-weight: 560; cursor: pointer;
  box-shadow: var(--e1);
  transition: background var(--fast) var(--ease), transform var(--fast) var(--ease),
              box-shadow var(--fast) var(--ease);
}
button:hover { background: var(--accent-hover); box-shadow: var(--e2); }
/* One pixel down on press. The cheapest possible "this is a real button". */
button:active { transform: translateY(1px); box-shadow: var(--e1); }
button[disabled] { opacity: .5; cursor: not-allowed; box-shadow: none; }
button.ok  { background: var(--ok);  color: var(--panel); }
button.bad { background: var(--bad); color: var(--panel); }
button.link, .link {
  background: none; border: none; color: var(--accent); box-shadow: none;
  padding: 0; cursor: pointer; text-decoration: none; font-weight: 500;
}
button.link:hover, .link:hover { color: var(--accent-hover); text-decoration: underline; }
/* Destructive, and coloured as such before it is pressed rather than only in the
   dialog that follows. */
button.link.danger { color: var(--bad); }
button.link.danger:hover { color: var(--bad); text-decoration: underline; }
.button {
  display: inline-block; padding: var(--s2) var(--s4); border-radius: var(--r-sm);
  background: var(--accent); color: var(--accent-ink); text-decoration: none;
  font-weight: 560; font-size: .9375rem; box-shadow: var(--e1);
  transition: background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.button:hover { background: var(--accent-hover); color: var(--accent-ink); box-shadow: var(--e2); }

.form { display: flex; flex-direction: column; gap: var(--s4); }
.field { display: flex; flex-direction: column; gap: var(--s1); }
.row { display: flex; gap: var(--s4); flex-wrap: wrap; }
.row .field { flex: 1 1 200px; }
.hint { margin: 0; font-size: .8125rem; color: var(--ink-soft); line-height: 1.55; }
.actions { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
details summary {
  cursor: pointer; font-size: .875rem; color: var(--ink-soft);
  font-weight: 550; margin-bottom: var(--s2);
}

.filters { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; margin-bottom: var(--s4); }
.filters select, .filters input { width: auto; min-width: 130px; }
.filters .auto { display: flex; align-items: center; gap: var(--s1); margin-left: auto; }
.filters .auto input { width: auto; min-width: 0; }
form.inline { display: flex; gap: var(--s1); align-items: center; margin: 0; }
form.inline .tiny { width: 150px; font-size: .875rem; }

/* -- table --------------------------------------------------------------- */

.grid {
  width: 100%; border-collapse: separate; border-spacing: 0;
  background: var(--panel); border: 1px solid var(--raised-line);
  border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--e1);
  margin-bottom: var(--s4);
}
.grid th, .grid td {
  padding: var(--s3) var(--s4); text-align: left;
  border-bottom: 1px solid var(--line);
}
.grid th {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint); background: var(--panel-2); font-weight: 600;
  /* A header that stays while a long table scrolls. */
  position: sticky; top: 0; z-index: 1;
}
.grid tbody tr:last-child td { border-bottom: none; }
.grid tbody tr { transition: background var(--fast) var(--ease); }
.grid tbody tr:hover { background: var(--accent-tint); }
/* Numbers line up only if they are tabular. */
.grid td.num, .grid th.num { text-align: right; font-variant-numeric: tabular-nums; }
.grid .empty td { color: var(--ink-soft); padding: var(--s6) var(--s4); text-align: center; }

/* -- bits ---------------------------------------------------------------- */

.pill {
  display: inline-flex; align-items: center; gap: var(--s1);
  padding: .15rem var(--s2); border-radius: var(--r-full);
  font-size: .75rem; font-weight: 600; letter-spacing: .01em;
  border: 1px solid transparent;
}
/* A status dot before the word: readable at a glance and colour-blind safe,
   because the word is still there. */
.pill::before {
  content: ""; width: 6px; height: 6px; border-radius: var(--r-full);
  background: currentColor; flex: none;
}
.pill-ok      { background: var(--ok-bg);   color: var(--ok);   border-color: color-mix(in oklab, var(--ok) 25%, transparent); }
.pill-error   { background: var(--bad-bg);  color: var(--bad);  border-color: color-mix(in oklab, var(--bad) 25%, transparent); }
.pill-pending { background: var(--warn-bg); color: var(--warn); border-color: color-mix(in oklab, var(--warn) 25%, transparent); }
.pill-elsewhere { background: var(--bg); color: var(--ink-soft); border-color: var(--line-strong); }
.pill-elsewhere::before { opacity: .5; }

.badge {
  display: inline-block; padding: .1rem var(--s2); border-radius: var(--r-sm);
  font-size: .6875rem; font-weight: 700; letter-spacing: .06em;
}
.badge-mock { background: var(--warn-bg); color: var(--warn); border: 1px solid var(--warn); }
.badge.small { font-size: .625rem; }

.facts { display: grid; grid-template-columns: minmax(130px, 180px) 1fr; gap: var(--s2) var(--s4); margin: 0; }
.facts dt { color: var(--ink-faint); font-size: .8125rem; font-weight: 550; padding-top: .1rem; }
.facts dd { margin: 0; }

.code {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: var(--s3) var(--s4); overflow-x: auto; margin: 0;
  font-family: var(--mono); font-size: .8125rem; line-height: 1.6;
  white-space: pre-wrap; word-break: break-word;
}
.inline-code { padding: var(--s1) var(--s2); }
code {
  font-family: var(--mono); font-size: .875em;
  background: var(--bg); border: 1px solid var(--line);
  border-radius: 4px; padding: .05em .35em;
}

.mono { font-family: var(--mono); font-size: .875rem; }
.muted { color: var(--ink-soft); }
.small { font-size: .8125rem; }
.nowrap { white-space: nowrap; }
.break { word-break: break-all; }

ul.plain { list-style: none; margin: 0; padding: 0; }
ul.plain li { padding: var(--s1) 0; }

/* -- tabs ---------------------------------------------------------------- */

.tabs {
  display: flex; gap: var(--s1); flex-wrap: wrap;
  border-bottom: 1px solid var(--line); margin-bottom: var(--s5);
}
.tab {
  padding: var(--s2) var(--s4); text-decoration: none; color: var(--ink-soft);
  font-weight: 550; font-size: .9375rem;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.tab:hover { color: var(--ink); }
/* An underline rather than a folder tab. Cleaner, and it stops the old file's
   trick of hiding the container border behind a matching bottom edge. */
.tab.here { color: var(--accent); border-bottom-color: var(--accent); }

a.chip { text-decoration: none; }
a.chip:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-tint); }

/* -- the conversation page ------------------------------------------------ */

.chat-layout {
  display: grid; grid-template-columns: 268px minmax(0, 1fr);
  gap: var(--s5); align-items: start;
}
.chat-side { position: sticky; top: 84px; display: flex; flex-direction: column; gap: var(--s3); }
.button.block { display: block; text-align: center; }
.side-head {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint); margin: var(--s2) 0 0;
}

.thread-tabs { display: flex; flex-direction: column; gap: 2px; }
.thread {
  display: flex; flex-direction: column; gap: 1px;
  padding: var(--s2) var(--s3); border-radius: var(--r-md);
  text-decoration: none; color: var(--ink-soft);
  border: 1px solid transparent;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.thread:hover { background: var(--panel); color: var(--ink); }
.thread.here {
  background: var(--accent-tint); color: var(--ink);
  border-color: var(--accent-line);
}
.thread.new { font-style: italic; cursor: default; }
.thread-title {
  font-size: .9375rem; font-weight: 550; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.thread.here .thread-title { font-weight: 640; }
.thread-meta { font-size: .75rem; color: var(--ink-faint); font-weight: 400; }

.chat-main { display: flex; flex-direction: column; min-width: 0; }
.chat-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--s4); flex-wrap: wrap; margin-bottom: var(--s4);
}

.chat-thread {
  display: flex; flex-direction: column; gap: var(--s3);
  height: min(64vh, 660px); overflow-y: auto;
  padding: var(--s5); border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--panel);
  scroll-behavior: smooth;
}
.thread-empty { margin: auto 0; max-width: 48ch; }
.thread-empty p { margin: 0 0 var(--s2); }

.bubble {
  max-width: min(70ch, 84%); padding: var(--s3) var(--s4);
  border-radius: var(--r-lg); border: 1px solid var(--line);
  background: var(--panel-2);
  display: flex; flex-direction: column; gap: var(--s2);
  box-shadow: var(--e1);
}
@media (prefers-reduced-motion: no-preference) {
  /* New bubbles arrive rather than appear. 160ms, once. */
  .bubble { animation: rise var(--slow) var(--ease) both; }
  @keyframes rise {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
  }
}
.bubble.mine {
  align-self: flex-end; background: var(--accent); color: var(--accent-ink);
  border-color: transparent; border-bottom-right-radius: var(--r-sm);
}
.bubble.theirs { align-self: flex-start; border-bottom-left-radius: var(--r-sm); }
.bubble-text { white-space: pre-wrap; word-break: break-word; line-height: 1.65; }
.bubble-when { font-size: .6875rem; opacity: .6; align-self: flex-end; }
.bubble.mine .bubble-when { color: var(--accent-ink); }

.bubble-warn {
  font-size: .8125rem; color: var(--warn); background: var(--warn-bg);
  border: 1px solid color-mix(in oklab, var(--warn) 30%, transparent);
  border-radius: var(--r-sm); padding: var(--s2) var(--s3);
}
.bubble-error {
  font-size: .8125rem; color: var(--bad); background: var(--bad-bg);
  border: 1px solid color-mix(in oklab, var(--bad) 30%, transparent);
  border-radius: var(--r-sm); padding: var(--s2) var(--s3);
}

/* The retrieval trace, as a stepper. It is the demo, so it gets structure rather
   than being four dim monospace lines. */
.trace {
  display: flex; flex-direction: column; gap: var(--s1);
  font-family: var(--mono); font-size: .75rem; color: var(--ink-faint);
  padding-left: var(--s4); position: relative;
}
.trace::before {
  content: ""; position: absolute; left: 3px; top: 6px; bottom: 6px;
  width: 2px; background: var(--line); border-radius: var(--r-full);
}
.trace-line { position: relative; }
.trace-line::before {
  content: ""; position: absolute; left: calc(var(--s4) * -1); top: .45em;
  width: 8px; height: 8px; border-radius: var(--r-full);
  background: var(--panel); border: 2px solid var(--line-strong);
}
.trace-line.warn { color: var(--warn); }
.trace-line.warn::before { border-color: var(--warn); }
/* The last step is the live one while a turn is in flight. */
@media (prefers-reduced-motion: no-preference) {
  .trace-line:last-child::before {
    border-color: var(--accent);
    animation: pulse 1.4s var(--ease) infinite;
  }
  @keyframes pulse {
    0%, 100% { box-shadow: 0 0 0 0 var(--ring); }
    50%      { box-shadow: 0 0 0 4px transparent; }
  }
}

.chips { display: flex; flex-wrap: wrap; gap: var(--s1); }
.chip {
  font-size: .75rem; padding: .15rem var(--s2); border-radius: var(--r-full);
  background: var(--bg); border: 1px solid var(--line); color: var(--ink-soft);
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.chip b { color: var(--accent); font-weight: 700; }

.composer {
  display: flex; gap: var(--s2); align-items: flex-end; margin-top: var(--s3);
  background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--r-lg); padding: var(--s2);
  box-shadow: var(--e1);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
/* The whole bar lights up, not just the textarea inside it. */
.composer:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); }
.composer textarea {
  flex: 1; resize: none; font-size: .9375rem; max-height: 160px; overflow-y: auto;
  border: none; background: none; box-shadow: none; padding: var(--s2);
}
.composer textarea:focus, .composer textarea:hover { border: none; box-shadow: none; }
.composer select { width: auto; min-width: 130px; border: none; background: none; }
.composer-note { margin: var(--s2) 0 0; }

@media (max-width: 860px) {
  .chat-layout { grid-template-columns: 1fr; }
  .chat-side { position: static; }
  .bubble { max-width: 92%; }
}
@media (max-width: 720px) {
  .facts { grid-template-columns: 1fr; }
  .bar { flex-direction: column; align-items: flex-start; }
  .grid { display: block; overflow-x: auto; }
  main { padding: var(--s4) var(--s3) var(--s6); }
}

/* Nothing moves for anyone who asked for that. */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; animation-iteration-count: 1 !important;
      transition-duration: .01ms !important; scroll-behavior: auto !important; }
}

/* -- the theme picker ------------------------------------------------------
   Sized down and quietened: it is a preference, not a tool, and it sits beside
   the operator's name rather than competing with the nav. */

.theme-picker {
  width: auto; min-width: 0;
  padding: var(--s1) var(--s2);
  font-size: .8125rem; font-weight: 500;
  color: var(--ink-soft);
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  cursor: pointer;
}
.theme-picker:hover { color: var(--ink); border-color: var(--line-strong); }
.theme-picker:focus { border-color: var(--accent); }

@media (max-width: 720px) {
  /* The bar stacks here, and a third control on its own row is more chrome than
     a phone-width page can spare. The configured default still applies. */
  .theme-picker { display: none; }
}

/* -- waiting ---------------------------------------------------------------
   A bar for "the page is coming" and a busy state for "your click landed".
   They answer different questions: a strip at the top of the window does not
   tell somebody at the bottom of a long table that their Delete registered. */

.progress {
  position: fixed; top: 0; left: 0; z-index: 60;
  height: 2px; width: 0;
  background: var(--accent);
  /* A brighter head, so a bar that has paused near the end still reads as live
     rather than as one that stopped. */
  box-shadow: 0 0 8px var(--accent), 0 0 2px var(--accent);
  opacity: 0;
  transition: width 140ms var(--ease), opacity 200ms var(--ease);
  pointer-events: none;
}
.progress.on { opacity: 1; }

/* Terminal has no radius and no glow anywhere else; a shadow here would be the
   one soft edge in the theme. */
:root[data-theme="terminal"] .progress { box-shadow: none; height: 3px; }

button[aria-busy="true"],
.button[aria-busy="true"] {
  /* Still legible, and visibly not accepting another press. */
  opacity: .75;
  cursor: progress;
}
button[aria-busy="true"]::after {
  content: "";
  display: inline-block; vertical-align: -1px;
  width: .7em; height: .7em; margin-left: .5em;
  border: 2px solid currentColor; border-top-color: transparent;
  border-radius: var(--r-full);
  animation: spin 700ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* A destructive button that is mid-flight should not also look pressable. */
button.link[aria-busy="true"] { text-decoration: none; }

@media (prefers-reduced-motion: reduce) {
  /* The bar still appears and still fills - it just stops being animated, because
     the information is "something is happening", not the movement itself. */
  .progress { transition: none; }
  button[aria-busy="true"]::after { animation: none; border-top-color: currentColor; }
}
