/* server.css — the agent's server: Settings → Agent server, and its validity
   under Settings → Payments. The common section / form vocabulary
   lives in sections.css. */

/* ── Server info grid (key/value pairs) ─────────────────────────── */
.grid2 {
  display: grid;
  grid-template-columns: minmax(110px, max-content) minmax(0, 1fr);
  row-gap: .45rem;
  column-gap: 1rem;
  font-size: .82rem;
}
.grid2 > div:nth-child(odd)  { color: var(--muted); white-space: nowrap }
.grid2 > div:nth-child(even) { color: var(--text); font-family: var(--mono); font-size: .78rem; word-break: break-all; min-width: 0 }

.state-ok   { color: var(--accent) }
.state-warn { color: var(--warn) }
.state-err  { color: var(--err) }

@media (max-width: 680px) {
  .grid2 { grid-template-columns: minmax(90px, max-content) minmax(0, 1fr) }
}

/* ── Stat bars (CPU/RAM/Disk) ───────────────────────────────────── */
.stat-row { margin-bottom: .75rem }
.stat-row:last-child { margin-bottom: 0 }

.stat-label {
  display: flex;
  justify-content: space-between;
  font-size: .8rem;
  margin-bottom: .3rem;
  color: var(--muted);
}
.stat-label strong { color: var(--text); font-weight: 600 }
.progress {
  height: 6px;
  background: var(--bg3);
  border-radius: 3px;
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width .4s ease;
  width: 0%;
}
.progress-bar.warn   { background: var(--warn) }
.progress-bar.danger { background: var(--err) }

/* ── Agent server ───────────────────────────────────────────────────
   Plain cards: how the machine is doing and what it is, how to reach it
   over SSH, and (as categories of their own) the file manager and the
   terminal. None folds away, so none has a header bar. */
section.panel-section.server-card {
  display: flex;
  flex-direction: column;
  gap: 1.15rem;
  /* A wide tool (the switch, a long path) scrolls inside the card. */
  min-width: 0;
  max-width: 100%;
  padding: 1.25rem;
  border: 1px solid var(--border2);
  border-radius: 14px;
  background: var(--card);
}
section.panel-section.server-card[hidden],
section.panel-section.server-card[data-search-hidden] { display: none }
.server-meters {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem 1.5rem;
}
.server-meters .stat-row { margin: 0 }
.server-card > * { min-width: 0 }
@media (max-width: 680px) {
  .server-meters { grid-template-columns: minmax(0, 1fr) }
}
.server-card .grid2,
.server-foot {
  padding-top: 1.15rem;
  border-top: 1px solid var(--border);
}
.server-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .75rem 1rem;
}
/* What the server is paid for is Payments' to tell; here it is one line
   and the way there. */
.server-validity {
  margin: 0;
  color: var(--muted);
  font-size: .82rem;
}
.server-validity a {
  margin-left: .5rem;
  color: var(--text);
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: var(--border2);
  text-underline-offset: 3px;
}
.server-validity a:hover { text-decoration-color: currentColor }
.server-validity a[hidden] { display: none }
.server-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

/* Restart, delete, extend: quiet buttons told apart by their words. Only the
   text takes a colour -- the danger's for deleting, the accent's for the one
   thing to do about a server that runs out. */
.lifetime-reboot,
.lifetime-delete,
.lifetime-extend {
  display: inline-flex;
  align-items: center;
  padding: .45rem .95rem;
  border: 1px solid var(--border2);
  border-radius: 8px;
  background: var(--card);
  color: var(--text);
  font-size: .82rem;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.lifetime-reboot:hover,
.lifetime-delete:hover,
.lifetime-extend:hover {
  background: var(--shell-hover);
  border-color: var(--outline-hover);
  color: var(--text);
  text-decoration: none;
  box-shadow: none;
}
.lifetime-reboot:disabled,
.lifetime-delete:disabled {
  opacity: .55;
  cursor: not-allowed;
}
.lifetime-delete,
.lifetime-delete:hover { color: var(--danger-action) }
.lifetime-extend,
.lifetime-extend:hover {
  color: var(--accent);
  font-weight: 600;
}
/* `display: inline-flex` above outranks the UA's `[hidden] { display: none }`. */
.lifetime-extend[hidden] { display: none }

/* ── Server validity (Settings → Payments) ────────────────────────── */
.validity-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .75rem 1rem;
}
.lifetime-state {
  font-size: 1.15rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -.01em;
  color: var(--text);
}
.lifetime-state.warn { color: var(--warn) }
.lifetime-state.danger,
.lifetime-state.critical { color: var(--err) }
.lifetime-paid {
  margin-top: .2rem;
  color: var(--muted);
  font-size: .82rem;
}
/* Close to running out, the card says so with its border too. */
.lifetime-section.danger,
.lifetime-section.critical { border-color: color-mix(in srgb, var(--err) 45%, transparent) }

