/* avy — compact, dense, two-theme. Hand-written, no build step.
 *
 * Theming: the light palette is the base definition on :root. Dark is redefined twice — once
 * behind prefers-color-scheme (guarded so an explicit light choice still wins) and once behind
 * [data-theme="dark"] (so the toggle wins in both directions). Nothing gets its only definition
 * inside a media query. */

:root {
  --bg-0: #ffffff;
  --bg-1: #f4f5f8;
  --bg-2: #e9ebf0;
  --bg-3: #dcdfe7;
  --border: #d6d9e2;
  --border-soft: #e4e6ed;
  --text-0: #1b1c21;
  --text-1: #4d505a;
  --text-2: #767987;
  --accent: #3f5ad4;
  --accent-2: #2c43ac;
  --on-accent: #ffffff;
  --ok: #12945a;
  --warn: #96690a;
  --bad: #c33049;
  --shadow: 0 10px 30px rgba(18, 22, 40, 0.18);
  --scrim: rgba(20, 24, 38, 0.42);
  --scrollbar: #c2c6d2;
  /* Code surfaces sit *under* the bubble rather than on it, so a fenced block reads as an inset
     panel in both palettes instead of a slightly different shade of the same card. */
  --code-bg: #f7f8fb;
  --code-border: #e0e3ec;
  --quote-bar: #c9cdda;

  --radius: 7px;
  --radius-lg: 10px;
  --rail-w: 236px;
  --chats-w: 272px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg-0: #1a1b20;
    --bg-1: #212228;
    --bg-2: #2b2d35;
    --bg-3: #363943;
    --border: #383b45;
    --border-soft: #2c2e37;
    --text-0: #e8e9ee;
    --text-1: #b6b8c2;
    --text-2: #8a8c98;
    --accent: #6d8dff;
    --accent-2: #8aa3ff;
    --on-accent: #111420;
    --ok: #57c78a;
    --warn: #e0b34d;
    --bad: #e0616f;
    --shadow: 0 10px 34px rgba(0, 0, 0, 0.55);
    --scrim: rgba(0, 0, 0, 0.55);
    --scrollbar: #43464f;
    --code-bg: #131418;
    --code-border: #32353e;
    --quote-bar: #4a4d58;
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg-0: #1a1b20;
  --bg-1: #212228;
  --bg-2: #2b2d35;
  --bg-3: #363943;
  --border: #383b45;
  --border-soft: #2c2e37;
  --text-0: #e8e9ee;
  --text-1: #b6b8c2;
  --text-2: #8a8c98;
  --accent: #6d8dff;
  --accent-2: #8aa3ff;
  --on-accent: #111420;
  --ok: #57c78a;
  --warn: #e0b34d;
  --bad: #e0616f;
  --shadow: 0 10px 34px rgba(0, 0, 0, 0.55);
  --scrim: rgba(0, 0, 0, 0.55);
  --scrollbar: #43464f;
  --code-bg: #131418;
  --code-border: #32353e;
  --quote-bar: #4a4d58;
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg-0);
  color: var(--text-0);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.45;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Every pane scrolls on its own now, so the bars are everywhere. Keep them out of the way. */
.rail-projects,
.chat-list,
.new-chat,
.transcript,
.landing,
.empty-state {
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar) transparent;
}

.rail-projects::-webkit-scrollbar,
.chat-list::-webkit-scrollbar,
.new-chat::-webkit-scrollbar,
.transcript::-webkit-scrollbar,
.landing::-webkit-scrollbar,
.empty-state::-webkit-scrollbar {
  width: 10px;
}

.rail-projects::-webkit-scrollbar-thumb,
.chat-list::-webkit-scrollbar-thumb,
.new-chat::-webkit-scrollbar-thumb,
.transcript::-webkit-scrollbar-thumb,
.landing::-webkit-scrollbar-thumb,
.empty-state::-webkit-scrollbar-thumb {
  background: var(--scrollbar);
  border: 3px solid transparent;
  background-clip: content-box;
  border-radius: 999px;
}

.rail-projects::-webkit-scrollbar-track,
.chat-list::-webkit-scrollbar-track,
.new-chat::-webkit-scrollbar-track,
.transcript::-webkit-scrollbar-track,
.landing::-webkit-scrollbar-track,
.empty-state::-webkit-scrollbar-track {
  background: transparent;
}

