/* Screen- and modal-specific rules that don't belong in the generic
   component library (css/components.css): the session-detail terminal
   chrome, the two hand-built modal surfaces (new-session wizard, folder
   picker) that live in app.js rather than a js/views/*.js screen, the login
   screen, and the handful of page-local layout/responsive rules. This file
   is what's left after webui/style.css was retired (Task 17) — literals
   were converted to css/tokens.css steps as they moved; a literal stays
   un-tokenized only when no step is a reasonably close match (see the task
   report for the exact mapping table used).

   Font-size conversions below all follow the exact groupings documented in
   tokens.css's own comments (e.g. "was 8.5 / 9.5 / 10 / 10.5" -> --fs-2xs),
   including two spots where that precedent already resolved an exact tie to
   the LARGER step rather than the smaller one (15px and 17px both landed on
   the bigger neighbour, --fs-xl and --fs-2xl) — cited here per the "smaller
   wins ties unless precedent says otherwise" rule. */

/* ─── Global resets (the rest of the reset lives in css/base.css) ─── */
body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--t-med) ease;
}
button { font: inherit; }
a { color: var(--blue); text-decoration: none; transition: all var(--t-fast) ease; }
a:hover { text-decoration: underline; }
/* .btn's own look lives in components.css, written for <button>s; a couple
   of .btn instances are literal <a> tags ("Open in claude.ai", "ai-memory"),
   so without this the global a/a:hover reset above would underline them. */
a.btn, a.btn:hover { text-decoration: none; }
/* app.js's own btn() helper (distinct from components.js's Button()) still
   emits class "btn small" (not components.css's "sm"), so that variant needs
   its own rule — same values as .btn.sm, kept as a separate class rather
   than rewriting every btn({size:"small"}) call site. */
.btn.small { padding: var(--sp-1) var(--sp-4); font-size: var(--fs-sm); border-radius: var(--r-sm); }
/* Not in components.css's .card block. */
.card:hover { border-color: var(--text-mute); }

/* ─── Plan / usage card (dashboard) ───
   .plan-line / .plan-note are gone: dashboard.js only ever renders
   .plan-links (a shortcut-buttons row), never the line-item summary or
   footnote the pre-migration renderer used to build. */
.plan-card { padding: var(--sp-6) var(--sp-7); }
.plan-card .plan-links { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.plan-card .plan-links .btn { padding: var(--sp-2) var(--sp-5); font-size: var(--fs-sm); }

/* Plan windows: one row per usage window from Anthropic's endpoint. The bar is
   the point — a percentage alone doesn't say how close the ceiling is. */
.plan-windows { display: flex; flex-direction: column; gap: var(--sp-5); }
.plan-windows:not(:empty) { margin-bottom: var(--sp-6); }
/* min-width:0 so a long scope name ellipsises instead of widening the card. */
.plan-win { min-width: 0; }
.plan-win-top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); }
.plan-win-name { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; font-size: var(--fs-md); }
.plan-win-scope {
  font-family: var(--mono); font-size: var(--fs-2xs); color: var(--text-dim);
  border: 1px solid var(--border); border-radius: var(--r-full); padding: 1px var(--sp-3);
}
.plan-win-live {
  font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--accent);
}
.plan-win-pct { font-size: var(--fs-md); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }
.plan-win-pct.warn { color: var(--status-warn); }
.plan-win-pct.high { color: var(--status-danger); }
.plan-bar {
  height: 6px; margin-top: var(--sp-2); border-radius: var(--r-full);
  background: var(--border); overflow: hidden;
}
.plan-bar-fill { display: block; height: 100%; border-radius: inherit; background: var(--status-ok); }
.plan-bar-fill.warn { background: var(--status-warn); }
.plan-bar-fill.high { background: var(--status-danger); }
.plan-win-reset { margin-top: var(--sp-2); font-size: var(--fs-xs); color: var(--text-mute); }
.plan-empty { font-size: var(--fs-sm); color: var(--text-dim); }

/* Dashboard summary: two rows, no countdowns — the Usage screen has the rest. */
.plan-summary .plan-card { padding: var(--sp-5) var(--sp-7) var(--sp-6); }
.plan-summary .head .count.link { cursor: pointer; }
.plan-summary .head .count.link:hover { color: var(--accent); }
/* One grid for the whole list, rows contributing their cells through
   `display: contents`: that is what makes the bars start at the same x across
   rows. As flex rows they each sized their own label, so "Weekly · Fable"
   pushed its bar right of the plain "Weekly" one and the column zig-zagged. */
.plan-mini {
  display: grid;
  grid-template-columns: auto minmax(0, auto) minmax(0, auto) minmax(40px, 1fr) auto;
  align-items: center;
  gap: var(--sp-4);
}
.plan-mini-row { display: contents; }
.plan-mini-ico { display: inline-flex; align-items: center; }
/* Agent first and in full colour, window second and dimmed: the row answers
   "whose limit is this" before "which window". */
.plan-mini-agent {
  min-width: 0; font-size: var(--fs-sm); color: var(--text);
  font-weight: var(--fw-medium);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.plan-mini-name {
  min-width: 0; font-size: var(--fs-sm); color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.plan-mini-bar {
  /* The bar yields first when the row is tight — the names carry the meaning. */
  min-width: 40px; height: 6px; border-radius: var(--r-full);
  background: var(--border); overflow: hidden;
}
.plan-mini-row .plan-win-pct { min-width: 38px; text-align: right; font-size: var(--fs-sm); }

/* ─── System screen: one column ───
   This screen was two columns (`.grid-2`) and always had a hole: the columns'
   heights come from hardware that differs per host — drive count, GPU, battery —
   so one ended before the other and the gap was dead space. Full-width sections
   have no other column to disagree with.

   The rows are FLEX, not the grid `.metrics-grid` normally is, and that is the
   whole trick: `repeat(auto-fit, minmax(180px, 1fr))` only collapses tracks
   nobody occupies, so five cards in a four-track row wrap to a second row with
   one card and three holes (measured: 652px of empty row at a 900px viewport).
   Flex items stretch per LINE, including the last one, so every row is full for
   any card count at any width. Capping the track width was tried too and just
   moved the same emptiness to the right-hand edge of every host. */
.sys-flow { display: flex; flex-direction: column; gap: var(--sp-8); }
.sys-flow .metrics-grid { display: flex; flex-wrap: wrap; }
.sys-flow .metrics-grid > .metric { flex: 1 1 180px; }

/* Network as a strip: four short facts that never grow, so they cost one line
   instead of the column-height card they used to be. */
.net-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-5);
  padding: var(--sp-5) var(--sp-7);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
}
.net-item { display: inline-flex; align-items: baseline; gap: var(--sp-3); min-width: 0; }
.net-item b {
  font-size: var(--fs-2xs); font-weight: var(--fw-bold); text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-mute);
}
.net-item code { font-family: var(--mono); font-size: var(--fs-xs); color: var(--text-dim); }
.net-sep { width: 1px; align-self: stretch; background: var(--border); }
@media (max-width: 560px) {
  /* The dividers only help while the items sit on one line. */
  .net-sep { display: none; }
  .net-strip { gap: var(--sp-2) var(--sp-6); }
}

/* Build stamp: the last thing on the dashboard, quiet enough to ignore and
   specific enough to quote in a bug report. */
.build-stamp {
  display: flex; justify-content: center; align-items: baseline; gap: var(--sp-3);
  margin: var(--sp-8) 0 var(--sp-6);
  font-size: var(--fs-xs); color: var(--text-mute);
}
.build-stamp:empty { display: none; }
.build-stamp .build-name { letter-spacing: 0.04em; }
.build-stamp .build-ver { color: var(--text-dim); font-weight: var(--fw-semi); }
.build-stamp .build-sep { opacity: 0.5; }
.build-stamp .build-sha { font-family: var(--mono); font-size: var(--fs-2xs); }

/* Usage screen: one card per agent that has data. */
.usage-cards { display: flex; flex-direction: column; }
.usage-cards .card:first-child { margin-top: 0; }
.usage-agent-ico { display: inline-flex; align-items: center; margin-right: var(--sp-3); vertical-align: middle; }


/* ─── Session detail: compact header ─── */
.sess-hdr {
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.sess-title {
  font-size: var(--fs-2xl); font-weight: var(--fw-black); margin: 0; letter-spacing: -0.2px; color: var(--fg);
}
.sess-hdr .chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-xs); font-weight: var(--fw-semi); padding: 2px var(--sp-3); border-radius: var(--r-full);
  border: 1px solid var(--border); background: var(--bg-elev-2); color: var(--fg-dim);
  white-space: nowrap;
}
.sess-hdr .chip.agent { color: var(--accent); background: var(--accent-soft); }
.sess-hdr .chip.agent .agent-logo-chip { width: 14px; height: 14px; }
.sess-hdr .chip.dir { font-family: var(--mono); font-size: var(--fs-xs); }

/* ─── Session detail / Resume: metadata list (network + versions cards on
   System also reuse this — see system.js) ─── */
/* ─── Session detail: resume-prompt banner ───
   Inline replica of claude's own "Resume from summary?" terminal picker,
   shown while state.resumePromptActive is true (js/views/session-detail.js).
   No rule existed for this in the pre-migration style.css either — the
   audit script (undefined-but-used) is what caught the gap, not a rule that
   needed moving. */
.resume-prompt-banner {
  background: var(--bg-elev);
  border: 1px solid var(--accent);
  border-radius: var(--r-lg);
  padding: var(--sp-6) var(--sp-7);
  margin-bottom: var(--sp-5);
  box-shadow: var(--shadow-sm);
}
.resume-prompt-banner .rpb-title {
  font-size: var(--fs-sm); font-weight: var(--fw-bold); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--accent); margin-bottom: var(--sp-2);
}
.resume-prompt-banner .rpb-text {
  font-size: var(--fs-md); color: var(--fg-dim); margin-bottom: var(--sp-5); line-height: 1.5;
}
.resume-prompt-banner .rpb-actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* ─── Attachments waiting to go with the next message (views/attachments.js) ───
   A strip right above the input, the same ground as the input bar. */
.attach-tray {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-7) 0;
  background: var(--bg-elev-2); border-top: 1px solid var(--border);
}
.attach-tray + .term-bar { border-top: none; }
.attach-chip {
  position: relative; width: 112px; display: flex; flex-direction: column; gap: var(--sp-1);
  padding: var(--sp-2); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-elev);
}
.attach-thumb, .attach-file {
  width: 100%; height: 68px; border-radius: var(--r-sm); background: var(--bg-elev-2);
}
/* The whole picture, not a crop: most attachments are screenshots whose
   point is at the edges as often as in the middle. */
.attach-thumb { object-fit: contain; display: block; }
.attach-file { display: grid; place-items: center; border: 1px dashed var(--border-strong); }
.attach-ext {
  font-family: var(--mono); font-size: var(--fs-sm); font-weight: var(--fw-bold);
  text-transform: uppercase; color: var(--fg-dim);
}
.attach-name {
  font-size: var(--fs-xs); color: var(--fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.attach-size { font-size: var(--fs-xs); color: var(--fg-mute); font-variant-numeric: tabular-nums; }
.attach-x {
  position: absolute; top: calc(-1 * var(--sp-2)); right: calc(-1 * var(--sp-2));
  width: var(--sp-7); height: var(--sp-7); border-radius: var(--r-full);
  display: grid; place-items: center; font: inherit; font-size: var(--fs-xs); line-height: 1;
  color: var(--fg); background: var(--bg-elev); border: 1px solid var(--border-strong); cursor: pointer;
}
.attach-x:hover { color: var(--on-status); background: var(--red); border-color: var(--red); }
.attach-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.composer.drop-target .term-bar { outline: 2px dashed var(--accent); outline-offset: -4px; }
.term-bar .icon-btn.attach svg { display: block; }

/* ─── The prompt dock (session-detail.js) ───
   Whatever Claude waits on opens as a modal anchored bottom-left, right above
   the input where the answer goes, floating over the pane's last lines. */
.composer { position: relative; }
.prompt-dock {
  position: absolute; left: var(--sp-5); bottom: calc(100% + var(--sp-3));
  z-index: var(--z-menu);
  width: min(600px, calc(100% - 2 * var(--sp-5)));
  max-height: min(68vh, 680px); overflow-y: auto; overscroll-behavior: contain;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow), 0 0 0 1px var(--border);
  animation: prompt-dock-in var(--t-med) ease-out;
}
.prompt-dock > .resume-prompt-banner { margin-bottom: 0; box-shadow: none; }
/* In the card's top-right corner, level with its title (a float would narrow
   the card: a flex container steps aside from floats). */
.prompt-dock-hide {
  position: absolute; top: var(--sp-5); right: var(--sp-5); z-index: 1;
  font: inherit; font-size: var(--fs-xs); font-weight: var(--fw-bold);
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--fg-dim); background: var(--bg-elev-2);
  border: 1px solid var(--border); border-radius: var(--r-full);
  padding: var(--sp-1) var(--sp-4); cursor: pointer;
}
.prompt-dock-hide:hover { color: var(--fg); border-color: var(--border-strong); }
.prompt-dock-hide:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.prompt-dock.folded {
  width: auto; max-height: none; overflow: visible; box-shadow: none; animation: none;
}
.prompt-pill {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--fg);
  background: var(--bg-elev); border: 1px solid var(--accent); border-radius: var(--r-full);
  padding: var(--sp-2) var(--sp-5); cursor: pointer; box-shadow: var(--shadow-sm);
}
.prompt-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.prompt-pill-dot {
  width: var(--sp-3); height: var(--sp-3); border-radius: var(--r-full); background: var(--accent);
  animation: prompt-pulse 1.6s ease-in-out infinite;
}
@keyframes prompt-dock-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes prompt-pulse { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) {
  .prompt-dock, .prompt-pill-dot { animation: none; }
}
@media (max-width: 720px) {
  .prompt-dock { left: var(--sp-3); width: calc(100% - 2 * var(--sp-3)); max-height: 62vh; }
}

