/*
 * Appli brand design tokens. Keep in sync with
 * `crates/core/src/theme.rs` — the design-tokens-drift CI job
 * diffs the generated list against this file.
 *
 * Two layers:
 *   1. The brand palette (`--appli-*`) — stable across themes; used
 *      directly for state pills, timeline source markers, button
 *      success/danger fills, and other brand-coded chrome.
 *   2. Semantic tokens (`--bg-*`, `--fg-*`, `--rule`) — theme-aware;
 *      every page/card/text/border swaps via `[data-theme="dark"]`
 *      on the document. Default is light; the no-FOUC bootstrap
 *      script in `index.html` reads `localStorage.aphotic_theme` and
 *      sets the attribute before stylesheet paint.
 */

:root {
  --appli-blue:      #1C2F5B;
  --appli-green:     #3FC38B;
  --appli-orange:    #F48255;
  --appli-red:       #F85663;
  --appli-yellow:    #F7CA11;
  --appli-black:     #131021;
  --appli-gray:      #F6F6F6;
  --appli-lightgray: #BEBEBE;
  --appli-white:     #FFFFFF;
  --appli-body-fg:   #212529;
  --appli-rule:      #dee2e6;

  /* Append explicit color-emoji families to every text stack so
   * subject lines like "🚀 Launch" render the glyph rather than
   * dropping to a missing-glyph box on platforms whose default
   * fallback chain doesn't include an emoji font. The list covers
   * the platforms we care about (macOS / Windows / modern Linux). */
  --font-display: 'SpaceGrotesk', 'Poppins', Arial, sans-serif,
                  'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji';
  --font-body:    'Poppins', Arial, Helvetica, sans-serif,
                  'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji';
  --font-mono:    SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
                  'Courier New', monospace,
                  'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji';

  /* --- Semantic tokens (light) ----------------------------------- */
  --bg-page:      var(--appli-white);
  --bg-card:      var(--appli-white);
  --bg-muted:     var(--appli-gray);
  --bg-input:     var(--appli-white);
  --bg-row-hover: var(--appli-gray);

  --fg-body:      var(--appli-body-fg);
  --fg-headline:  var(--appli-blue);
  --fg-muted:     var(--appli-lightgray);
  --fg-link:      var(--appli-blue);
  --fg-link-hover:var(--appli-green);

  --rule:         var(--appli-rule);
}

/* --- Dark theme overrides ----------------------------------------
 * Page bg = appli-blue. Cards lifted slightly. Text is a tinted
 * near-white so the contrast against #1C2F5B is solid (WCAG AA at
 * 16 px). Brand pills + state colors are left alone — they read as
 * intended on either background.
 */
:root[data-theme="dark"] {
  --bg-page:      var(--appli-blue);
  --bg-card:      #253b70;
  --bg-muted:     #16264a;
  --bg-input:     #253b70;
  --bg-row-hover: #2a4280;

  --fg-body:      #e8ecf3;
  --fg-headline:  #ffffff;
  --fg-muted:     #9aa6c0;
  --fg-link:      var(--appli-green);
  --fg-link-hover:#5cd8a1;

  --rule:         rgba(255, 255, 255, 0.14);
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg-page);
  color: var(--fg-body);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 25px;
}

h1, h2, h3 {
  font-family: var(--font-display);
  color: var(--fg-headline);
}

main {
  max-width: 1200px;
  margin: 0 auto;
  padding: 32px 24px;
  border-top: 2px solid var(--rule);
}

button {
  background: var(--appli-green);
  color: var(--appli-white);
  border: 0;
  border-radius: 4px;
  padding: 8px 16px;
  font-family: var(--font-body);
  font-weight: 600;
  cursor: pointer;
}
button:disabled {
  background: var(--appli-lightgray);
  cursor: not-allowed;
}

a {
  color: var(--fg-link);
}
a:hover {
  text-decoration: underline;
  color: var(--fg-link-hover);
}

