:root {
  --bg: #0b0b0f;
  --bg-2: #101017;
  --surface: #14141c;
  --surface-2: #1b1b25;
  --border: #262633;
  --text: #e9e9f0;
  --muted: #8a8a9a;
  --faint: #5a5a6a;
  --accent: #6d6cff;
  --accent-2: #00d3a7;
  --danger: #ff5c72;
  --warn: #ffb454;
  --radius: 12px;
  --font-ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Hiragino Kaku Gothic ProN", "Noto Sans JP", sans-serif;
  --font-mono: ui-monospace, "Cascadia Code", "JetBrains Mono", Consolas, monospace;
}

* {
  box-sizing: border-box;
}

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

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
}

button {
  font-family: inherit;
}

/* ---- Anaty mark ---- */
.anaty-mark {
  display: inline-grid;
  flex: none;
  width: 1.25rem;
  aspect-ratio: 1;
  place-items: center;
  line-height: 0;
}

.anaty-mark svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.anaty-mark__middle,
.anaty-mark__outer {
  transform-box: view-box;
  transform-origin: 627px 627px;
  will-change: transform;
}

.anaty-mark--ambient .anaty-mark__middle {
  animation: anaty-spin 22s linear infinite;
}

.anaty-mark--ambient .anaty-mark__outer {
  animation: anaty-spin-reverse 30s linear infinite;
}

.anaty-mark--thinking .anaty-mark__middle {
  animation: anaty-spin 2.2s linear infinite;
}

.anaty-mark--thinking .anaty-mark__outer {
  animation: anaty-spin-reverse 3s linear infinite;
}