/* Claude's permission dialog (question-card.js permissionCard). */
/* A dialog with no title leaves its head row empty: no gap for nothing. */
.pm-card .qa-head:empty { display: none; }
.pm-details {
  font-family: var(--mono); font-size: var(--fs-sm); color: var(--fg-dim);
  background: var(--bg-elev-2); border: 1px solid var(--border-soft);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-1); overflow-x: auto;
}
.pm-details .pm-cmd { color: var(--fg); white-space: pre-wrap; overflow-wrap: anywhere; }
.pm-details .pm-line { white-space: pre-wrap; overflow-wrap: anywhere; }
.pm-hook {
  font-size: var(--fs-sm); line-height: 1.45; color: var(--fg);
  border-left: 3px solid var(--yellow); background: var(--yellow-soft);
  border-radius: 0 var(--r-md) var(--r-md) 0; padding: var(--sp-3) var(--sp-5);
  overflow-wrap: anywhere;
}
.pm-num {
  flex: none; min-width: var(--sp-7); height: var(--sp-7); margin-top: 1px;
  display: grid; place-items: center; font-family: var(--mono); font-size: var(--fs-sm);
  font-weight: var(--fw-bold); color: var(--fg-dim);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
}
.pm-opt.on .pm-num, .pm-opt:hover .pm-num { color: var(--accent); border-color: var(--accent); }

/* ─── Claude's question (question-card.js) ───
   Choices are buttons with role radio/checkbox, never <input>s (SPA-15). */
.qa-card { display: flex; flex-direction: column; gap: var(--sp-6); }
.qa-card .rpb-title { margin-bottom: 0; }
.qa-q { display: flex; flex-direction: column; gap: var(--sp-3); }
.qa-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3); }
.qa-chip {
  font-size: var(--fs-xs); font-weight: var(--fw-bold); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--accent-deep); background: var(--accent-soft);
  border-radius: var(--r-full); padding: var(--sp-1) var(--sp-3);
}
.qa-text { font-size: var(--fs-md); font-weight: var(--fw-medium); color: var(--fg); }
.qa-hint { font-size: var(--fs-xs); color: var(--fg-mute); }
.qa-opts { display: flex; flex-direction: column; gap: var(--sp-2); }
.qa-opt {
  display: flex; align-items: flex-start; gap: var(--sp-4); width: 100%;
  text-align: left; font: inherit; color: var(--fg); cursor: pointer;
  background: var(--bg-elev-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--sp-4) var(--sp-5);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.qa-opt:hover { border-color: var(--border-strong); }
.qa-opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.qa-opt.on { border-color: var(--accent); background: var(--accent-soft); }
.qa-mark {
  flex: none; width: var(--sp-6); height: var(--sp-6); margin-top: var(--sp-1);
  border: 2px solid var(--border-strong); border-radius: var(--r-full);
  display: grid; place-items: center;
}
.qa-opt[role="checkbox"] .qa-mark { border-radius: var(--r-xs); }
.qa-opt.on .qa-mark { border-color: var(--accent); background: var(--accent); }
.qa-opt.on .qa-mark::after {
  content: ""; width: var(--sp-2); height: var(--sp-2);
  border-radius: var(--r-full); background: var(--on-accent);
}
.qa-opt[role="checkbox"].on .qa-mark::after { border-radius: 1px; }
.qa-body { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.qa-label { font-size: var(--fs-md); font-weight: var(--fw-medium); overflow-wrap: anywhere; }
.qa-desc { font-size: var(--fs-sm); color: var(--fg-dim); line-height: 1.45; overflow-wrap: anywhere; }
/* The free-text answer: a box of its own, so it reads as a place to type. */
.qa-other {
  border: 1px dashed var(--border-strong); border-radius: var(--r-md);
  background: var(--bg-elev-2); padding: var(--sp-3) var(--sp-5);
  transition: border-color var(--t-fast);
}
.qa-other:focus-within { border-style: solid; border-color: var(--accent); }
.qa-other .term-input { width: 100%; font-family: var(--font-sans); font-size: var(--fs-md); }

/* ─── Session detail: pane card ─── */
.pane-card { background: var(--term-bg); border: 1px solid var(--border); border-radius: var(--r-xl); overflow: hidden; position: relative; box-shadow: var(--shadow-sm); }
/* The bar sits a step off the terminal's own background, so it moves with the
   session's theme instead of being a fixed wash of black -- which turned into a
   grey smear the moment a light theme was picked. Two declarations on purpose:
   the first is the fallback for engines without color-mix, the second wins
   everywhere else. The active tab reads the same variable, which is how it
   stays visually attached to the card. */
.pane-card {
  --pane-bar: var(--bg-elev-2);
  --pane-bar: color-mix(in srgb, var(--term-bg) 93%, var(--fg) 7%);
}
/* The bar floats over the terminal's top-right corner instead of taking a band
   of height off every screen: the pane starts at the top of the card and gets
   all 46px back. It recedes while you read and comes back on approach, so a
   cluster of controls is not sitting at full strength on the output's first
   line. Kept inside .pane-card deliberately -- that card clips overflow, which
   is exactly why no menu is anchored in here any more (the theme picker lives
   in the header). */
.pane-card .head {
  position: absolute; top: var(--sp-3); right: var(--sp-3); z-index: 3;
  display: flex; gap: var(--sp-3); align-items: center;
  padding: var(--sp-2) var(--sp-3);
  background: color-mix(in srgb, var(--pane-bar) 88%, transparent);
  border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  backdrop-filter: blur(8px);
  opacity: var(--pane-bar-rest); transition: opacity var(--t-fast) ease;
}
.pane-card:hover .head,
.pane-card .head:focus-within { opacity: 1; }
/* A fallback for engines without color-mix: a flat bar colour rather than a
   transparent box over the output. */
@supports not (background: color-mix(in srgb, red, blue)) {
  .pane-card .head { background: var(--pane-bar); }
}
@media (prefers-reduced-motion: reduce) {
  .pane-card .head { transition: none; }
}
/* No extra top padding: the bar floats over the RIGHT of the card, and terminal
   output starts at the left margin. Padding here would have been overridden by
   the .pane-card pre rule further down anyway (same specificity, later wins). */
.pane-card .head .pill { font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-dim); display: inline-flex; align-items: center; gap: var(--sp-2); font-weight: var(--fw-semi); }
/* Which agent is driving this pane, in the same key as the other pills on
   this bar rather than the accent-coloured chip it was beside the title. */
.pane-card .head .pill.agent { color: var(--text-dim); }
.pane-card .head .pill.agent .agent-logo-chip { width: 12px; height: 12px; }

.pane-card .live-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--green); display: inline-block;
  box-shadow: 0 0 6px var(--green);
}
.pane-card .live-dot.dropped { background: var(--red); box-shadow: none; }
.pane-card .live-dot.ended { background: var(--text-mute); box-shadow: none; }
/* Starting: the session was spawned/resumed and has not drawn anything yet.
   Amber and pulsing, so it reads as "working on it" rather than as the red
   "stream dropped" or the green "live" — both of which were lies here. */
.pane-card .live-dot.starting {
  background: var(--status-warn); box-shadow: 0 0 6px var(--status-warn);
  animation: pane-starting 1.1s ease-in-out infinite;
}
@keyframes pane-starting { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) {
  .pane-card .live-dot.starting { animation: none; }
}
/* The one scrolling box: the "load older" control, the transcript and the live
   terminal all sit inside it, so the whole conversation is a single continuous
   scroll. The <pre> below therefore does NOT scroll — two scrollbars is what
   made "jump to latest" move the wrong one. */
.pane-scroll {
  flex: 1; min-height: 0; overflow: auto;
  display: flex; flex-direction: column;
}
/* Pins a short conversation to the foot of the box, so a young session reads
   from the bottom like a terminal instead of floating in the middle.
   `margin-top: auto` on the child, NOT `justify-content: flex-end` on the
   parent: that centres the overflow in a scroll container, which puts the
   content above the top edge where no scrollbar can reach it — the "load
   older" button became unclickable the moment the history outgrew the box. */
.pane-scroll > pre { margin-top: auto; }
.pane-card pre {
  font-family: var(--term-font);
  /* Kept as a literal, not tokenized: app.js's PANE_FONT_MAX (12.5) is
     documented as matching this value, and fitPaneFont() only ever shrinks
     from here — moving this to --fs-sm (12) would silently drift the two
     apart. */
  font-size: 12.5px;
  margin: 0; padding: var(--sp-6) var(--sp-7);
  /* No overflow of its own: .pane-scroll above clips and scrolls both
     axes for the whole conversation. */
  overflow: visible; flex: 0 0 auto;
  /* The pane is a fixed 200-column pyte screen, so a line must never wrap:
     claude's full-width rules and box drawing only line up when one screen
     row is one rendered row. fitPaneFont() shrinks the type to fit those columns
     (down to a readable floor, then this scrolls sideways). */
  white-space: pre; color: var(--term-fg); line-height: 1.55;
  caret-color: var(--term-cursor);
  /* Fallback only — the desktop flex chain below stretches it to fill. */
  height: 520px;
}
.pane-card .jump-latest {
  position: absolute; right: var(--sp-6); bottom: var(--sp-6); z-index: 2;
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent); border-radius: var(--r-full);
  padding: var(--sp-2) var(--sp-5); font-size: var(--fs-sm); cursor: pointer;
  box-shadow: var(--shadow); transition: all var(--t-fast) ease;
  font-weight: var(--fw-semi);
}
.pane-card .jump-latest:hover { background: var(--accent); color: var(--on-accent); }

/* ─── Terminal page + session-detail send bar ─── */
.term-card {
  background: var(--term-bg) !important;
  display: flex;
  flex-direction: column;
}
.term-card .head {
  background: var(--bg-elev-2) !important;
}
.term-screen {
  flex: 1;
  font-family: var(--term-font);
  font-size: var(--fs-md);
  line-height: 1.5;
  color: var(--term-fg);
  background: var(--term-bg);
  padding: var(--sp-7);
  margin: 0;
  overflow-y: auto;
  outline: none;
  cursor: text;
  border: none;
}
.term-screen:focus {
  background: var(--term-bg);
}
.term-bar {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-5);
  padding: var(--sp-5) var(--sp-7);
  background: var(--bg-elev-2);
  border-top: 1px solid var(--border);
}
.term-bar::before {
  content: "❯";
  color: var(--accent);
  font-family: var(--mono);
  font-weight: var(--fw-black);
  font-size: var(--fs-lg);
  user-select: none;
}
/* Os dois campos de digitação — a mensagem da sessão (várias linhas) e a linha
   de comando da tela Terminal (uma só). Nenhum dos dois é `<textarea>` ou
   `<input>`: são `contenteditable`, para sair da varredura dos gerenciadores
   de senha (ver `TerminalField()` em components.js). O que o controle de
   formulário dava de graça está reposto aqui — a quebra de linha, o teto de
   altura e o placeholder. */
.term-input {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--term-fg);
  font-family: var(--mono);
  font-size: var(--fs-md);
  line-height: 1.5;
  outline: none;
  padding: var(--sp-1) 0;
  width: 100%;
  cursor: text;
  /* Âncora do placeholder, que fica fora do fluxo do texto (abaixo). */
  position: relative;
  /* Um `<input>` não quebra linha e rola para o lado; sem isto o div quebraria. */
  white-space: pre;
  overflow-x: auto;
  min-height: 1.5em;
}
.term-input.multiline {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  overflow-x: hidden;
  /* Cresce com o texto e para em oito linhas, daí rola por dentro — uma caixa
     sem teto empurraria o terminal para fora da tela. Era medido em JS a cada
     tecla; `em` acompanha o tamanho da fonte, que muda no celular. */
  max-height: 12em;
  overflow-y: auto;
}
/* O placeholder de um contenteditable é conteúdo gerado. Não entra no
   `textContent`, então `value` continua vazio enquanto ele está à mostra.
   Fora do fluxo do texto (absolute): em linha, ele ocupava a linha, e o cursor
   podia piscar DEPOIS dele — visto no macOS quando a edição deixa um `<br>`
   sobrando no campo vazio. Assim o cursor fica sempre no começo. */