/* ── Automatic-updates rows (now inside Settings tab) ───────────── */
.auto-updates-list {
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.au-group-label {
  /* Group labels were removed when we moved every channel to the
     pull-model — but rootpw-toggle (Server access tab) still nests an
     .au-row, and any future consumer might re-introduce a group. Keep
     the style; the markup just doesn't emit one anymore. */
  margin: .6rem 0 .15rem;
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--muted2);
  padding-left: .1rem;
}
.au-group-label:first-child { margin-top: 0; }
.au-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .65rem .8rem;
  border-radius: 8px;
  border: 1px solid var(--border2);
  background: var(--surface-flat);
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.au-row:hover { border-color: var(--accent); background: var(--surface-flat-hover) }
/* `display: flex` above outranks the UA's `[hidden] { display: none }`, so a
   row JS hides (the Agent-extensions channel while the extensions switch is
   off) painted anyway until this companion rule existed (2026-08). */
.au-row[hidden] { display: none }
/* Update notices: a choice, not a switch — the row itself is not a click
   target, so it neither points nor lights up. */
.au-notices-row { margin-top: .5rem; cursor: default }
.au-notices-row:hover { border-color: var(--border2); background: var(--surface-flat) }
.au-notices-select { flex-shrink: 0; max-width: 45% }
/* overflow-wrap: on a phone the row's button and switch leave the text a
   narrow strip, and a long word (a Hermes commit SHA, a compound like
   "funktsiooniuuendused") would otherwise run out of the row. */
.au-text { flex: 1; display: flex; flex-direction: column; gap: .15rem; min-width: 0; overflow-wrap: anywhere }
.au-text strong { color: var(--text); font-weight: 600; font-size: .9rem }
.au-sub { color: var(--muted); font-size: .78rem; line-height: 1.35 }
.au-last {
  /* "Last updated 2 hours ago" — fainter, smaller, sits under the desc. */
  color: var(--muted2);
  font-size: .72rem;
  margin-top: .12rem;
  font-variant-numeric: tabular-nums;
}
.au-last[data-state="running"] { color: var(--accent) }
.au-last[data-state="error"] { color: var(--err) }

/* Per-row "Update now" + top-level "Update all now". Same visual weight
   as outlined chip — flat fill that picks up --accent on hover so it
   reads as actionable without competing with the toggle for attention. */
.au-update-btn,
.au-update-all-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .32rem .7rem;
  background: var(--surface-control);
  color: var(--text);
  border: 1px solid var(--outline-subtle);
  border-radius: 8px;
  font: inherit;
  font-size: .78rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.au-update-btn:hover:not(:disabled),
.au-update-all-btn:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
}
.au-update-btn:disabled,
.au-update-all-btn:disabled { opacity: .5; cursor: progress }
.au-update-btn[data-state="running"],
.au-update-all-btn[data-state="running"] {
  border-color: var(--accent);
  color: var(--accent);
}
.au-update-btn[data-state="ok"],
.au-update-all-btn[data-state="ok"] {
  border-color: var(--accent);
  color: var(--accent);
}
.au-update-btn[data-state="error"],
.au-update-all-btn[data-state="error"] {
  border-color: var(--err);
  color: var(--err);
}

/* Running state: cursor stays as "in progress" instead of the dimmed
   :disabled look, since the spinner already conveys disabled-while-busy. */
.au-update-btn[data-state="running"],
.au-update-all-btn[data-state="running"] { opacity: 1 }
.au-update-btn[data-state="ok"],
.au-update-all-btn[data-state="ok"] { opacity: 1 }

/* Inline state icons that sit beside the label inside the button. The
   .35rem gap from .au-update-btn handles spacing — no margin needed. */
.au-btn-spin {
  width: .85em;
  height: .85em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  display: inline-block;
  animation: au-btn-spin 0.65s linear infinite;
  flex: 0 0 auto;
}
@keyframes au-btn-spin {
  to { transform: rotate(360deg); }
}
.au-btn-check {
  width: .95em;
  height: .95em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  animation: au-btn-pop 0.32s cubic-bezier(.34, 1.56, .64, 1) both;
}
.au-btn-check svg {
  width: 100%;
  height: 100%;
  display: block;
}
@keyframes au-btn-pop {
  0%   { transform: scale(0);    opacity: 0; }
  60%  { transform: scale(1.2); opacity: 1; }
  100% { transform: scale(1);    opacity: 1; }
}
.au-btn-label { display: inline-block; }