.muted { color: var(--fg-muted); }

.login-shell form { display: flex; flex-direction: column; gap: 12px; max-width: 360px; }
.login-shell label { display: flex; flex-direction: column; gap: 4px; }
.login-shell input {
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  background: var(--bg-input);
  color: var(--fg-body);
}

.metrics-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  margin: 16px 0 32px;
}
.metric-tile {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--bg-card);
}
.metric-tile.wide { grid-column: span 2; }
.metric-label {
  font-size: 13px;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.metric-value {
  font-family: var(--font-display);
  font-size: 32px;
  color: var(--fg-headline);
}
.metric-value.small { font-size: 16px; }
.error { color: var(--appli-red); }

.crud-table {
  width: 100%;
  border-collapse: collapse;
  margin: 16px 0;
}
.crud-table th,
.crud-table td {
  padding: 8px 12px;
  border-bottom: 1px solid var(--rule);
  text-align: left;
}
.crud-table th {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--fg-muted);
}
.state-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 9999px;
  font-size: 12px;
  color: var(--appli-white);
  background: var(--appli-lightgray);
}
.state-pill.state-enabled  { background: var(--appli-green);  }
.state-pill.state-shadow   { background: var(--appli-orange); }
.state-pill.state-disabled { background: var(--appli-lightgray); }

/* Newly mounted queue rows fade in. The keyed `<For>` only mounts a
 * row when its queue_id first appears, so the animation runs once
 * per genuinely new row — unchanged rows are not remounted. */
@keyframes peek-row-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
tr.peek-row {
  animation: peek-row-fade-in 200ms ease-out;
  transition-property: opacity;
}

.log-filters {
  display: flex;
  gap: 8px;
  margin: 12px 0;
  flex-wrap: wrap;
}
.log-filters input,
.log-filters select {
  padding: 6px 10px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  min-width: 180px;
  background: var(--bg-input);
  color: var(--fg-body);
}
.row-error { background: rgba(248, 86, 99, 0.12); }