.term-input[data-empty]::before {
  content: attr(data-placeholder);
  position: absolute;
  inset: 0;
  /* Centrado na altura do campo vazio (padding simétrico), na mesma linha em
     que o texto digitado aparece. */
  display: flex;
  align-items: center;
  overflow: hidden;
  white-space: nowrap;
  color: var(--fg-mute);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  opacity: 0.8;
  pointer-events: none;
}
.term-controls {
  display: flex;
  gap: var(--sp-3);
  align-items: center;
}
.term-idle { flex: 1; color: var(--fg-mute); font-size: var(--fs-sm); }
.term-bar.idle::before { opacity: 0.4; }
.term-bar .icon-btn {
  width: 30px; height: 30px; flex: 0 0 auto; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-md); border: 1px solid var(--border);
  background: var(--bg-elev); color: var(--fg-dim); cursor: pointer;
  font-size: var(--fs-md); transition: all var(--t-fast) ease;
}
.term-bar .icon-btn:hover { color: var(--fg); border-color: var(--fg-mute); }
.term-bar .icon-btn.send { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.term-bar .icon-btn.send:hover { filter: brightness(1.08); }

/* Full-height layout to fit the screen and avoid outer scrollbars */
body[data-route="terminal"] {
  height: 100vh;
  overflow: hidden;
}
body[data-route="terminal"] .app {
  height: 100vh;
  min-height: 100vh;
  overflow: hidden;
}
body[data-route="terminal"] .main {
  height: calc(100vh - 70px);
  padding: 30px 40px 30px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
body[data-route="terminal"] .term-card {
  flex: 1;
  min-height: 0;
}
body[data-route="terminal"] .term-screen {
  flex: 1;
  min-height: 0;
  max-height: none;
}

/* Session detail: the pane is a live terminal, so on desktop it fills the
   available screen height/width (no outer scroll) — same model as the terminal
   page. The header/tags/tabs are fixed-height rows above it; the send bar stays
   pinned below. Mobile keeps the stacked, naturally-scrolling layout. */
.detail-col.wide { min-width: 0; }
@media (min-width: 721px) {
  body[data-route="session-detail"], body[data-route="session-detail"] .app { height: 100vh; min-height: 100vh; overflow: hidden; }
  body[data-route="session-detail"] .main { height: calc(100vh - 70px); padding-bottom: 30px; display: flex; flex-direction: column; overflow: hidden; }
  /* Header rows keep their natural height; only the terminal column grows. */
  /* Target the strip, not .tabs itself: .tabs now sits INSIDE .tab-strip and
     has to grow so the "+" and the all-sessions menu stay pinned right. */
  body[data-route="session-detail"] .sess-hdr,
  body[data-route="session-detail"] .mtags,
  body[data-route="session-detail"] .tab-strip { flex: 0 0 auto; }
  body[data-route="session-detail"] .detail-col { flex: 1; display: flex; flex-direction: column; min-height: 0; }
  body[data-route="session-detail"] .detail-col .pane-card { flex: 1; min-height: 0; display: flex; flex-direction: column; }
  body[data-route="session-detail"] .detail-col .pane-card .pane-scroll { flex: 1; height: auto; min-height: 0; }
}

/* ─── The attention rail (js/views/attention-rail.js) ───
   Beside the terminal from 1180px up, where it replaces the tab strip; below
   that the tabs (and the phone's session select) stay and the rail is gone. */
.sd-split { display: flex; gap: var(--sp-6); min-height: 0; }
/* It takes the screen's height at every width, not only beside the rail: below
   1180px it sized to its content, so a short phone conversation left the
   message box mid-screen and a 1024px terminal stopped 30px short. */
body[data-route="session-detail"] .sd-split { flex: 1; }
.sd-split > .detail-col { flex: 1 1 auto; min-width: 0; }
.att-rail { display: none; }
@media (min-width: 1180px) {
  body[data-route="session-detail"] .sd-split { flex: 1; }
  body[data-route="session-detail"] .tab-strip { display: none; }
  body[data-route="session-detail"] .detail-col > .tab-strip + .pane-card { border-top-left-radius: var(--r-lg); }
  .att-rail {
    display: flex; flex-direction: column; gap: var(--sp-6);
    flex: 0 0 280px; overflow-y: auto; min-height: 0;
    padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-lg);
    background: var(--bg-elev);
  }
  .att-rail.folded { flex-basis: 52px; gap: var(--sp-2); align-items: center; padding: var(--sp-3) var(--sp-2); }
}
.att-fold {
  align-self: flex-end; width: 32px; height: 32px; flex: none;
  display: grid; place-items: center; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: transparent; color: var(--fg-mute); cursor: pointer;
}
.att-rail.folded .att-fold { align-self: center; }
.att-fold:hover { color: var(--fg); border-color: var(--border-strong); }
.att-fold:focus-visible, .att-mini:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.att-mini {
  width: 36px; height: 36px; flex: none; display: grid; place-items: center;
  border: 0; border-radius: var(--r-sm); background: transparent; cursor: pointer;
}
.att-mini:hover, .att-mini.on { background: var(--bg-elev-2); }
.att-mini.on { box-shadow: inset 0 0 0 1px var(--border); }
.att-group { display: flex; flex-direction: column; gap: 2px; }
.att-head {
  display: flex; justify-content: space-between; padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-2xs); font-weight: var(--fw-semi); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--fg-mute);
}
.att-count { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.att-needs .att-head { color: var(--attention); }
.att-row {
  display: flex; align-items: center; gap: var(--sp-4); width: 100%; min-height: 48px;
  padding: var(--sp-3); border: 0; border-radius: var(--r-md); background: transparent;
  color: var(--fg); font: inherit; text-align: left; cursor: pointer;
}
.att-row:hover { background: var(--bg-elev-2); }
.att-row.on { background: var(--bg-elev-2); box-shadow: inset 0 0 0 1px var(--border); }
.att-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.att-dot { flex: none; width: 8px; height: 8px; border-radius: var(--r-full); background: var(--fg-mute); }
.att-dot.needs { background: var(--attention); }
.att-dot.working { background: var(--green); }
.att-dot.done { background: var(--blue); }
.att-dot.off { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fg-mute); }
.att-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.att-top { display: flex; justify-content: space-between; gap: var(--sp-3); }
.att-name { font-size: var(--fs-md); font-weight: var(--fw-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.att-age { flex: none; font-family: var(--mono); font-size: var(--fs-2xs); color: var(--fg-mute); }
.att-line { font-size: var(--fs-xs); color: var(--fg-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.att-needs .att-line { color: var(--fg-dim); }

/* ─── The session's context drawer (js/views/context-drawer.js) ───
   Slides over the right of the terminal, never beside it: a column there
   would come off the terminal's fitted font. */
.ctx-open .ctx-count {
  font-family: var(--mono); font-size: var(--fs-2xs); font-variant-numeric: tabular-nums;
  padding: 0 var(--sp-2); border-radius: var(--r-sm); background: var(--bg-elev-2); color: var(--fg-dim);
}
.ctx-open .ctx-count:empty { display: none; }
.ctx-drawer {
  position: fixed; top: calc(var(--nav-h) + var(--sp-6)); right: var(--sp-6); bottom: var(--sp-6);
  z-index: var(--z-menu); width: min(460px, calc(100vw - 2 * var(--sp-6)));
  display: flex; flex-direction: column; background: var(--bg-elev);
  border: 1px solid var(--border-strong); border-radius: var(--r-lg); box-shadow: var(--shadow);
}
.ctx-drawer[hidden] { display: none; }
.ctx-head { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-4); border-bottom: 1px solid var(--border); }
.ctx-tabs { flex: 1; display: flex; gap: var(--sp-1); padding: 3px; border: 1px solid var(--border); border-radius: var(--r-md); }
.ctx-tab {
  flex: 1; min-height: 34px; border: 0; border-radius: var(--r-sm); background: transparent;
  color: var(--fg-mute); font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-medium); cursor: pointer;
}
.ctx-tab.on { background: var(--bg-elev-2); color: var(--fg); }
.ctx-close {
  width: 34px; height: 34px; display: grid; place-items: center; border: 1px solid var(--border);
  border-radius: var(--r-sm); background: transparent; color: var(--fg-mute); cursor: pointer;
}
.ctx-close:hover { color: var(--fg); }
.ctx-tab:focus-visible, .ctx-close:focus-visible, .ctx-file:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ctx-body { flex: 1; overflow-y: auto; padding: var(--sp-5) var(--sp-6); display: flex; flex-direction: column; gap: var(--sp-5); }
.ctx-meta {
  display: flex; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-4);
  font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-mute);
}
.ctx-empty { color: var(--fg-mute); font-size: var(--fs-md); padding: var(--sp-3) 0; }
.ctx-files { display: flex; flex-direction: column; gap: 2px; }
.ctx-file {
  display: flex; align-items: center; gap: var(--sp-4); width: 100%; min-height: 40px;
  padding: 0 var(--sp-4); border: 0; border-radius: var(--r-sm); background: var(--bg-elev-2);
  color: var(--fg); font: inherit; text-align: left; cursor: pointer;
}
.ctx-file:hover { box-shadow: inset 0 0 0 1px var(--border-strong); }
.ctx-st { flex: none; width: 16px; font-family: var(--mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); color: var(--fg-mute); }
.ctx-path { flex: 1; min-width: 0; font-family: var(--mono); font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }
.ctx-nums { flex: none; display: flex; gap: var(--sp-2); font-family: var(--mono); font-size: var(--fs-xs); }
.ctx-add { color: var(--green); }
.ctx-del { color: var(--red); }
/* Git G2: branch, sync, pull/push, the files to commit, the message. */
.ctx-git {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-4);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); background: var(--bg-elev-2);
}
.ctx-branch {
  display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 30px; padding: 0 var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg-elev); color: var(--fg);
  font-family: var(--mono); font-size: var(--fs-xs); cursor: pointer; max-width: 100%;
}
.ctx-branch span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctx-branch:disabled { cursor: default; }
.ctx-branch:focus-visible, .ctx-pick:focus-visible, .ctx-branch-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ctx-sync { font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-mute); }
.ctx-git-actions { display: inline-flex; gap: var(--sp-2); margin-left: auto; }
.ctx-git-msg { margin: 0 0 var(--sp-4); }
.ctx-git-msg a { color: var(--accent); overflow-wrap: anywhere; }
.ctx-file-row { display: flex; align-items: center; gap: var(--sp-3); }
.ctx-file-row .ctx-file { flex: 1; min-width: 0; }
.ctx-pick { flex: none; width: 16px; height: 16px; accent-color: var(--accent); }
.ctx-commit { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-5); }
.ctx-msg {
  width: 100%; resize: vertical; padding: var(--sp-3) var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg); color: var(--fg); font: inherit; font-size: var(--fs-sm);
}
.ctx-msg:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.ctx-commit-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.ctx-branches { display: flex; flex-direction: column; gap: 2px; margin-bottom: var(--sp-5); max-height: 40vh; overflow-y: auto; }
.ctx-branch-item {
  text-align: left; padding: var(--sp-3) var(--sp-4); border: 0; border-radius: var(--r-sm); background: var(--bg-elev-2);
  color: var(--fg); font-family: var(--mono); font-size: var(--fs-sm); cursor: pointer;
}
.ctx-branch-item.on { color: var(--accent); cursor: default; }
.ctx-diff-wrap { display: flex; flex-direction: column; gap: var(--sp-4); align-items: flex-start; }
.ctx-diff-path { font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-dim); word-break: break-all; }
.ctx-diff {
  align-self: stretch; overflow-x: auto; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--term-bg); padding: var(--sp-3) 0; font-family: var(--term-font); font-size: var(--fs-xs); line-height: 1.5;
}
.ctx-dl { padding: 0 var(--sp-4); white-space: pre; color: var(--term-fg); }
.ctx-dl.add { background: var(--green-soft); color: var(--fg); }
.ctx-dl.del { background: var(--red-soft); color: var(--fg); }
.ctx-dl.hunk { color: var(--blue); }

/* The workspace lives beside the title on desktop; this copy is the phone's,
   floating at the top of the terminal where there is room for it. */
.pane-dir { display: none; }

/* Starting a session draws nothing for seconds. A pill in the corner is easy
   to miss on a wide screen, so this says it where the eye already is: the
   middle of the empty terminal. Absolute rather than in flow, so it never
   shifts the pane once real output replaces it. */
.pane-starting {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3); pointer-events: none;
  color: var(--text-dim);
}
.pane-starting-title { font-size: var(--fs-md); font-weight: var(--fw-semi); color: var(--text); }
.pane-starting-sub { font-size: var(--fs-sm); color: var(--text-mute); }

/* An ended session: dim the frozen frame it left behind and name the state.
   Without this it looked identical to a live terminal that simply had nothing
   new to say. The overlay does not cover the output -- the last frame is often
   exactly what the operator wants to read -- so it sits at the bottom. */
.pane-card.ended pre { opacity: 0.5; filter: grayscale(0.35); }
.pane-ended {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-1); padding: var(--sp-3) var(--sp-4);
  pointer-events: none; text-align: center;
  background: var(--bg-elev-2); border-top: 1px solid var(--border);
}
.pane-ended-title { font-size: var(--fs-md); font-weight: var(--fw-semi); color: var(--text); }
.pane-ended-sub { font-size: var(--fs-sm); color: var(--text-mute); }
/* The card is the positioning context for the block above. */
.pane-card { position: relative; }

/* The tab strip lives INSIDE the pane's control bar now, so it loses the
   full-width chrome it had as a standalone row: no bottom border to sit on, no
   margin, and it must be the part that shrinks when the bar runs out of room —
   the live pill, agent and zoom controls are fixed-width and must not wrap. */
/* ── Session tabs: folder tabs above the card, not pills inside its bar ──
   The strip lives outside .pane-card, so the palette is set one level up on
   .detail-col and both read the same --term-* properties. The selected tab
   wears the terminal's own background and loses its bottom border, so it and
   the pane read as one object; the card's top-left corner is squared off for
   the same reason. */
.detail-col > .tab-strip {
  border-bottom: none; margin-bottom: 0; gap: var(--sp-1);
  align-items: flex-end; flex: 0 0 auto; padding-bottom: 0;
}
.detail-col > .tab-strip .tabs { border-bottom: none; margin-bottom: 0; gap: var(--sp-1); }
/* Selection is signalled STRUCTURALLY: only the selected tab is drawn as a tab.
   The unselected ones are flat labels — no frame, no fill.

   The previous design distinguished them by background alone, and that is a bet
   that cannot be won: the selected tab wears --term-bg, which is whatever the
   session's terminal theme happens to be, and most themes sit within a few
   percent of the app's own surface in the matching colour mode. Measured at a
   1.05 contrast ratio in dark and 1.06 in light — indistinguishable, exactly as
   reported. Moving the others to --bg only traded one collapse for another,
   because --term-bg lands BETWEEN the two app greys.

   So the cue is the presence of a frame, which no palette can erase, backed by
   three more that fail independently: the accent rail (the one colour that
   never follows the terminal theme), full-strength text against muted, and
   semibold against medium. */
.detail-col > .tab-strip .tab {
  border: 1px solid transparent; border-bottom: none;
  border-radius: var(--r-md) var(--r-md) 0 0;
  padding: var(--sp-3) var(--sp-5);
  background: transparent; color: var(--text-mute);
  font-weight: var(--fw-medium);
  position: relative; z-index: 1;
}
.detail-col > .tab-strip .tab:hover {
  color: var(--text-dim); background: var(--surface-raised);
}
.detail-col > .tab-strip .tab.on {
  background: var(--term-bg); color: var(--term-fg);
  font-weight: var(--fw-semi);
  border-color: var(--border);
  /* The rail, drawn inside the border so it follows the rounded top corners. */
  box-shadow: inset 0 2px 0 0 var(--accent);
  /* Overlaps the card's top border so the tab and the pane share an edge. */
  margin-bottom: -1px; padding-bottom: calc(var(--sp-3) + 1px);
}
.detail-col > .tab-strip .tab.on:hover { background: var(--term-bg); }
.detail-col > .tab-strip + .pane-card { border-top-left-radius: 0; }
/* Menus anchored in the tab strip open DOWNWARD. The default opens upward
   (`bottom: 100%`), which is right for the send bar at the foot of the column
   and wrong here: the strip is the first thing in the column, so the menu was
   drawn above the viewport and the button looked dead. */