/* Header grid — intro+warn on the left, "Update all" on the right.
   Stacks on narrow widths so the button sits below the text. */
.au-header-grid {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  margin: 0 0 .55rem;
}
.au-header-text { flex: 1 1 auto; min-width: 0 }
.au-header-text .au-intro,
.au-header-text .au-warn { margin-bottom: 0 }
.au-header-text .au-intro { margin-bottom: .25rem }
.au-header-action {
  flex: 0 0 auto;
  padding-top: .1rem;
}
@media (max-width: 640px) {
  .au-header-grid { flex-direction: column; gap: .55rem }
  .au-header-action { align-self: flex-start }
  /* Each channel row stacks the same way: beside the button and the switch
     a phone left the text a ~100px strip, one word per line. The button
     drops under the text; the switch keeps its place on the first line.
     :not([hidden]) so this display can't outrank .au-row[hidden]. */
  .auto-updates-list > .au-row:not([hidden]) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: .55rem 1rem;
  }
  .auto-updates-list > .au-row > .au-toggle { grid-area: 1 / 2 }
  .auto-updates-list > .au-row > .au-update-btn { grid-area: 2 / 1; justify-self: start }
}
.au-update-all-btn { font-weight: 600 }

/* Master toggle + chevron sit together on the right side of the
   section header. Default panel-section-head is title + chevron with
   space-between; wrapping right-side items lets us avoid that gap
   collapsing the master switch toward the title. */
.panel-section-head-actions {
  display: inline-flex;
  align-items: center;
  gap: .75rem;
  flex-shrink: 0;
}
/* Stop the toggle from feeling like part of the channel rows below —
   it's a header-level "kill switch" so we keep it visually slightly
   smaller and the cursor stays a pointer on hover. */
.au-master-toggle { cursor: pointer; }

/* Toggle switch (pure CSS). */
.au-toggle {
  position: relative;
  display: inline-block;
  flex: 0 0 auto;
  width: 38px;
  height: 22px;
}
.au-toggle input[type="checkbox"] {
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
  position: relative;
  z-index: 1;
}
.au-slider {
  position: absolute;
  inset: 0;
  /* Off state: a few shades lighter than the panel surface so the track
     reads as a distinct control, not a hole in the card. */
  background: var(--control-track-off);
  border: 1px solid var(--control-track-off-border);
  border-radius: 22px;
  transition: background .15s ease, border-color .15s ease;
}
.au-slider::before {
  content: "";
  position: absolute;
  width: 16px;
  height: 16px;
  top: 2px;
  left: 2px;
  background: var(--text);
  border-radius: 50%;
  transition: transform .15s ease;
  box-shadow: 0 1px 2px rgba(0,0,0,.45);
}
/* On state uses a dedicated filled-control palette: restrained mint on the
   dark canvas, airy indigo track with a dark indigo knob in light mode. */
.au-toggle input:checked ~ .au-slider {
  background: var(--accent-control);
  border-color: var(--accent-control-border);
}
.au-toggle input:checked ~ .au-slider::before {
  background: var(--accent-control-knob);
  transform: translateX(16px);
}
.au-toggle input:disabled ~ .au-slider { opacity: .5; cursor: not-allowed }
.au-status { margin: 0; font-size: .75rem }
.au-status.au-error { color: var(--err) }

/* Intro paragraph that wraps a shared HH:00 picker inline with the
   sentence. Use inline-flex so the <select> sits on the text baseline
   with breathing room either side, and wraps cleanly on narrow widths. */
.au-intro {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .45rem .55rem;
  line-height: 1.45;
  margin-bottom: .25rem;
}
.au-warn {
  /* Sits tight under the intro — they read as one block, not two
     paragraphs. Negative top margin pulls the warning up flush against
     the time picker's baseline. */
  margin: -.05rem 0 .55rem;
  color: var(--muted);
  font-size: .78rem;
  line-height: 1.35;
}

/* Shared time picker — custom button + popover. We deliberately avoid the
   native <select> because the OS-styled option dropdown can't be themed
   to match the rest of the panel (panel uses --bg2 cards + --accent
   highlights; native dropdowns are flat OS chrome). The popover itself is
   viewport-anchored (see .au-time-pop); the wrapper just keeps the trigger
   and its list one outside-click unit. */