.admin-shell nav ul { list-style: none; padding: 0; display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.admin-shell nav a {
  display: block;
  padding: 12px 16px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  text-decoration: none;
  background: var(--bg-card);
}
.admin-shell nav a:hover {
  border-color: var(--appli-green);
}

.agent-summary { margin-bottom: 24px; }

.usage-table td { vertical-align: top; }
.usage-table .token-count { font-family: var(--font-mono); font-size: 14px; }
.usage-table .token-cost  { font-family: var(--font-mono); font-size: 12px; margin-top: 2px; }
.usage-table .total-row   { background: var(--bg-muted); }
.usage-table .total-cell  { font-family: var(--font-mono); font-size: 16px; color: var(--fg-headline); }

.timeline {
  list-style: none;
  padding: 0;
  margin: 16px 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.timeline-entry {
  border-left: 3px solid var(--rule);
  padding: 8px 12px;
  background: var(--bg-muted);
  border-radius: 0 4px 4px 0;
}
.timeline-entry.source-message  { border-left-color: var(--appli-blue); }
.timeline-entry.source-queue    { border-left-color: var(--appli-green); }
.timeline-entry.source-agent    { border-left-color: var(--appli-orange); }
.timeline-entry.source-action   { border-left-color: var(--appli-yellow); }
.timeline-entry.source-delivery { border-left-color: var(--appli-lightgray); }
.timeline-head {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  font-size: 13px;
}
.timeline-at   { font-family: var(--font-mono); color: var(--fg-muted); }
.timeline-kind { font-weight: 600; }
.timeline-payload {
  margin: 6px 0 0;
  padding: 8px;
  background: var(--bg-card);
  border: 1px solid var(--rule);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 12px;
  white-space: pre-wrap;
  word-break: break-word;
}

.pricing-form {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin: 12px 0;
  max-width: 1000px;
}
.pricing-form label { display: flex; flex-direction: column; gap: 4px; }
.pricing-form input,
.pricing-form select {
  padding: 6px 10px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  background: var(--bg-input);
  color: var(--fg-body);
}
.pricing-form button { grid-column: 1 / -1; max-width: 160px; }

/* --- /admin/pricing — upsert form (keys above costs) ----------------
 *
 * Two stacked grids per the user spec: row 1 = the three key fields
 * (provider, model_pattern, url) on one line; row 2 = the four cost
 * rates on the next line. Wraps to multiple visual rows on narrow
 * viewports.
 */
.pricing-upsert-form {
  margin: 12px 0 24px;
  padding: 16px;
  border: 1px dashed var(--rule);
  border-radius: 4px;
  background: var(--bg-card);
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.pricing-keys-row,
.pricing-costs-row {
  display: grid;
  gap: 12px;
}
.pricing-keys-row {
  grid-template-columns: minmax(160px, 220px) minmax(200px, 1fr) minmax(220px, 1fr);
}
.pricing-costs-row {
  grid-template-columns: repeat(4, minmax(140px, 1fr));
}
.pricing-keys-row label,
.pricing-costs-row label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 14px;
  color: var(--fg-headline);
  font-weight: 500;
}
.pricing-keys-row input,
.pricing-keys-row select,
.pricing-costs-row input {
  padding: 6px 10px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  background: var(--bg-input);
  color: var(--fg-body);
  box-sizing: border-box;
}
.pricing-actions-row {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
}
@media (max-width: 768px) {
  .pricing-keys-row { grid-template-columns: 1fr; }
  .pricing-costs-row { grid-template-columns: repeat(2, 1fr); }
}

/* Stacked single-column variant for forms that are mainly vertical
 * text-entry (e.g. profile Change Password). Auto-fit grids align
 * inputs visually only when label text is the same length — for
 * password / display-name forms with mixed-length captions the inputs
 * end up at different y-offsets and look misaligned. The stacked
 * variant pins one column so each input lands on its own row,
 * inheriting padding from .pricing-form. */
.pricing-form.stacked {
  grid-template-columns: minmax(0, 480px);
}

.top-nav {
  display: flex;
  gap: 16px;
  margin: 4px 0 16px;
  font-size: 14px;
}

.oidc-buttons {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 8px 0 16px;
  max-width: 360px;
}
.oidc-button {
  display: block;
  padding: 8px 16px;
  border: 1px solid var(--fg-link);
  border-radius: 4px;
  text-decoration: none;
  text-align: center;
  color: var(--fg-link);
  background: transparent;
}
.oidc-button:hover {
  background: var(--fg-link);
  color: var(--bg-page);
}
.passkey-button {
  background: var(--bg-card);
  color: var(--fg-link);
  border: 1px solid var(--fg-link);
  margin-top: 8px;
}

.queue-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 12px 0;
  flex-wrap: wrap;
}

/* Sticky action bar for the bulk-close / bulk-release UI on the
   queue page. Hidden when no rows are checked; the `.visible`
   modifier flips display:flex on. */
.bulk-action-bar {
  display: none;
  position: sticky;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 10px 12px;
  background: var(--appli-blue);
  color: var(--appli-white);
  border-top: 1px solid var(--appli-lightgray);
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  z-index: 10;
}
.bulk-action-bar.visible {
  display: flex;
}
.bulk-action-bar .bulk-count {
  font-weight: 600;
}
.bulk-action-bar button[disabled] {
  opacity: 0.6;
  cursor: not-allowed;
}
.bulk-action-bar .bulk-clear {
  margin-left: auto;
}

.reply-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 8px 0;
}
.reply-form textarea {
  width: 100%;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  resize: vertical;
  background: var(--bg-input);
  color: var(--fg-body);
}

