/* Hallmark · genre: modern-minimal · macrostructure: Workbench · theme: Cobalt
 * enrichment: none · nav: N9 edge-aligned minimal · footer: Ft4 dense colophon
 * tone: utilitarian · anchor hue: 256 (electric cobalt)
 *
 * Tokens live in tokens.css. Nothing below declares a raw colour or a raw
 * font-family - every value here is a var(). If a value is missing, it gets a
 * name in tokens.css first.
 */

/* --- reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  /* clip, never hidden: hidden would kill position:sticky on the nav */
  overflow-x: clip;
  margin: 0;
}

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--color-paper);
  color: var(--color-ink-2);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--lh-body);
  font-weight: 400;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-style: normal;           /* headings are roman, always */
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: var(--track-display);
  color: var(--color-ink);
  overflow-wrap: anywhere;
  min-width: 0;
  margin: 0;
}

p { margin: 0; }

/* --- shared type registers ---------------------------------------------- */
.mono {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-mono);
}

/* Labels are body text. They were uppercase mono, which is monospace worn as a
   costume for "technical" - a field label is not code, data or a measurement.
   Mono now appears only where it earns it: env var names, paths, config, status
   readouts and numerals. */
.label {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--color-ink);
  line-height: 1.35;
}

.hint {
  color: var(--color-muted);
  font-size: var(--text-sm);
  max-width: 68ch;
}

a {
  color: var(--color-accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* --- focus: instant, never animated ------------------------------------- */
:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
:focus:not(:focus-visible) { outline: none; }

/* --- nav · N9 edge-aligned minimal -------------------------------------- */
.nav {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky-nav);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-xs) clamp(var(--space-sm), 4vw, var(--space-lg));
  background: var(--color-paper);
  border-bottom: var(--rule) solid var(--color-rule);
}

.nav__mark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-md);
  letter-spacing: var(--track-display);
  color: var(--color-ink);
  line-height: 1;
  white-space: nowrap;
}

.nav__right {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* --- status pill --------------------------------------------------------- */
.status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-3xs) var(--space-2xs);
  border: var(--rule) solid var(--color-rule);
  border-radius: var(--radius-sm);
  background: var(--color-paper-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  line-height: 1;
  color: var(--color-muted);
  white-space: nowrap;
}
.status__dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--color-muted);
  flex: none;
}
.status[data-health="ok"]      { color: var(--color-ok);  border-color: var(--color-rule-2); }
.status[data-health="ok"]      .status__dot { background: var(--color-ok); }
.status[data-health="down"]    { color: var(--color-err); border-color: var(--color-rule-2); }
.status[data-health="down"]    .status__dot { background: var(--color-err); }
.status[data-health="working"] .status__dot { background: var(--color-warn); animation: pulse 1.1s var(--ease-in-out) infinite; }

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

/* --- layout -------------------------------------------------------------- */
.shell {
  max-width: 68rem;
  margin: 0 auto;
  padding: var(--space-lg) clamp(var(--space-sm), 4vw, var(--space-lg)) var(--space-2xl);
  display: grid;
  gap: var(--space-md);
}

/* --- panel · the Workbench frame ---------------------------------------- */
.panel {
  border: var(--rule) solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-paper-2);
  padding: var(--space-md);
}

/* Gate 54: eyebrow and heading stack vertically in one column, never side by side. */
.panel__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3xs);
  margin-bottom: var(--space-sm);
}
.panel__title { font-size: var(--text-lg); }

.panel__body  { display: grid; gap: var(--space-sm); }

.panel__foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-sm);
  margin-top: var(--space-md);
  padding-top: var(--space-sm);
  border-top: var(--rule) solid var(--color-rule);
}

/* --- fields -------------------------------------------------------------- */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  /* Three implicit row tracks per visual row - label, control, hint - so a label
     that wraps to two lines pushes every control in that row down together
     instead of leaving them on four different baselines. Measured before this:
     4 of 4 rows ragged, controls up to 6px apart. */
  grid-auto-rows: auto;
  gap: var(--space-2xs) var(--space-sm);
  align-items: start;
}

.field {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3;
  row-gap: var(--space-3xs);
  min-width: 0;
}
/* Subgrid needs three tracks even when a field has no hint, or the control
   stretches to fill the empty one. */
.field > .label   { align-self: end; }
.field > .field__hint { align-self: start; }