.au-timepicker {
  display: inline-block;
  vertical-align: baseline;
}
.au-tz {
  color: var(--muted);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  margin-left: .1rem;
}

.au-time-btn {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .28rem .55rem .28rem .7rem;
  background: var(--surface-control);
  color: var(--text);
  border: 1px solid var(--outline-subtle);
  border-radius: 8px;
  font: inherit;
  font-size: .9rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.au-time-btn:hover:not(:disabled),
.au-time-btn[aria-expanded="true"] {
  border-color: var(--accent);
  background: var(--bg);
}
.au-time-btn:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 14%, transparent);
}
.au-time-btn:disabled { opacity: .55; cursor: progress }
.au-time-btn-value { font-weight: 500 }
.au-time-btn-chevron {
  display: inline-flex;
  color: var(--muted);
  transition: transform .18s ease, color .15s ease;
}
.au-time-btn:hover:not(:disabled) .au-time-btn-chevron,
.au-time-btn[aria-expanded="true"] .au-time-btn-chevron { color: var(--accent) }
.au-time-btn[aria-expanded="true"] .au-time-btn-chevron { transform: rotate(180deg) }

/* Anchored in the viewport by popover.js (top/left/max-height are set there),
   so the scrolling settings column can neither clip it nor paint over it.
   z-index clears the panel's own layers, stays under topbar (100)/modals. */
.au-time-pop {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 90;
  width: 6.5rem;
  max-height: 14rem;
  overflow-y: auto;
  padding: .3rem;
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .35);
  /* Tabular numbers so the column stays clean. */
  font-variant-numeric: tabular-nums;
  /* Reveal animation — also handles the close transition gracefully. */
  animation: au-time-pop-in .14s ease-out;
}
@keyframes au-time-pop-in {
  from { opacity: 0; transform: translateY(-4px) }
  to   { opacity: 1; transform: translateY(0) }
}
.au-time-pop[hidden] { display: none }
.au-time-pop::-webkit-scrollbar { width: 6px }
.au-time-pop::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px }
.au-time-pop::-webkit-scrollbar-thumb:hover { background: var(--muted) }

.au-time-opt {
  display: block;
  width: 100%;
  padding: .35rem .6rem;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: .88rem;
  font-variant-numeric: tabular-nums;
  text-align: left;
  cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.au-time-opt:hover,
.au-time-opt:focus-visible {
  background: var(--bg);
  color: var(--accent);
  outline: none;
}
.au-time-opt[aria-selected="true"] {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent);
  font-weight: 600;
}

/* ── Persona overlay — user-editable text appended to SOUL.md ──── */

.persona-textarea {
  width: 100%;
  min-height: 12rem;
  padding: .75rem .85rem;
  background: var(--bg2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .85rem;
  line-height: 1.5;
  resize: vertical;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.persona-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 12%, transparent);
}
.persona-textarea:disabled { opacity: .55; cursor: progress }

.persona-actions {
  display: flex;
  align-items: center;
  gap: .35rem;
  margin-top: .65rem;
  font-size: .8rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.persona-actions #personaSave {
  margin-left: auto;
  min-width: 6.5rem;
}
.persona-counter { color: var(--text); font-weight: 500 }
.persona-counter-sep { color: var(--muted2) }
.persona-counter.over { color: var(--persona-danger) }
.persona-status { margin-top: .55rem }
.persona-status.persona-error { color: var(--persona-danger) }
.persona-status.persona-ok { color: var(--accent) }

/* ── Server access — SSH key list ──────────────────────────────── */

/* Hint text + click-to-copy `ssh root@…` command share a row.
   Two 50/50 columns when there's room, stack vertically below 540px. */
.ssh-info-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin: .15rem 0 0;
  flex-wrap: wrap;
}
.ssh-info-row .ssh-info-text {
  flex: 1 1 calc(50% - .375rem);
  margin: 0;
  min-width: 12rem;
  text-align: right;
}
.ssh-info-row .ssh-cmd-copy {
  flex: 1 1 calc(50% - .375rem);
  min-width: 14rem;
  margin: 0;
}

/* Click-to-copy `ssh root@…` command shown above the add-key form.
   It's a <button> (so keyboard / a11y work the same as any other
   action) but styled like an inline terminal block. */