/* Filter row used on /admin/audit and /admin/log */
.filter-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 12px 0;
  flex-wrap: wrap;
}
.filter-row input,
.filter-row select {
  padding: 4px 8px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  background: var(--bg-input);
  color: var(--fg-body);
}
.pager {
  display: flex;
  gap: 8px;
  margin: 12px 0;
}
.audit-payload {
  background: var(--bg-muted);
  padding: 8px;
  border-radius: 4px;
  max-width: 600px;
  overflow-x: auto;
  font-size: 12px;
  color: var(--fg-body);
}

/* /admin/settings — list / editor / new-key form */
.settings-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
  margin: 12px 0;
}
.settings-group {
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 8px 12px;
  background: var(--bg-card);
}
.settings-group h3 {
  margin: 0 0 8px 0;
  font-size: 14px;
  color: var(--fg-headline);
}
.settings-group ul {
  list-style: none;
  padding: 0;
  margin: 0;
}
.settings-group li {
  padding: 2px 0;
}
.settings-editor {
  margin: 16px 0;
  padding: 12px;
  border: 1px solid var(--fg-link);
  border-radius: 4px;
  background: var(--bg-card);
}
.settings-json {
  width: 100%;
  font-family: var(--font-mono);
  font-size: 13px;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  resize: vertical;
  background: var(--bg-input);
  color: var(--fg-body);
}
.settings-new {
  margin: 16px 0;
  padding: 12px;
  border: 1px dashed var(--rule);
  border-radius: 4px;
  background: var(--bg-card);
}
.settings-new details.advanced-params {
  margin: 8px 0;
  padding: 8px 0 0 0;
  border-top: 1px dashed var(--rule);
}
.settings-new details.advanced-params > summary {
  cursor: pointer;
  padding: 4px 0;
  color: var(--fg-headline);
  font-size: 13px;
}
.settings-new details.advanced-params > summary::-webkit-details-marker {
  color: var(--fg-headline);
}
.settings-new input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
.settings-new textarea,
.settings-new select {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  margin: 4px 0;
  background: var(--bg-input);
  color: var(--fg-body);
}
/* Checkboxes inside a settings-new form must keep their native size;
 * the rule above used to expand them to 100 % which made them giant
 * bars and pushed the descriptive text far to the right. */
.settings-new input[type="checkbox"],
.settings-editor input[type="checkbox"] {
  width: auto;
  margin: 0;
  flex: 0 0 auto;
  vertical-align: middle;
}
.settings-new textarea {
  font-family: var(--font-mono);
  resize: vertical;
}
.action-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
  flex-wrap: wrap;
}
.action-row .status {
  color: var(--fg-headline);
  font-size: 13px;
}
.link-button {
  background: none;
  border: none;
  color: var(--fg-link);
  cursor: pointer;
  text-decoration: underline;
  padding: 0;
  font: inherit;
}
.link-button:hover {
  color: var(--fg-link-hover);
}
button.danger {
  background: var(--appli-red);
  color: var(--appli-white);
}
button.danger:hover {
  filter: brightness(0.9);
}
.small {
  font-size: 11px;
}

/* --- Agent Test panel ------------------------------------------------ */
.agent-test-panel {
  margin: 16px 0 24px 0;
  padding: 12px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--bg-muted);
}
.agent-test-header {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
}
.agent-test-button {
  padding: 6px 14px;
  font-weight: 600;
}
.agent-test-result {
  margin-top: 12px;
}
.agent-test-summary {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.agent-test-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.5px;
}
.agent-test-chip.ok {
  background: var(--appli-green);
  color: var(--appli-white);
}
.agent-test-chip.fail {
  background: var(--appli-red);
  color: var(--appli-white);
}
.agent-test-stale {
  color: var(--appli-orange);
  font-size: 12px;
}
.agent-test-said {
  margin: 8px 0;
  padding: 8px 12px;
  border-left: 3px solid var(--fg-link);
  background: var(--bg-card);
  font-style: italic;
}
.agent-test-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.agent-test-section h4 {
  margin: 0 0 4px 0;
  font-size: 13px;
  color: var(--fg-headline);
}
.agent-test-section ul {
  margin: 0;
  padding-left: 16px;
  font-size: 13px;
}
.agent-test-tokens {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 13px;
}
.agent-test-warnings {
  margin-top: 12px;
  padding: 8px 12px 8px 28px;
  background: var(--appli-yellow);
  border-radius: 4px;
  color: var(--appli-black);
}
.agent-test-warnings li {
  font-size: 13px;
}