/* ---------------------------------------------------------------- layout
 *
 * One viewport-tall grid that never itself scrolls; each pane owns its own scrollbar. The
 * explicit `minmax(0, 1fr)` row is what stops the panes from being sized by their content —
 * without it the implicit `auto` row grows past 100dvh and the whole document scrolls. */

.app-shell {
  display: grid;
  grid-template-columns: var(--rail-w) var(--chats-w) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  grid-template-areas: "rail chats main";
  height: 100dvh;
  overflow: hidden;
}

.app-shell.no-chats {
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  grid-template-areas: "rail main";
}

.app-shell.no-chats .chat-list-pane {
  display: none;
}

.rail {
  grid-area: rail;
  background: var(--bg-1);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

.rail-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 10px 10px 14px;
  flex-shrink: 0;
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.02em;
  margin-right: auto;
}

/* The icon is already a circle with its own background, so it needs no ring or padding — just a
   fixed box so a slow image load can't reflow the header. */
.brand-mark {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
}

.rail-filter {
  flex-shrink: 0;
  padding: 0 10px 8px;
}

.filter-input {
  width: 100%;
  background: var(--bg-0);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 9px;
  font-size: 13px;
  color: var(--text-0);
}

.filter-input::placeholder {
  color: var(--text-2);
}

.filter-input:focus {
  outline: none;
  border-color: var(--accent);
}

.rail-projects {
  flex: 1 1 auto;
  min-height: 0;
  padding: 0 8px 12px;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.rail-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 10px;
  border-radius: var(--radius);
  color: var(--text-1);
  min-width: 0;
  position: relative;
}

.rail-item:hover {
  background: var(--bg-2);
  color: var(--text-0);
}

.rail-item.active {
  background: var(--bg-3);
  color: var(--text-0);
  font-weight: 600;
}

.rail-item.active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 6px;
  bottom: 6px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
}

.rail-item .project-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rail-hint,
.filter-empty {
  padding: 8px 10px;
}

.rail-meta {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
}

/* Stored-chat count. Deliberately quiet — it is a hint about where the work is, not a badge
   demanding attention. */
.count-pill {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  padding: 3px 6px;
  border-radius: 999px;
  background: var(--bg-3);
  color: var(--text-2);
}

.rail-item.active .count-pill,
.rail-item:hover .count-pill {
  color: var(--text-1);
}

.worker-dots {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}

.worker-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ok);
  display: inline-block;
}

/* ---------------------------------------------------------------- chat list pane */

.chat-list-pane {
  grid-area: chats;
  background: var(--bg-1);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

.chat-list-header {
  flex-shrink: 0;
  padding: 14px 14px 8px;
}

.chat-list-header h2 {
  margin: 0;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-list {
  flex: 1 1 auto;
  min-height: 0;
  padding: 0 10px 10px;
}

.chat-list-group {
  margin-bottom: 12px;
}

.chat-list-group-header {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-2);
  padding: 6px 4px 4px;
  position: sticky;
  top: 0;
  background: var(--bg-1);
  z-index: 1;
}

.chat-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 10px;
  border-radius: var(--radius);
  color: var(--text-1);
  margin-bottom: 1px;
}

.chat-item:hover {
  background: var(--bg-2);
  color: var(--text-0);
}

.chat-item.active {
  background: var(--bg-3);
  color: var(--text-0);
  font-weight: 600;
}

.chat-item-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-state {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 1px 6px;
  border-radius: 999px;
  flex-shrink: 0;
  background: var(--bg-3);
  color: var(--text-2);
}

.chat-state.running {
  background: color-mix(in srgb, var(--warn) 18%, transparent);
  color: var(--warn);
}

.chat-state.cancelled {
  background: color-mix(in srgb, var(--text-2) 14%, transparent);
  color: var(--text-1);
}

.chat-state.failed {
  background: color-mix(in srgb, var(--bad) 18%, transparent);
  color: var(--bad);
}

/* The new-chat form is pinned under the chat list and scrolls inside itself, so a long stack of
   model / effort / permission controls can never push its own submit button out of view. */
.new-chat {
  flex-shrink: 0;
  max-height: 64%;
  overflow-y: auto;
  overscroll-behavior: contain;
  border-top: 1px solid var(--border);
  background: var(--bg-1);
  padding: 10px 12px 12px;
}

.new-chat summary {
  cursor: pointer;
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 2px 0;
}

