/* Settings and administration screens. */

/* --- Page scaffolding ------------------------------------------------------
   One scroll container per screen, and this is the rule that decides which.

   `.admin-scroll` is it on every admin page. `.tabs__body` is it only where the
   tabs are a *bounded* flex child -- `.main > .tabs` on the settings page --
   which is why the selector below says so rather than naming the class alone.

   It used to name the class alone, and the result was two scrollers stacked on
   /admin/prompts, where `.tabs` sits inside `.admin-scroll > .admin-page`, a
   plain block. `flex: 1` and `min-height: 0` mean nothing there, so
   `.tabs__body` had `height: auto` and never scrolled while still declaring
   `overflow-y: auto` -- and everything written to reset "the scroller" reset
   that one, silently, while the reader was lost in the other. Under
   `.admin-scroll` the body is now an ordinary block and the page scrolls as one.
*/
.admin-scroll,
.main > .tabs > .tabs__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}

.page,
.admin-page {
  max-width: 48rem;
  margin: 0 auto;
  padding: var(--sp-6) var(--sp-5) var(--sp-12);
}

/* A directory chosen rather than typed. The path is the only part allowed to
   shrink, and it truncates -- an absolute path on somebody else's machine is
   long enough to push the Clear button off the card otherwise. */
.dir-row { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.dir-row > .btn { min-width: 0; }
.dir-row__path {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.page-header { margin-bottom: var(--sp-6); }
.admin-lede,
.page-header__lede {
  color: var(--ink-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  margin: 0 0 var(--sp-6);
  max-width: 44rem;
}

.admin-section-title,
.section-title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-lg);
  margin: var(--sp-8) 0 var(--sp-4);
}

/* --- Tabs ------------------------------------------------------------------
   Radio inputs plus sibling selectors: no JavaScript, and the browser keeps
   the chosen tab across a re-render.
*/
.tabs { display: flex; flex-direction: column; flex: 1; min-height: 0; }

.tabs__bar {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0 var(--sp-5);
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  flex: none;
  overflow-x: auto;
  scrollbar-width: none;
  /* Sticky where the *page* is the scroller, which is the admin layout. The
     Tools panel is longer than a screen, so without this the bar scrolls away
     and changing tab means scrolling back up to find it. Harmless on the
     settings page, where `.tabs__body` scrolls underneath a bar that never
     moves anyway.

     It needs the opaque `background` above it already has, or the panel would
     show through. `z-index` because a panel's own cards establish stacking
     contexts and would otherwise paint over it. */
  position: sticky;
  top: 0;
  z-index: 1;
}

.tabs__tab {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--control-h-lg);
  padding: 0 var(--sp-4);
  border-bottom: 2px solid transparent;
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.tabs__tab:hover { color: var(--ink); }
/* The library's tabs are links between pages rather than radios, so the active
   one is marked server-side. Same bar, same look. */
.tabs__tab.is-active { color: var(--ink); border-bottom-color: var(--accent); }
a.tabs__tab { text-decoration: none; }

.tabs__panel { display: none; }

/* The active tab's label. Each radio is immediately followed by its own label,
   so this needs to know nothing about how many tabs there are or what they are
   called. */
.tabs__bar input:checked + .tabs__tab {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

/*
  The active panel, matched by position.

  CSS cannot compare a radio's id with a panel's data-tab, so this used to name
  every tab twice -- and a tab added without also adding its two rules here
  rendered a label that selected nothing. That is not a failure anyone spots in
  review; it looks like a blank page.

  Position is derivable, so it is used instead: the Nth radio shows the Nth
  panel. Both lists are rendered in the same order, and a conditional tab drops
  out of both at once, so they cannot drift apart. :nth-of-type counts by
  element name, which is why the panels are <section> and the alerts above them
  are <div> -- the alerts are not counted.

  Enumerated to eight, comfortably more than exist. A ninth tab needs one line.
*/
.tabs__bar:has(input:nth-of-type(1):checked) ~ .tabs__body .tabs__panel:nth-of-type(1),
.tabs__bar:has(input:nth-of-type(2):checked) ~ .tabs__body .tabs__panel:nth-of-type(2),
.tabs__bar:has(input:nth-of-type(3):checked) ~ .tabs__body .tabs__panel:nth-of-type(3),
.tabs__bar:has(input:nth-of-type(4):checked) ~ .tabs__body .tabs__panel:nth-of-type(4),
.tabs__bar:has(input:nth-of-type(5):checked) ~ .tabs__body .tabs__panel:nth-of-type(5),
.tabs__bar:has(input:nth-of-type(6):checked) ~ .tabs__body .tabs__panel:nth-of-type(6),
.tabs__bar:has(input:nth-of-type(7):checked) ~ .tabs__body .tabs__panel:nth-of-type(7),
.tabs__bar:has(input:nth-of-type(8):checked) ~ .tabs__body .tabs__panel:nth-of-type(8) {
  display: block;
}
.tabs__tab:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }

/*
  A form's action row, and the space after the form it closes.

  Not a plain .btn-row: a settings form is a stack of cards, and Save has to
  read as belonging to the cards above it rather than to whatever comes next.
  The gap that matters is the one *after* the form -- a card following it (the
  "Try it" panel on the search page, say) otherwise sits flush against Save and
  looks like another field of the same form. That margin therefore belongs to
  the form, not to the action row: the action row is always its form's last
  child, so a bottom margin there would have nothing to push away from.
*/
.form-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-top: var(--sp-5);
}