/* --- Header-scoped theme toggle ------------------------------------
 * The toggle now lives inside the persistent app header rather than
 * in a fixed-position overlay (see crates/ui/src/header.rs). Keeps
 * the same rotate-on-hover affordance and the icon-swap logic via
 * `[data-theme="dark"]`.
 */
.header-theme-toggle {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: var(--bg-card);
  color: var(--fg-body);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 0;
  font-weight: normal;
  transition: transform 150ms ease-out, border-color 150ms ease-out;
}
.header-theme-toggle:hover {
  border-color: var(--appli-green);
  transform: rotate(20deg);
}
.header-theme-toggle .light-icon { display: inline; }
.header-theme-toggle .dark-icon  { display: none; }
:root[data-theme="dark"] .header-theme-toggle .light-icon { display: none; }
:root[data-theme="dark"] .header-theme-toggle .dark-icon  { display: inline; }
/* --- /admin/agents — create form + per-row delete confirm ----------- */
.checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0;
  /* Keep each row's leading column aligned: a fixed 18 px box on the
   * left so multiple checkbox-rows stack with the boxes in a column,
   * and the label text starts at the same x-offset on every line. */
  line-height: 1.4;
}
.checkbox-row > input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin: 0;
  flex: 0 0 18px;
}
.agent-delete > summary {
  cursor: pointer;
  color: var(--appli-red);
  list-style: none;
  font-size: 13px;
}
.agent-delete > summary::-webkit-details-marker {
  display: none;
}
.agent-delete .action-row {
  margin-top: 4px;
}

/* --- /admin/agents/:id — edit panel + model parameters --------------
 *
 * Two-column form-grid pattern: every label-text + control pair is a
 * row, with all labels aligned in column 1 and all inputs aligned in
 * column 2. `<label>` becomes `display: contents` so its inner text +
 * input become direct grid children of the body. Multi-column items
 * (textareas, action-row, checkbox-row variants) explicitly span both
 * columns via `grid-column: 1 / -1`.
 */
.agent-edit-body,
.run-control-body,
.agent-tools-body {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 10px 16px;
  align-items: center;
  padding: 8px 0 0;
}
/* Plain `<label>"Text:"<input/></label>` rows: flatten so the text
 * lands in column 1 and the control in column 2. */
.agent-edit-body > label:not(.checkbox-row),
.run-control-body > label:not(.checkbox-row) {
  display: contents;
}
/* Checkbox rows already use their own flex layout; keep them aligned
 * to the left edge by spanning both columns. */
.agent-edit-body > label.checkbox-row,
.run-control-body > label.checkbox-row {
  grid-column: 1 / -1;
}
/* Action rows (Save / status / Delete) span the whole grid width. */
.agent-edit-body > .action-row,
.run-control-body > .action-row {
  grid-column: 1 / -1;
}
/* Intro paragraphs / muted help text span both columns. */
.agent-edit-body > p,
.run-control-body > p,
.model-params-body > p {
  grid-column: 1 / -1;
}
/* The system-prompt label has a `<textarea>` that wants the full
 * width; opt out of the contents-flatten and span both cols. */
.agent-edit-body > label.full-width {
  display: block;
  grid-column: 1 / -1;
}
/* Make column-1 inputs (textareas) inside contents-flattened labels
 * full width of the column, but text inputs stay at a sensible cap. */