.sess-hdr .tab-strip-end .menu { top: calc(100% + var(--sp-3)); bottom: auto; }

/* The strip moved out of the bar and above the card (see the folder-tab rules
   further up), so the in-bar tab styling is gone with it. */
.pane-card .head .tab-strip-end { padding-bottom: 0; }

/* ─── Session picker ──────────────────────────────────────────────────────
   A scrolling tab strip does not work on a phone: the tabs overflow and the
   overflow menu is a second control to hunt for. Below the breakpoint one
   native select does both jobs — it names the session you are in and picks
   any other — while `+` and Resume stay beside it. */
.tab-select-wrap { display: none; position: relative; flex: 1 1 auto; min-width: 0; }
/* The chevron is drawn here, not left to the native one: on a phone the system
   arrow is a hairline in the text colour, and against a dark terminal the whole
   control read as the terminal's heading rather than as something to tap. */
.tab-select-wrap::after {
  content: ""; position: absolute; right: var(--sp-4); top: 50%;
  width: 7px; height: 7px; margin-top: -5px;
  border-right: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
  transform: rotate(45deg); pointer-events: none;
}
.tab-select {
  display: none;
  width: 100%; min-width: 0;
  font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-semi);
  height: 34px; padding: 0 var(--sp-3);
  color: var(--text); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-sm);
}

/* ─── Conversation history, pulled from the transcript on demand ───────────
   The terminal cannot hold history (the agent redraws in the alternate screen
   buffer and never scrolls), so older turns are fetched a page at a time and
   stacked ABOVE the live pane: older upward, live at the bottom, which is the
   direction a terminal already reads. */
/* Scrolls with the content: it marks the top of the conversation, and a
   button pinned outside the scroll claimed to be part of a stack it was not
   in. */
.pane-more-bar {
  flex: 0 0 auto;
  display: flex; justify-content: center; gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-4) var(--sp-2);
}
.pane-more {
  font: inherit; font-size: var(--fs-xs); font-weight: var(--fw-semi);
  cursor: pointer; padding: var(--sp-2) var(--sp-5);
  color: var(--text-dim); background: transparent;
  border: 1px dashed var(--border); border-radius: var(--r-full);
  transition: all var(--t-fast) ease;
}
.pane-more:hover:not(:disabled) {
  color: var(--accent); border-color: var(--accent); background: var(--accent-soft);
}
.pane-more:disabled { opacity: 0.55; cursor: default; }
/* The transcript is inside the terminal, so it wears the terminal's palette --
   not the app's. Left on the app's colours it was the largest thing on screen
   and made a themed pane look untouched. */
/* Inside the same scroll as the terminal now, so no height cap and no
   scrollbar of its own — it simply continues upward from the live output.
   Monospaced at the terminal's own size so the seam between transcript and
   pane is not a change of typeface halfway up the conversation. */
.pane-history {
  flex: 0 0 auto;
  padding: var(--sp-4) var(--sp-7);
  border-bottom: 1px solid var(--border);
  font-family: var(--term-font); font-size: 12.5px; line-height: 1.55;
  color: var(--term-fg);
}
.phist-entry { padding: var(--sp-3) 0; border-top: 1px solid var(--border); }
.phist-entry:first-child { border-top: none; }
.phist-who {
  font-size: var(--fs-2xs); font-weight: var(--fw-bold); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--term-dim); margin-bottom: var(--sp-1);
}
.phist-ts { font-weight: var(--fw-medium); text-transform: none; letter-spacing: 0; }
.phist-text { white-space: pre-wrap; overflow-wrap: anywhere; color: var(--term-fg); }
/* The operator's own turns in the theme's blue, the way an agent marks them. */
.phist-user .phist-who { color: var(--term-ansi-4, var(--accent)); }
/* Tool traffic is context, not conversation — present but recessive. */
.phist-tool .phist-text { color: var(--term-dim); font-family: var(--term-font); font-size: var(--fs-2xs); }

/* The send bar reads as the terminal's own input line: the pane loses its
   bottom rounding and the bar picks it up. It stays OUTSIDE .pane-card because
   that card clips overflow, which would cut off the upward actions menu. */
body[data-route="session-detail"] .pane-card { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
body[data-route="session-detail"] .term-bar {
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 var(--r-xl) var(--r-xl);
}

/* ─── Session detail: actions menu ───
   A separate class family from components.css's .menu/.menu-item (same
   shape, kept distinct rather than rewriting session-detail.js's markup). */
.amenu-wrap { position: relative; flex: 0 0 auto; }
.amenu {
  position: absolute; right: 0; bottom: calc(100% + var(--sp-3)); width: 214px; z-index: var(--z-menu);
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow); padding: var(--sp-1); display: none;
}
.amenu-wrap.open .amenu { display: block; }
.amenu-item {
  width: 100%; text-align: left; font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-semi);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-sm); border: none; background: transparent;
  color: var(--fg-dim); cursor: pointer; display: flex; align-items: center; gap: var(--sp-3);
}
.amenu-item:hover { background: var(--bg-elev-2); color: var(--fg); }
.amenu-item.danger { color: var(--red); }
.amenu-item.danger:hover { background: var(--red-soft); }
.amenu-item .k { width: 15px; text-align: center; opacity: 0.85; }
.amenu hr { border: none; border-top: 1px solid var(--border); margin: var(--sp-1) 2px; }

/* ─── Resume: workspace folder list ─── */
.folder-list { padding: 0; max-height: min(60vh, 520px); overflow-y: auto; }
.folder { padding: var(--sp-5) var(--sp-6); cursor: pointer; border-bottom: 1px solid var(--border-soft); font-family: var(--mono); font-size: var(--fs-sm); color: var(--fg-dim); transition: all var(--t-fast) ease; }
.folder:hover { background: var(--bg-elev-2); color: var(--fg); }
.folder.active { background: var(--bg-elev-2); color: var(--accent); border-left: 3px solid var(--accent); font-weight: var(--fw-semi); }
.folder .count { float: right; color: var(--fg-mute); font-family: var(--font-sans); }

/* Head right-group (row count + page-size selector) + pagination footer —
   a deliberately separate implementation from components.css's .pager (see
   js/views/resume.js's header comment for why Pager wasn't adopted here). */
.rsm-below { display: block; }

/* ─── Resume: a busca e a lista de workspaces acompanham a rolagem ────────
   Uma busca cujo campo sai da tela obriga a rolar de volta para refiná-la, e
   uma lista de resultados longa é exatamente quando se quer trocar de pasta.
   As duas coisas ficam ancoradas enquanto os resultados correm por baixo.

   O contexto de rolagem aqui é o DOCUMENTO — `.main` é `overflow: visible`, e
   nenhum ancestral rola —, então o `top` é medido a partir do topo da janela.
   Um `position: sticky` dentro de um pai com `overflow` diferente de visible
   não gruda em nada, que é por que isso importa.

   O topo da janela já é da navegação (`--nav-h`), que também é sticky e tem
   z-index maior: grudar em 0 esconde o campo de busca atrás dela — só a
   linha de filtros aparecia. */
.rsm-searchbar {
  position: sticky; top: var(--nav-h); z-index: var(--z-menu);
  /* Fundo próprio: sem ele as linhas passam por baixo e leem através da barra.
     A sombra separa o que está fixo do que está correndo. */
  background: var(--surface);
  box-shadow: 0 6px 16px -12px rgba(0, 0, 0, 0.55);
}
/* A lista de workspaces só é barra LATERAL acima de 720px; abaixo disso o
   `.split` vira uma coluna só e ela passa a ficar ACIMA dos resultados, na
   largura toda — grudada ali seria um cabeçalho gordo comendo metade da tela,
   o oposto do pedido. Por isso o bloco inteiro é condicionado à largura, em
   vez de ser desfeito depois: desfazer deixaria o `max-height: none` de baixo
   vencendo por especificidade o limite que o mobile impõe à lista. */
@media (min-width: 721px) {
  /* Abaixo da barra, não sob ela: o topo é a altura que a barra ocupa. Como
     ela cresce com os filtros, a medida vem de uma custom property que o JS
     ajusta — um valor fixo aqui descolaria no primeiro filtro novo. */
  .split > .card:first-child {
    position: sticky; top: calc(var(--nav-h) + var(--rsm-bar-h, 88px));
    /* Nunca mais alta que a janela, senão a parte de baixo fica inalcançável. */
    max-height: calc(100vh - var(--nav-h) - var(--rsm-bar-h, 88px) - var(--sp-8));
    display: flex; flex-direction: column;
  }
  .split > .card:first-child .folder-list {
    /* A própria lista rola quando há muitas pastas; o card fica parado. */
    flex: 1 1 auto; min-height: 0; max-height: none;
  }
}

/* ─── Folder picker (hierarchical drill-down) ──────────────────────────
   Modal surface built in app.js's folderPicker(), used by the new-session
   wizard's "Workspace folder" step — not a screen, so it never moved into
   js/views/*.js. */
.fp { margin-bottom: var(--sp-5); }
.fp .fp-selected {
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  font-size: var(--fs-md);
}
.fp .fp-selected b { color: var(--fg-mute); font-weight: var(--fw-medium); margin-right: var(--sp-2); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.4px; }
.fp .fp-selected code { font-family: var(--mono); font-size: var(--fs-sm); color: var(--fg); }
.fp .fp-selected.empty code { color: var(--fg-mute); }

.fp .fp-breadcrumb {
  background: var(--bg);
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  padding: var(--sp-2) var(--sp-4);
  font-family: var(--mono); font-size: var(--fs-sm);
  color: var(--fg-dim);
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1);
}
.fp .fp-breadcrumb .fp-crumb {
  cursor: pointer;
  padding: 1px var(--sp-1); border-radius: var(--r-xs);
}
.fp .fp-breadcrumb .fp-crumb:hover { background: var(--bg-elev-2); color: var(--fg); }
.fp .fp-breadcrumb .fp-crumb.current { color: var(--accent); cursor: default; }
.fp .fp-breadcrumb .fp-crumb.current:hover { background: transparent; }
.fp .fp-breadcrumb .fp-sep { color: var(--fg-mute); }

.fp .fp-toolbar {
  display: flex; gap: var(--sp-2); align-items: center;
  padding: var(--sp-2) var(--sp-4);
  background: var(--bg-elev-2);
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  font-size: var(--fs-xs);
}
.fp .fp-toolbar .btn { padding: 3px var(--sp-3); font-size: var(--fs-xs); }

.fp .fp-list {
  border: 1px solid var(--border);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  background: var(--bg);
  max-height: 220px; overflow-y: auto;
}
.fp .fp-entry {
  padding: var(--sp-2) var(--sp-4);
  display: flex; align-items: center; gap: var(--sp-3);
  border-bottom: 1px solid var(--border-soft);
  cursor: pointer;
  font-family: var(--mono); font-size: var(--fs-sm);
  color: var(--fg-dim);
}
.fp .fp-entry:last-child { border-bottom: none; }
.fp .fp-entry:hover { background: var(--bg-elev-2); color: var(--fg); }
.fp .fp-entry.selected { background: var(--accent-soft); }
.fp .fp-entry.selected .fp-name { color: var(--accent); }
.fp .fp-entry.up { color: var(--fg-mute); }
.fp .fp-entry .fp-name { flex: 1; min-width: 0; word-break: break-all; }
.fp .fp-entry .fp-tag {
  font-size: var(--fs-2xs); padding: 1px var(--sp-2); border-radius: var(--r-xs);
  background: rgba(63,185,80,0.13); color: var(--green);
  text-transform: uppercase; letter-spacing: 0.4px;
}
.fp .fp-entry .fp-arrow {
  color: var(--fg-mute);
  padding: 0 var(--sp-1);
  cursor: pointer;
  border-radius: var(--r-xs);
}
.fp .fp-entry .fp-arrow:hover { background: var(--bg-elev); color: var(--fg); }
.fp .fp-entry .fp-arrow.disabled { visibility: hidden; }

/* Hover-revealed per-row actions: rename + delete. opacity:0 keeps the layout
   width stable whether visible or not. */
.fp .fp-entry .fp-rowact {
  display: inline-flex; gap: 2px; align-items: center;
  opacity: 0;
  transition: opacity var(--t-fast);
}
.fp .fp-entry:hover .fp-rowact,
.fp .fp-entry:focus-within .fp-rowact { opacity: 1; }
.fp .fp-entry .fp-rowact button {
  background: transparent; border: 1px solid transparent;
  color: var(--fg-mute); cursor: pointer;
  padding: 2px var(--sp-2); border-radius: var(--r-xs);
  font-size: var(--fs-sm); line-height: 1;
}
.fp .fp-entry .fp-rowact button.ren:hover { background: var(--bg-elev); color: var(--fg); border-color: var(--border); }
.fp .fp-entry .fp-rowact button.del:hover { background: var(--red-soft); color: var(--red); border-color: var(--red); }
.fp .empty {
  padding: var(--sp-6) var(--sp-4); text-align: center;
  color: var(--fg-mute); font-size: var(--fs-sm);
}

/* ─── Visible-list combobox (app.js's combobox()) ───
   Filterable "input + always-open options list" — built to replace
   <datalist> (see the function's own header comment). It currently has no
   caller (grep confirms), but the audit script flagged .combo/.options/.opt
   as used regardless, since the class-constructing code itself is live,
   reachable JS — a class-name matcher can't know a function has zero call
   sites without call-graph analysis. Styled rather than deleted: the
   surrounding function is a real, documented piece of the picker toolkit,
   not stale markup. */