.ssh-cmd-copy {
  display: flex;
  align-items: center;
  gap: .55rem;
  width: 100%;
  margin: 0 0 .55rem;
  padding: .6rem .85rem;
  background: var(--bg3);
  border: 1px solid var(--border2);
  border-radius: 8px;
  font-family: var(--mono);
  font-size: .85rem;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.ssh-cmd-copy:hover {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-color: color-mix(in srgb, var(--accent) 42%, transparent);
  color: var(--text);
}
.ssh-cmd-copy.copied {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}
.ssh-cmd-copy .ssh-cmd-prompt {
  color: var(--accent);
  font-weight: 600;
  user-select: none;
  flex-shrink: 0;
}
.ssh-cmd-copy code {
  flex: 1;
  min-width: 0;
  background: transparent;
  padding: 0;
  font-size: .85rem;
  color: var(--text);
  word-break: break-all;
}
.ssh-cmd-copy .ssh-cmd-status {
  flex-shrink: 0;
  font-family: var(--font);
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}
.ssh-cmd-copy.copied .ssh-cmd-status { color: var(--accent) }

/* "＋ Add SSH key" trigger row — visually quiet so the list stays the
   focus, but clearly tappable. */
.ssh-add-trigger {
  display: flex;
  justify-content: flex-start;
  margin: .15rem 0 .15rem;
}
.ssh-add-open {
  /* Inherits the panel's default button look (soft accent fill, solid
     border) — keeps the trigger consistent with every other action button
     and avoids the dashed-outline look that felt out of place. */
  padding: .5rem .9rem;
}

/* The form itself — boxed card so it stands clearly apart from the
   list above it when expanded. */
.ssh-add {
  display: flex;
  flex-direction: column;
  gap: .65rem;
  margin-top: .25rem;
  padding: .9rem 1rem 1rem;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 4%, transparent);
}
/* `display: flex` above outranks the UA's `[hidden] { display: none }`,
   so the form would render even when the `hidden` attribute is set.
   Restore the intended hide behaviour explicitly. */
.ssh-add[hidden] { display: none; }
.ssh-add-heading {
  margin: 0 0 .1rem;
  font-size: .82rem;
  font-weight: 600;
  color: var(--text);
  letter-spacing: .01em;
}
.ssh-add textarea {
  font-family: var(--mono);
  font-size: .78rem;
  line-height: 1.4;
  white-space: pre;
  word-break: break-all;
  resize: none;
}
.ssh-add-actions {
  display: flex;
  justify-content: flex-end;
  gap: .55rem;
  margin-top: .15rem;
}
.ssh-error { color: var(--err); margin: 0 }

.ssh-list {
  display: flex;
  flex-direction: column;
  gap: .45rem;
}
.ssh-list .empty { color: var(--muted); font-size: .82rem; margin: 0 }

.ssh-row {
  display: flex;
  align-items: center;
  gap: .85rem;
  padding: .65rem .8rem;
  border: 1px solid var(--border2);
  border-radius: 8px;
  background: var(--surface-subtle);
}
.ssh-row .ssh-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .2rem }
.ssh-row .ssh-line { display: flex; flex-wrap: wrap; gap: .45rem; align-items: baseline; font-size: .82rem }
.ssh-row .ssh-type {
  font-family: var(--mono);
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-softer);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
  padding: .08rem .45rem;
  border-radius: 4px;
  flex-shrink: 0;
}
.ssh-row .ssh-comment {
  color: var(--text);
  font-weight: 500;
  overflow-wrap: anywhere;
}
.ssh-row .ssh-fp {
  font-family: var(--mono);
  font-size: .72rem;
  color: var(--muted);
  word-break: break-all;
}
.ssh-row .ssh-protected-tag {
  font-size: .68rem;
  letter-spacing: .02em;
  color: var(--warn);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
  padding: .08rem .45rem;
  border-radius: 4px;
  font-weight: 600;
  flex-shrink: 0;
}
.ssh-row button.ssh-del {
  flex-shrink: 0;
  padding: .35rem .7rem;
  font-size: .76rem;
  background: color-mix(in srgb, var(--err) 7%, transparent);
  color: var(--err);
  border-color: color-mix(in srgb, var(--err) 35%, transparent);
}
.ssh-row button.ssh-del:hover {
  background: color-mix(in srgb, var(--err) 14%, transparent);
  border-color: color-mix(in srgb, var(--err) 55%, transparent);
  color: var(--err);
}
.ssh-row.invalid { border-style: dashed; opacity: .9 }
.ssh-row.invalid .ssh-comment { color: var(--warn) }