.agent-edit-body > label > input[type="text"],
.agent-edit-body > label > input[type="email"],
.agent-edit-body > label > input[type="number"] {
  max-width: 480px;
}
/* All form controls in the agent-detail panes share the body font
 * size + use border-box sizing so `width: 100%` on a textarea
 * doesn't overflow by `2 * padding + 2 * border`. Without these the
 * Edit Basics inputs render at the browser's default (≈ 13 px on
 * macOS) while Model Parameters inputs inherit the 16 px body font
 * — the size mismatch reads as inconsistent design. */
.agent-edit-body input,
.agent-edit-body textarea,
.agent-edit-body select,
.run-control-body input,
.run-control-body textarea,
.run-control-body select,
.model-params-body input,
.model-params-body textarea,
.model-params-body select {
  font: inherit;
  box-sizing: border-box;
}
/* The system-prompt textarea uses `.settings-json { width: 100% }`;
 * pin border-box on it explicitly so the rule above wins regardless
 * of cascade order. */
.agent-edit-body textarea.settings-json {
  width: 100%;
  box-sizing: border-box;
}

/* Model parameters body uses subgrid so each `<label class="param-row">`
 * inherits the parent's column tracks — labels in every row now share
 * the same x. Falls back to the old min-content sizing when subgrid
 * isn't supported (Safari < 16). */
.model-params-body {
  display: grid;
  grid-template-columns: max-content auto auto auto auto;
  gap: 10px 12px;
  align-items: center;
  padding: 8px 0 0;
}
.model-params-body > p,
.model-params-body > h4,
.model-params-body > .action-row {
  grid-column: 1 / -1;
}
.model-params .param-row,
.run-control .param-row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  gap: 8px;
  align-items: center;
}
@supports not (grid-template-columns: subgrid) {
  .model-params .param-row,
  .run-control .param-row {
    grid-template-columns: minmax(220px, max-content) auto auto auto auto;
  }
}
.model-params .param-row.column,
.run-control .param-row.column {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  grid-column: 1 / -1;
}
/* Param labels: bigger (was 13 px — too small to scan), and
 * theme-aware so they read on both light + dark. `--fg-headline`
 * is appli-blue in light mode and white in dark — both legible
 * against the card background. */
.param-label {
  font-size: 14px;
  color: var(--fg-headline);
  font-weight: 500;
}
.param-row input[type="number"] {
  width: 96px;
  padding: 4px 6px;
  border: 1px solid var(--appli-lightgray);
  border-radius: 4px;
  font: inherit;
}
.param-row input[type="range"] {
  min-width: 160px;
}
.param-row select {
  padding: 4px 8px;
  border: 1px solid var(--appli-lightgray);
  border-radius: 4px;
  font: inherit;
}
.reset-button {
  font-size: 16px;
  line-height: 1;
  padding: 0 4px;
  text-decoration: none;
}
.reset-button:hover {
  color: var(--appli-green);
}
.chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
  padding: 4px;
  border: 1px solid var(--appli-lightgray);
  border-radius: 4px;
  background: var(--appli-white);
}
/* --- /admin/mcps: chip-list + env-table + warn banner ------------- */
.mcp-form { display: grid; gap: 12px; margin: 8px 0; max-width: 720px; }
.mcp-form fieldset {
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 8px 12px;
  background: var(--bg-card);
}
.mcp-form fieldset legend {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--fg-muted);
  padding: 0 4px;
}
.mcp-form label { display: flex; flex-direction: column; gap: 4px; }
.mcp-form label.inline {
  flex-direction: row;
  align-items: center;
  gap: 6px;
}
.mcp-form input,
.mcp-form select {
  padding: 6px 10px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  background: var(--bg-input);
  color: var(--fg-body);
}
.warn-banner {
  background: var(--appli-yellow);
  color: var(--appli-black);
  padding: 8px 12px;
  border-radius: 4px;
  margin: 4px 0;
  font-size: 13px;
}
.env-editor { display: flex; flex-direction: column; gap: 6px; }
.env-table { width: 100%; border-collapse: collapse; }
.env-table th,
.env-table td { padding: 4px 6px; }
.env-table input {
  width: 100%;
  padding: 4px 8px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  background: var(--bg-input);
  color: var(--fg-body);
}
.env-table input:disabled {
  background: var(--bg-muted);
  color: var(--fg-muted);
}
.chip-list { display: flex; flex-direction: column; gap: 6px; }
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px;
  border: 1px solid var(--appli-rule);
  border-radius: 4px;
  background: var(--appli-gray);
  font-size: 12px;
}
.chip-input {
  flex: 1 1 160px;
  min-width: 160px;
  padding: 2px 6px;
  border: none;
  outline: none;
  font: inherit;
  background: transparent;
}