.new-chat summary::-webkit-details-marker {
  display: none;
}

.new-chat summary::before {
  content: "+";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 17px;
  height: 17px;
  border-radius: 5px;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  font-weight: 700;
  line-height: 1;
}

.new-chat[open] summary::before {
  content: "\2212";
}

.new-chat form {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Stacked, full-width controls in the narrow pane — the row layout the composer uses runs the
   permission select clean off the edge at this width. */
.new-chat .model-effort {
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
}

.new-chat .model-effort .select {
  width: 100%;
}

.new-chat .btn-primary {
  width: 100%;
  margin-top: 2px;
}

/* ---------------------------------------------------------------- main pane */

.main {
  grid-area: main;
  background: var(--bg-0);
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

/* ---------------------------------------------------------------- top bar (narrow only) */

.topbar {
  grid-area: topbar;
  display: none;
  align-items: center;
  gap: 6px;
  padding: 7px 8px;
  background: var(--bg-1);
  border-bottom: 1px solid var(--border);
}

.topbar-title {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin: 0 4px 0 2px;
  flex: 0 1 auto;
  min-width: 0;
}

/* Pins the theme + status group right whether or not the title is showing. */
.topbar .theme-toggle {
  margin-left: auto;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--text-1);
  padding: 6px;
  cursor: pointer;
  flex-shrink: 0;
}

/* Reached as an <a> too — the sessions link — which would otherwise be underlined. */
.icon-btn {
  text-decoration: none;
}

.icon-btn:hover {
  background: var(--bg-2);
  color: var(--text-0);
}

.icon-btn svg {
  width: 17px;
  height: 17px;
  display: block;
}

/* Only the icon for the current theme mode is painted. */
.theme-toggle .ico {
  display: none;
}

:root .theme-toggle .ico-system,
:root[data-theme-mode="system"] .theme-toggle .ico-system,
:root[data-theme-mode="light"] .theme-toggle .ico-light,
:root[data-theme-mode="dark"] .theme-toggle .ico-dark {
  display: block;
}

:root[data-theme-mode="light"] .theme-toggle .ico-system,
:root[data-theme-mode="dark"] .theme-toggle .ico-system {
  display: none;
}

.scrim {
  display: none;
}

/* ---------------------------------------------------------------- status badge */

.status-badge {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-2);
  flex-shrink: 0;
}

.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

.status-dot.status-ok {
  background: var(--ok);
}

.status-dot.status-warn {
  background: var(--warn);
}

.status-dot.status-bad {
  background: var(--bad);
}

/* ---------------------------------------------------------------- landing / project grid */

.landing {
  flex: 1 1 auto;
  min-height: 0;
  padding: 24px;
}

.landing-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 18px;
}

.landing h1 {
  margin: 0;
  font-size: 20px;
}

.landing-head .hint {
  margin: 0;
}

.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 12px;
}

.project-card {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  position: relative;
  min-width: 0;
}

.project-card:hover {
  border-color: var(--accent);
}

.project-card h2 {
  margin: 0;
  font-size: 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.project-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-2);
  margin-top: -2px;
}

.meta-sep {
  opacity: 0.5;
}

.multi-worker-tag {
  color: var(--accent);
  font-weight: 600;
}

.worker-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.worker-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--text-1);
  background: var(--bg-2);
  border-radius: 999px;
  padding: 3px 8px;
}

.empty-state {
  flex: 1 1 auto;
  min-height: 0;
  padding: 32px 40px;
  display: grid;
  align-content: safe center;
  justify-items: start;
}

.empty-state h1 {
  margin-top: 0;
  font-size: 20px;
}

.empty-state p {
  color: var(--text-1);
  max-width: 52ch;
}

.empty-state .btn-primary {
  display: inline-block;
  margin-top: 8px;
}

/* ---------------------------------------------------------------- chat page */

.chat-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 20px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  min-width: 0;
}