/* ── Server access — Root password ─────────────────────────────── */
.rootpw-card {
  display: flex;
  flex-direction: column;
  gap: .8rem;
  padding: .9rem 1rem;
  border: 1px solid var(--outline-subtle);
  border-radius: 10px;
  background: var(--surface-subtle);
}
.rootpw-display {
  display: flex;
  align-items: center;
  gap: .55rem;
  font-family: var(--mono);
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: .04em;
  padding: .8rem 1rem;
  border-radius: 9px;
  background: var(--bg3);
  border: 1px solid var(--border2);
  color: var(--text);
  word-break: break-all;
}
.rootpw-display.empty {
  font-family: inherit;
  font-size: .85rem;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: 0;
  font-style: italic;
}
.rootpw-copy {
  flex-shrink: 0;
  padding: .35rem .7rem;
  font-size: .76rem;
}
.rootpw-value-clickable {
  cursor: pointer;
  border-radius: 4px;
  transition: color .12s ease, background-color .12s ease;
}
.rootpw-value-clickable:hover { color: var(--accent) }
.rootpw-value-clickable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.rootpw-meta { font-size: .75rem; color: var(--muted) }
.rootpw-field {
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.rootpw-label {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
.rootpw-display-row {
  display: flex;
  align-items: stretch;
  gap: .55rem;
  flex-wrap: wrap;
}
.rootpw-display-row .rootpw-display {
  flex: 1 1 calc(50% - .275rem);
  min-width: 14rem;
  margin: 0;
}
.rootpw-display-row .rootpw-rotate {
  flex: 1 1 calc(50% - .275rem);
  min-width: 12rem;
}

/* SSH password-login toggle. The "--top" variant is the master switch
   at the head of the Root password subview; the password block below
   only renders when this toggle is on. */
.rootpw-toggle {
  display: flex;
  flex-direction: column;
  gap: .55rem;
}
.rootpw-toggle--top {
  margin: 0;
  padding: 0;
  border-top: none;
}
.rootpw-toggle .au-row { cursor: pointer }
.rootpw-toggle .hint { margin: 0; font-size: .76rem; line-height: 1.4 }

/* ── Server access — Terminal ───────────────────────────────────── */
.terminal-controls {
  display: flex;
  align-items: center;
  gap: .65rem;
  flex-wrap: wrap;
}
.terminal-status {
  font-size: .78rem;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: .35rem;
}
.terminal-status::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--muted2);
}
/* Connected: a lamp in LED green and the word in green (feedback #16). */
.terminal-status.connected { color: var(--success-status) }
.terminal-status.connected::before { background: var(--led-on) }
.terminal-status.error { color: var(--err) }
.terminal-status.error::before { background: var(--led-err) }

.terminal-frame {
  border: 1px solid var(--border2);
  border-radius: 10px;
  background: #000;
  overflow: hidden;
  /* Fits comfortably in the panel; xterm fills 100% of inner area. */
  height: clamp(280px, 50vh, 540px);
  position: relative;
}
/* Shown on its own (the sidebar's Terminal shortcut, the agent's open_panel
   tool) the terminal is the whole dialog: the frame takes every row under
   the controls instead of stopping at its fixed height with a bare strip
   below. shell.css passes the dialog's height down to the card; xterm's
   fit addon follows the frame through its ResizeObserver. */
.settings-view[data-focus="terminal"] .terminal-frame {
  flex: 1 1 auto;
  height: auto;
  min-height: 200px;
}
.terminal-canvas {
  width: 100%;
  height: 100%;
  padding: .35rem;
  box-sizing: border-box;
}
.terminal-canvas .xterm,
.terminal-canvas .xterm-viewport,
.terminal-canvas .xterm-screen {
  width: 100% !important;
  height: 100% !important;
}

/* The shell's own light background (server_access.js keeps the choice in
   this browser, apart from the panel's theme): the frame goes white, and
   xterm's colours follow from the module. */