/* --- /admin/agents/:id — agent_tools allowlist editor --------------- */
.agent-tools-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
  margin: 8px 0;
}
.agent-tools-mcp h4 {
  margin: 0 0 4px 0;
  font-size: 13px;
  color: var(--appli-blue);
}
.agent-tools-mcp textarea {
  width: 100%;
  padding: 4px 8px;
  border-radius: 9999px;
  background: var(--bg-muted);
  color: var(--fg-body);
  font-size: 13px;
}
.chip code { font-family: var(--font-mono); font-size: 12px; }
.chip-x {
  background: transparent;
  color: var(--fg-body);
  border: 0;
  cursor: pointer;
  font-size: 14px;
  padding: 0 4px;
  line-height: 1;
}
.chip-x:hover { color: var(--appli-red); }
.chip-input-row { display: flex; gap: 6px; }
.chip-input-row input {
  flex: 1;
  padding: 6px 10px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  background: var(--bg-input);
  color: var(--fg-body);
}
.mcp-confirm {
  margin: 8px 0;
  padding: 8px;
  border: 1px solid var(--appli-red);
  border-radius: 4px;
  background: var(--bg-card);
}
.mcp-confirm summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--appli-red);
}

/* --- Persistent app header (M7 polish) -----------------------------
 * Sticky top bar that wraps every page via the <HeaderShell>
 * component (see crates/ui/src/header.rs). Layout: logo | nav
 * groups | (auto-margin) | theme toggle + user menu / Sign in.
 */