.chat-header h1 {
  margin: 0;
  font-size: 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Rename is a disclosure so the header shows the chat's name once, not twice. */
.rename {
  position: relative;
  margin-left: auto;
  flex-shrink: 0;
}

.rename > summary {
  list-style: none;
  cursor: pointer;
}

.rename > summary::-webkit-details-marker {
  display: none;
}

.rename[open] > summary {
  background: var(--bg-2);
  color: var(--text-0);
}

.rename-form {
  display: flex;
  gap: 6px;
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 5;
  padding: 8px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.rename-form input {
  background: var(--bg-0);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 5px 9px;
  width: 200px;
  min-width: 0;
}

.rename-form input:focus {
  outline: none;
  border-color: var(--accent);
}

.transcript {
  flex: 1 1 auto;
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
}

.msg {
  max-width: min(760px, 100%);
  border-radius: var(--radius-lg);
  padding: 10px 13px;
  background: var(--bg-1);
  border: 1px solid var(--border-soft);
  min-width: 0;
}

.msg-user {
  align-self: flex-end;
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-0));
  border-color: color-mix(in srgb, var(--accent) 32%, transparent);
}

.msg-assistant {
  align-self: flex-start;
}

.msg-system {
  align-self: center;
  background: transparent;
  border-style: dashed;
  border-color: var(--border);
  color: var(--text-2);
}

.msg-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--text-2);
  margin-bottom: 6px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.msg-role {
  font-weight: 700;
}

.msg-time {
  margin-left: auto;
}

.live-indicator {
  color: var(--warn);
}

.msg-text {
  word-break: break-word;
}

.msg-error {
  margin-top: 8px;
  color: var(--bad);
}

.msg-usage {
  margin-top: 8px;
  font-size: 11px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

.msg-tools {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 6px;
}

.msg-tools:empty {
  display: none;
  margin-bottom: 0;
}

.tool-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 4px 8px;
  font-size: 12px;
  font-family: var(--mono);
  min-width: 0;
}

.tool-name {
  font-weight: 700;
  color: var(--accent);
  flex-shrink: 0;
}

.tool-detail {
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tool-status {
  margin-left: auto;
  text-transform: uppercase;
  font-size: 10px;
  color: var(--text-2);
  flex-shrink: 0;
}

.tool-chip.ok .tool-status {
  color: var(--ok);
}

.tool-chip.err .tool-status {
  color: var(--bad);
}

.tool-chip.pending .tool-status {
  color: var(--warn);
}

.notice-line {
  font-size: 12px;
  color: var(--text-2);
  font-style: italic;
}

/* Reasoning during a live turn. It is not the answer and it is not kept once the turn lands, so
   it sits shut by default and stays visually quieter than the message body around it. */
.thinking {
  margin-bottom: 6px;
  font-size: 12px;
  color: var(--text-2);
}

.thinking > summary {
  cursor: pointer;
  font-style: italic;
  color: var(--text-2);
  list-style: none;
}

.thinking > summary::before {
  content: "▸ ";
}

.thinking[open] > summary::before {
  content: "▾ ";
}

.thinking > summary::-webkit-details-marker {
  display: none;
}

.thinking-text {
  margin-top: 4px;
  padding: 6px 8px;
  max-height: 14em;
  overflow-y: auto;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  font-family: var(--mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- rendered markdown
 *
 * Message bodies are markdown (views/markdown.rs), so one bubble can hold anything from a single
 * sentence to a document with headings, tables and fenced code. Two rules keep that readable as
 * a chat message rather than as a web page:
 *
 *   - Vertical rhythm lives in the gaps *between* blocks, never in the outer edges: every child
 *     carries a bottom margin and the first/last are zeroed, so the bubble's own padding is the
 *     only thing touching the border. Nothing here depends on margin collapsing.
 *   - Anything that can outgrow the bubble — tables, fenced code — scrolls inside itself, so the
 *     transcript column never grows a horizontal scrollbar.
 */

.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: 18px 0 8px;
  line-height: 1.3;
  font-weight: 650;
}

/* An answer that opens with `##` and nests to `###` is the common case, so those two levels are
   the ones that have to be told apart at a glance: a rule under the section title, plain bold
   below it. `#` is rare enough to just be a slightly larger `##`. */
.md h1 {
  font-size: 19px;
  letter-spacing: -0.015em;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

.md h2 {
  font-size: 16.5px;
  letter-spacing: -0.01em;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--border);
}

.md h3 {
  font-size: 14.5px;
  letter-spacing: -0.005em;
}

.md h4 {
  font-size: 13px;
  font-weight: 700;
}

.md h5,
.md h6 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-1);
}

.md ul,
.md ol {
  margin: 0 0 10px;
  padding-left: 22px;
}

.md li {
  margin-bottom: 3px;
}

.md li > p {
  margin-bottom: 6px;
}