.admin-page > form { margin-bottom: var(--sp-8); }
.admin-page > form:last-child { margin-bottom: 0; }

/* --- Cards ----------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--sp-5);
  margin-bottom: var(--sp-4);
}
.card:last-child { margin-bottom: 0; }
.card__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-md);
  margin-bottom: var(--sp-2);
}
.card__lede {
  color: var(--ink-muted);
  font-size: var(--text-sm);
  margin-bottom: var(--sp-4);
  line-height: var(--leading-relaxed);
}
.card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}
.card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
  flex-wrap: wrap;
}

/*
  Two or three short fields on one line.

  Numbers with their own units — width and height, steps and cfg and denoise —
  read as a set and take a fraction of the width each, so stacking them makes a
  card that is mostly whitespace and a form that is mostly scrolling. Auto-fit
  rather than a fixed count: the same markup gives three columns on a wide
  screen and one on a narrow one with no breakpoint, which matters because
  `chat.css` has a test refusing media queries and this file should not drift
  from that habit without a reason.
*/
.field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--sp-3);
}
.field-row > .field { margin-bottom: var(--sp-4); }

/* Legacy aliases so existing admin templates keep their spacing. */
.form-grid { display: block; }
.connection__head { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); margin-bottom: var(--sp-4); flex-wrap: wrap; }
.connection__footer { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--border); flex-wrap: wrap; }
.field--actions { margin-top: var(--sp-5); margin-bottom: 0; }

/* --- Definition lists ------------------------------------------------------ */
.detail-list {
  display: grid;
  grid-template-columns: minmax(6rem, auto) 1fr;
  gap: var(--sp-2) var(--sp-4);
  margin: 0;
  font-size: var(--text-sm);
}
.detail-list dt { color: var(--ink-muted); font-weight: 500; }
.detail-list dd { margin: 0; }

/* --- Status ---------------------------------------------------------------- */
.status-dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: var(--radius-full);
  flex: none;
  background: var(--ink-faint);
}
.status-dot.is-ok { background: var(--success); }
.status-dot.is-bad { background: var(--danger); }
.status-dot.is-off { background: var(--ink-faint); }

/* --- Filter bar ------------------------------------------------------------ */
.filter-bar {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}