@supports not (grid-template-rows: subgrid) {
  .field { grid-row: auto; grid-template-rows: none; }
}

input, select, textarea {
  width: 100%;
  min-width: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.4;
  color: var(--color-ink);
  background: var(--color-paper);
  border: var(--rule) solid var(--color-rule-2);
  border-radius: var(--radius-sm);
  padding: var(--space-2xs) var(--space-xs);
  transition: border-color var(--dur-fast) var(--ease-out);
}
textarea {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.6;
  min-height: 22rem;
  resize: vertical;
}
input:hover:not(:disabled), select:hover:not(:disabled), textarea:hover:not(:disabled) {
  border-color: var(--color-accent);
}
input::placeholder, textarea::placeholder { color: var(--color-muted); opacity: 1; }
input:disabled, select:disabled, textarea:disabled {
  background: var(--color-paper-3);
  color: var(--color-muted);
  border-color: var(--color-rule);
  cursor: not-allowed;
}
input[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: var(--color-err); }

/* --- buttons · eight states --------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  min-height: 44px;
  padding: var(--space-2xs) var(--space-sm);
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;              /* gate 49: a button label never wraps */
  border: var(--rule) solid var(--color-rule-2);
  border-radius: var(--radius-sm);
  background: var(--color-paper);
  color: var(--color-ink);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.btn:hover:not(:disabled)  { border-color: var(--color-accent); color: var(--color-accent); }
.btn:active:not(:disabled) { background: var(--color-paper-3); }
.btn:disabled              { opacity: 0.55; cursor: not-allowed; }

.btn--primary {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-accent-ink);
}
.btn--primary:hover:not(:disabled)  { background: var(--color-accent); color: var(--color-accent-ink); filter: brightness(1.12); }
.btn--primary:active:not(:disabled) { filter: brightness(0.92); }

.btn--danger { color: var(--color-err); border-color: var(--color-rule-2); }
.btn--danger:hover:not(:disabled) { border-color: var(--color-err); color: var(--color-err); background: var(--color-err-soft); }
.btn--danger[data-armed="true"]   { background: var(--color-err); border-color: var(--color-err); color: var(--color-accent-ink); }

.btn--sm { min-height: 32px; padding: var(--space-3xs) var(--space-2xs); font-size: var(--text-xs); }

.btn[data-state="loading"] { cursor: progress; }
.btn[data-state="loading"] .btn__label::after {
  content: "";
  display: inline-block;
  width: 1.6em;
  text-align: left;
  animation: dots 1.2s steps(1, end) infinite;
}
@keyframes dots {
  0%   { content: ""; }
  25%  { content: "."; }
  50%  { content: ".."; }
  75%  { content: "..."; }
}

.btn--link {
  min-height: auto;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-muted);
  font-size: var(--text-sm);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.btn--link:hover:not(:disabled) { color: var(--color-accent); }

/* --- the result line: persistent, never a self-hiding toast ------------- */
.result {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-mono);
  line-height: 1.5;
  color: var(--color-muted);
  margin-right: auto;
  overflow-wrap: anywhere;
  min-width: 0;
}
/* An empty result line still occupies a grid row and its gap, which opens a hole
   under the sign-in button before anything has been reported. */
.result:empty { display: none; }
.result[data-tone="ok"]   { color: var(--color-ok); }
.result[data-tone="bad"]  { color: var(--color-err); }
.result[data-tone="busy"] { color: var(--color-warn); }

/* --- tables -------------------------------------------------------------- */
.table-wrap { overflow-x: auto; }
table {
  width: 100%;
  min-width: 26rem;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
th, td {
  text-align: left;
  padding: var(--space-2xs) var(--space-2xs) var(--space-2xs) 0;
  border-bottom: var(--rule) solid var(--color-rule);
  vertical-align: middle;
}
th {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  font-weight: 500;
  color: var(--color-muted);
}
td.mono { color: var(--color-ink-2); overflow-wrap: anywhere; }
tr:last-child td { border-bottom: 0; }
.empty { color: var(--color-muted); font-style: normal; }

/* --- login --------------------------------------------------------------- */
.gate {
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: var(--space-lg) var(--space-sm);
}
.gate__card {
  width: min(24rem, 100%);
  border: var(--rule) solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-paper-2);
  padding: var(--space-lg);
  display: grid;
  gap: var(--space-sm);
  /* text stays left-aligned inside a centred card: gate 6 wants the elements
     off a single centred axis, not the card off-centre */
  text-align: left;
}
.gate__title { font-size: var(--text-xl); }
.gate__foot {
  margin-top: var(--space-md);
  padding-top: var(--space-sm);
  border-top: var(--rule) solid var(--color-rule);
}