.combo { position: relative; }
.combo input { width: 100%; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md); color: var(--fg); padding: var(--sp-4) var(--sp-5); font: inherit; font-size: var(--fs-md); }
.combo input:focus { outline: none; border-color: var(--accent); }
.combo .options { margin-top: var(--sp-2); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg); max-height: 180px; overflow-y: auto; }
.combo .options .opt { padding: var(--sp-3) var(--sp-4); cursor: pointer; font-family: var(--mono); font-size: var(--fs-sm); color: var(--fg-dim); border-bottom: 1px solid var(--border-soft); }
.combo .options .opt:last-child { border-bottom: none; }
.combo .options .opt:hover { background: var(--bg-elev-2); color: var(--fg); }
.combo .options .opt.selected { background: var(--accent-soft); color: var(--accent); }
.combo .options .empty { padding: var(--sp-5) var(--sp-4); }

/* ─── System / process table ───
   table.std / .proc-table dress up the generic .table primitive
   (webui/css/components.css, Table component) for the System screen's
   process table — system.js adds both classes alongside "table". */
.table-scroll { overflow-x: auto; }
table.std { width: 100%; border-collapse: collapse; margin-top: var(--sp-5); box-shadow: var(--shadow-sm); border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--border); }
table.std th { background: rgba(0, 0, 0, 0.15); color: var(--fg-dim); font-size: var(--fs-xs); font-weight: var(--fw-bold); text-transform: uppercase; padding: var(--sp-5) var(--sp-6); border-bottom: 1px solid var(--border); text-align: left; white-space: nowrap; }
table.std th:hover { color: var(--fg); }
table.std td { padding: var(--sp-5) var(--sp-6); border-bottom: 1px solid var(--border-soft); font-size: var(--fs-md); }
table.std tr:last-child td { border-bottom: none; }
table.std code { font-family: var(--mono); font-size: var(--fs-sm); }
table.std .btn { padding: var(--sp-1) var(--sp-4); font-size: var(--fs-xs); }

/* User-processes table: checkbox / expand-caret / PID / name / directory /
   CPU / mem columns, in that fixed order. Table (components.js) has no
   per-column class hook, so these are positional rather than class-based.
   Selection highlight keys off the checkbox's own :checked state (:has())
   since Table's row <tr> carries no data-driven class either; the detail
   (params/path) row is the only <td> with a colspan attribute, so that's
   the hook used to style it instead of a Table-assigned class. */
.proc-table th:first-child, .proc-table td:first-child { width: 30px; text-align: center; padding-left: var(--sp-5); padding-right: 0; }
.proc-table td:first-child input { cursor: pointer; }
.proc-table th:nth-child(2), .proc-table td:nth-child(2) { width: 18px; padding-left: 2px; padding-right: 2px; }
.proc-table td:nth-child(3) { font-family: var(--mono); font-size: var(--fs-sm); color: var(--fg-dim); }
.proc-table td:nth-child(4) { font-weight: var(--fw-semi); }
.proc-table td:nth-child(5) { font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-mute); max-width: 380px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.proc-table tbody tr:has(td:first-child input:checked) td { background: var(--accent-soft); }
.proc-table .proc-caret { color: var(--fg-mute); font-size: var(--fs-xs); display: inline-block; width: 12px; }
.proc-table .proc-caret.disabled { opacity: 0; }
.proc-table td[colspan] { padding-top: 0; background: var(--bg); }
.proc-params { display: flex; flex-direction: column; gap: var(--sp-1); padding: 2px 0 var(--sp-3); }
.proc-params > div { display: flex; gap: var(--sp-4); align-items: baseline; }
.proc-params .ppk { font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.4px; color: var(--fg-mute); min-width: 44px; }
.proc-params code { font-family: var(--mono); font-size: var(--fs-sm); color: var(--fg-dim); word-break: break-all; }

/* ─── New-session wizard (two-step, sidebar + main) ─────────────────── */
.modal.nsw { width: 900px; max-width: 95vw; padding: 0; }
.nsw-grid { display: flex; min-height: 520px; max-height: calc(100vh - 48px); }
.nsw-side {
  width: 280px;
  flex: none;
  background: var(--bg);
  border-right: 1px solid var(--border);
  padding: 28px var(--sp-8);
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
}
.nsw-side .nsw-title { font-size: var(--fs-2xl); font-weight: var(--fw-bold); letter-spacing: -0.01em; }
.nsw-side .nsw-subtitle { font-size: var(--fs-sm); color: var(--fg-dim); margin-top: 2px; }

/* step indicator */
.nsw-steps { display: flex; flex-direction: column; }
.nsw-step { display: flex; gap: var(--sp-5); align-items: flex-start; position: relative; }
.nsw-step + .nsw-step { margin-top: var(--sp-2); }
.nsw-step .nsw-num {
  width: 32px; height: 32px; flex: none;
  border-radius: 50%;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  color: var(--fg-dim);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-md); font-weight: var(--fw-bold);
  transition: all var(--t-fast);
  z-index: 1;
}
/* vertical connector between the two step bubbles */
.nsw-step:not(:last-child) .nsw-num::after {
  content: ''; position: absolute;
  left: 15px; top: 32px;
  width: 2px; height: calc(100% - 26px);
  background: var(--border);
}
.nsw-step.done:not(:last-child) .nsw-num::after { background: var(--green); }
.nsw-step .nsw-step-txt .t { font-size: var(--fs-md); font-weight: var(--fw-semi); }
.nsw-step .nsw-step-txt .d { font-size: var(--fs-xs); color: var(--fg-mute); margin-top: 1px; }
.nsw-step.active .nsw-num {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.nsw-step.active .nsw-step-txt .t { color: var(--fg); }
.nsw-step.done .nsw-num { background: var(--green); border-color: var(--green); color: var(--on-status); }
.nsw-step.clickable { cursor: pointer; }
.nsw-step:not(.clickable) .nsw-step-txt .t { color: var(--fg-dim); }

/* live preview box */
.nsw-preview {
  margin-top: auto;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-5);
}
.nsw-preview .nsw-pv-label {
  font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--fg-mute); font-weight: var(--fw-bold); margin-bottom: var(--sp-4);
}
.nsw-pv-item { display: flex; gap: var(--sp-4); align-items: center; }
.nsw-pv-item + .nsw-pv-item { margin-top: var(--sp-4); }
.nsw-pv-ico {
  width: 28px; height: 28px; flex: none;
  border-radius: var(--r-md);
  background: var(--bg);
  border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-lg);
}
.nsw-pv-txt { min-width: 0; }
.nsw-pv-txt .t { font-size: var(--fs-sm); color: var(--fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nsw-pv-txt .s { font-size: var(--fs-xs); color: var(--fg-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* main content */
.nsw-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.nsw-body { padding: 26px 28px; overflow-y: auto; flex: 1; }
.nsw-body .nsw-h { font-size: var(--fs-xl); font-weight: var(--fw-bold); margin: 0 0 var(--sp-6); }
.nsw-field { margin-bottom: var(--sp-7); }
.nsw-field:last-child { margin-bottom: 0; }
.nsw-label {
  display: block;
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--fg-dim); font-weight: var(--fw-semi); margin-bottom: var(--sp-3);
}
.nsw-input {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--fg);
  padding: var(--sp-4) var(--sp-5);
  font: inherit; font-size: var(--fs-lg);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.nsw-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.nsw-input.ok { border-color: var(--green); }
.nsw-input.bad { border-color: var(--red); }
/* .nsw-input is a plain class selector, so it already styles a <textarea>
   (background/border/color/padding/font) — this just adds the sizing a
   multi-line task field needs on top. */
.nsw-task { min-height: 140px; line-height: 1.5; resize: vertical; }
.nsw-hint { font-size: var(--fs-xs); color: var(--fg-mute); margin-top: var(--sp-2); min-height: 15px; }
.nsw-hint.ok { color: var(--green); }
.nsw-hint.bad { color: var(--red); }

/* agent cards */
.nsw-agents { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); }
.nsw-agent {
  position: relative;
  padding: var(--sp-6) var(--sp-5);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  cursor: pointer;
  text-align: center;
  transition: transform var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.nsw-agent:hover { border-color: var(--fg-mute); transform: translateY(-2px); }
.nsw-agent.sel { border-color: var(--accent); background: var(--accent-soft); }
/* An agent that cannot run on this host: still shown (so the operator knows it
   exists and what is missing), but visibly not a choice. */
.nsw-agent.off { opacity: 0.55; cursor: not-allowed; }
.nsw-agent.off:hover { border-color: var(--border); transform: none; }
.nsw-agent .nsw-aoff {
  margin-top: var(--sp-2); font-size: var(--fs-2xs); color: var(--status-warn);
  text-transform: uppercase; letter-spacing: 0.04em;
}
.nsw-agent.sel::after {
  content: '✓'; position: absolute; top: var(--sp-3); right: var(--sp-3);
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent); color: var(--on-accent);
  font-size: var(--fs-xs); display: flex; align-items: center; justify-content: center;
}
.nsw-agent .nsw-av {
  width: 44px; height: 44px; margin: 0 auto var(--sp-4);
  border-radius: var(--r-lg);
  display: flex; align-items: center; justify-content: center;
  /* Fixed dark chip (theme-independent): the Kimi and Antigravity marks carry
     white fills, so they need a dark backdrop to read in both themes. */
  background: #0f1320;
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.nsw-agent .nsw-av.nsw-av-emoji { font-size: var(--fs-3xl); }
.nsw-agent .nsw-av .nsw-logo { width: 26px; height: 26px; display: block; }
.nsw-agent .nsw-an { font-size: var(--fs-md); font-weight: var(--fw-semi); }

/* segmented mode toggle */
.nsw-seg { display: flex; gap: var(--sp-1); background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--sp-1); }
.nsw-seg button {
  position: relative;
  flex: 1;
  background: transparent; border: none; border-radius: var(--r-md);
  padding: var(--sp-4) var(--sp-3); cursor: pointer;
  color: var(--fg-dim); font: inherit; text-align: center;
  transition: all var(--t-fast);
}
.nsw-seg button:hover { color: var(--fg); }
.nsw-seg button.sel { background: var(--bg-elev-2); color: var(--fg); box-shadow: var(--shadow-sm); }
.nsw-seg button .sn { font-size: var(--fs-md); font-weight: var(--fw-semi); display: block; }
.nsw-seg button .sd { font-size: var(--fs-2xs); color: var(--fg-mute); margin-top: 2px; display: block; }
.nsw-seg button.sel .sn { color: var(--accent); }
.nsw-seg button .nsw-badge {
  position: absolute; top: -7px; right: var(--sp-2);
  background: var(--accent); color: var(--on-accent);
  font-size: var(--fs-2xs); font-weight: var(--fw-bold); letter-spacing: 0.04em;
  padding: 2px var(--sp-2); border-radius: var(--r-md);
}

/* model / effort pills */
.nsw-two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); }
.nsw-block { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--sp-6); }
.nsw-block .nsw-bt { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--fg-dim); font-weight: var(--fw-semi); margin-bottom: var(--sp-5); }
.nsw-pills { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.nsw-pill {
  padding: var(--sp-2) var(--sp-5); border-radius: var(--r-full);
  border: 1px solid var(--border); background: transparent;
  color: var(--fg-dim); font: inherit; font-size: var(--fs-sm); cursor: pointer;
  transition: all var(--t-fast);
}
.nsw-pill:hover { border-color: var(--fg-mute); color: var(--fg); }
.nsw-pill.sel { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* footer */
.nsw-foot {
  padding: var(--sp-6) 28px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
}
.nsw-foot .nsw-foot-l, .nsw-foot .nsw-foot-r { display: flex; gap: var(--sp-4); }

/* Wizard status line: sits above the footer so a refused create is visible
   right where the button is, without the modal closing. */
.nsw-status { padding: 0 28px var(--sp-5); font-size: var(--fs-xs); color: var(--fg-mute); }
.nsw-status:empty { display: none; }
.nsw-status.bad { color: var(--red); }

@media (max-width: 768px) {
  /* Stacked, the wizard is a column: header, then a body that must SCROLL
     between it and the footer. Two things broke that on a phone (2026-09-25,
     "the scroll doesn't work, I can't reach the buttons"): a flex item's
     min-height defaults to its content, so .nsw-main grew to fit everything
     and the modal's overflow:hidden cut the footer off instead of the body
     scrolling; and 100vh on a phone is the height BEHIND the browser's bars.
     So every level of the column may shrink, and the height is the visible
     one (dvh, with vh as the fallback for engines without it). */
  .modal.nsw { max-height: calc(100vh - 24px); max-height: calc(100dvh - 24px); }
  .nsw-grid { flex-direction: column; min-height: 0; max-height: none; flex: 1 1 auto; }
  .nsw-main { min-height: 0; flex: 1 1 auto; }
  .nsw-body { min-height: 0; padding: var(--sp-6) var(--sp-6); }
  .nsw-foot { padding: var(--sp-5) var(--sp-6); }
  .nsw-side { width: auto; border-right: none; border-bottom: 1px solid var(--border); padding: var(--sp-5) var(--sp-6); gap: var(--sp-4); flex-direction: row; flex-wrap: wrap; align-items: center; }
  .nsw-side .nsw-hd { flex: 1 1 100%; }
  .nsw-steps { flex-direction: row; flex: 1 1 100%; gap: var(--sp-6); }
  .nsw-step + .nsw-step { margin-top: 0; }
  .nsw-step:not(:last-child) .nsw-num::after { display: none; }
  .nsw-preview { display: none; }
  .nsw-agents { grid-template-columns: 1fr; }
  .nsw-two { grid-template-columns: 1fr; }
}

/* ─── Login screen ───────────────────────────────── */
.login-screen {
  position: fixed;
  inset: 0;
  /* Must sit above the modal/toast layers (--z-modal 200, --z-toast 300) —
     a login gate has to block everything, so it stays a literal above both
     rather than a step on that scale. */
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-8);
  background:
    radial-gradient(1200px 600px at 50% -15%, var(--accent-soft), transparent 60%),
    var(--bg);
}
.login-card {
  width: 100%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  padding: 32px 28px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow);
}
.login-brand {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  font-family: var(--mono);
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  color: var(--fg);
}
.login-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
}
.login-sub {
  margin: -6px 0 var(--sp-1);
  color: var(--fg-dim);
  font-size: var(--fs-md);
}
.login-input {
  width: 100%;
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--fg);
  font: inherit;
  font-size: var(--fs-lg);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.login-input::placeholder { color: var(--fg-mute); }