.anaty-mark--thinking {
  filter: drop-shadow(0 0 4px color-mix(in oklab, #00c9f2 45%, transparent));
}

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

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

@media (prefers-reduced-motion: reduce) {
  .anaty-mark__middle,
  .anaty-mark__outer {
    animation: none !important;
    will-change: auto;
  }
}

/* ---- scrollbars ----
   Chromium's default is a light-grey chrome widget with stepper arrows and a
   raised track. On a #0b0b0f window it is the brightest thing on screen and it
   frames the conversation like a 1998 text area.

   Both mechanisms are needed and they are MUTUALLY EXCLUSIVE, which is the
   whole reason for the @supports below. `scrollbar-color` is the standard and
   is what Firefox reads; `::-webkit-scrollbar` is what Chromium reads — but
   the moment `scrollbar-color` applies to an element, Chromium honours that
   and ignores every pseudo-element rule for it. Stated globally it therefore
   silently disables all of the styling below: measured here at 15px, against
   10px once the standard property was removed. So the standard form is scoped
   to engines that have no pseudo-elements to lose. */
@supports not selector(::-webkit-scrollbar) {
  * {
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
  }
}

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  /* Inset by a transparent border rather than by width, so the thumb is a
     6px bar in a 10px lane: it never touches the content and never touches
     the edge of the window. */
  background-clip: padding-box;
  border: 2px solid transparent;
  border-radius: 999px;
  background-color: color-mix(in oklab, var(--text) 16%, transparent);
}

::-webkit-scrollbar-thumb:hover {
  background-color: color-mix(in oklab, var(--text) 30%, transparent);
}

::-webkit-scrollbar-thumb:active {
  background-color: color-mix(in oklab, var(--accent) 70%, transparent);
}

/* The corner where two bars meet, and the stepper arrows. Both are chrome
   drawn in the platform's colours, and neither has any business here. */
::-webkit-scrollbar-corner {
  background: transparent;
}

::-webkit-scrollbar-button {
  display: none;
}


/* ---- layout ---- */
.app {
  display: grid;
  grid-template-columns: 184px 1fr;
  /* The row must be the WINDOW's height, not the content's.
     An implicit grid row is `auto`-sized, so it grows to fit whatever is in
     it; `height: 100%` on the child then resolves against that grown row and
     the whole column marches off the bottom of the window — the composer with
     it. `minmax(0, 1fr)` pins the row to the container and lets it shrink,
     which is what makes the inner `overflow-y: auto` actually scroll. */
  grid-template-rows: minmax(0, 1fr);
  height: 100%;
  overflow: hidden;
}

/* The log is a real column, not an overlay: the conversation reflows to make
   room rather than being covered by the thing you opened to compare against it.
   Four tracks now — the third is the drag handle. `--logw` is set inline by the
   shell; the fallback is the width the column had before it was draggable. */
.app--log {
  grid-template-columns: 184px minmax(0, 1fr) 6px var(--logw, clamp(260px, 24vw, 380px));
}

/* ---- the seam between the conversation and the log ---- */
.resizer {
  position: relative;
  cursor: col-resize;
  /* The track is 6px, but a 6px target is a target you miss. The padding
     widens the hit area to 15px without moving anything either side of it. */
  padding-inline: 4px;
  margin-inline: -4px;
  z-index: 20;
  background: transparent;
  border: 0;
  touch-action: none;
}

.resizer__grip {
  display: block;
  width: 1px;
  height: 100%;
  margin-inline: auto;
  background: var(--border);
  transition: background 0.12s ease, width 0.12s ease;
}

.resizer:hover .resizer__grip,
.resizer:focus-visible .resizer__grip {
  width: 3px;
  background: var(--accent);
}

.resizer:focus-visible {
  outline: none;
}

/* The log's own left border would double the seam. The handle IS the border. */
.app--log .activity {
  border-left: 0;
}

/* ---- sidebar ---- */
.sidebar {
  display: flex;
  flex-direction: column;
  /* Grid items default to min-height:auto — same trap as .chat below. */
  min-height: 0;
  overflow-y: auto;
  gap: 0.35rem;
  padding: 0 0.5rem 0.5rem;
  background: var(--bg-2);
  border-right: 1px solid var(--border);
}

.sidebar__brand-row {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  height: 42px;
  min-height: 42px;
  margin-inline: -0.5rem;
  padding: 0 0.5rem;
  border-bottom: 1px solid var(--border);
}

.sidebar__brand-group {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  min-width: 0;
  white-space: nowrap;
}

.sidebar__mark {
  width: 20px;
}

.sidebar__brand-lockup {
  display: flex;
  align-items: baseline;
  gap: 0.22rem;
  min-width: 0;
}

.sidebar__brand {
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: -0.03em;
}

.sidebar__version {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.55rem;
  line-height: 1;
}

.sidebar__update.btn--sm {
  flex: none;
  transform: translateY(2px);
  height: 20px;
  min-height: 20px;
  padding: 0 0.25rem;
  border-radius: 5px;
  font-size: 0.54rem;
  line-height: 1;
  white-space: nowrap;
}

.sidebar__dot {
  color: var(--accent);
}

/* ---- telemetry chip (CPU / RAM / GPU / VRAM) ---- */
/* Three columns so the GPU rows line up under the CPU/RAM row: the third holds
   the temperature, and the CPU row leaves it empty. `1fr 1fr` splits the two metric
   cells evenly and `minmax(0, …)` lets them shrink instead of overflowing. */
.tele {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  align-items: center;
  gap: 1px 2px;
  padding: 0.2rem 0.3rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  font-size: 0.6rem;
  line-height: 1;
  /* Digits must not reflow the row as the numbers change every 3s. */
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  cursor: default;
}

.tele__metric {
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
  padding-right: 0.25rem;
}

.tele__metric--secondary {
  padding-right: 0;
}

.tele__label {
  flex: 0 0 4.2ch;
  min-width: 4.2ch;
  overflow: visible;
  white-space: nowrap;
  color: var(--muted);
  font-weight: 600;
}

.tele__label--lower {
  transform: translateY(1px);
}

/* Pushed right so every value sits on the same edge of its cell. */
.tele__value {
  flex: 0 0 4ch;
  width: 4ch;
  margin-left: auto;
  color: var(--text);
  font-family: var(--font-mono);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: right;
}

.tele__value--warn {
  color: var(--warn);
}

.tele__value--crit {
  color: var(--danger);
}

.tele__temp {
  justify-self: end;
  min-width: 4ch;
  padding-left: 0.15rem;
  color: var(--muted);
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.58rem;
  font-variant-numeric: tabular-nums;
  transform: translateY(-1px);
}

.tele__ring {
  width: 11px;
  height: 11px;
  flex: none;
}

.tele__ring circle {
  fill: none;
  stroke-width: 2.5;
}

.tele__ring-track {
  stroke: var(--border);
}

.tele__ring-fill {
  stroke-linecap: round;
  /* Start the arc at 12 o'clock instead of 3. */
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
  transition: stroke-dasharray 0.4s ease;
}

.tele__ring-fill--ok {
  stroke: var(--accent);
}

.tele__ring-fill--warn {
  stroke: var(--warn);
}

.tele__ring-fill--crit {
  stroke: var(--danger);
}

@media (prefers-reduced-motion: reduce) {
  .tele__ring-fill {
    transition: none;
  }
}

.sidebar__new {
  width: 100%;
}

.sidebar__label {
  margin-top: 0.75rem;
  padding: 0 0.5rem;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---- session list ---- */
/* Takes the sidebar's spare height: conversations are what accumulate here,
   and the connection below is picked once and then left alone. */
.sess-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  margin-top: 0;
}

.sess {
  display: flex;
  align-items: stretch;
  position: relative;
  border-radius: 10px;
  border: 1px solid transparent;
  cursor: grab;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.sess:active {
  cursor: grabbing;
}

.sess:hover {
  background: var(--surface);
}

.sess--drag-over::before {
  content: '';
  position: absolute;
  top: -2px;
  right: 4px;
  left: 4px;
  height: 2px;
  border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 6px color-mix(in oklab, var(--accent) 65%, transparent);
  pointer-events: none;
}

/* The final insertion gap owns all spare list height, so dropping below the
   last session is as easy as dropping between two rows. Only its top edge is
   highlighted: the destination is a gap, not a session card. */
.sess-list__end {
  position: relative;
  flex: 1 0 8px;
  min-height: 8px;
}

.sess-list__end--over::before {
  content: '';
  position: absolute;
  top: 1px;
  right: 4px;
  left: 4px;
  height: 2px;
  border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 6px color-mix(in oklab, var(--accent) 65%, transparent);
}

.sess--active {
  background: var(--surface);
  border-color: color-mix(in oklab, var(--accent) 45%, transparent);
}

.sess__open {
  flex: 1 1 100%;
  width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  padding: 0.25rem 0.45rem;
  background: transparent;
  border: none;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}

.sess__title {
  display: block;
  width: 100%;
  font-size: 0.78rem;
  line-height: 1.15;
  /* Keep the full session name readable; only unusually long names add a line. */
  white-space: normal;
  overflow-wrap: anywhere;
}

.sess__meta {
  font-size: 0.62rem;
  line-height: 1.1;
  color: var(--faint);
}

/* The only place a background run is visible from. */
.sess__dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 5px;
  border-radius: 50%;
  background: var(--accent-2);
  animation: sess-pulse 1.4s ease-in-out infinite;
  vertical-align: middle;
}

@keyframes sess-pulse {
  50% {
    opacity: 0.25;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sess__dot {
    animation: none;
  }
}

.sess__act {
  position: absolute;
  top: 50%;
  flex: none;
  align-self: center;
  transform: translateY(-50%);
  padding: 0 0.35rem;
  background: transparent;
  border: none;
  color: var(--faint);
  font-size: 0.9rem;
  line-height: 1;
  cursor: pointer;
  /* Hidden until the row is hovered or focused: a delete control sitting under
     the cursor on every row is an accident waiting for a mis-click. Rename
     rides the same reveal so the two read as one group. */
  opacity: 0;
}

.sess__act:not(.sess__act--danger) {
  right: 1.35rem;
}

.sess__act--danger {
  right: 0.15rem;
}

.sess:hover .sess__act,
.sess__act:focus-visible {
  opacity: 1;
}

.sess__act:hover {
  color: var(--text);
}

.sess__act--danger {
  font-size: 1rem;
}

.sess__act--danger:hover {
  color: var(--danger);
}

.sess__act:disabled {
  opacity: 0.25;
  cursor: not-allowed;
}

.sess__rename {
  width: 100%;
  padding: 0.4rem 0.5rem;
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: 10px;
  color: var(--text);
  font: inherit;
  font-size: 0.82rem;
}

.sidebar__pick {
  width: 100%;
  padding: 0.45rem 0.5rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  font: inherit;
  font-size: 0.78rem;
}

.conn-list {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  overflow-y: auto;
  flex: 1;
}

.conn-list__error {
  margin: 0.25rem 0.5rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid color-mix(in oklab, var(--danger) 45%, transparent);
  border-radius: 10px;
  background: color-mix(in oklab, var(--danger) 8%, transparent);
  color: var(--text);
  font-size: 0.72rem;
  line-height: 1.5;
}

.conn-list__empty {
  color: var(--faint);
  font-size: 0.8rem;
  padding: 0.25rem 0.5rem;
}

.conn-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 0.5rem 0.6rem;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.conn-item:hover {
  background: var(--surface);
}

.conn-item--active {
  background: var(--surface-2);
  border-color: color-mix(in oklab, var(--accent) 50%, transparent);
}

.conn-item__name {
  font-weight: 600;
}

.conn-item__model {
  font-size: 0.72rem;
  color: var(--muted);
  font-family: var(--font-mono);
}

.sidebar__settings {
  margin-top: auto;
}

/* ---- chat ---- */
.chat {
  display: flex;
  flex-direction: column;
  position: relative;
  height: 100%;
  /* Without this the grid item refuses to shrink below its content, so the
     column overflows the window instead of the scroll area scrolling. */
  min-height: 0;
  min-width: 0;
}

.chat__bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  height: 42px;
  min-height: 42px;
  padding: 0 0.75rem;
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}

.chat__title {
  flex: 0 1 auto;
  font-weight: 700;
  /* One line: a title derived from a pasted paragraph must not wrap the bar. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Reads as the heading it is until you point at it, then as a control. */
.chat__title--edit {
  max-width: 46ch;
  padding: 0.15rem 0.35rem;
  margin-left: -0.35rem;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: text;
}

.chat__title--edit:hover:not(:disabled) {
  border-color: var(--border);
  background: var(--surface);
}

.chat__title--edit:disabled {
  cursor: default;
}

.chat__titleinput {
  max-width: 46ch;
  flex: 0 1 auto;
  min-width: 0;
  padding: 0.15rem 0.35rem;
  margin-left: -0.35rem;
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: 8px;
  color: var(--text);
  font: inherit;
  font-weight: 700;
}

.chat__session-controls {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.35rem;
  min-width: 0;
  margin-left: auto;
}

.chat__model {
  flex: 0 1 clamp(24ch, 42%, 60ch);
  min-width: 0;
  max-width: 60ch;
  height: 26px;
  padding: 0 1.45rem 0 0.42rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: 6px;
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  font-size: 0.75rem;
  color: var(--muted);
  font-family: var(--font-mono);
}

.chat__settings-button {
  flex: none;
  display: grid;
  width: 26px;
  height: 26px;
  padding: 0;
  place-items: center;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

.chat__settings-button:hover:not(:disabled) {
  color: var(--text);
  border-color: var(--accent);
}

.chat__settings-button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.chat__model:hover:not(:disabled),
.chat__model:focus-visible {
  border-color: var(--accent, #8b7bd8);
  color: var(--text);
  outline: none;
}

/* not-allowed, not default: this control is temporarily locked (a run is
   in flight), not decorative. `default` reads as dead, which is what made a
   correctly-disabled select look broken. */
.chat__model:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

/* The working directory, shown the way Claude Code and Codex show a cwd:
   always on screen, because it decides what every file and command tool in
   this session can touch, and it is the thing you most need to have noticed
   BEFORE pressing send rather than after. Reads as a chip, not a button, so it
   is information first and a control second. */
.chat__cwd {
  flex: 0 1 clamp(24ch, 36%, 56ch);
  min-width: 0;
  max-width: 56ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0.1rem 0.45rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  cursor: pointer;
}

.chat__cwd:hover:not(:disabled) {
  border-color: var(--border);
  color: var(--text);
}

.chat__cwd:disabled {
  cursor: default;
  opacity: 0.5;
}

/* Deliberately no sandbox: the file and command tools are OFF. Warning
   colour, because the failure it prevents is silent — the model simply
   reports that it cannot read anything, and nothing on screen says why. */
.chat__cwd--off {
  color: var(--danger, #f87171);
  border-color: color-mix(in srgb, var(--danger, #f87171) 35%, transparent);
}

.chat__scroll {
  flex: 1;
  /* A flex item defaults to min-height:auto, i.e. "never shrink below my
     content". With enough messages the scroll area therefore grew past the
     window and pushed the composer out of view instead of scrolling — the
     shorter the window, the worse. This is the fix; the `flex: none` rules on
     the surrounding chrome below are the other half. */
  min-height: 0;
  overflow-y: auto;
  padding: 1.25rem;
  /* AFTER the shorthand, deliberately: vertical padding shrinks with the
     window so the transcript gives up its last pixels before the composer
     has to. */
  padding-block: clamp(0px, 2vh, 1.25rem);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

/* The transcript SCROLLS; it never compresses.
   `.chat__scroll` is a column flex container, so its children are flex items
   and shrink by default. A flex item is normally protected from that by
   `min-height: auto` — but only while its `overflow` is `visible`. `.tool`
   sets `overflow: hidden` (to clip its rounded corners), which drops its
   automatic minimum size to 0, so once a run produced more tool cards than fit,
   every one of them was squeezed to its two borders: a screen of bare
   horizontal lines, red where the card was error/denied, with no text and
   nothing to scroll. Observed 2026-08-20.
   Stated as `> *` rather than on `.tool` on purpose — any future item that
   clips its own overflow inherits the fix instead of rediscovering the bug. */
.chat__scroll > * {
  flex: none;
}

.chat__empty {
  margin: auto;
  text-align: center;
}

.chat__empty-title {
  font-size: 1.4rem;
  font-weight: 700;
  margin: 0 0 0.4rem;
}

.chat__empty-sub {
  color: var(--muted);
  margin: 0;
}

.msg {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  max-width: 760px;
  width: 100%;
  margin: 0 auto;
}

.msg__role {
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Secondary to the model name: which connection it came through, for when
   two profiles point at the same model. */
.msg__provider {
  margin-left: 0.4rem;
  padding-left: 0.4rem;
  border-left: 1px solid var(--border);
  color: var(--faint);
  text-transform: none;
}

.msg__body {
  white-space: pre-wrap;
  line-height: 1.6;
  padding: 0.7rem 0.95rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
}

/* ---- rendered markdown ----
   `.msg__body` is `white-space: pre-wrap`, which is right for plain text and
   wrong the moment there is structure: it would keep every newline the source
   had AND the margins the blocks bring, doubling the gaps. Inside `.md` the
   blocks own the spacing. */
.md {
  white-space: normal;
}

.md > :first-child {
  margin-top: 0;
}

.md > :last-child {
  margin-bottom: 0;
}

.md p {
  margin: 0 0 0.65em;
}

.md__h {
  /* Chat headings are signposts in a paragraph of text, not a document title —
     a browser-default <h1> next to 14px body text reads as shouting. */
  margin: 1.1em 0 0.5em;
  line-height: 1.35;
  font-weight: 700;
}

.md h1.md__h {
  font-size: 1.28em;
}
.md h2.md__h {
  font-size: 1.16em;
}
.md h3.md__h {
  font-size: 1.06em;
}
.md h4.md__h,
.md h5.md__h,
.md h6.md__h {
  font-size: 1em;
  color: var(--muted);
}

.md__list {
  margin: 0 0 0.65em;
  padding-left: 1.4em;
}

.md__list li {
  margin: 0.15em 0;
}

.md__list .md__list {
  margin-bottom: 0;
}

.md__code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  padding: 0.12em 0.35em;
  border-radius: 5px;
  background: color-mix(in oklab, var(--text) 10%, transparent);
  overflow-wrap: anywhere;
}

/* The label is a sibling of the <pre>, not a child — see Markdown.tsx. The
   wrapper is what carries the positioning context. */
.md__codeblock {
  position: relative;
  margin: 0.6em 0;
}

.md__pre {
  margin: 0;
  padding: 0.7em 0.85em;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg);
  /* The one place sideways scrolling is right: code must not be re-wrapped,
     because a wrapped line is a different line. It scrolls in its own box, so
     the transcript column itself never does. */
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 0.86em;
  line-height: 1.5;
}

.md__pre code {
  font: inherit;
  white-space: pre;
}

.md__lang {
  position: absolute;
  top: 0.35em;
  right: 0.6em;
  font-size: 0.78em;
  color: var(--faint);
  user-select: none;
  pointer-events: none;
}

.md__quote {
  margin: 0.6em 0;
  padding: 0.1em 0 0.1em 0.85em;
  border-left: 3px solid color-mix(in oklab, var(--accent) 55%, transparent);
  color: var(--muted);
}

.md__hr {
  margin: 1em 0;
  border: 0;
  border-top: 1px solid var(--border);
}

.md a {
  color: var(--accent-2);
  text-decoration-color: color-mix(in oklab, var(--accent-2) 45%, transparent);
  text-underline-offset: 2px;
  overflow-wrap: anywhere;
}

.md a:hover {
  text-decoration-color: currentColor;
}

/* A table the model wrote is wider than the column it lands in more often than
   not. It gets its own scroll box, so the transcript never scrolls sideways —
   same rule as the tool cards and the code blocks. */
.md__tablewrap {
  margin: 0.7em 0;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
}

.md__table {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.92em;
}

.md__table th,
.md__table td {
  padding: 0.42em 0.7em;
  border-bottom: 1px solid var(--border);
  border-right: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
}

.md__table th:last-child,
.md__table td:last-child {
  border-right: 0;
}

.md__table tbody tr:last-child td {
  border-bottom: 0;
}

.md__table thead th {
  background: color-mix(in oklab, var(--text) 6%, transparent);
  font-weight: 700;
  white-space: nowrap;
}

.md__table tbody tr:nth-child(even) {
  /* Zebra striping, faint. The tables models write are wide and the eye loses
     its row halfway across. */
  background: color-mix(in oklab, var(--text) 3%, transparent);
}

.msg--user .msg__body {
  background: color-mix(in oklab, var(--accent) 14%, var(--surface));
  border-color: color-mix(in oklab, var(--accent) 35%, transparent);
}

.msg--assistant .msg__body {
  background: var(--surface);
}

/* The run's reading of the request, framed so it can be found at a glance.
   Asked for 2026-09-04: the interpretation was arriving as an ordinary reply,
   so knowing what the model thought it had been asked meant reading the top of
   a wall of text and inferring it. A rail and a label make it a place. */
.msg--interpretation .msg__body {
  background: color-mix(in oklab, var(--accent) 7%, var(--surface));
  border-left: 2px solid color-mix(in oklab, var(--accent) 55%, transparent);
  border-radius: 0;
}

.msg__tag {
  margin-right: 0.5rem;
  padding: 0.05rem 0.4rem;
  border-radius: 3px;
  background: color-mix(in oklab, var(--accent) 22%, transparent);
  color: var(--accent-2, var(--accent));
  letter-spacing: 0.04em;
}

.msg__caret {
  display: inline-block;
  width: 8px;
  height: 1.05em;
  vertical-align: text-bottom;
  background: var(--accent-2);
  animation: blink 1s steps(2) infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

/* ---- composer ---- */
/* Always reachable: the composer is the one element that must survive any
   window height. */
.composer {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: end;
  padding: 0.9rem 1.25rem 1.1rem;
  border-top: 1px solid var(--border);
}

.composer__chips {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  width: 100%;
  margin: 0;
}

.composer__controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.6rem;
  align-items: end;
  width: 100%;
}

.composer__input {
  grid-column: 1;
  grid-row: 1;
  width: 100%;
  min-width: 0;
  resize: none;
  /* Bounded: a pasted wall of text scrolls inside the box instead of growing
     the composer until the conversation is off-screen. */
  max-height: min(40vh, 260px);
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  padding: 0.65rem 0.8rem;
  font-size: 0.95rem;
  line-height: 1.5;
  outline: none;
}

.composer__input:focus {
  border-color: color-mix(in oklab, var(--accent) 55%, transparent);
}

.composer__actions {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.35rem;
}

.composer__actions > .btn {
  width: 100%;
}

/* ---- buttons ---- */
.btn {
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  padding: 0.5rem 0.9rem;
  border-radius: 10px;
  cursor: pointer;
  font-weight: 600;
  transition: filter 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}

.btn:hover:not(:disabled) {
  filter: brightness(1.15);
}

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn--primary {
  background: linear-gradient(135deg, var(--accent), color-mix(in oklab, var(--accent) 70%, var(--accent-2)));
  border-color: transparent;
  color: white;
}

.btn--ghost {
  background: transparent;
}

.btn--ghost:hover:not(:disabled) {
  background: var(--surface);
}

.btn--stop {
  background: transparent;
  border-color: color-mix(in oklab, var(--danger) 60%, transparent);
  color: var(--danger);
}

.btn--sm {
  padding: 0.3rem 0.6rem;
  font-size: 0.78rem;
}

.sidebar__new {
  height: 26px;
  min-height: 26px;
  padding: 0 0.65rem;
  border-radius: 8px;
  color: var(--muted);
  font-size: 0.75rem;
  line-height: 1;
}

/* ---- modal / connection manager ---- */
.modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
}

.modal__panel {
  width: min(880px, 92vw);
  max-height: 86vh;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 16px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
}

.modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
}

.modal__head h2 {
  margin: 0;
  font-size: 1.05rem;
}

.modal__x {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
}

.modal__body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
  padding: 1.25rem;
  overflow-y: auto;
}

.conn-manage {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.conn-row {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.conn-row__info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.conn-row__name {
  font-weight: 600;
}

.conn-row__meta {
  font-size: 0.72rem;
  color: var(--accent-2);
  font-family: var(--font-mono);
}

.conn-row__url {
  font-size: 0.72rem;
  color: var(--muted);
  font-family: var(--font-mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.conn-row__actions {
  display: flex;
  gap: 0.3rem;
  align-items: flex-start;
  flex-shrink: 0;
}

.conn-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem;
}

.conn-form__title {
  font-weight: 700;
  margin-bottom: 0.2rem;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.field > span {
  font-size: 0.78rem;
  color: var(--muted);
}

.field em {
  color: var(--faint);
  font-style: normal;
}

.field input,
.field select {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text);
  padding: 0.5rem 0.65rem;
  font-size: 0.9rem;
  outline: none;
}

.field input:focus,
.field select:focus {
  border-color: color-mix(in oklab, var(--accent) 55%, transparent);
}

/* ---- inline connection help ---- */
/* Collapsed by default: it answers a question you only have once, and an
   always-open block would push the form it explains off the panel. */
.conn-help {
  border: 1px dashed var(--border);
  border-radius: 10px;
  padding: 0.4rem 0.6rem;
  font-size: 0.72rem;
  color: var(--muted);
}

.conn-help > summary {
  cursor: pointer;
  list-style: none;
  color: var(--accent);
}

.conn-help > summary::marker,
.conn-help > summary::-webkit-details-marker {
  display: none;
}

.conn-help > summary::before {
  content: '\25b8 ';
}

.conn-help[open] > summary::before {
  content: '\25be ';
}

.conn-help__note {
  margin: 0.5rem 0 0;
  line-height: 1.7;
}

.conn-help code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  color: var(--accent-2);
}

.conn-help__table {
  width: 100%;
  margin-top: 0.5rem;
  border-collapse: collapse;
}

.conn-help__table th {
  width: 8.5rem;
  padding: 0.2rem 0.5rem 0.2rem 0;
  text-align: left;
  font-weight: 600;
  color: var(--text);
  vertical-align: top;
  white-space: nowrap;
}

.conn-help__table td {
  padding: 0.2rem 0;
  vertical-align: top;
}

.conn-form__warn {
  margin: 0.35rem 0 0;
  font-size: 0.72rem;
  line-height: 1.6;
  color: var(--warn);
}

.conn-form__revert {
  align-self: flex-start;
  margin-top: 0.35rem;
}

.conn-form__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.3rem;
}

.conn-form__spacer {
  flex: 1;
}

.conn-form__result {
  margin: 0.2rem 0 0;
  font-size: 0.82rem;
  font-family: var(--font-mono);
  /* The detail now carries the attempted URL and the advice on their own
     lines; collapsing them would put the fix back out of sight. */
  white-space: pre-line;
}

.conn-form__result.is-ok {
  color: var(--accent-2);
}

.conn-form__result.is-err {
  color: var(--danger);
}

@media (max-width: 720px) {
  .modal__body {
    grid-template-columns: 1fr;
  }
}

/* ---- sidebar footer ---- */
/* ---- provider account usage ---- */
/* Only rendered when a provider actually reported a figure, so this never
   shows an empty bar that could be read as zero. */
.acct {
  margin-top: 0.5rem;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  font-size: 0.68rem;
  cursor: default;
}

.acct__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}

.acct__label {
  color: var(--muted);
  font-weight: 600;
}

.acct__pct {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.acct__bar {
  height: 4px;
  margin: 0.3rem 0;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}

.acct__fill {
  height: 100%;
  background: var(--accent);
  transition: width 0.4s ease;
}

.acct--warn .acct__fill { background: var(--warn); }
.acct--warn .acct__pct  { color: var(--warn); }
.acct--crit .acct__fill { background: var(--danger); }
.acct--crit .acct__pct  { color: var(--danger); }

.acct__text {
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}

.acct__reset {
  margin-left: 0.35rem;
}

@media (prefers-reduced-motion: reduce) {
  .acct__fill { transition: none; }
}

.sidebar__footer {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.sidebar__tools {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.25rem;
}

.sidebar__tools .btn {
  height: 28px;
  min-height: 28px;
  padding: 0 0.35rem;
  border-radius: 8px;
  font-size: 0.74rem;
  line-height: 1;
}

.sidebar__account {
  margin-top: 0.15rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--border);
}

.sidebar__account-id {
  display: block;
  margin-bottom: 0.25rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.72rem;
  line-height: 1.2;
}

.sidebar__account-email {
  color: var(--muted);
}

.sidebar__account-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.4rem;
}

.sidebar__account .btn {
  height: 26px;
  min-height: 26px;
  padding: 0 0.35rem;
  font-size: 0.72rem;
  line-height: 1;
  width: 100%;
}

.sidebar__quit {
  color: var(--danger);
}

/* ---- chat error banner ---- */
.chat__error {
  max-width: 760px;
  width: 100%;
  margin: 0 auto;
  padding: 0.6rem 0.9rem;
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--danger) 14%, var(--surface));
  border: 1px solid color-mix(in oklab, var(--danger) 45%, transparent);
  color: var(--danger);
  font-size: 0.85rem;
}

/* ---- tool call cards ---- */
.tool {
  max-width: 760px;
  width: 100%;
  margin: 0 auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.tool--awaiting {
  border-color: color-mix(in oklab, #f5a623 55%, transparent);
}
.tool--error,
.tool--denied {
  border-color: color-mix(in oklab, var(--danger) 45%, transparent);
}

.tool__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.55rem 0.8rem;
  background: var(--surface-2);
}

/* The header is the toggle. Reset the button chrome so it still reads as the
   card's title bar, and give the whole row the hand cursor so the affordance
   is the row, not a tiny chevron. */
.tool__head--toggle {
  width: 100%;
  gap: 0.5rem;
  border: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.tool__head--toggle:hover {
  background: color-mix(in oklab, var(--surface-2) 80%, var(--accent) 20%);
}

/* Collapsed tool calls are primarily a transcript index. Keep their one-line
   headers compact while leaving expanded arguments and results comfortable to
   read. */
.tool--collapsed .tool__head {
  min-height: 22px;
  padding: 0.12rem 0.45rem;
  line-height: 1.2;
}

.tool--collapsed .tool__head--toggle {
  gap: 0.22rem;
}

.tool--collapsed .tool__badge {
  padding: 0 0.32rem;
  line-height: 1.25;
}

.tool--collapsed .tool__chev {
  width: 0.65rem;
  font-size: 0.68rem;
}

.tool--collapsed .tool__gist {
  font-size: 0.66rem;
}

.tool--collapsed .tool__name {
  font-size: 0.72rem;
}

.tool__chev {
  flex: none;
  width: 0.9rem;
  color: var(--faint);
  font-size: 0.8rem;
}

/* One-line summary shown only while collapsed: takes the slack, truncates. */
.tool__gist {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--muted);
}

.tool__head--toggle .tool__name {
  flex: none;
}

.tool__head--toggle .tool__badge {
  flex: none;
  margin-left: auto;
}

.tool__name {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 600;
}

.tool__badge {
  font-size: 0.68rem;
  padding: 0.12rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
}
.tool__badge--running {
  color: var(--accent);
  border-color: color-mix(in oklab, var(--accent) 45%, transparent);
}
.tool__badge--awaiting {
  color: #f5a623;
  border-color: color-mix(in oklab, #f5a623 50%, transparent);
}
.tool__badge--done {
  color: var(--accent-2);
  border-color: color-mix(in oklab, var(--accent-2) 45%, transparent);
}
.tool__badge--denied,
.tool__badge--error {
  color: var(--danger);
  border-color: color-mix(in oklab, var(--danger) 45%, transparent);
}

.tool__args,
.tool__result {
  margin: 0;
  padding: 0.6rem 0.8rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 260px;
  overflow: auto;
}

.tool__result {
  border-top: 1px dashed var(--border);
  color: var(--muted);
}

.tool__approve {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.6rem 0.8rem;
  border-top: 1px solid var(--border);
  background: color-mix(in oklab, #f5a623 8%, transparent);
}

.tool__approve-q {
  font-size: 0.82rem;
}

.tool__approve-actions {
  display: flex;
  gap: 0.4rem;
  flex-shrink: 0;
}

/* ---- settings panel ---- */
.modal__panel--narrow {
  width: min(640px, 92vw);
}

.modal__body--single {
  grid-template-columns: 1fr;
  display: block;
}

.settings {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

.settings__group {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.settings__label {
  font-size: 0.78rem;
  color: var(--muted);
  font-weight: 600;
}

.settings__row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.settings__path {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 0.45rem 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--accent-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.settings__hint {
  margin: 0;
  font-size: 0.74rem;
  color: var(--faint);
}

.settings__toggle {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 0.88rem;
  cursor: pointer;
}

.settings__num {
  width: 90px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text);
  padding: 0.4rem 0.55rem;
}

.settings__text,
.settings__group select {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text);
  padding: 0.45rem 0.55rem;
}

/* ---- system prompt editor ---- */

/* The prompt is long, so the field is a real editing surface rather than a
   token gesture at one. Monospace because the default is structured Markdown
   with fenced tool names, and proportional type makes its shape unreadable. */
.settings__prompt {
  width: 100%;
  box-sizing: border-box;
  min-height: 260px;
  resize: vertical;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text);
  padding: 0.55rem 0.65rem;
  font-family: var(--font-mono);
  font-size: 0.76rem;
  line-height: 1.6;
  /* The default prompt has no long unbroken tokens, but a pasted one might,
     and the modal must not start scrolling sideways because of it. */
  overflow-wrap: anywhere;
}

.settings__prompt:focus-visible {
  outline: none;
  border-color: var(--accent);
}

/* States the eye should catch without reading: whether this install is on the
   built-in prompt or a pinned copy of its own. */
.settings__badge {
  margin-left: 0.5rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--faint);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.settings__badge--on {
  border-color: color-mix(in oklab, var(--accent) 45%, transparent);
  background: color-mix(in oklab, var(--accent) 16%, transparent);
  color: var(--accent-2);
}

.settings__count {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}

.settings__count--over {
  color: var(--danger);
}

.settings__actions {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.settings__saved {
  font-size: 0.72rem;
  color: var(--accent-2);
}

/* The org value's provenance — live, or a cached copy and how old. Muted
   because it is context for the line above it, not a warning of its own. */
.settings__stale {
  color: var(--faint);
}

/* A failed publish must not look like a saved one. */
.settings__hint--error {
  color: var(--danger);
}

/* Not decoration: this one says which safeguards a person is about to delete. */
.settings__hint--warn {
  color: var(--warn);
}

.settings__tools {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.settings__tool {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
}

.settings__tool-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.settings__tool-name {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  font-weight: 600;
}

.settings__tool-desc {
  font-size: 0.76rem;
  color: var(--muted);
}

/* A tool the model is not being offered. Dimmed rather than hidden: the user
   still needs to know it exists and what would switch it back on. */
.settings__tool--off {
  opacity: 0.55;
}
.settings__tool-why {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.72rem;
  color: var(--warning, #fbbf24);
}
.tool__badge--off {
  color: var(--muted);
  border-color: color-mix(in oklab, var(--muted) 45%, transparent);
}

/* ---- web token gate ---- */
.gate {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
  overflow: hidden;
  padding: 1rem;
}

.gate__glow {
  position: absolute;
  inset: -40% 20% auto 20%;
  height: 60vh;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--accent) 35%, transparent), transparent);
  filter: blur(40px);
  opacity: 0.5;
  pointer-events: none;
}

.gate__brand {
  font-size: clamp(2.2rem, 1.4rem + 3.5vw, 3.6rem);
  font-weight: 800;
  letter-spacing: -0.04em;
  margin: 0;
  background: linear-gradient(120deg, var(--text), var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.gate__brand-lockup {
  display: flex;
  align-items: center;
  gap: 0.8rem;
}

.gate__mark {
  width: 4.4rem;
}

.gate__dot {
  color: var(--accent);
  -webkit-text-fill-color: var(--accent);
}

.gate__tag {
  margin: 0;
  color: var(--muted);
}

.gate__form {
  display: flex;
  gap: 0.5rem;
  width: min(420px, 90vw);
}

.gate__input {
  flex: 1;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  padding: 0.6rem 0.8rem;
  outline: none;
}

.gate__input:focus {
  border-color: color-mix(in oklab, var(--accent) 55%, transparent);
}

/* Two actions when the gate is reachable-but-not-signed-in vs offline. */
.gate__actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  justify-content: center;
}

.gate__error {
  margin: 0;
  color: var(--danger);
  font-size: 0.85rem;
}

/* ---- responsive: mobile drawer ---- */
.chat__menu {
  display: none;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  width: 34px;
  height: 34px;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
}

.sidebar__backdrop {
  display: none;
}

@media (max-width: 760px) {
  .app {
    grid-template-columns: 1fr;
  }

  .chat__menu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(80vw, 280px);
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    z-index: 60;
    box-shadow: 0 0 50px rgba(0, 0, 0, 0.55);
  }

  .sidebar--open {
    transform: translateX(0);
  }

  .sidebar__backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 55;
  }

  .chat__bar {
    gap: 0.6rem;
  }

  .chat__scroll {
    padding: 1rem 0.8rem;
  }

  .composer {
    padding: 0.7rem 0.8rem 0.9rem;
  }

  .msg,
  .tool,
  .chat__error {
    max-width: 100%;
  }

  .modal {
    padding: 0;
  }

  .modal__panel {
    max-height: 100vh;
    border-radius: 0;
    width: 100vw;
  }

  /* Below this width there is no room for a third column, so the log becomes a
     drawer over the conversation — the mirror of what the nav does on the left. */
  .app--log {
    grid-template-columns: 1fr;
  }

  /* No seam to drag when the log is an overlay rather than a column. */
  .resizer {
    display: none;
  }

  .app--log .activity {
    border-left: 1px solid var(--border);
  }

  .activity {
    position: fixed;
    top: 0;
    bottom: 0;
    right: 0;
    width: min(88vw, 340px);
    z-index: 60;
    box-shadow: 0 0 50px rgba(0, 0, 0, 0.55);
  }

  /* Specificity, not just source order: the base `display: none` below sits
     LATER in the file, and at equal specificity the later rule wins even from
     outside a media query. */
  .app--log .activity__backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 55;
  }
}

/* ---- working / thinking indicator ---- */
.msg__working {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted);
}

.msg__working-mark {
  width: 22px;
}

/* Per-model inference params (settings) + the context meter (chat header).
   2026-08-16: these knobs existed in the engine for months with no way to
   reach them from the UI, and the meter is what makes the effective window
   auditable rather than asserted. */
.settings__row--between {
  justify-content: space-between;
  align-items: center;
}

.settings__field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 10px;
  font-size: 12px;
  color: var(--ink-2, #b9b3c9);
}

.settings__field > span {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.settings__field b {
  color: var(--ink, #efe9ff);
  font-variant-numeric: tabular-nums;
}

.settings__field input[type='range'] {
  width: 100%;
}

.ctxmeter {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 12px;
  font-size: 11px;
  color: var(--ink-3, #8b849c);
}

.ctxmeter__bar {
  position: relative;
  flex: 1;
  height: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}

.ctxmeter__fill {
  height: 100%;
  transition: width 200ms ease-out, background 200ms ease-out;
}

.ctxmeter__num {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ctxmeter__used {
  color: color-mix(in srgb, var(--accent) 65%, var(--text));
  font-weight: 600;
}

.ctxmeter__unit {
  margin-left: 0.25rem;
}

.ctxmeter__unknown {
  margin-left: 0.4rem;
}

/* Run play-by-play. Open by default so progress is visible without a detour. */
/* ---- 実行ログ: full-height right column ---- */
.activity {
  /* A grid column of .app, so it is as tall as the window and never competes
     with the composer for vertical space. Long chronological lists read by
     their SHAPE — the same phase five times, a retry, a recovery followed by
     another timeout — and twenty visible lines show that where three did not. */
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  border-left: 1px solid var(--border);
  background: var(--bg-2);
  font-size: 11px;
}

.activity__head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px;
  height: 42px; /* lines up with .chat__bar */
  min-height: 42px;
  border-bottom: 1px solid var(--border);
}

.activity__title {
  flex: none;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--text);
  white-space: nowrap;
}

.activity__count {
  flex: none;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  opacity: 0.7;
}

.activity__x {
  flex: none;
  margin-left: auto;
  background: transparent;
  border: 0;
  color: var(--muted);
  cursor: pointer;
  font-size: 12px;
  padding: 2px 3px;
}
.activity__x:hover {
  color: var(--text);
}

.activity__scroll {
  /* Takes all remaining height; min-height:0 is what lets it scroll instead of
     stretching the column. */
  flex: 1;
  min-height: 0;
  /* Vertical only. A log that scrolls sideways hides the end of a line behind
     a gesture nobody makes while reading a chronological list — and the end of
     the line is where the error message is. Everything inside wraps instead. */
  overflow-y: auto;
  overflow-x: hidden;
  padding: 8px 10px;
  background: rgba(0, 0, 0, 0.25);
}

/* The other half of "no horizontal scroll": with the overflow hidden, anything
   that cannot wrap is simply cut off instead. A path, a URL or a stack frame
   has no spaces to break at, so it is allowed to break anywhere. */
.activity__scroll,
.activity__scroll * {
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: normal;
}

.activity__row {
  display: flex;
  gap: 8px;
  align-items: baseline;
  line-height: 1.6;
  /* Wraps now: a narrow column would otherwise hide the end of every line,
     and the detail is often the part that matters. */
  flex-wrap: wrap;
}

.activity__row--block {
  flex-direction: column;
  align-items: stretch;
  gap: 0.2rem;
}

.activity__blockhead {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
}

/* The merged reasoning. Pre-wrap so the model's own paragraph breaks survive;
   a slightly smaller, calmer face than the event rows because it is prose
   to be read, not events to be scanned. */
.activity__block {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-height: 1.55;
  font-size: 0.74rem;
  color: #c7cdf5;
  padding: 0.15rem 0 0.25rem 0.25rem;
  border-left: 2px solid color-mix(in oklab, #a5b4fc 45%, transparent);
}

.activity__time {
  color: var(--muted);
  opacity: 0.6;
  font-variant-numeric: tabular-nums;
  flex: none;
}

.activity__label {
  /* Was `flex: none`. It is the short half of the row, but "short" is the
     model's opinion — a tool name it invented can be longer than the column,
     and with the sideways scroll gone that would clip rather than wrap. */
  flex: 0 1 auto;
}

.activity__detail {
  color: var(--muted);
  min-width: 0;
  overflow-wrap: anywhere;
}

.activity__empty {
  padding: 6px 2px;
  color: var(--muted);
}

.activity__foot {
  flex: none;
  padding: 6px 10px;
  border-top: 1px solid var(--border);
  color: var(--muted);
}

/* Only ever shown on narrow screens, where the column becomes a drawer. */
.activity__backdrop {
  display: none;
}

/* Vertical toggle at the conversation/log boundary. It remains available when
   the log is open, so the header does not need another horizontal control. */
.chat__lograil {
  position: absolute;
  top: 50%;
  right: 0;
  z-index: 15;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  width: 18px;
  min-height: 72px;
  padding: 0.35rem 0.1rem;
  border: 1px solid var(--border);
  border-right: 0;
  border-radius: 8px 0 0 8px;
  background: var(--surface-2);
  color: var(--muted);
  cursor: pointer;
  transform: translateY(-50%);
}

.chat__lograil:hover {
  color: var(--text);
  border-color: var(--accent, #8b7bd8);
  background: color-mix(in oklab, var(--surface-2) 82%, var(--accent) 18%);
}

.chat__lograil--closed {
  color: var(--text);
  border-color: var(--accent, #8b7bd8);
  background: color-mix(in oklab, var(--accent) 16%, var(--surface-2));
}

.chat__lograil-arrow {
  font-size: 0.85rem;
  line-height: 1;
}

.chat__lograil-label {
  writing-mode: vertical-rl;
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  line-height: 1;
}

.composer__chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 11px;
  color: var(--ink-2, #b9b3c9);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.composer__chip-x {
  background: transparent;
  border: 0;
  color: var(--muted);
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
}

.composer__attach {
  flex: none;
  padding: 6px 10px;
}

/* Measured-token badge on a message bubble. Deliberately quiet: it is
   reference information, not part of the message. */
.msg__tokens {
  /* .msg__role uppercases its text; the badge must not read "1,234 TOK". */
  text-transform: none;
  letter-spacing: 0;
  margin-left: 0.5rem;
  padding: 0.05rem 0.36rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  cursor: help;
}

/* Release the model's VRAM. Sits at the right edge of the chat header. */
.chat__unload {
  flex: none;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  font-size: 0.75rem;
  cursor: pointer;
}

.settings__hint--scope {
  min-width: 0;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat__unload:hover:not(:disabled) {
  color: var(--text);
  border-color: var(--accent, #8b7bd8);
}
.chat__unload:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* 要約ボタン — lives in the context meter row, acting on what the bar shows. */
.ctxmeter__compact {
  flex: none;
  margin-left: 4px;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font-size: 10.5px;
  cursor: pointer;
}
.ctxmeter__compact:hover:not(:disabled) {
  color: var(--text);
  border-color: var(--accent, #8b7bd8);
}
.ctxmeter__compact:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* A thing that happened TO the conversation: a divider, not a message. The
   summary itself is one click away rather than filling the transcript. */
.notice {
  align-self: center;
  max-width: 760px;
  width: 100%;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  padding: 6px 10px;
  font-size: 11.5px;
  color: var(--muted);
}
/* A run that ended early is not the same kind of event as a 要約, and the
   dashed muted style reads as "housekeeping, ignore me" — exactly the wrong
   cue for the one line explaining why the work stopped. */
.notice--warn {
  border-style: solid;
  border-color: color-mix(in oklab, var(--warn) 45%, transparent);
  background: color-mix(in oklab, var(--warn) 7%, transparent);
  color: var(--text);
}

.notice__line {
  cursor: pointer;
  list-style: none;
}
.notice__line::marker,
.notice__line::-webkit-details-marker {
  display: none;
}
.notice__line::before {
  content: '▸ ';
  opacity: 0.7;
}
.notice[open] .notice__line::before {
  content: '▾ ';
}
.notice__body {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
  white-space: pre-wrap;
  color: var(--ink-2, #b9b3c9);
  line-height: 1.65;
}

/* ---- run meter ---- */
/* Sits under the context meter and reads as the same family: same size, same
   muted ink, same padding. It answers a different question — how long has this
   been going and is anything coming out — so it is a separate row rather than
   more numbers crowded onto the context line. */
.runmeter {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px 4px;
  font-size: 11px;
  color: var(--ink-3, #8b849c);
}

/* A finished run keeps its final figures, dimmed so a still number is never
   mistaken for a stalled clock. */
.runmeter--done {
  opacity: 0.6;
}

.runmeter__label {
  letter-spacing: 0.06em;
}

/* Both figures change once a second; tabular digits stop the row twitching. */
.runmeter__elapsed,
.runmeter__rate {
  font-variant-numeric: tabular-nums;
}

.runmeter__rate {
  color: var(--ink-2, #b3adc4);
}

/* The model's own rate, distinguished from the wall-clock one beside it. The
   two are meant to be compared, so they sit together and differ only in ink. */
.runmeter__genrate {
  font-variant-numeric: tabular-nums;
  color: var(--ink-3, #8b849c);
}