/* A nested list belongs to its parent item, so it hugs it instead of opening the full
   between-blocks gap. */
.md li > ul,
.md li > ol,
.md li > p:last-child {
  margin-bottom: 0;
}

/* A drawn bullet rather than list-style: the browser's is tied to the font size, and at 14px it
   sits too heavy against text this dense. */
.md ul {
  list-style: none;
}

.md ul > li {
  position: relative;
}

.md ul > li::before {
  content: "";
  position: absolute;
  left: -13px;
  top: 0.62em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--text-2);
}

/* Task list items bring their own marker. */
.md ul > li:has(> input[type="checkbox"])::before {
  display: none;
}

.md input[type="checkbox"] {
  margin: 0 6px 0 -18px;
  accent-color: var(--accent);
}

.md a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
  text-underline-offset: 2px;
}

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

.md strong {
  font-weight: 680;
  color: var(--text-0);
}

.md del {
  color: var(--text-2);
}

.md hr {
  height: 1px;
  border: 0;
  background: var(--border);
  margin: 16px 0;
}

.md blockquote {
  margin: 0 0 10px;
  padding: 1px 0 1px 12px;
  border-left: 3px solid var(--quote-bar);
  color: var(--text-1);
}

/* -------- code --------
 *
 * The bubble breaks long words to stay inside its column; code opts back out and scrolls
 * instead, which is the only way a flag like --dangerously-skip-permissions survives intact. */

/* `break-word` rather than `anywhere`: both stop a long path from overflowing, but only
   `anywhere` lets an identifier count as zero-width when the browser is deciding how wide a
   table column needs to be — which is how `RoundManagementWorldSubsystem` ends up split across
   two lines in a column that had room to hold it. */
.md code {
  font-family: var(--mono);
  font-size: 0.88em;
  word-break: normal;
  overflow-wrap: break-word;
}

/* No border: an identifier every second sentence turns a bordered pill into visual static. The
   fill alone is enough to say "this is a name, not prose". */
.md :not(pre) > code {
  background: var(--bg-2);
  border-radius: 4px;
  padding: 0.1em 0.32em;
}

.md pre {
  position: relative;
  margin: 0 0 12px;
  padding: 10px 12px;
  background: var(--code-bg);
  border: 1px solid var(--code-border);
  border-radius: var(--radius);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar) transparent;
}

.md pre code {
  display: block;
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre;
  word-break: normal;
  overflow-wrap: normal;
  background: none;
  border: 0;
  padding: 0;
}

/* The fence's language, printed in the corner. `data-lang` is only set when the fence named one,
   so a bare fence stays clean. It scrolls with the block's content rather than pinning to the
   viewport edge, which is the price of not wrapping every `pre` in an extra element. */
.md pre[data-lang]::before {
  content: attr(data-lang);
  position: absolute;
  top: 0;
  right: 0;
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-2);
  background: var(--code-bg);
  border-left: 1px solid var(--code-border);
  border-bottom: 1px solid var(--code-border);
  border-radius: 0 var(--radius) 0 var(--radius);
  pointer-events: none;
}

/* Sits over the language label — the label is decoration, the button is the thing you reach
   for. Hidden until the block is hovered or the button itself is focused, so a transcript full
   of code isn't a wall of buttons. */
.copy-code {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 1;
  padding: 2px 8px;
  font-size: 11px;
  font-family: var(--font);
  color: var(--text-1);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 120ms ease;
}

.code-wrap:hover .copy-code,
.copy-code:focus-visible,
.copy-code.copied {
  opacity: 1;
}

.copy-code.copied {
  color: var(--ok);
  border-color: color-mix(in srgb, var(--ok) 45%, transparent);
}

/* Wrapper added by app.js so the copy button and the language label are positioned against the
   block rather than against its scrolling contents. app.js moves `data-lang` up here at the same
   time, so only one of the two rules ever paints. */
.code-wrap {
  position: relative;
  margin-bottom: 12px;
}

.code-wrap > pre {
  margin-bottom: 0;
}

.md .code-wrap[data-lang]::before {
  content: attr(data-lang);
  position: absolute;
  top: 0;
  right: 0;
  /* The <pre> is positioned too and comes later in the box order, so without this the label is
     painted first and then covered by the block's own background. */
  z-index: 1;
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-2);
  background: var(--code-bg);
  border-left: 1px solid var(--code-border);
  border-bottom: 1px solid var(--code-border);
  border-radius: 0 var(--radius) 0 var(--radius);
  pointer-events: none;
}