.login-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.login-err {
  color: var(--red);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
}
.login-err:empty { display: none; }
.login-card .btn.primary {
  margin-top: var(--sp-1);
  padding: var(--sp-4) var(--sp-6);
  font-size: var(--fs-lg);
}

/* ─── Slim top progress bar during route-navigation fetches ─── */
#nav-progress { position: fixed; top: 0; left: 0; height: 2px; width: 100%; z-index: 9999; background: transparent; opacity: 0; transition: opacity var(--t-fast) ease; pointer-events: none; }
#nav-progress.active { opacity: 1; }
#nav-progress.active::before { content: ""; position: absolute; top: 0; left: 0; height: 100%; width: 40%; background: var(--accent); box-shadow: 0 0 8px var(--accent); animation: nav-indeterminate 1.1s ease-in-out infinite; }
@keyframes nav-indeterminate { 0% { left: -40%; } 100% { left: 100%; } }

/* ─── Responsive: phone ───────────────────────────── */
@media (max-width: 720px) {
  body[data-route="terminal"] .main {
    height: 100vh;
    padding: 74px var(--sp-5) var(--sp-5);
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  .topbar h1 { font-size: var(--fs-xl); }
  /* The 1fr has to land on the NAME, not on the agent icon — with `14px 1fr
     auto auto` the icon absorbed the row and pushed the title to the right. */
  .session-row { grid-template-columns: 14px auto minmax(0, 1fr) auto auto; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); }
  /* SessionRow renders the model through Tag now (.tag.t-<model>), so only
     .tag needs hiding here — the old .badge selector this rule used to also
     carry was already dead before this rule ever fired. */
  .session-row .tag,
  .session-row .last { display: none; }
  .session-row .dir { font-size: var(--fs-xs); }
  .pane-card pre { font-size: var(--fs-xs); padding: var(--sp-4) var(--sp-5); }
  .pane-card .pane-scroll { max-height: 360px; }
  .term-screen { font-size: var(--fs-xs); padding: var(--sp-4) var(--sp-5); max-height: 360px; min-height: 250px; }
  body[data-route="terminal"] .term-screen {
    max-height: none;
    min-height: 0;
  }
  .term-bar { padding: var(--sp-4) var(--sp-5); gap: var(--sp-3); }
  .term-bar::before { font-size: var(--fs-sm); }
  .term-input { font-size: var(--fs-xs); }
  /* 15px ties evenly between --fs-lg (14) and --fs-xl (16); tokens.css's own
     "was 15 / 16" comment already resolved that exact tie to the larger
     step, so this follows that precedent instead of the smaller-wins
     default. */
  .sess-title { font-size: var(--fs-xl); }
  .sess-hdr { gap: var(--sp-2); }
  .mtag { font-size: var(--fs-2xs); }
  .resumable-row { grid-template-columns: 1fr; gap: var(--sp-3); padding: var(--sp-5); }
  .resumable-row .rsm-actions { flex-direction: row; justify-content: flex-start; }
  table.std th, table.std td { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-xs); }
}

/* The "All workspaces" row heads the folder list and is the default selection:
   it lists the most recent sessions across every workspace. */
.folder.folder-all { font-family: var(--font-sans); font-weight: var(--fw-bold); }

/* ─── Session tab strip: tabs on the left, "+" and the all-sessions menu
   pinned to the right. The menu is what replaced the sessions-list screen,
   so it must stay reachable no matter how many tabs are open. ─── */
.tab-strip { display: flex; align-items: flex-end; gap: var(--sp-3); border-bottom: 1px solid var(--border); margin-bottom: var(--sp-5); }
.tab-strip .tabs { flex: 1 1 auto; min-width: 0; border-bottom: none; margin-bottom: 0; }
.tab-strip-end { display: flex; align-items: center; gap: var(--sp-1); flex: 0 0 auto; padding-bottom: var(--sp-1); }
/* New + Resume: the two ways to get work started from this screen. They carry
   labels rather than bare glyphs — Resume in particular has no other entry
   point in the app since it left the nav, so it cannot be a shape you have to
   hover to identify. */
.tab-act {
  height: 26px; padding: 0 var(--sp-3); cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: transparent; color: var(--text-dim);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  font: inherit; font-size: var(--fs-xs); font-weight: var(--fw-semi);
  line-height: 1; white-space: nowrap;
  transition: all var(--t-fast) ease;
}
.tab-act .tab-act-icon { font-size: var(--fs-md); line-height: 1; }
.tab-act:hover { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
/* Starting a session is this screen's primary action, so it reads as one. */
.tab-act-new { color: var(--accent); border-color: var(--accent); }
/* The overflow menu drops DOWN here (the actions menu opens up from the send bar). */
.menu-wrap.tab-all .menu { top: calc(100% + var(--sp-2)); bottom: auto; width: 280px; }
.menu-wrap.tab-all .menu-btn { width: 26px; height: 26px; font-size: var(--fs-sm); }
.menu-wrap.tab-all .menu-item { font-family: var(--mono); font-size: var(--fs-xs); }

/* ─── Empty state: no sessions at all. The app's entry point when nothing
   is running, so "new session" is the primary action. ─── */
.sess-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-4); text-align: center; padding: 12vh var(--sp-7);
}
.sess-empty-icon { color: var(--text-mute); opacity: 0.55; line-height: 0; }
.sess-empty h2 { margin: 0; font-size: var(--fs-2xl); font-weight: var(--fw-bold); color: var(--text); }
.sess-empty p { margin: 0; color: var(--text-dim); font-size: var(--fs-md); max-width: 42ch; }
.sess-empty-actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; justify-content: center; margin-top: var(--sp-3); }

/* The terminal is the one screen whose content has a fixed width in CHARACTERS
   (a 200-column pyte screen), so capping the page at 1400px directly costs font
   size. Give this route the full window; every other screen keeps the cap. */
body[data-route="session-detail"] .main { max-width: none; }

/* Reader zoom for the terminal, in the pane head. */
.pane-zoom { display: inline-flex; align-items: center; gap: var(--sp-1); }
.pane-zoom-btn {
  min-width: 22px; height: 20px; padding: 0 var(--sp-1); cursor: pointer;
  background: transparent; color: var(--text-mute);
  border: 1px solid var(--border); border-radius: var(--r-xs);
  font: inherit; font-size: var(--fs-2xs); font-weight: var(--fw-bold); line-height: 1;
  transition: all var(--t-fast) ease;
}
.pane-zoom-btn:hover { color: var(--accent); border-color: var(--accent); }
.pane-zoom-val { font-family: var(--mono); font-size: var(--fs-2xs); color: var(--text-mute); min-width: 34px; text-align: center; }

/* ─── Phone layout ───────────────────────────────────────────────────────
   Fixes from the mobile pass: the toast sat over the page title (both are
   near the top, and the header is already crowded by the fixed hamburger);
   the workspace list filled the screen so the sessions below it were a long
   scroll away; the terminal screen did not fill the viewport, leaving a dead
   block under the send bar; and several controls were below a comfortable
   tap size. */
@media (max-width: 720px) {
  /* Toasts move to the bottom, clear of the header and the hamburger. */
  #toast-root {
    top: auto; bottom: var(--sp-6);
    left: var(--sp-5); right: var(--sp-5);
    transform: none; align-items: stretch;
  }
  .toast { width: 100%; padding: var(--sp-5) var(--sp-6); }
  /* On the terminal screen the bottom belongs to the send bar, and a toast
     lands there exactly when you have just sent something — lift it clear. */
  body[data-route="session-detail"] #toast-root { bottom: 84px; }

  /* The workspace list is a filter, not the content — cap it so the session
     list it filters is reachable without scrolling past every folder. */
  .folder-list { max-height: 34vh; }

  /* The terminal is the whole point of this screen, so give it the viewport
     here too rather than a 360px box with dead space under it. */
  body[data-route="session-detail"], body[data-route="session-detail"] .app { height: 100dvh; overflow: hidden; }
  body[data-route="session-detail"] .main {
    height: 100dvh; padding: 74px var(--sp-5) var(--sp-5);
    display: flex; flex-direction: column; overflow: hidden;
  }
  body[data-route="session-detail"] .sess-hdr,
  body[data-route="session-detail"] .mtags,
  body[data-route="session-detail"] .tab-strip { flex: 0 0 auto; }
  body[data-route="session-detail"] .detail-col { flex: 1; display: flex; flex-direction: column; min-height: 0; }
  body[data-route="session-detail"] .detail-col .pane-card { flex: 1; min-height: 0; display: flex; flex-direction: column; }
  body[data-route="session-detail"] .pane-card .pane-scroll { flex: 1; height: auto; max-height: none; min-height: 0; }

  /* The metadata strip costs three rows on a phone. Keep what you act on and
     drop what you would only ever read on a big screen. */
  .mtags .mtag.m-secondary { display: none; }

  /* One select replaces the strip AND its overflow menu. */
  .tab-strip .tabs { display: none; }
  .menu-wrap.tab-all { display: none; }
  .tab-select-wrap { display: block; }
  .tab-select {
    display: block;
    /* Raised off the page and off the terminal below it. On the phone the
       picker wore --surface, which is within 1.1 of both — measured — so it
       read as the top of the terminal rather than as a control. */
    background: var(--bg-elev-2);
    /* Neutral, not accent. A coloured outline around the whole control reads as
       a validation state — "something is wrong here, click me" — which is the
       wrong sentence for a session picker. The chevron carries the affordance;
       the outline only has to be visible. */
    border-color: var(--border-strong);
    /* 44px is the touch target a thumb expects; 34 was a desktop control
       shrunk onto a phone. */
    height: 44px; padding: 0 var(--sp-8) 0 var(--sp-4);
    border-radius: var(--r-md);
    /* The native arrow is replaced by the wrapper's chevron. */
    appearance: none; -webkit-appearance: none;
  }
  /* Air between the picker and the terminal: they were touching — measured at a
     0px gap — which is most of why they looked like one object. The selector
     matches the desktop rule that sets `padding-bottom: 0`, which otherwise
     wins on specificity inside this query. */
  .tab-strip,
  .detail-col > .tab-strip {
    align-items: center; gap: var(--sp-2); padding-bottom: var(--sp-4);
  }

  /* The title moves up beside the hamburger instead of below it, which is a
     whole row of a short screen back. */
  body[data-route="session-detail"] .main { padding-top: var(--sp-4); }
  body[data-route="session-detail"] .sess-hdr {
    padding-left: 46px; min-height: 38px; align-items: center;
  }
  body[data-route="session-detail"] .sess-title { font-size: var(--fs-lg); }

  /* Tapping an input must not zoom the page: iOS zooms whenever the focused
     field is under 16px, and no viewport tag prevents that — only the size. */
  .term-input, .tab-select { font-size: 16px; }

  /* Desktop merges the tabs into this bar; 390px cannot hold the picker AND
     the live pill AND the agent AND the zoom on one line — they overlapped.
     So the picker takes a row of its own INSIDE the card. That is the same two
     rows the phone had before, now grouped in one place instead of split
     between a strip above the card and a bar below it. */
  /* The bar floats on desktop, where it sits clear of the output in the card's
     top-right corner. At this width the same cluster measured 93% of the card,
     so it would sit ON the terminal rather than beside it: back into the flow. */
  .pane-card .head {
    position: static; opacity: 1; backdrop-filter: none;
    border: none; border-bottom: 1px solid var(--border); border-radius: 0;
    box-shadow: none; background: var(--pane-bar);
    padding: var(--sp-3) var(--sp-4); gap: var(--sp-3); flex-wrap: wrap;
  }
  .pane-card .head .tab-strip { flex: 1 0 100%; }
  .pane-card .head .spacer { display: none; }
  /* With the spacer gone everything packed left. The text-size controls are
     the one thing you reach for repeatedly, so they take the right edge. */
  .pane-card .head .pane-zoom { margin-left: auto; }
  /* The theme picker sat between the status pills and read as another label,
     so it went unfound on a phone. A full-width row makes it a control. */
  .pane-card .head .menu-wrap { order: 5; flex: 1 0 100%; }
  .pane-card .head .menu-btn.wide { width: 100%; justify-content: center; }

  /* The workspace moves off the title row, which a long session name already
     fills, and floats at the top of the terminal instead. */
  .sess-hdr .chip.dir { display: none; }
  .pane-dir { display: inline-flex; }
  .pane-more-bar { flex-wrap: wrap; }
  .pane-card .head .pill { white-space: nowrap; }
  /* Uptime is already in the metadata strip right above — once is enough. */
  .pane-card .head .pill.pane-up { display: none; }

  /* Comfortable tap targets. */
  .tab-act { height: 34px; }
  .menu-wrap.tab-all .menu-btn { width: 34px; height: 34px; }
  /* A phone has no hover, so a glyph with only a tooltip is unreadable there.
     "+" is self-evident and its label goes; "↺" is not, and its label stays. */
  .tab-act-new .tab-act-label { display: none; }
  .tab-act-new { padding: 0 var(--sp-4); }
  .pane-zoom-btn { min-width: 32px; height: 30px; }
  .term-bar .icon-btn { width: 36px; height: 36px; }
  .tab { padding: var(--sp-3) var(--sp-4); }
}

/* ─── Phone density ──────────────────────────────────────────────────────
   A phone screen is ~840px tall and the chrome was eating it: the dashboard
   banner alone took a third of the viewport for a heading, a paragraph of
   description and four status pills. Trim what you read once, keep what you
   act on, and tighten the repeating rows. */