.filter-tabs {
  display: flex;
  gap: var(--sp-1);
  flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
}
.filter-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--control-h);
  padding: 0 var(--sp-3);
  border-bottom: 2px solid transparent;
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.filter-tab:hover { color: var(--ink); }
.filter-tab.is-active { color: var(--ink); border-bottom-color: var(--accent); }
.filter-tab__count {
  font-size: var(--text-xs);
  color: var(--ink-faint);
  background: var(--surface-active);
  border-radius: var(--radius-full);
  padding: 0 0.4rem;
  min-width: 1.4rem;
  text-align: center;
}
.filter-tab.is-active .filter-tab__count { background: var(--accent-soft); color: var(--accent); }

.filter-form { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.filter-form .input { width: auto; flex: 1; min-width: 12rem; }
.filter-form .select { width: auto; min-width: 10rem; }

/* --- Model list ------------------------------------------------------------
   Compact rows only. Editing is a page of its own -- a connection can advertise
   a hundred models, and a list that renders a form for each is unusable.
*/
.bulk-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  border-bottom: 0;
  background: var(--bg-sunken);
}
.bulk-bar__label { font-size: var(--text-sm); color: var(--ink-muted); }

.model-rows {
  border: 1px solid var(--border);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  overflow: hidden;
  background: var(--surface);
}
.model-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.model-row:last-child { border-bottom: 0; }
.model-row:hover { background: var(--surface-hover); }
.model-row.is-off { opacity: 0.55; }
.model-row__check { accent-color: var(--accent); width: 1rem; height: 1rem; flex: none; }
.model-row__pos {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-faint);
  min-width: 1.75rem;
  text-align: right;
  flex: none;
}
.model-row__avatar { flex: none; width: 1.75rem; height: 1.75rem; }
.model-row__main { flex: 1; min-width: 0; }
.model-row__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.model-row__name {
  color: var(--ink);
  font-weight: 500;
  font-size: var(--text-sm);
  text-decoration: none;
}
.model-row__name:hover { color: var(--accent); text-decoration: underline; }
.model-row__id {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
}
.model-row__actions { display: flex; align-items: center; gap: var(--sp-1); flex: none; }

.list-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
  flex-wrap: wrap;
}

/* --- Model detail ---------------------------------------------------------- */
.crumbs {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
  font-size: var(--text-sm);
}
.crumbs > a:first-child {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  color: var(--ink-muted);
  text-decoration: none;
}
.crumbs > a:first-child:hover { color: var(--ink); }
.crumbs__back { transform: rotate(180deg); }
.model-detail__avatar { width: 3rem; height: 3rem; flex: none; }

.model-list { list-style: none; margin: 0; padding: 0; }
.model-list__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
}
.model-list__item:first-child { padding-top: 0; }
.model-list__item:last-child { border-bottom: 0; padding-bottom: 0; }

/* --- Permission grids ------------------------------------------------------ */
.checkbox-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
}
.checkbox-row .checkbox { flex: 0 0 auto; }
.checkbox.is-muted { opacity: 0.6; }

.perm-row {
  align-items: flex-start;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
}
.perm-row:last-child { border-bottom: 0; }
.perm-row input { margin-top: 0.15rem; }
.perm-row__desc {
  display: block;
  font-size: var(--text-xs);
  color: var(--ink-faint);
  font-weight: 400;
  line-height: var(--leading-normal);
  margin-top: 0.1rem;
}

.perm-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.perm-list__item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-sm);
}
.perm-list__state {
  display: grid;
  place-items: center;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: var(--radius-full);
  background: var(--surface-active);
  color: var(--ink-faint);
  flex: none;
}
.perm-list__state.is-on { background: var(--success-soft); color: var(--success); }

/* --- Reference lists -------------------------------------------------------
   The variable legend on the prompts page, and the read-only tool list beneath
   it. A grid rather than a table because both have to collapse to a stack on a
   narrow screen, which a table cannot do without abandoning its header.
*/
.ref-list { display: flex; flex-direction: column; }