/* -------- tables --------
 *
 * `display: block` is what makes the scroll container work at all: a table box ignores
 * `overflow`, so without it a wide table drags the whole transcript sideways. `max-content` then
 * gets the columns sized like a table again inside that box. */

.md table {
  display: block;
  width: max-content;
  max-width: 100%;
  margin: 0 0 12px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-collapse: collapse;
  font-size: 13px;
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar) transparent;
}

.md th,
.md td {
  border: 1px solid var(--border);
  padding: 5px 10px;
  text-align: left;
  vertical-align: top;
}

.md th {
  background: var(--bg-2);
  font-weight: 650;
  white-space: nowrap;
}

.md tbody tr:nth-child(even) td {
  background: color-mix(in srgb, var(--bg-2) 45%, transparent);
}

.md img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius);
}

/* The un-rendered tail of a streaming message: whatever arrived since the last markdown
   re-render, shown as-is so the text never stalls waiting for one. */
.live-tail {
  white-space: pre-wrap;
}

/* Inside the accent bubble a user's own message is usually a sentence or two, and the heavier
   markdown furniture (rules under headings, panel fills) reads as noise. */
.msg-user .md h2 {
  border-bottom: 0;
  padding-bottom: 0;
}

.msg-user .md pre {
  background: color-mix(in srgb, var(--bg-0) 60%, transparent);
  border-color: color-mix(in srgb, var(--accent) 22%, transparent);
}

.msg-user .md :not(pre) > code {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}

.msg-user .md th {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* ---------------------------------------------------------------- composer */

.composer {
  border-top: 1px solid var(--border);
  padding: 12px 20px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex-shrink: 0;
  background: var(--bg-0);
}

.composer-text {
  width: 100%;
  min-height: 62px;
  max-height: 40vh;
  resize: vertical;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 10px 12px;
}

.composer-text:focus {
  outline: none;
  border-color: var(--accent);
}

.composer-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.model-effort {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}

.select {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 8px;
  min-width: 0;
  max-width: 100%;
}

/* A permission mode the worker flagged as dangerous. Loud enough that you cannot pick it by
   accident, quiet enough that it is not shouting during the whole session. */
.select-danger {
  border-color: var(--bad);
  color: var(--bad);
}

.permission-warning {
  flex-basis: 100%;
  margin: 6px 0 0;
  padding: 7px 10px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--bad);
  background: color-mix(in srgb, var(--bad) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--bad) 45%, transparent);
  border-radius: var(--radius);
}

.permission-warning strong {
  color: var(--bad);
}

.turn-status {
  font-size: 12px;
  color: var(--text-2);
  min-width: 0;
}

.composer-disabled .composer-text {
  opacity: 0.6;
}

/* ---------------------------------------------------------------- buttons & forms */

.btn-primary,
.btn-secondary,
.btn-danger {
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 7px 14px;
  cursor: pointer;
  font-weight: 600;
}

.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
}

.btn-primary:hover {
  background: var(--accent-2);
}

.btn-primary:disabled {
  background: var(--bg-3);
  color: var(--text-2);
  cursor: not-allowed;
}

.btn-secondary {
  background: var(--bg-2);
  border-color: var(--border);
  color: var(--text-0);
}

.btn-secondary:hover {
  background: var(--bg-3);
}

.btn-danger {
  background: transparent;
  border-color: var(--bad);
  color: var(--bad);
}

.btn-danger:hover {
  background: color-mix(in srgb, var(--bad) 12%, transparent);
}

.field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--text-2);
}

.field input {
  background: var(--bg-0);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 8px;
  color: var(--text-0);
  width: 100%;
}

.field input:focus {
  outline: none;
  border-color: var(--accent);
}

.hint {
  color: var(--text-2);
  font-size: 12px;
}

/* ---------------------------------------------------------------- banners */

.banner {
  border-radius: var(--radius);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
}

.banner-error {
  background: color-mix(in srgb, var(--bad) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--bad) 35%, transparent);
  color: var(--bad);
}

.banner-warn {
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
  color: var(--warn);
}

.banner-detail {
  color: var(--text-1);
  font-weight: 400;
}

/* ---------------------------------------------------------------- narrow windows */