@media (max-width: 720px) {
  /* Read-once description; the pills below already carry the live facts. */

  /* Card chrome: smaller heads, tighter bodies. */
  .card .head { padding: var(--sp-4) var(--sp-5); }
  .card .head h2 { font-size: var(--fs-lg); }
  .card .body { padding: var(--sp-5); }
  .card .body.tight { padding: 0; }

  /* Repeating rows carry the most total height, so they gain the most. */
  .session-row { padding: var(--sp-3) var(--sp-4); gap: var(--sp-2); }
  .session-row .name { font-size: var(--fs-md); }
  .session-row .dir { font-size: var(--fs-2xs); }
  /* The process word restates the status dot beside it. */
  .session-row .proc { display: none; }
  .alert { padding: var(--sp-4) var(--sp-5); }

  /* Metric tiles: four of them stack, so their padding multiplies. */
  .metrics-grid { gap: var(--sp-3); }
  .metric { padding: var(--sp-5); }
  .metric .value { font-size: var(--fs-2xl); }

  .topbar { margin-bottom: var(--sp-5); padding-bottom: var(--sp-4); }
}

/* History position, shown only while the arrows are walking the history. */
.term-hist {
  flex: 0 0 auto; align-self: center;
  font-family: var(--mono); font-size: var(--fs-2xs); font-weight: var(--fw-bold);
  color: var(--accent); background: var(--accent-soft);
  border: 1px solid var(--border); border-radius: var(--r-xs);
  padding: 2px var(--sp-2); letter-spacing: 0.3px;
}

/* ─── System header: host facts and CLI versions under the title ─── */
.topbar-below { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-5); margin-top: var(--sp-3); }
.hdr-badges, .hdr-versions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.hdr-badge {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-family: var(--mono); font-size: var(--fs-2xs); color: var(--text-dim);
  background: var(--surface-raised); border: 1px solid var(--border);
  border-radius: var(--r-xs); padding: 2px var(--sp-3);
}
.hdr-badge b { color: var(--text-mute); text-transform: uppercase; font-weight: var(--fw-bold); }
/* Version chips: the icon names the binary, so only the number is spelled out. */
.hdr-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--r-full);
  padding: 0 var(--sp-3); background: var(--surface);
  height: 24px;   /* fixed, so a chip's height never follows its icon */
}
/* An agent whose CLI has a newer release out. The chip keeps its size and only
   gains the version it could move to, so a row of six chips does not reflow
   when one of them has news. */
.hdr-chip.upd { border-color: var(--status-warn-soft); }
.hdr-chip-up {
  font-family: var(--mono); font-size: var(--fs-2xs); line-height: 1;
  color: var(--status-warn);
}
.hdr-chip code { font-family: var(--mono); font-size: var(--fs-2xs); color: var(--text-dim); line-height: 1; }
/* Every icon gets the same 14px box whether it is an SVG logo (the agent CLIs)
   or a text glyph (agent-deck's own) — a glyph's line box is taller than the
   logo's, which is what made the first chip stand 6px taller than the rest. */
.hdr-chip > :first-child {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; flex: 0 0 auto;
  font-size: 12px; line-height: 1;
}


/* ── Resume dialog ──────────────────────────────────────────────────────
   The one-step sibling of the new-session wizard: it borrows that screen's
   vocabulary wholesale (.nsw-label / .nsw-input / .nsw-seg / .nsw-pills /
   .nsw-foot) instead of inventing controls that exist nowhere else, and adds
   the one thing the old dialog never showed -- WHICH conversation is being
   loaded. The agent chip is .agent-logo-chip, the same one the rest of the
   app uses. */
.modal.rsd { width: 620px; }
.rsd-hd { padding: var(--sp-7) 28px var(--sp-5); }
.rsd-title { font-size: var(--fs-2xl); font-weight: var(--fw-bold); }
.rsd-sub { font-size: var(--fs-sm); color: var(--fg-dim); margin-top: var(--sp-1); }
.rsd-body { padding: 0 28px var(--sp-7); overflow-y: auto; flex: 1; }

/* the transcript being resumed */
.rsd-card {
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--sp-6); margin-bottom: var(--sp-7);
}
.rsd-card-top { display: flex; align-items: center; gap: var(--sp-4); }
.rsd-id { min-width: 0; flex: 1; }
.rsd-name {
  font-size: var(--fs-lg); font-weight: var(--fw-semi); color: var(--fg);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rsd-where {
  font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-mute);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rsd-preview {
  margin: var(--sp-5) 0 0; font-size: var(--fs-sm); line-height: 1.55; color: var(--fg-dim);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.rsd-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-3);
  margin-top: var(--sp-5); padding-top: var(--sp-5);
  border-top: 1px solid var(--border-soft);
  font-size: var(--fs-xs); color: var(--fg-mute);
}
.rsd-dot { width: 3px; height: 3px; border-radius: 50%; background: var(--fg-mute); opacity: 0.6; }
/* How much context is left is what decides whether a transcript is worth
   resuming at all, so it reads as a quantity, not another label. */
.rsd-ctx { display: inline-flex; align-items: center; gap: var(--sp-3); }
.rsd-ctx-bar { width: 44px; height: 4px; border-radius: var(--r-full); background: var(--border); overflow: hidden; }
.rsd-ctx-fill { display: block; height: 100%; border-radius: inherit; background: var(--status-ok); }
.rsd-ctx-fill.warn { background: var(--status-warn); }
.rsd-ctx-fill.high { background: var(--status-danger); }
.rsd-ctx-num { color: var(--fg-dim); font-weight: var(--fw-semi); }
.rsd-uuid { font-family: var(--mono); font-size: var(--fs-2xs); color: var(--fg-mute); }
.nsw-hint.warn { color: var(--status-warn); }

@media (max-width: 560px) {
  .rsd-hd { padding: var(--sp-6) var(--sp-6) var(--sp-4); }
  .rsd-body { padding: 0 var(--sp-6) var(--sp-6); }
  .rsd .nsw-foot { padding: var(--sp-5) var(--sp-6); }
  /* Three mode descriptions do not fit a phone: the names carry the choice,
     and wrapping each to three lines is what made this dialog feel dense in
     the first place. Scoped to .rsd so the wizard keeps its own layout. */
  .rsd .nsw-seg button .sd { display: none; }
  .rsd .nsw-seg button { padding: var(--sp-4) var(--sp-2); }
  /* Transcript size and uuid are reference detail, not what you scan on a
     phone -- dropping them keeps the meta line to one row. */
  .rsd-meta .rsd-opt { display: none; }
}

/* ── Phone layout C (redesign, phase 5): Inbox, conversation, keys, tabs ──
   The Inbox screen works at any width (a desktop just has no tab to reach it);
   everything else here exists only at <=720px. */
.inbox { display: flex; flex-direction: column; gap: var(--sp-4); max-width: 720px; }
.inbox-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); }
.inbox-head h1 { margin: 0; font-size: 26px; font-weight: var(--fw-semi); letter-spacing: -0.02em; }
.inbox-count { font-size: var(--fs-md); color: var(--fg-mute); }
.inbox-count.attention { color: var(--attention); }
.inbox-list { display: flex; flex-direction: column; gap: var(--sp-4); }
.inbox-group {
  margin-top: var(--sp-3); font-size: var(--fs-xs); color: var(--fg-mute);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.inbox-card {
  display: flex; flex-direction: column; gap: var(--sp-3); width: 100%; text-align: left;
  padding: var(--sp-6); border-radius: var(--r-lg); cursor: pointer;
  background: var(--bg-elev); border: 1px solid var(--border); color: var(--fg); font: inherit;
}
.inbox-card.waiting { border-color: var(--attention); }
.inbox-card:hover { border-color: var(--border-strong); }
.inbox-card.waiting:hover { border-color: var(--attention); background: var(--bg-elev-2); }
.inbox-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.inbox-card-top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.inbox-name { font-weight: var(--fw-semi); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inbox-badge {
  flex: none; font-size: var(--fs-sm); font-weight: var(--fw-medium);
  padding: 2px var(--sp-4); border-radius: var(--r-full);
  color: var(--fg-dim); background: var(--bg-elev-2);
}
.inbox-badge.attention { color: var(--attention); background: var(--attention-soft); }
.inbox-badge.working { color: var(--blue); background: var(--blue-soft); }
.inbox-badge.done { color: var(--green); background: var(--green-soft); }
.inbox-line { font-size: var(--fs-md); color: var(--fg-dim); overflow-wrap: anywhere; }
.inbox-line.ask { font-size: var(--fs-lg); color: var(--fg); }
.inbox-go { align-self: flex-start; font-size: var(--fs-sm); color: var(--fg-mute); }
.inbox-card.waiting .inbox-go { color: var(--attention); font-weight: var(--fw-semi); }

.phone-tabs, .pview-toggle, .pconv, .phone-rows { display: none; }

@media (max-width: 720px) {
  :root { --phone-tabs-h: 56px; }
  .phone-tabs {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0;
    z-index: calc(var(--z-backdrop) - 1);
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--bg-elev); border-top: 1px solid var(--border);
  }
  .phone-tab {
    flex: 1; min-height: var(--phone-tabs-h); border: 0; background: transparent; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
    font: inherit; font-size: var(--fs-lg); color: var(--fg-mute);
  }
  .phone-tab.active { color: var(--fg); font-weight: var(--fw-semi); }
  .phone-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
  .phone-tab-badge {
    min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-full);
    display: inline-grid; place-items: center;
    background: var(--attention); color: var(--on-status);
    font-size: var(--fs-xs); font-weight: var(--fw-semi);
  }
  .phone-tab-badge[hidden] { display: none; }

  /* Room for the tabs under every screen. */
  .main { padding-bottom: calc(var(--phone-tabs-h) + 40px + env(safe-area-inset-bottom)); }
  body[data-route="session-detail"] .main {
    height: calc(100dvh - var(--phone-tabs-h) - env(safe-area-inset-bottom));
    padding-bottom: var(--sp-3);
  }

  .pview-toggle {
    display: inline-flex; align-items: center; height: 36px; padding: 0 var(--sp-4);
    border-radius: var(--r-md); border: 1px solid var(--border-strong);
    background: transparent; color: var(--fg-dim); font: inherit; font-size: var(--fs-sm); cursor: pointer;
  }
  .pview-toggle[aria-pressed="true"] { background: var(--bg-elev-2); color: var(--fg); }

  /* Conversation view: the transcript instead of the terminal. */
  body[data-route="session-detail"] .detail-col.phone-convo .pane-card { display: none; }
  body[data-route="session-detail"] .detail-col.phone-convo .pconv {
    display: block; flex: 1; min-height: 0; overflow-y: auto;
    padding: var(--sp-4) var(--sp-2) var(--sp-6);
  }
  .pconv-list { display: flex; flex-direction: column; gap: var(--sp-5); }
  .pconv-you {
    align-self: flex-end; max-width: 85%; padding: var(--sp-4) var(--sp-5);
    border-radius: 14px 14px 4px 14px; background: var(--bg-elev-2); border: 1px solid var(--border);
    white-space: pre-wrap; overflow-wrap: anywhere;
  }
  .pconv-agent { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.5; color: var(--fg); }
  .pconv-tools-wrap { display: flex; flex-direction: column; gap: var(--sp-2); }
  .pconv-tools {
    display: flex; align-items: center; gap: var(--sp-4); min-height: 44px; padding: 0 var(--sp-5);
    border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-elev);
    color: var(--fg-dim); font: inherit; text-align: left; cursor: pointer;
  }
  .pconv-tools-label { flex: 1; }
  .pconv-tools-hint { font-size: var(--fs-sm); color: var(--fg-mute); }
  .pconv-tools-body {
    font-family: var(--term-font); font-size: var(--fs-sm); color: var(--fg-dim);
    padding: var(--sp-4) var(--sp-5); border-radius: var(--r-md);
    background: var(--term-bg); border: 1px solid var(--border);
    display: flex; flex-direction: column; gap: var(--sp-1);
    white-space: pre-wrap; overflow-wrap: anywhere;
  }
  .pconv-tools-body[hidden] { display: none; }
  .pconv-empty { color: var(--fg-mute); font-size: var(--fs-md); padding: var(--sp-6) 0; }

  /* Quick messages and the missing keys, above the message box. */
  .phone-rows { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-3) 0; }
  .pchips { display: flex; gap: var(--sp-2); overflow-x: auto; scrollbar-width: none; }
  .pchip {
    flex: none; min-height: 36px; padding: 0 var(--sp-5); border-radius: var(--r-full);
    border: 1px solid var(--border-strong); background: var(--bg-elev);
    color: var(--fg-dim); font: inherit; font-size: var(--fs-md); cursor: pointer;
  }
  .pkeys { display: flex; gap: var(--sp-1); }
  .pkey {
    flex: 1; min-width: 0; min-height: 36px; padding: 0;
    border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg-elev);
    color: var(--fg-dim); font-family: var(--mono); font-size: var(--fs-sm); cursor: pointer;
  }
  .pchip:active, .pkey:active { background: var(--bg-elev-2); color: var(--fg); }
  .pchip:focus-visible, .pkey:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
}

/* ── Multi-user (docs/MULTIUSER.md): sign-in, the signed-in user, Users & roles ── */
.nav-item[hidden], .settings-menu .menu-item[hidden], .menu-me[hidden], .menu-divider[hidden] { display: none; }
.login-alt { display: flex; flex-direction: column; gap: var(--sp-4); }
.login-alt:empty { display: none; }
.login-or {
  display: flex; align-items: center; gap: var(--sp-4); font-size: var(--fs-xs);
  color: var(--fg-mute); text-transform: uppercase; letter-spacing: 0.08em;
}
.login-or::before, .login-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.login-note { margin: 0; font-size: var(--fs-sm); line-height: 1.5; color: var(--fg-dim); }
.menu-me { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4);
           padding: var(--sp-3) var(--sp-3) var(--sp-2); }
.menu-me-name { font-weight: var(--fw-semi); color: var(--fg); }
.menu-me-role { font-size: var(--fs-xs); color: var(--fg-mute); text-transform: uppercase; letter-spacing: 0.06em; }