/* --- footer · Ft4 dense colophon ---------------------------------------- */
.colophon {
  border-top: var(--rule) solid var(--color-rule);
  padding: var(--space-md) clamp(var(--space-sm), 4vw, var(--space-lg));
  color: var(--color-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-mono);
  line-height: 1.7;
  overflow-wrap: anywhere;
}

/* --- narrow viewports ---------------------------------------------------- */
@media (max-width: 40rem) {
  /* WCAG AA hit target. Sign out is styled as a text link, which leaves it 13px
     tall - fine with a mouse, not with a thumb. */
  .btn--link { min-height: 44px; display: inline-flex; align-items: center; }
  .nav { flex-wrap: wrap; row-gap: var(--space-2xs); }
  .nav__right { width: 100%; justify-content: space-between; }
  .panel { padding: var(--space-sm); }
  .panel__foot { justify-content: stretch; }
  .panel__foot .btn { flex: 1 1 auto; }
  .result { flex-basis: 100%; margin-right: 0; }
}

/* --- reduced motion ------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .status[data-health="working"] .status__dot { animation: none; opacity: 1; }
  .btn[data-state="loading"] .btn__label::after { content: "..."; animation: none; }
}

/* --- password field with a reveal toggle -------------------------------- */
/* The LiteLLM dashboard at /ui shares this origin, so a browser password manager
   will fill its saved credential here. Without a way to see the field, a wrong
   password you never typed looks identical to one you did. */
.pw { display: flex; align-items: stretch; gap: var(--space-2xs); min-width: 0; }
.pw input { flex: 1 1 auto; }
.pw__peek {
  flex: none;
  min-height: 44px;
  padding: var(--space-2xs) var(--space-xs);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  color: var(--color-muted);
  background: var(--color-paper);
  border: var(--rule) solid var(--color-rule-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.pw__peek:hover  { border-color: var(--color-accent); color: var(--color-accent); }
.pw__peek:active { background: var(--color-paper-3); }
.pw__peek[aria-pressed="true"] { color: var(--color-accent); border-color: var(--color-accent); }

/* --- field hint ---------------------------------------------------------- */
/* Sentence case, under the control. Folding the description into the uppercase
   mono label wrapped every label to two lines and left the inputs ragged. */
.field__hint {
  font-size: var(--text-xs);
  line-height: 1.45;
  color: var(--color-muted);
}

/* A provider prefix is an identifier; breaking "commandcode" across two lines
   reads as a rendering fault. The table already scrolls in its own container. */
#provTable td.mono:first-child { white-space: nowrap; }

/* --- sheet · native <dialog> -------------------------------------------- */
/* showModal() gives focus trapping, Esc, backdrop inertness and top-layer
   stacking from the platform. A hand-rolled overlay reimplements all four, worse. */
.sheet {
  width: min(44rem, calc(100vw - 2 * var(--space-md)));
  max-height: calc(100vh - 2 * var(--space-lg));
  padding: 0;
  border: var(--rule) solid var(--color-rule-2);
  border-radius: var(--radius-md);
  background: var(--color-paper-2);
  color: var(--color-ink-2);
  /* The UA gives <dialog> its own overflow. Left on, it scrolls alongside
     .sheet__body and you get two scrollbars, with the heading sliding out of
     view and the first field clipped. Only the body scrolls. */
  overflow: hidden;
}
.sheet::backdrop { background: oklch(0% 0 0 / 0.55); }

.sheet__form {
  display: flex;
  flex-direction: column;
  max-height: inherit;
  min-height: 0;
}

.sheet__head {
  padding: var(--space-md) var(--space-md) var(--space-sm);
  border-bottom: var(--rule) solid var(--color-rule);
  display: grid;
  gap: var(--space-2xs);
}
.sheet__title { font-size: var(--text-lg); }

/* The body scrolls, so the actions never leave the viewport on a short screen. */
.sheet__body {
  padding: var(--space-md);
  display: grid;
  gap: var(--space-md);
  overflow-y: auto;
  min-height: 0;
}

.sheet__foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-sm);
  padding: var(--space-sm) var(--space-md) var(--space-md);
  border-top: var(--rule) solid var(--color-rule);
}
.sheet .result { padding: 0 var(--space-md); }