.app-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 24px;
  height: 72px;
  padding: 0 32px;
  background: var(--bg-card);
  border-bottom: 1px solid var(--rule);
}
.app-header-logo {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: var(--fg-headline);
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.app-header-logo:hover {
  color: var(--appli-green);
}
.app-header-logo-mark {
  display: block;
  width: 40px;
  height: 40px;
}
.app-header-wordmark {
  letter-spacing: -0.005em;
}
.app-header-nav {
  display: flex;
  align-items: center;
  gap: 4px;
}
.app-header-nav-group {
  position: relative;
}
.app-header-nav-group > button {
  background: transparent;
  color: var(--fg-body);
  border: 0;
  border-radius: 4px;
  padding: 10px 16px;
  font-family: var(--font-body);
  font-size: 18px;
  font-weight: 500;
  cursor: pointer;
}
.app-header-nav-group > button:hover {
  background: var(--bg-muted);
}
.app-header-nav-group > button[aria-expanded="true"] {
  background: var(--bg-muted);
}
.app-header-nav-menu {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 200px;
  background: var(--bg-card);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 4px 0;
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
  display: none;
  z-index: 60;
}
.app-header-nav-menu.open {
  display: block;
}
.app-header-nav-menu a,
.app-header-nav-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 14px;
  background: transparent;
  border: 0;
  color: var(--fg-body);
  text-decoration: none;
  font: inherit;
  cursor: pointer;
}
.app-header-nav-menu a:hover,
.app-header-nav-menu button:hover {
  background: var(--bg-muted);
}
.app-header-nav-menu a.active {
  border-bottom: 2px solid var(--appli-green);
}
.app-header-right {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.app-header-user {
  position: relative;
}
.app-header-user > button {
  background: transparent;
  color: var(--fg-body);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 8px 14px;
  font-family: var(--font-body);
  font-size: 16px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.app-header-user > button:hover {
  background: var(--bg-muted);
}
.app-header-user-name {
  font-weight: 600;
}
.app-header-user-role {
  font-size: 12px;
  background: var(--bg-muted);
  padding: 2px 6px;
  border-radius: 999px;
  color: var(--fg-muted);
}
.app-header-user-menu {
  right: 0;
  left: auto;
}
.app-header-lang {
  position: relative;
}
.app-header-lang-btn {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: var(--bg-card);
  color: var(--fg-body);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 0;
  transition: transform 150ms ease-out, border-color 150ms ease-out;
}
.app-header-lang-btn:hover {
  border-color: var(--appli-green);
}
.app-header-lang-flag {
  font-size: 18px;
  line-height: 1;
}
.app-header-signin {
  color: var(--fg-link);
  text-decoration: none;
  padding: 6px 12px;
  border: 1px solid var(--rule);
  border-radius: 4px;
}
.app-header-signin:hover {
  background: var(--bg-muted);
}
/* --- Password reveal/hide eye toggle ---------------------------- */
.password-input-wrapper {
  position: relative;
  display: flex;
  align-items: stretch;
  width: 100%;
}
.password-input-wrapper > .password-input {
  width: 100%;
  padding: 6px 36px 6px 8px;  /* room for the eye button on the right */
  border: 1px solid var(--rule);
  border-radius: 4px;
  font: inherit;
  background: var(--bg-input);
  color: var(--fg-body);
}
.password-reveal-btn {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--fg-muted, var(--fg-body));
  border-radius: 4px;
  transition: color 150ms ease-out, background 150ms ease-out;
}
.password-reveal-btn:hover {
  color: var(--fg-body);
  background: var(--bg-muted);
}
.password-reveal-btn:focus-visible {
  outline: 2px solid var(--appli-green);
  outline-offset: 1px;
}
.password-reveal-btn svg {
  display: block;
}
.app-header-mobile-toggle {
  display: none;
  background: transparent;
  color: var(--fg-body);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 6px 10px;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

/* --- Ingress-status banner ---------------------------------------
 * Sits between <Header /> and <main>; visible to every authenticated
 * user when the ingress agent has fallen behind. Loud (red bg) so it
 * doesn't blend into the rest of the chrome. The polling loop in
 * crates/ui/src/header.rs::IngressStatusBanner refreshes every 30s.
 */
.ingress-banner {
  background: var(--appli-red);
  color: var(--appli-white);
  padding: 10px 24px;
  font-size: 14px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.2);
}
.ingress-banner strong {
  margin-right: 6px;
}
.ingress-banner .muted {
  color: rgba(255, 255, 255, 0.85);
}
.breadcrumb {
  font-size: 13px;
  color: var(--fg-muted);
  margin-top: 4px;
}
.breadcrumb a {
  color: var(--fg-link);
}

/* Mobile (≤ 768 px): collapse the inline groups behind a hamburger.
 * Open state turns the nav into a vertical drawer that drops below
 * the bar. CSS-only via class:mobile-open on the <nav>. */
@media (max-width: 768px) {
  .app-header {
    flex-wrap: wrap;
    height: auto;
    padding: 8px 16px;
  }
  .app-header-mobile-toggle {
    display: inline-flex;
  }
  .app-header-nav {
    display: none;
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px 0;
    border-top: 1px solid var(--rule);
  }
  .app-header-nav.mobile-open {
    display: flex;
  }
  .app-header-nav-group {
    width: 100%;
  }
  .app-header-nav-group > button {
    width: 100%;
    text-align: left;
  }
  .app-header-nav-menu {
    position: static;
    width: 100%;
    box-shadow: none;
    border: 0;
    padding-left: 16px;
  }
}