.users-grid { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: var(--sp-8); align-items: start; }
.users-card { display: flex; flex-direction: column; gap: var(--sp-5); padding: var(--sp-6); }
.users-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.users-head h2 { margin: 0; font-size: var(--fs-lg); }
.users-list { display: flex; flex-direction: column; }
.users-row {
  display: grid; grid-template-columns: minmax(0, 1fr) 120px 400px;
  align-items: center; gap: var(--sp-4); padding: var(--sp-4) 0; border-top: 1px solid var(--border);
}
.users-row.disabled { opacity: 0.6; }
.users-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.users-name { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-3);
              font-weight: var(--fw-semi); color: var(--fg); }
.users-login, .users-how { font-size: var(--fs-sm); color: var(--fg-dim); overflow-wrap: anywhere; }
.users-how { color: var(--fg-mute); }
.users-role {
  min-height: 32px; padding: 0 var(--sp-3); border-radius: var(--r-md); border: 1px solid var(--border);
  background: var(--bg-elev-2); color: var(--fg); font: inherit; font-size: var(--fs-sm);
}
.users-role-label { display: flex; flex-direction: column; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--fg-dim); }
.users-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }
.users-roles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
.users-role-help { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-4);
                   border-radius: var(--r-md); background: var(--bg-elev-2); font-size: var(--fs-sm); color: var(--fg-dim); }
.users-role-help strong { color: var(--fg); text-transform: capitalize; }
.users-hint { margin: 0; font-size: var(--fs-sm); color: var(--fg-mute); }
.users-audit { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.users-audit-row { display: flex; gap: var(--sp-4); padding: var(--sp-3) 0; border-top: 1px solid var(--border);
                   font-size: var(--fs-sm); color: var(--fg-dim); }
.users-audit-when { flex: none; width: 112px; color: var(--fg-mute); font-variant-numeric: tabular-nums; }
.users-audit-what strong { color: var(--fg); font-weight: var(--fw-semi); }
@media (max-width: 900px) {
  .users-grid { grid-template-columns: minmax(0, 1fr); }
  .users-row { grid-template-columns: minmax(0, 1fr) 110px; }

  .users-actions { grid-column: 1 / -1; justify-content: flex-start; }
  .users-roles { grid-template-columns: minmax(0, 1fr); }
}

/* ── Git & GitHub (docs/MULTIUSER.md, Git G1) ── */
.git-fields { margin-bottom: 0; }

/* ── Sessions with an owner (docs/MULTIUSER.md, phase 3a) ── */
.row-owner {
  margin-left: var(--sp-3); padding: 1px var(--sp-3); border-radius: var(--r-full);
  background: var(--bg-elev-2); color: var(--fg-dim); font-size: var(--fs-xs); font-weight: var(--fw-semi);
  vertical-align: middle; white-space: nowrap;
}
.sess-hdr .chip.owner { color: var(--fg); }
.sess-hdr .chip.profile { color: var(--status-warn); border-color: var(--status-warn); }

/* ── Agents & keys and the first-run setup (docs/MULTIUSER.md, phase 2) ── */
.ak-note {
  margin: 0 0 var(--sp-6); padding: var(--sp-4) var(--sp-5); border-radius: var(--r-md);
  background: var(--status-warn-soft); color: var(--fg); font-size: var(--fs-sm); line-height: 1.5;
}
.ak-grid { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: var(--sp-8); align-items: start; }
.ak-list { display: flex; flex-direction: column; gap: var(--sp-5); }
.ak-card {
  display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--sp-6);
  border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg-elev);
}
.ak-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.ak-who { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; flex-wrap: wrap; }
.ak-name { font-weight: var(--fw-semi); font-size: var(--fs-lg); color: var(--fg); }
.ak-version { font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-mute); }
.ak-form, .ak-saved { display: flex; flex-direction: column; gap: var(--sp-3); }
.ak-methods { display: inline-flex; gap: var(--sp-1); padding: 3px; border-radius: var(--r-md);
              background: var(--bg-elev-2); align-self: flex-start; }
.ak-methods[hidden] { display: none; }
.ak-method {
  border: 0; border-radius: var(--r-sm); padding: var(--sp-2) var(--sp-4); background: transparent;
  color: var(--fg-dim); font: inherit; font-size: var(--fs-sm); cursor: pointer;
}
.ak-method.on { background: var(--bg-elev); color: var(--fg); box-shadow: var(--shadow-sm); font-weight: var(--fw-semi); }
.ak-method:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ak-where, .ak-checked, .ak-later { margin: 0; font-size: var(--fs-sm); color: var(--fg-mute); line-height: 1.5; }
.ak-row { display: flex; gap: var(--sp-3); align-items: center; }
.ak-secret { flex: 1; min-width: 0; font-family: var(--mono); }
.ak-result { margin: 0; font-size: var(--fs-sm); color: var(--fg-dim); overflow-wrap: anywhere; }
.ak-result:empty { display: none; }
.ak-result[data-state="testing"] { color: var(--blue); }
.ak-result[data-state="ok"] { color: var(--status-ok); }
.ak-result[data-state="fail"] { color: var(--status-danger); }
.ak-line { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; font-size: var(--fs-sm); }
.ak-kind { color: var(--fg); font-weight: var(--fw-semi); }
.ak-hint { font-family: var(--mono); color: var(--fg); }
.ak-when { color: var(--fg-mute); }
.ak-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.ak-aside { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-6); }
.ak-aside h2 { margin: 0; font-size: var(--fs-lg); }
.ak-aside p { margin: 0; font-size: var(--fs-sm); color: var(--fg-dim); line-height: 1.55; }

.setup { display: grid; grid-template-columns: 280px minmax(0, 1fr); gap: var(--sp-8); align-items: start; }
.setup-side { position: sticky; top: 90px; display: flex; flex-direction: column; gap: var(--sp-5); }
.setup-eyebrow { margin: 0; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--fg-mute); }
.setup-title { margin: 0; font-size: var(--fs-2xl); text-wrap: balance; }
.setup-rail { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.setup-step-btn {
  width: 100%; display: flex; gap: var(--sp-4); align-items: center; min-height: 52px; padding: var(--sp-2) var(--sp-4);
  border: 0; border-radius: var(--r-md); background: transparent; color: var(--fg-dim); font: inherit; text-align: left;
}
.setup-step-btn:not(:disabled) { cursor: pointer; }
.setup-step.on .setup-step-btn { background: var(--bg-elev); color: var(--fg); }
.setup-step-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.setup-mark {
  width: 28px; height: 28px; flex: none; border-radius: var(--r-full); display: grid; place-items: center;
  font-size: var(--fs-sm); font-weight: var(--fw-bold); border: 1px solid var(--border); color: var(--fg-mute);
}
.setup-step.on .setup-mark { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.setup-step.done .setup-mark { color: var(--accent); }
.setup-step-text { display: flex; flex-direction: column; gap: 1px; }
.setup-step-label { font-weight: var(--fw-semi); }
.setup-step-hint { font-size: var(--fs-xs); color: var(--fg-mute); }
.setup-later { margin: 0; font-size: var(--fs-sm); color: var(--fg-mute); line-height: 1.5; }
.setup-main { display: flex; flex-direction: column; gap: var(--sp-6); min-width: 0; }
.setup-content { display: flex; flex-direction: column; gap: var(--sp-4); }
.setup-h { margin: 0; font-size: var(--fs-xl); }
.setup-p { margin: 0; color: var(--fg-dim); line-height: 1.55; }
.setup-agents { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--sp-4); }
.setup-agent {
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-5); min-height: 108px;
  padding: var(--sp-5); border-radius: var(--r-lg); border: 1px solid var(--border); background: var(--bg-elev);
  color: var(--fg); font: inherit; text-align: left; cursor: pointer;
}
.setup-agent.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.setup-agent.off { cursor: default; opacity: 0.6; border-style: dashed; background: transparent; }
.setup-agent:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.setup-agent-top { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3); }
.setup-agent-name { font-weight: var(--fw-semi); }
.setup-agent-pick {
  font-size: var(--fs-xs); font-weight: var(--fw-semi); padding: 2px var(--sp-3); border-radius: var(--r-full);
  border: 1px solid var(--border); color: var(--fg-dim); white-space: nowrap;
}
.setup-agent.on .setup-agent-pick { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.setup-agent-host { font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-mute); }
.setup-review { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.setup-review-row { display: flex; justify-content: space-between; align-items: center; padding: var(--sp-4) 0;
                    border-top: 1px solid var(--border); }
.setup-review-name { font-weight: var(--fw-semi); }
/* The footer stays at the foot of the window on every step: the column fills
   the window, so a short step doesn't pull Continue up and a long one scrolls
   under it instead of pushing it out of sight. */
body[data-route="setup"] .main {
  display: flex; flex-direction: column; padding-bottom: 0;
  min-height: calc(100dvh - var(--nav-h));          /* the top bar sits above .main */
}
body[data-route="setup"] .setup { flex: 1; }
.setup-main { align-self: stretch; }
.setup-footer { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-4);
                margin-top: auto; position: sticky; bottom: var(--setup-foot-bottom, 0px); z-index: 2;
                padding: var(--sp-5) 0 var(--sp-6); border-top: 1px solid var(--border); background: var(--bg); }
@media (max-width: 720px) {
  /* No top bar here, and the phone tabs are fixed at the bottom: stop above them. */
  body[data-route="setup"] { --setup-foot-bottom: calc(var(--phone-tabs-h) + env(safe-area-inset-bottom)); }
  body[data-route="setup"] .main { min-height: 100dvh; padding-bottom: var(--setup-foot-bottom); }
}
.setup-footer-actions { display: flex; gap: var(--sp-3); margin-left: auto; }
@media (max-width: 900px) {
  .ak-grid { grid-template-columns: minmax(0, 1fr); }
  .setup { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; gap: var(--sp-6); }
  .setup-side { position: static; }
  .setup-rail { flex-direction: row; overflow-x: auto; }
  .setup-step-hint { display: none; }
}
@media (max-width: 520px) {
  .setup-agents { gap: var(--sp-3); }
  .setup-agent { min-height: 0; gap: var(--sp-3); padding: var(--sp-4); }
  .ak-row { flex-wrap: wrap; }
  .ak-row .ak-secret { flex-basis: 100%; }
  .setup-rail .setup-step-label { display: none; }
  .setup-step.on .setup-step-label { display: inline; }
}

/* ── Two-step sign-in and Security (docs/MULTIUSER.md, phase 1.5) ── */
.login-wide { width: 100%; justify-content: center; }
.login-step { display: flex; flex-direction: column; gap: var(--sp-4); }
.login-label { font-size: var(--fs-sm); color: var(--fg-dim); }
.login-code {
  font-family: var(--mono); font-size: var(--fs-2xl); letter-spacing: 0.18em; text-align: center;
  font-variant-numeric: tabular-nums;
}
.login-code::placeholder { letter-spacing: 0.12em; }
.login-links { display: flex; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.login-links:has(> :only-child), .login-links:has(> [hidden] + *) { justify-content: center; }
.login-link {
  padding: 0; border: 0; background: none; font: inherit; font-size: var(--fs-sm);
  color: var(--fg-dim); text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.login-link:hover { color: var(--fg); }
.login-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-xs); }
.login-link[hidden] { display: none; }
.login-choice {
  min-height: 60px; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: var(--sp-3) var(--sp-6); text-align: left;
}
.login-choice-what { font-weight: var(--fw-semi); }
.login-choice-how { font-size: var(--fs-xs); opacity: 0.75; }
.mfa-enroll { display: flex; flex-direction: column; gap: var(--sp-4); }
/* The QR stays black on white in both themes: that is what cameras read. */
.mfa-qr { align-self: center; padding: var(--sp-3); background: #fff; border-radius: var(--r-md); line-height: 0; }
.mfa-qr svg { display: block; width: 184px; height: 184px; }
.mfa-manual summary { cursor: pointer; font-size: var(--fs-sm); color: var(--fg-dim); }
.mfa-key {
  display: block; margin-top: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
  background: var(--bg); border: 1px solid var(--border); font-family: var(--mono); font-size: var(--fs-sm);
  color: var(--fg); overflow-wrap: anywhere; user-select: all;
}
.mfa-codes-block { display: flex; flex-direction: column; gap: var(--sp-4); }
.mfa-codes {
  list-style: none; margin: 0; padding: var(--sp-4); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-2) var(--sp-6); border-radius: var(--r-md); background: var(--bg); border: 1px solid var(--border);
  font-family: var(--mono); font-size: var(--fs-md); color: var(--fg); font-variant-numeric: tabular-nums;
  user-select: all;
}
.mfa-codes-actions { display: flex; gap: var(--sp-2); }
.mfa-saved { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-sm); color: var(--fg-dim); cursor: pointer; }
.mfa-saved input { width: 16px; height: 16px; accent-color: var(--accent); }

.sec-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-8); align-items: start; }
.sec-list { display: flex; flex-direction: column; }
.sec-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-4) 0; border-top: 1px solid var(--border);
}
.sec-what { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sec-name { font-weight: var(--fw-semi); color: var(--fg); overflow-wrap: anywhere; }
.sec-detail { font-size: var(--fs-sm); color: var(--fg-mute); overflow-wrap: anywhere; }
.sec-actions { display: flex; gap: var(--sp-2); flex: none; }
.sec-token {
  display: block; padding: var(--sp-4); border-radius: var(--r-md); background: var(--bg); border: 1px solid var(--border);
  font-family: var(--mono); font-size: var(--fs-sm); color: var(--fg); overflow-wrap: anywhere; user-select: all;
}
.sec-curl {
  margin: 0; padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); background: var(--bg-elev-2);
  font-family: var(--mono); font-size: var(--fs-xs); color: var(--fg-dim); white-space: pre-wrap; overflow-wrap: anywhere;
}
@media (max-width: 900px) {
  .sec-grid { grid-template-columns: minmax(0, 1fr); }
  .sec-row { flex-direction: column; align-items: flex-start; }
}