.ref-row {
  display: grid;
  grid-template-columns: minmax(7rem, 11rem) 1fr minmax(0, 12rem);
  gap: var(--sp-3);
  align-items: baseline;
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--border);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.ref-row:first-child { border-top: 0; padding-top: 0; }
.ref-row > code { overflow-wrap: anywhere; }
.ref-row__value {
  color: var(--ink-faint);
  font-size: var(--text-xs);
  overflow-wrap: anywhere;
}

@media (max-width: 44rem) {
  .ref-row { grid-template-columns: 1fr; gap: var(--sp-1); }
}

/* The assembled prompt. Wraps rather than scrolls sideways -- it is prose, and
   a horizontal scrollbar on prose is unreadable. */
.prompt-preview {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-3);
  max-height: 28rem;
  overflow-y: auto;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--code-bg);
  border: 1px solid var(--code-border);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--ink-muted);
}
.prompt-preview code { font-family: inherit; background: none; border: 0; padding: 0; }

/* --- Misc ------------------------------------------------------------------ */
.input--file {
  height: auto;
  padding: 0.35rem;
  font-size: var(--text-xs);
  background: var(--surface-raised);
}

.nav-item.is-disabled { opacity: 0.4; cursor: default; }
.nav-item.is-disabled:hover { background: none; color: var(--ink-muted); }

.field__hint code,
.card__lede code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  padding: 0.05em 0.3em;
  border-radius: var(--radius-sm);
  background: var(--code-bg);
  border: 1px solid var(--code-border);
}

/* --- The permission modes, explained on the agents page ------------------- */
.mode-list { margin: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
/* Whatever follows the list inside a card needs air -- on /admin/updates that is
   the "Check the remote" button, and it sat flush against the last row as
   though it were one. Keyed on *not being last* rather than on the sibling's
   class, because three different things follow it there depending on the
   host's state (the button, the version-mismatch alert, the not-a-checkout
   hint) and enumerating them is how the fourth one gets missed. */
.mode-list:not(:last-child) { margin-bottom: var(--sp-5); }
.mode-list__row { display: flex; gap: var(--sp-3); align-items: baseline; }
.mode-list__row dt { flex: 0 0 5rem; color: var(--ink); }
.mode-list__row dd { margin: 0; color: var(--ink-muted); font-size: var(--text-sm); }

/* --- The schedule setup form ------------------------------------------------ */
/*
  Which "when" fieldset is showing follows the radio, with no JavaScript. `:has()`
  is what makes that possible, and it is the same move the "Something else" box
  on an approval card makes: a control and the thing it reveals cannot fall out
  of step if the stylesheet is the only thing relating them.

  Hidden with `display: none` on the container rather than `[hidden]`, which
  would need `!important` here -- see the note in app.css about `.btn` being
  `inline-flex`. Fields inside a hidden fieldset are still submitted, which is
  correct: `_rule_from_form` reads only the keys the chosen repeat mode uses.
*/
.schedule-repeat {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--sp-4);
  margin-bottom: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.schedule-repeat > legend { padding: 0 var(--sp-2); }
.schedule-repeat [data-repeat] { display: none; }
.schedule-repeat:has(input[value="every"]:checked) [data-repeat="every"] { display: block; }
.schedule-repeat:has(input[value="calendar"]:checked) [data-repeat="calendar"] { display: block; }

/*
  A row of buttons above a list. `.btn-row` carries no bottom margin -- it is
  used inside forms where `.field` provides the rhythm -- so "Add a workflow"
  sat flush against the first row of the list it adds to, and the two read as
  one control. Stated as an adjacency rather than a margin on the button row,
  because the row is right to have none everywhere else it appears.
*/
.btn-row + .model-rows,
.btn-row + .model-list { margin-top: var(--sp-4); }