@media (max-width: 1080px) {
  :root {
    --rail-w: 200px;
    --chats-w: 240px;
  }
}

/* ---------------------------------------------------------------- login
 *
 * The one page that renders without the app shell, so it sets its own background rather than
 * inheriting one from `.app-shell`. */

body.bare {
  background: var(--bg-1);
  color: var(--text-0);
}

.login {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.login-card {
  width: min(340px, 100%);
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 24px;
  background: var(--bg-0);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.02em;
  margin: 0;
}

.login-mark {
  width: 32px;
  height: 32px;
}

.login-hint {
  color: var(--text-2);
  font-size: 12px;
  margin: -8px 0 0;
}

.login-error {
  color: var(--bad);
  font-size: 12px;
  margin: 0;
}

/* The sign-out control is a form purely so it can POST; it must not become a flex item of its
   own between the theme toggle and the status badge. */
.logout-form {
  display: contents;
}

/* ---------------------------------------------------------------- sessions
 *
 * /settings/security. Read on a phone, in a hurry, about a device that is not in the room, so
 * every row states what it is and what ending it would cost before the button that ends it. */

.settings-lede {
  max-width: 62ch;
  margin: -8px 0 18px;
}

.sessions {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 720px;
}

.session {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-1);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* The row you are holding. An outline rather than a different background, so it reads as "this
   one" without looking like the one being warned about. */
.session-current {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
}

.session-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}

/* The raw User-Agent, which is long and has no spaces to break on. */
.session-agent {
  font-size: 13px;
  color: var(--text-0);
  overflow-wrap: anywhere;
}

.session-tag {
  font-size: 11px;
  padding: 1px 7px;
  border-radius: 999px;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  flex-shrink: 0;
}

.session-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 12px;
  color: var(--text-2);
}

.session-revoke {
  display: flex;
}

/* The lost-device drill, set apart from the list: it is the one control here that acts on
   devices you are not looking at. */
.sessions-drill {
  max-width: 720px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
}

.sessions-drill .hint {
  max-width: 62ch;
  margin: 0;
}

/* Phones and narrow windows: one column for the conversation, with the project rail and the chat
   list as overlay drawers off the top bar. Each drawer still scrolls internally. */
@media (max-width: 800px) {
  .app-shell,
  .app-shell.no-chats {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
      "topbar"
      "main";
  }

  .topbar {
    display: flex;
  }

  .rail,
  .chat-list-pane {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 30;
    /* Leaves a comfortable strip of scrim to tap for "close". */
    width: min(78vw, 320px);
    transform: translateX(-101%);
    transition: transform 160ms ease;
    box-shadow: var(--shadow);
  }

  body[data-drawer="projects"] .rail,
  body[data-drawer="chats"] .chat-list-pane {
    transform: none;
  }

  .scrim {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: var(--scrim);
  }

  body[data-drawer] .scrim {
    display: block;
  }

  .topbar .status-label {
    display: none;
  }

  .rail-header {
    padding-top: 14px;
  }

  .new-chat {
    max-height: 70%;
  }

  /* A chat page has its own header with the title (and the rename control) in it, so the top
     bar drops its copy rather than printing the name twice down the screen. */
  body:has(.chat-header) .topbar-title {
    display: none;
  }

  .chat-header {
    padding: 10px 14px;
  }

  .rename-form {
    right: auto;
    left: 8px;
    width: calc(100vw - 32px);
  }

  .rename-form input {
    flex: 1 1 auto;
    width: auto;
  }

  .transcript {
    padding: 14px;
  }

  .composer {
    padding: 10px 14px calc(12px + env(safe-area-inset-bottom));
  }

  .composer-controls .model-effort {
    flex: 1 1 100%;
  }

  .composer-controls .select {
    flex: 1 1 auto;
  }

  .composer-controls .btn-primary,
  .composer-controls .btn-danger {
    flex: 1 1 auto;
    padding: 9px 14px;
  }

  .msg {
    max-width: 100%;
  }

  .landing {
    padding: 16px;
  }

  /* A full-width target: ending a session is a deliberate act done with a thumb. */
  .session-revoke .btn-danger,
  .session-revoke .btn-secondary,
  .sessions-drill .btn-danger {
    width: 100%;
  }

  .sessions-drill {
    align-items: stretch;
  }

  .empty-state {
    padding: 32px 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rail,
  .chat-list-pane {
    transition: none;
  }
}