.sheet input[readonly] {
  background: var(--color-paper-3);
  color: var(--color-muted);
  cursor: not-allowed;
}

.row-actions { text-align: right; white-space: nowrap; }
.row-actions .btn { margin-left: var(--space-2xs); }

@media (max-width: 40rem) {
  .sheet__foot { justify-content: stretch; }
  .sheet__foot .btn { flex: 1 1 auto; }
}


/* --- browser surfaces ---------------------------------------------------- */
/* The parts not drawn here still carry the design. Left at defaults they belong
   to no design system and read as assembled rather than built. */
::selection {
  background: var(--color-accent);
  color: var(--color-accent-ink);
}
input, textarea, select { caret-color: var(--color-accent); }

* { scrollbar-width: thin; scrollbar-color: var(--color-rule-2) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--color-rule-2);
  border: 3px solid transparent;
  background-clip: content-box;
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover { background: var(--color-muted); background-clip: content-box; }

/* Digits that line up column to column: character counts, ports, timeouts. */
input[type="number"], .result, .colophon, td.mono, .status {
  font-variant-numeric: tabular-nums;
}

/* The primary action for a table sits with the table, not in the panel footer a
   screen away from the rows it creates. */
.panel__action { display: flex; justify-content: flex-end; }

/* --- pool weights -------------------------------------------------------- */
/* A weight is two or three digits. A full-width field for it reads as a text
   box and invites a sentence; this one is sized to its content. */
.pool__weight {
  width: 5.5rem;
  text-align: right;
}
.pool__share {
  display: grid;
  grid-template-columns: 3rem 1fr;
  align-items: center;
  gap: var(--space-2xs);
}
/* Fixed columns, so WEIGHT and SHARE sit at the same x in every pool. Sized by
   content, each table set its own column widths and the two groups read as two
   unrelated tables stacked on top of each other. */
/* min-width must cover the three fixed columns below. Left at the shared 26rem,
   a fixed layout squeezed the member column to a few characters at phone width
   and every host name wrapped to five lines - the wrapper scrolls, so there is
   no reason to let that happen. */
.pool__group table { table-layout: fixed; min-width: 40rem; }
.pool__group th:nth-child(1), .pool__group td:nth-child(1) { width: 18rem; }
.pool__group th:nth-child(2), .pool__group td:nth-child(2) { width: 8rem; }
.pool__group th:nth-child(3), .pool__group td:nth-child(3) { width: 14rem; }
.pool__pct {
  font-variant-numeric: tabular-nums;
  color: var(--color-ink-2);
  text-align: right;
  white-space: nowrap;
}
/* The bar is decoration for a number already written beside it, so it is hidden
   from assistive technology rather than labelled twice. */
.pool__bar {
  height: 6px;
  border-radius: 999px;
  background: var(--color-rule);
  overflow: hidden;
}
/* scaleX, not width: width is a layout property and animating it relays the row
   on every frame while a weight is being typed. The fill is a plain rectangle,
   so a transform is visually identical and stays on the compositor. */
.pool__bar > span {
  display: block;
  height: 100%;
  width: 100%;
  transform-origin: left center;
  background: var(--color-accent);
  border-radius: 999px;
  transition: transform var(--dur-base) var(--ease-out);
}
.pool__bar[data-zero="true"] > span { background: var(--color-muted); }
.pool__name { display: grid; gap: 2px; }
.pool__group {
  display: grid;
  gap: var(--space-2xs);
  padding-block-end: var(--space-sm);
}
.pool__group + .pool__group { border-top: var(--rule) solid var(--color-rule); padding-block-start: var(--space-sm); }
.pool__group-name {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-ink);
}
/* A uniform border in the warn colour, not a thick bar down one side. The side
   tab is a tell, and this page carries its tones on the border all the way
   round already - see .btn--danger. */
.notice {
  border: var(--rule) solid var(--color-warn);
  border-radius: var(--radius-sm);
  padding: var(--space-2xs) var(--space-xs);
  font-size: var(--text-sm);
  color: var(--color-ink-2);
  background: var(--color-paper-2);
}

/* A label that a screen reader reads and the eye does not. The column header
   says "Weight" once for the whole table; a screen reader moving field to field
   needs to hear which member each field belongs to. clip-path rather than
   display:none, which would remove it from the accessibility tree as well. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}