.terminal-frame[data-terminal-theme="light"] { background: #fff }

/* The frame's corner buttons — sun/moon and fullscreen, small overlays in
   the top-right. They stay visible at low opacity and brighten on hover. */
.terminal-corner-btn {
  position: absolute;
  top: 6px;
  z-index: 2;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--text) 18%, transparent);
  background: rgba(0,0,0,.55);
  color: #d8dde2;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  opacity: .55;
  transition: opacity .15s, background .15s, border-color .15s, color .15s;
}
.terminal-corner-btn:hover {
  opacity: 1;
  background: rgba(0,0,0,.78);
  border-color: var(--accent);
  color: var(--accent);
}
.terminal-corner-btn.on { color: var(--accent); border-color: var(--accent); opacity: .9 }
.terminal-frame[data-terminal-theme="light"] .terminal-corner-btn {
  background: rgba(255,255,255,.7);
  color: #4b5563;
}
.terminal-frame[data-terminal-theme="light"] .terminal-corner-btn:hover {
  background: rgba(255,255,255,.95);
  color: var(--accent);
}
.terminal-fs-btn { right: 6px }
.terminal-theme-btn { right: 40px }
.terminal-ico { width: 15px; height: 15px }
/* The sun on a dark shell, the moon on a light one: what a click gives. */
.terminal-theme-btn .ico-moon { display: none }
.terminal-frame[data-terminal-theme="light"] .terminal-theme-btn .ico-sun { display: none }
.terminal-frame[data-terminal-theme="light"] .terminal-theme-btn .ico-moon { display: inline }

/* When the frame itself is the fullscreen element, fill the viewport
   and let xterm expand to use it. */
.terminal-frame:fullscreen {
  width: 100vw;
  height: 100vh;
  border-radius: 0;
  border: none;
}
.terminal-frame:fullscreen .terminal-canvas { padding: .5rem }

/* ── Projects (Settings → Projects, projects.js) ───────────────── */
/* The list: one bordered column with a hairline between rows (the shape of
   the LLM-provider list). The selected row — where new chats start — is
   tinted and wears its badge; a row's menu button shows on hover, and always
   where there is no hover to speak of. */
.prj-list {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--outline-subtle);
  border-radius: 12px;
  overflow: hidden;
}
.prj-list:empty { display: none }
.prj-list > .hint { margin: 0; padding: .8rem 1rem }
.prj-row {
  display: flex;
  align-items: center;
  gap: .8rem;
  min-height: 3.3rem;
  padding: .55rem .6rem .55rem .85rem;
  border-top: 1px solid var(--outline-subtle);
  background: var(--surface-subtle);
  transition: background .15s;
}
.prj-row:first-child { border-top: 0 }
.prj-row:hover { background: var(--surface-hover) }
.prj-row.is-selected { background: color-mix(in srgb, var(--accent) 6%, var(--surface-subtle)) }
.prj-row.is-unavailable .prj-text { opacity: .6 }
.prj-icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 9px;
  background: var(--surface-hover);
  color: var(--muted);
}
.prj-icon svg { width: 17px; height: 17px }
.prj-row.is-selected .prj-icon { background: var(--accent-soft); color: var(--accent) }
.prj-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .12rem }
.prj-head { display: flex; align-items: center; gap: .45rem; min-width: 0 }
.prj-name {
  min-width: 0;
  font-size: .92rem;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Who sees it. On a one-user agent private is the only kind there is, so
   its tag shows under body[data-shared-agent] alone (member_view.js). */
.prj-tag {
  flex: none;
  max-width: 12rem;
  padding: .06rem .45rem;
  border: 1px solid var(--border2);
  border-radius: 999px;
  font-size: .66rem;
  font-weight: 600;
  color: var(--muted2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prj-tag--private { display: none }
body[data-shared-agent] .prj-tag--private { display: inline-block }
.prj-meta { font-size: .76rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.prj-meta .is-warn { color: var(--warn) }
.prj-selected {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: 0 .6rem 0 .45rem;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: .7rem;
  font-weight: 600;
  line-height: 1.5rem;
  white-space: nowrap;
}
.prj-selected svg { width: 12px; height: 12px; flex: none }
.prj-more { flex: none; opacity: 0; transition: opacity .15s }
.prj-row:hover .prj-more,
.prj-row:focus-within .prj-more,
.prj-more[aria-expanded="true"] { opacity: 1 }
@media (hover: none) { .prj-more { opacity: 1 } }
@media (max-width: 480px) {
  /* The badge keeps its check mark; the words go to the tooltip. */
  .prj-selected { padding: 0 .4rem }
  .prj-selected-text { display: none }
}
.prj-rename-input {
  width: 100%;
  max-width: 22rem;
  margin: 0;
  padding: .15rem .4rem;
  font: inherit;
  font-size: .92rem;
  font-weight: 600;
}

/* Creating: a dashed "+ New project" line stands where the form will be;
   the form takes its place when asked for (the invite flow's shape). */
.prj-create-open {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  width: 100%;
  padding: .6rem .8rem;
  font: inherit;
  font-size: .86rem;
  font-weight: 500;
  color: var(--muted);
  background: transparent;
  border: 1px dashed var(--border2);
  border-radius: 10px;
  box-shadow: none;
  cursor: pointer;
  transition: color .15s, border-color .15s, background .15s;
}
.prj-create-open:hover { color: var(--accent); border-color: var(--accent); background: var(--accent-softer) }
.prj-create-open[hidden] { display: none }
.prj-create-plus { font-size: 1.15rem; line-height: 1 }
.prj-create-pane {
  display: flex;
  flex-direction: column;
  gap: .55rem;
  padding: .9rem 1rem 1rem;
  background: var(--surface-row);
  border: 1px solid var(--border2);
  border-left: 2px solid var(--accent);
  border-radius: 10px;
  animation: byok-form-fade .18s ease-out;
}
.prj-create-pane[hidden] { display: none }
.prj-field-label {
  display: block;
  margin: 0;
  padding: 0;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
}
.prj-create-input { margin: 0 }
.prj-visibility {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  min-width: 0;
  margin: .25rem 0 0;
  padding: 0;
  border: 0;
}
/* Who sees it is a question only where somebody else could: an agent with
   other users (member_view.js sets body[data-shared-agent]). The quick-create
   dialog leaves the fieldset out altogether (projects.js openCreate). */
.prj-create-pane .prj-visibility { display: none }
body[data-shared-agent] .prj-create-pane .prj-visibility { display: flex }
/* In the quick-create dialog: as far from the name as the name's label is
   from the dialog head. */
.modal-body .prj-visibility { margin-top: .9rem }
.prj-vis-options { display: flex; flex-direction: column; gap: .1rem }
/* One plain radio line per option, one under the other: no card, no frame.
   The radio itself is read by the keyboard and the screen reader only, the
   dot shows what it holds. Scoped to the fieldset so the quick-create
   dialog's form-label look (modal.css `.modal-body label`: uppercase,
   block) stays off the lines. */
.prj-visibility .prj-vis-option {
  position: relative;
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 0;
  padding: .35rem 0;
  font-size: .88rem;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
  background: none;
  border: 0;
  cursor: pointer;
}
.prj-vis-option input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none }
.prj-vis-mark {
  position: relative;
  flex: none;
  width: 16px;
  height: 16px;
  border: 1.5px solid var(--muted2);
  border-radius: 50%;
  transition: border-color .12s;
}
.prj-vis-option:hover .prj-vis-mark { border-color: var(--outline-hover) }
.prj-vis-option:has(input:checked) .prj-vis-mark { border-color: var(--accent) }
.prj-vis-option:has(input:checked) .prj-vis-mark::after {
  content: '';
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--accent);
}
.prj-vis-option:has(input:focus-visible) .prj-vis-mark { outline: 2px solid var(--focus-outline); outline-offset: 2px }
.prj-create-actions { display: flex; justify-content: flex-end; gap: .5rem; margin-top: .25rem }

/* Removed: a quiet disclosure line under the list, its rows a shade
   fainter than the live ones. */
.prj-removed[hidden] { display: none }
.prj-removed-toggle {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .15rem 0;
  font: inherit;
  font-size: .8rem;
  color: var(--muted);
  background: none;
  border: 0;
  box-shadow: none;
  cursor: pointer;
}
.prj-removed-toggle:hover { color: var(--text); background: none }
.prj-removed-toggle::before { content: '▸'; font-size: .72rem; transition: transform .15s }
.prj-removed-toggle[aria-expanded="true"]::before { transform: rotate(90deg) }
.prj-removed-body { display: flex; flex-direction: column; gap: .6rem; margin-top: .5rem }
.prj-removed-body[hidden] { display: none }
.prj-removed-body > .hint { margin: 0 }
.prj-list--removed .prj-row { background: transparent }
.prj-list--removed .prj-name { color: var(--muted); font-weight: 500 }
.prj-list--removed .prj-icon { background: transparent; border: 1px dashed var(--border2) }

/* The instructions editor and the permanent-delete dialog (modals). */
.prj-instructions-body .mb-hint { margin-top: 0 }
.prj-folder { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .5rem; margin: 0 0 .6rem; font-size: .76rem; color: var(--muted) }
.prj-folder code { font-family: var(--mono); font-size: .74rem; color: var(--text); overflow-wrap: anywhere }
.prj-instructions {
  width: 100%;
  min-height: 15rem;
  resize: vertical;
  font-family: var(--mono);
  font-size: .82rem;
  line-height: 1.5;
}
.prj-purge-input { font-family: var(--mono) }
