/* ============================================================
   AI Gateway · Admin Console — Hi-fi system
   "Precision instrument": near-black canvas, signal grid,
   hairline panels, Space Grotesk + IBM Plex Mono, lime signal.
   ============================================================ */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

/* The console hides role-restricted UI by setting el.hidden = true (the nav
   links in applyRole(), the Logs delete bar, group captions). The HTML `hidden`
   attribute only carries the UA rule `display:none`, which ANY author rule with
   a class selector outranks — `.navlink{display:flex}` below did exactly that,
   so every admin-only nav item stayed visible to regular users. The server
   still refused those screens, so nothing leaked, but the menu advertised an
   admin surface the user could not use. This restores the attribute's meaning
   for the whole console; keep it above the component rules. */
[hidden]{ display:none !important; }

:root{
  /* dark (default) */
  --bg:        oklch(0.155 0.012 264);
  --bg-2:      oklch(0.135 0.012 264);
  --panel:     oklch(0.188 0.012 264);
  --panel-2:   oklch(0.224 0.013 264);
  --border:    oklch(0.30 0.013 264);
  --border-soft: oklch(0.255 0.012 264);
  --text:      oklch(0.95 0.006 264);
  --text-2:    oklch(0.73 0.012 264);
  --text-3:    oklch(0.56 0.013 264);

  --accent:    oklch(0.88 0.20 124);
  --accent-2:  oklch(0.80 0.18 124);
  --accent-on: oklch(0.20 0.04 124);
  --accent-dim: oklch(0.88 0.20 124 / .12);
  --accent-glow: oklch(0.88 0.20 124 / .22);

  --ok:   oklch(0.80 0.13 172);
  --warn: oklch(0.83 0.14 80);
  --crit: oklch(0.68 0.19 26);
  --info: oklch(0.75 0.13 246);
  --ok-dim:   oklch(0.80 0.13 172 / .14);
  --warn-dim: oklch(0.83 0.14 80 / .14);
  --crit-dim: oklch(0.68 0.19 26 / .15);
  --info-dim: oklch(0.75 0.13 246 / .14);

  --mono: 'IBM Plex Mono', ui-monospace, monospace;
  --sans: 'Space Grotesk', system-ui, sans-serif;

  --r:   12px;
  --r-sm: 8px;
  --r-lg: 18px;
  --rail-w: 232px;
  --shadow: 0 1px 0 oklch(1 0 0 / .04) inset, 0 8px 28px -14px oklch(0 0 0 / .7);
  --ease: cubic-bezier(.22,.61,.36,1);
}

[data-theme="light"]{
  --bg:        oklch(0.965 0.006 264);
  --bg-2:      oklch(0.94 0.006 264);
  --panel:     oklch(0.995 0.003 264);
  --panel-2:   oklch(0.955 0.006 264);
  --border:    oklch(0.88 0.008 264);
  --border-soft: oklch(0.915 0.006 264);
  --text:      oklch(0.26 0.014 264);
  --text-2:    oklch(0.46 0.014 264);
  --text-3:    oklch(0.62 0.012 264);
  --accent:    oklch(0.72 0.17 128);
  --accent-2:  oklch(0.64 0.16 128);
  --accent-on: oklch(0.99 0.02 124);
  --accent-dim: oklch(0.72 0.17 128 / .14);
  --accent-glow: oklch(0.72 0.17 128 / .18);
  --ok:   oklch(0.58 0.13 168);
  --warn: oklch(0.66 0.14 70);
  --crit: oklch(0.58 0.20 26);
  --info: oklch(0.55 0.15 250);
  --shadow: 0 1px 2px oklch(0 0 0 / .04), 0 10px 30px -18px oklch(0 0 0 / .25);
}

*{ box-sizing:border-box; }
html,body{ margin:0; height:100%; }
body{
  font-family:var(--sans);
  color:var(--text);
  background:var(--bg);
  font-size:14px;
  line-height:1.45;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
body::before{
  /* signal grid + corner glow */
  content:''; position:fixed; inset:0; z-index:0; pointer-events:none;
  background:
    radial-gradient(900px 500px at 12% -8%, var(--accent-glow), transparent 60%),
    radial-gradient(700px 600px at 100% 0%, oklch(0.75 0.13 246 / .08), transparent 55%),
    linear-gradient(var(--border-soft) 1px, transparent 1px) 0 0 / 100% 34px,
    linear-gradient(90deg, var(--border-soft) 1px, transparent 1px) 0 0 / 34px 100%;
  opacity:.5; mask-image:linear-gradient(180deg, oklch(0 0 0/.9), oklch(0 0 0/.25));
}
[data-theme="light"] body::before{ opacity:.55; }

button{ font-family:inherit; cursor:pointer; }
.mono{ font-family:var(--mono); font-feature-settings:"tnum" 1; }
.num{ font-family:var(--mono); font-variant-numeric:tabular-nums; }

/* ===================== APP LAYOUT ===================== */
.app{
  position:relative; z-index:1;
  display:grid;
  grid-template-columns:var(--rail-w) 1fr;
  grid-template-rows:auto 1fr;
  grid-template-areas:"rail top" "rail main";
  min-height:100vh;
  transition:grid-template-columns .18s ease;
}
/* hamburger (#navToggle) collapses the sidebar to give the main area full width */
.app.nav-collapsed{ grid-template-columns:0 1fr; }
.app.nav-collapsed .rail{
  overflow:hidden; padding-left:0; padding-right:0; border-right:0;
  opacity:0; pointer-events:none;
}

/* ---- topbar ---- */
.topbar{
  grid-area:top;
  display:flex; align-items:center; gap:16px;
  padding:0 22px; height:60px;
  border-bottom:1px solid var(--border);
  background:color-mix(in oklch, var(--bg) 80%, transparent);
  backdrop-filter:blur(8px);
  position:sticky; top:0; z-index:30;
}
.cmd{
  flex:1; max-width:520px; display:flex; align-items:center; gap:10px;
  height:38px; padding:0 12px;
  border:1px solid var(--border); border-radius:var(--r-sm);
  background:var(--panel); color:var(--text-3);
  transition:border-color .15s, box-shadow .15s;
}
.cmd:hover{ border-color:var(--text-3); }
.cmd .ph{ flex:1; font-size:13.5px; }
.cmd .kbd{ font-family:var(--mono); font-size:11px; color:var(--text-3);
  border:1px solid var(--border); border-radius:5px; padding:2px 6px; }
.cmd svg{ width:16px; height:16px; color:var(--text-3); flex:none; }

.tb-right{ display:flex; align-items:center; gap:10px; margin-left:auto; }
.seg{ display:flex; border:1px solid var(--border); border-radius:var(--r-sm); overflow:hidden; background:var(--panel); }
.seg button{ border:0; background:transparent; color:var(--text-2); font-size:12.5px; padding:7px 12px;
  font-family:var(--mono); letter-spacing:.02em; }
.seg button+button{ border-left:1px solid var(--border); }
.seg button.on{ background:var(--accent); color:var(--accent-on); font-weight:600; }
.tz{ font-family:var(--mono); font-size:12px; color:var(--text-3); background:transparent; border:1px solid transparent;
  border-radius:6px; padding:4px 7px; cursor:pointer; }
.tz:hover{ color:var(--text); border-color:var(--border); background:var(--panel); }
.tz[aria-expanded="true"]{ color:var(--text); border-color:var(--accent); background:var(--panel); }
/* timezone popover menu */
.tz-menu{ position:absolute; z-index:60; min-width:210px; max-height:60vh; overflow-y:auto;
  background:var(--panel); border:1px solid var(--border); border-radius:var(--r-sm); box-shadow:var(--shadow);
  padding:5px; opacity:0; transform:translateY(-4px); transition:.12s var(--ease); pointer-events:none; }
.tz-menu.show{ opacity:1; transform:translateY(0); pointer-events:auto; }
.tz-menu .tz-opt{ display:flex; align-items:center; justify-content:space-between; gap:14px; width:100%;
  border:0; background:transparent; color:var(--text-2); font-size:12.5px; text-align:left;
  padding:7px 9px; border-radius:6px; cursor:pointer; }
.tz-menu .tz-opt:hover{ background:var(--panel-2); color:var(--text); }
.tz-menu .tz-opt.on{ color:var(--text); font-weight:600; }
.tz-menu .tz-opt .off{ font-family:var(--mono); font-size:11px; color:var(--text-3); }
.tz-menu .tz-opt.on .off{ color:var(--accent); }
.tz-menu .tz-sep{ height:1px; background:var(--border); margin:4px 2px; }
.env{ font-family:var(--mono); font-size:11px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--crit); border:1px solid color-mix(in oklch, var(--crit) 50%, var(--border));
  background:var(--crit-dim); border-radius:6px; padding:4px 8px; }
.lang-sel{ height:36px; border:1px solid var(--border); background:var(--panel); color:var(--text-2);
  border-radius:var(--r-sm); font-size:12.5px; padding:0 8px; cursor:pointer; }
.lang-sel:hover{ color:var(--text); border-color:var(--text-3); }
.lang-sel:focus{ outline:none; border-color:var(--accent); }
.icon-btn{ width:36px; height:36px; display:grid; place-items:center; border:1px solid var(--border);
  background:var(--panel); border-radius:var(--r-sm); color:var(--text-2); }
.icon-btn:hover{ color:var(--text); border-color:var(--text-3); }
.icon-btn svg{ width:17px; height:17px; }
.avatar{ width:36px; height:36px; border-radius:50%; display:grid; place-items:center;
  background:linear-gradient(150deg, var(--accent), var(--accent-2)); color:var(--accent-on);
  font-weight:700; font-size:13px; }

/* ---- rail ---- */
.rail{
  grid-area:rail;
  border-right:1px solid var(--border);
  background:var(--bg-2);
  padding:18px 14px;
  display:flex; flex-direction:column; gap:4px;
  position:sticky; top:0; height:100vh; overflow:auto;
}
.logo{ display:flex; align-items:center; gap:11px; padding:4px 8px 18px; }
.logo .mark{ width:30px; height:30px; border-radius:9px; position:relative; flex:none;
  background:linear-gradient(150deg, var(--accent), var(--accent-2));
  box-shadow:0 0 0 1px oklch(0 0 0 /.2) inset, 0 6px 18px -8px var(--accent-glow); }
.logo .mark::after{ content:''; position:absolute; inset:9px; border-radius:3px;
  background:var(--accent-on); clip-path:polygon(0 50%,38% 50%,52% 18%,72% 82%,86% 50%,100% 50%,100% 62%,80% 62%,72% 96%,52% 40%,42% 62%,0 62%); }
.logo b{ font-size:16px; letter-spacing:.01em; }
.logo b span{ color:var(--text-3); font-weight:500; }
.nav-cap{ font-family:var(--mono); font-size:10.5px; letter-spacing:.13em; text-transform:uppercase;
  color:var(--text-3); padding:14px 10px 5px; }
.navlink{ display:flex; align-items:center; gap:11px; padding:8px 10px; border-radius:var(--r-sm);
  color:var(--text-2); font-size:13.5px; font-weight:500; border:1px solid transparent; position:relative;
  transition:background .14s, color .14s; }
.navlink svg{ width:17px; height:17px; flex:none; opacity:.85; }
.navlink:hover{ background:var(--panel); color:var(--text); }
.navlink.sel{ background:var(--panel); color:var(--text); border-color:var(--border); }
.navlink.sel::before{ content:''; position:absolute; left:-14px; top:8px; bottom:8px; width:3px;
  border-radius:0 3px 3px 0; background:var(--accent); box-shadow:0 0 12px var(--accent-glow); }
.navlink .lk{ margin-left:auto; opacity:.6; }
.navlink .badge{ margin-left:auto; font-family:var(--mono); font-size:10.5px; color:var(--crit);
  background:var(--crit-dim); border-radius:20px; padding:1px 7px; }
.navlink.sub{ margin-left:18px; font-size:12.5px; }      /* sub-item under Providers */
.navlink.sub svg{ width:15px; height:15px; }

/* Collapsible nav group (Providers & Models / Tests).
   The header is a <button> so it is keyboard-reachable and announces its state via
   aria-expanded; the chevron rotates off that same attribute, so there is one source
   of truth for "open" instead of a class that can drift from the ARIA state.
   Children are .navlink.grp and are hidden with [hidden] (see the global rule at the
   top of this file — a bare display:none would lose to .navlink{display:flex}). */
.navgrp{ display:flex; align-items:center; gap:11px; width:100%; padding:8px 10px; border-radius:var(--r-sm);
  background:none; border:1px solid transparent; color:var(--text-2); font:inherit; font-size:13.5px;
  font-weight:500; text-align:left; cursor:pointer; transition:background .14s, color .14s; }
.navgrp:hover{ background:var(--panel); color:var(--text); }
.navgrp svg{ width:17px; height:17px; flex:none; opacity:.85; }
.navgrp .chev{ width:13px; height:13px; opacity:.6; transition:transform .16s; }
.navgrp[aria-expanded="true"] .chev{ transform:rotate(90deg); }
/* A closed group still has to show WHERE you are, so the header of a group holding
   the current screen keeps the selected treatment even while collapsed. */
.navgrp.has-sel{ color:var(--text); }
.navgrp.has-sel .chev{ opacity:1; color:var(--accent); }
.navlink.grp{ margin-left:18px; font-size:12.5px; }
.navlink.grp svg{ width:15px; height:15px; }

/* Image Models comparison page */
.stars{ color:var(--accent); letter-spacing:1px; font-size:12.5px; white-space:nowrap; }
.cap-y{ color:var(--ok, #7bd88f); font-weight:700; }
.cap-m{ color:var(--warn, #e3b341); font-weight:700; }
.cap-n{ color:var(--crit, #f0626b); font-weight:700; opacity:.85; }
#imgTbl.fit-page-width{ width:100%; }
#imgTbl tr.vfirst td, #txtTbl tr.vfirst td{ border-top:1px solid var(--border); }
#imgTbl .im-sup, #txtTbl .tm-sup{ width:15px; height:15px; accent-color:var(--accent); cursor:pointer; }
/* rows added by the latest regeneration — colored + NEW badge, awaiting selection */
#imgTbl tr.im-new td, #txtTbl tr.im-new td{ background:var(--accent-dim); }
#imgTbl tr.im-new td:first-child, #txtTbl tr.im-new td:first-child{ box-shadow:inset 3px 0 0 var(--accent); }
.im-new-badge{ display:inline-block; margin-left:6px; padding:1px 6px; border-radius:20px;
  font-family:var(--mono); font-size:9.5px; font-weight:700; letter-spacing:.4px; vertical-align:middle;
  color:var(--accent-on); background:var(--accent); }
/* "≤N" max reference-photo limit shown next to the 多图生图 capability tick */
.im-maximg{ display:inline-block; padding:0 5px; border-radius:10px; font-family:var(--mono);
  font-size:10px; font-weight:600; vertical-align:middle; color:var(--muted); border:1px solid var(--border); }
/* Text Models: token limit the vendor does not publish — gateway default in force */
.tm-unverified{ color:var(--warn, #e3b341); font-weight:700; cursor:help; }
/* The reason under a Text Models status chip. Visible in the cell rather than
   hidden behind a hover, because an "Alert" with no stated cause is just noise.
   Clamped to two lines so one long provider message cannot stretch the row. */
.tm-why{ display:-webkit-box; margin-top:4px; max-width:34ch; font-size:10.5px;
  line-height:1.35; color:var(--text-3); cursor:help; overflow:hidden;
  -webkit-box-orient:vertical; -webkit-line-clamp:2; }
/* the same line, but as the link into Logs */
a.tm-why-link{ cursor:pointer; text-decoration:none; border-bottom:1px dotted transparent; }
a.tm-why-link:hover{ color:var(--accent); border-bottom-color:currentColor; }
a.tm-why-link:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:3px; }

/* custom modal confirm (replaces window.confirm) */
.modal-ov{ position:fixed; inset:0; z-index:1000; display:flex; align-items:center; justify-content:center;
  background:oklch(0 0 0 / .5); opacity:0; transition:opacity .15s; padding:20px; }
.modal-ov.show{ opacity:1; }
.modal{ width:min(440px,100%); background:var(--panel); border:1px solid var(--border); border-radius:var(--r-md, 12px);
  box-shadow:0 24px 60px -20px oklch(0 0 0 / .6); transform:translateY(8px) scale(.98); transition:transform .15s; overflow:hidden; }
.modal-ov.show .modal{ transform:none; }
.modal-h{ padding:16px 18px 0; font-size:15px; font-weight:600; color:var(--text); }
.modal-b{ padding:10px 18px 4px; font-size:13px; line-height:1.55; color:var(--text-2); }
.modal-f{ display:flex; justify-content:flex-end; gap:9px; padding:14px 18px 16px; }
/* Logs → stored-images viewer (wider modal; thumbnails open full size in a new tab) */
.modal:has(.logimg-sec){ width:min(720px,100%); }
.modal:has(.logimg-sec) .modal-b{ max-height:70vh; overflow:auto; }
/* Status guide: long reference table — cap height and scroll within the modal. */
/* ---- Releases → What's New (illustrated changelog) ----
   The card leads with version + timestamp because that is what a reader is matching
   against ("we upgraded on the 9th — what did we get"), and the screenshots sit under
   the items rather than beside them so a wide dashboard shot is legible at thumbnail
   size instead of squeezed into a column. */
.wn-bar{ align-items:center; gap:12px; flex-wrap:wrap; margin-top:12px; }
.wn-lbl{ font-size:13px; font-weight:500; }
.wn-count{ font-size:11.5px; margin-left:auto; }
.wn-card{ margin-bottom:16px; }
.wn-head{ display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; margin-bottom:8px; }
.wn-ver{ font-size:12px; font-weight:600; color:var(--accent);
  border:1px solid color-mix(in oklch, var(--accent) 45%, var(--border));
  background:var(--accent-dim); border-radius:999px; padding:2px 10px; }
.wn-when{ display:inline-flex; align-items:baseline; gap:7px; font-size:11.5px; color:var(--text-3); }
.wn-time{ color:var(--text-2); font-weight:600; }
.wn-tz{ font-size:10.5px; }
.wn-title{ flex:1 1 100%; margin:4px 0 0; font-size:14.5px; }
.wn-shots{ display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:14px; margin-top:14px; }
.wn-shot{ margin:0; }
.wn-shot-btn{ display:block; width:100%; padding:0; border:1px solid var(--border); border-radius:var(--r-sm);
  overflow:hidden; background:var(--panel-2); cursor:zoom-in; transition:border-color .14s, transform .14s; }
.wn-shot-btn:hover{ border-color:var(--accent); transform:translateY(-1px); }
.wn-shot-btn img{ display:block; width:100%; height:auto; }
.wn-shot figcaption{ font-size:11.5px; color:var(--text-3); line-height:1.5; margin-top:7px; }
.wn-noshot{ font-size:11.5px; margin:12px 0 0; font-style:italic; }
/* A version that several people shipped into keeps each contributor's title. */
.wn-part + .wn-part{ margin-top:14px; padding-top:14px; border-top:1px solid var(--border-soft); }
.wn-part-title{ margin:0 0 6px; font-size:13px; font-weight:600; color:var(--text-2); }
.wn-pager{ margin-top:4px; }

/* A card the reader was sent to — from the Daily Digest's "Full note" link, or a
   heatmap cell — is marked for a moment so it can be told from its neighbours. */
.wn-flash{ animation:wnflash 2.6s ease-out; }
@keyframes wnflash{ 0%,45%{ box-shadow:0 0 0 2px var(--accent), 0 0 0 8px var(--accent-glow); } 100%{ box-shadow:none; } }

/* Dashboard red bar: today's spend crossed the operator's limit. Deliberately the
   loudest thing in the console — it is a bill that is still growing. */
.spend-bar{ display:flex; align-items:center; gap:10px; margin:0 0 14px; padding:11px 14px; border-radius:10px;
  background:color-mix(in srgb, var(--crit) 16%, var(--panel)); border:1px solid color-mix(in srgb, var(--crit) 55%, var(--border));
  color:var(--text); font-size:13px; }
.spend-bar b{ color:var(--crit); }
.spend-bar a{ color:var(--crit); font-weight:600; white-space:nowrap; }
.spend-bar-dot{ width:9px; height:9px; border-radius:50%; background:var(--crit); box-shadow:0 0 0 4px color-mix(in srgb, var(--crit) 25%, transparent); flex:none; animation:spendpulse 1.6s ease-in-out infinite; }
@keyframes spendpulse{ 50%{ box-shadow:0 0 0 7px color-mix(in srgb, var(--crit) 10%, transparent); } }

/* ---------- Daily Digest ---------- */
/* Heatmap: one cell per day, one column per week, Sunday at the top — the GitHub
   contribution calendar, because everyone already knows how to read one. Colour is
   the accent at four strengths so it sits inside the theme in both modes. */
.hm-wrap{ --hm-cell:13px; --hm-gap:3px; margin-top:14px; }
.hm-scroll{ overflow-x:auto; padding-bottom:4px; }
.hm{ display:grid; grid-auto-rows:var(--hm-cell); gap:var(--hm-gap); align-items:center; width:max-content;
  padding:2px 2px 2px 0; font-size:10.5px; color:var(--text-3); }
.hm-mo{ grid-row:1; white-space:nowrap; line-height:1; align-self:end; padding-bottom:2px; cursor:default; }
.hm-dow{ grid-column:1; padding-right:6px; line-height:1; text-align:right; }
.hm-c{ display:block; width:var(--hm-cell); height:var(--hm-cell); border-radius:3px; padding:0; margin:0;
  border:1px solid transparent; background:var(--panel-2); box-shadow:inset 0 0 0 1px var(--border-soft); }
.hm-c.l1{ background:color-mix(in srgb, var(--accent) 32%, var(--panel-2)); box-shadow:none; }
.hm-c.l2{ background:color-mix(in srgb, var(--accent) 56%, var(--panel-2)); box-shadow:none; }
.hm-c.l3{ background:color-mix(in srgb, var(--accent) 80%, var(--panel-2)); box-shadow:none; }
.hm-c.l4{ background:var(--accent); box-shadow:none; }
/* Outside the chosen date window: still there, still clickable (a click widens the
   window back), but visibly not part of what the rows below are showing. */
.hm-c.hm-out{ opacity:.28; }
button.hm-c{ cursor:pointer; transition:transform .12s; }
button.hm-c:hover{ transform:scale(1.25); outline:1px solid var(--text-2); z-index:1; position:relative; }
.hm-legend{ display:flex; align-items:center; gap:4px; margin-top:8px; font-size:10.5px; }
.hm-legend .hm-c{ width:11px; height:11px; }
.hm-legend .faint + .hm-c{ margin-left:2px; }
.hm-tot{ margin-left:auto; font-size:11.5px; }

/* One row per day. The summary is prose the reader can stop at; the list beneath is
   for the reader who wants a specific release, and each line links to its full note. */
.dd-card{ margin-bottom:16px; }
.dd-head{ display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; margin-bottom:8px; }
.dd-date{ font-size:14px; font-weight:700; color:var(--text); }
.dd-dow{ font-size:12px; }
.dd-count{ font-size:11.5px; font-weight:600; color:var(--accent);
  border:1px solid color-mix(in oklch, var(--accent) 45%, var(--border));
  background:var(--accent-dim); border-radius:999px; padding:2px 10px; }
.dd-span{ font-size:11.5px; margin-left:auto; }
.dd-sum{ margin:0 0 10px; font-size:13.5px; line-height:1.65; color:var(--text-2); }
/* An unauthored day shows its titles in ship order, styled as the list it is — never
   dressed up as a paragraph somebody wrote. */
.dd-sum-auto{ font-size:12.5px; color:var(--text-3); font-style:italic; }
.dd-list{ list-style:none; margin:0; padding:0; border-top:1px solid var(--border-soft); }
.dd-item{ display:grid; grid-template-columns:auto auto 1fr auto; gap:10px; align-items:baseline;
  padding:7px 0; border-bottom:1px solid var(--border-soft); font-size:13px; }
.dd-ver{ font-size:12px; font-weight:600; color:var(--accent); }
.dd-time{ font-size:11.5px; }
.dd-title{ color:var(--text-2); line-height:1.5; }
.dd-more{ background:none; border:0; padding:0; font:inherit; font-size:12px; color:var(--accent); cursor:pointer;
  white-space:nowrap; opacity:.85; }
.dd-more:hover{ text-decoration:underline; opacity:1; }
@media (max-width:640px){
  .dd-item{ grid-template-columns:auto 1fr; }
  .dd-title{ grid-column:1 / -1; }
  .dd-more{ grid-column:2; justify-self:end; }
}

/* Full-size screenshot viewer — a changelog shot nobody can read is decoration. */
.shot-modal{ width:min(1280px,96vw); }
.shot-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:16px;
  padding:16px 20px 12px; font-size:13.5px; font-weight:500; line-height:1.5; }
.shot-body{ padding:0 20px 20px; max-height:80vh; overflow:auto; }
.shot-body img{ display:block; width:100%; height:auto; border:1px solid var(--border); border-radius:var(--r-sm); }

/* Cost-over-time expanded view: wide, because the point of expanding is to fit a
   labelled axis per bucket rather than four thinned ticks. */
.cost-modal{ width:min(1040px,96vw); }
.cost-modal .modal-b{ padding:14px 20px 20px; max-height:80vh; overflow:auto; }
.cost-head{ display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:16px 20px 12px; flex-wrap:wrap; }
.cost-head .sub{ font-size:12px; font-weight:400; color:var(--text-3); }
.cost-actions{ display:flex; align-items:center; gap:10px; }
.cost-stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:16px; }
.cost-stat{ border:1px solid var(--border); border-radius:var(--r-sm); padding:10px 12px;
  background:var(--panel-2); display:flex; flex-direction:column; gap:3px; }
.cost-stat span{ font-size:11px; color:var(--text-3); letter-spacing:.01em; }
.cost-stat b{ font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:16px; color:var(--text); }
@media (max-width:720px){ .cost-stats{ grid-template-columns:repeat(2,1fr); } }
.modal:has(.status-guide){ width:min(560px,100%); }
.modal:has(.status-guide) .modal-b{ max-height:70vh; overflow:auto; }
.logimg-sec{ margin:6px 0 12px; }
.logimg-h{ font-size:11.5px; font-weight:600; color:var(--text-2); margin:0 0 7px; }
.logimg-grid{ display:flex; flex-wrap:wrap; gap:8px; }
.logimg{ display:inline-flex; padding:0; border:0; background:none; cursor:zoom-in; }
/* Full-size viewer for a log image. Sits above .modal-ov (z 1000) because it is
   opened FROM the request-detail modal and must cover it. */
.imgview{ position:fixed; inset:0; z-index:1100; display:flex; align-items:center; justify-content:center;
  background:rgba(0,0,0,.78); padding:24px; opacity:0; transition:opacity .15s ease; cursor:zoom-out; }
.imgview.show{ opacity:1; }
.imgview img{ max-width:100%; max-height:100%; object-fit:contain; border-radius:var(--r-sm); box-shadow:0 12px 40px rgba(0,0,0,.5); }
.logimg img{ max-width:200px; max-height:200px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--bg); object-fit:contain; }
.logtxt{ display:flex; flex-direction:column; gap:8px; margin:0 0 8px; }
.logtxt-item{ display:flex; flex-direction:column; gap:3px; }
.logtxt-label{ font-size:10.5px; font-weight:600; letter-spacing:.02em; text-transform:uppercase; color:var(--text-2); }
.logtxt-body{ margin:0; padding:8px 10px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--bg); color:var(--text); font:12px/1.5 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace); white-space:pre-wrap; word-break:break-word; max-height:240px; overflow:auto; }
.logtxt-body.err{ border-color:var(--danger,#e03131); background:color-mix(in srgb,var(--danger,#e03131) 8%,transparent); color:var(--danger,#e03131); }
button.link{ background:none; border:0; padding:0; cursor:pointer; font:inherit; color:var(--accent); font-size:12.5px; font-weight:500; }
button.link:hover{ text-decoration:underline; }
.btn.danger{ background:var(--crit); border-color:var(--crit); color:#fff; }
/* Admin panel: the collapsed sections stack normally; the TOGGLE is what gets
   pushed to the bottom of the rail, so it reads as a foot control whether the
   panel is open or shut. The foot itself must then not also claim the free space
   — two auto margins would split it and leave a gap between the two. */
.adminpanel{ display:flex; flex-direction:column; gap:4px; }
.adminbtn{ margin-top:auto; display:flex; align-items:center; gap:11px; width:100%;
  padding:9px 10px; border-radius:var(--r-sm); background:none; border:1px solid transparent;
  color:var(--accent); font:inherit; font-size:13.5px; font-weight:600; text-align:left;
  cursor:pointer; transition:background .14s, color .14s; }
.adminbtn:hover{ background:var(--panel); }
.adminbtn svg{ width:17px; height:17px; flex:none; }
.adminbtn .chev{ width:13px; height:13px; margin-left:auto; opacity:.7; transition:transform .16s; }
.adminbtn[aria-expanded="true"] .chev{ transform:rotate(90deg); }
.adminbtn + .rail-foot{ margin-top:0; }
.rail-foot{ margin-top:auto; padding-top:14px; border-top:1px solid var(--border-soft); }
.rail-foot .who{ display:flex; align-items:center; gap:10px; padding:6px 8px; }
.rail-foot .who small{ color:var(--text-3); font-size:11.5px; }

/* ===================== MAIN ===================== */
.main{ grid-area:main; padding:24px 28px 60px; min-width:0; }
.page-head{ display:flex; align-items:flex-end; gap:16px; margin-bottom:22px; flex-wrap:wrap; }
.page-head h1{ font-size:25px; font-weight:600; letter-spacing:-.01em; margin:0; }
.page-head .crumb{ font-family:var(--mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--text-3); margin-bottom:4px; }
.status-pill{ display:inline-flex; align-items:center; gap:8px; font-size:12.5px; color:var(--ok);
  border:1px solid color-mix(in oklch, var(--ok) 45%, var(--border)); background:var(--ok-dim);
  border-radius:20px; padding:5px 12px 5px 10px; font-weight:500; }
.dot{ width:8px; height:8px; border-radius:50%; background:currentColor; position:relative; }
.dot.live::after{ content:''; position:absolute; inset:-4px; border-radius:50%; border:2px solid currentColor;
  animation:pulse 1.8s var(--ease) infinite; }
@keyframes pulse{ 0%{ transform:scale(.6); opacity:.8 } 100%{ transform:scale(1.7); opacity:0 } }
.upd{ font-family:var(--mono); font-size:11.5px; color:var(--text-3); margin-left:auto; }
.upd b{ color:var(--text-2); font-weight:500; }
/* Two .upd spans share a page head (role view + version); only the first floats. */
.upd + .upd{ margin-left:14px; }
.js-role-view{ font-family:var(--sans); display:inline-flex; align-items:center; gap:6px; }
.js-role-view .inp{ width:auto; }
.js-role-only{ display:inline-flex; align-items:center; gap:5px; margin-left:8px; font-size:12px; color:var(--text-2); cursor:pointer; white-space:nowrap; }

.lvar{ display:flex; gap:6px; }
.lvar button{ font-family:var(--mono); font-size:11.5px; letter-spacing:.02em; color:var(--text-2);
  border:1px solid var(--border); background:var(--panel); border-radius:var(--r-sm); padding:7px 12px; white-space:nowrap; }
.lvar button.on{ background:var(--text); color:var(--bg); border-color:var(--text); }

/* ---- panels ---- */
.panel{ background:var(--panel); border:1px solid var(--border); border-radius:var(--r);
  box-shadow:var(--shadow); padding:18px; }
.panel-h{ display:flex; align-items:center; gap:10px; margin-bottom:14px; }
.panel-h h3{ font-size:14.5px; font-weight:600; margin:0; }
.panel-h .sub{ font-family:var(--mono); font-size:11px; color:var(--text-3); letter-spacing:.02em; }
.panel-h .right{ margin-left:auto; display:flex; gap:8px; align-items:center; }
.dash-balances{ margin-bottom:18px; }
.dash-balance-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:12px; }
.dash-balance-item{ min-width:0; padding:12px 14px; border:1px solid var(--border-soft); border-radius:var(--r-sm); background:var(--panel-2); }
.dash-balance-title{ font-weight:600; overflow-wrap:anywhere; }
.dash-balance-value{ display:block; margin:5px 0; font:600 20px var(--mono); color:var(--text); font-variant-numeric:tabular-nums; }
.dash-balance-meta{ display:block; color:var(--text-3); font-size:11.5px; }
.dash-balance-item small{ display:block; color:var(--text-2); font-size:11px; line-height:1.5; }
.dash-balance-item .chip{ margin-top:6px; }
.dash-balances .g-note{ margin:10px 2px 0; font-size:11px; }
.link{ color:var(--accent); font-size:12.5px; font-weight:500; text-decoration:none; }
.link:hover{ text-decoration:underline; }

/* ---- KPI cards ---- */
.kpis{ display:grid; grid-template-columns:repeat(6,1fr); gap:14px; margin-bottom:18px; }
.kpi{ background:var(--panel); border:1px solid var(--border); border-radius:var(--r); padding:14px 15px;
  position:relative; overflow:hidden; cursor:pointer; transition:transform .16s var(--ease), border-color .16s, box-shadow .16s; }
.kpi:hover{ transform:translateY(-3px); border-color:color-mix(in oklch, var(--accent) 40%, var(--border));
  box-shadow:0 12px 30px -16px var(--accent-glow); }
.kpi .k-label{ font-family:var(--mono); font-size:10.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--text-3); }
.kpi .k-num{ font-size:27px; font-weight:600; letter-spacing:-.02em; margin-top:7px; line-height:1; }
.kpi .k-foot{ display:flex; align-items:center; justify-content:space-between; margin-top:9px; }
.kpi .delta{ font-family:var(--mono); font-size:11.5px; display:inline-flex; align-items:center; gap:3px; }
.kpi .delta.up{ color:var(--crit); } .kpi .delta.down{ color:var(--ok); } .kpi .delta.flat{ color:var(--text-3); }
.kpi .spark{ width:62px; height:24px; opacity:.9; }
.kpi.warn{ border-color:color-mix(in oklch, var(--crit) 40%, var(--border)); }
.kpi .drill{ position:absolute; top:12px; right:13px; color:var(--accent); opacity:0; transform:translateX(-4px);
  transition:.16s var(--ease); }
.kpi:hover .drill{ opacity:1; transform:none; }
.kpi .drill svg{ width:15px; height:15px; }

/* ---- grids ---- */
.grid{ display:grid; gap:18px; }
/* The three dashboard panels are one row and must READ as one row: `align-items:start`
   let each size to its own content, so "Needs attention" — whose empty state is a big
   centred tick — stood taller than the two charts beside it and broke the line. They
   stretch to the tallest instead, and the alert panel centres its content in whatever
   height that turns out to be. */
.dash-mid{ grid-template-columns:1fr 1fr 312px; align-items:stretch; }
.dash-mid > .panel{ display:flex; flex-direction:column; }
.dash-mid > .panel > .chart{ flex:1; display:flex; align-items:center; }
.dash-mid > .panel > .chart > svg{ margin:auto; }
.dash-mid > .panel > #alertsA{ flex:1; display:flex; flex-direction:column; justify-content:center; }
.dash-mid > .panel > #alertsA > .empty{ padding:18px 12px; }
.dash-bot{ grid-template-columns:1fr 1fr; margin-top:18px; }
.g2{ grid-template-columns:1fr 1fr; } .g3{ grid-template-columns:repeat(3,1fr); }

/* ---- charts ---- */
.chart{ width:100%; }
.chart svg{ display:block; width:100%; height:auto; overflow:visible; }
.axis-l{ fill:var(--text-3); font-family:var(--mono); font-size:10px; }
.axis-l.axis-y{ font-size:10px; }
.axis-line{ stroke:var(--border); stroke-width:1; }
.axis-cap{ fill:var(--text-3); font-size:10.5px; font-weight:500; letter-spacing:.01em; }
.grid-l{ stroke:var(--border-soft); stroke-width:1; }
.legend{ display:flex; gap:16px; font-family:var(--mono); font-size:11px; color:var(--text-3); margin-top:4px; }
.legend i{ width:14px; height:3px; border-radius:2px; display:inline-block; vertical-align:middle; margin-right:6px; }

/* ---- alerts ---- */
.alert{ display:flex; gap:11px; padding:12px; border-radius:var(--r-sm); border:1px solid var(--border-soft);
  background:var(--panel-2); position:relative; }
.alert + .alert{ margin-top:10px; }
.alert .bar{ position:absolute; left:0; top:10px; bottom:10px; width:3px; border-radius:3px; }
.alert.crit .bar{ background:var(--crit); } .alert.warn .bar{ background:var(--warn); } .alert.info .bar{ background:var(--info); }
.alert .a-ic{ width:30px; height:30px; border-radius:8px; display:grid; place-items:center; flex:none; margin-left:6px; }
.alert.crit .a-ic{ background:var(--crit-dim); color:var(--crit); }
.alert.warn .a-ic{ background:var(--warn-dim); color:var(--warn); }
.alert.info .a-ic{ background:var(--info-dim); color:var(--info); }
.alert .a-ic svg{ width:16px; height:16px; }
.alert b{ font-size:13px; font-weight:600; display:block; }
.alert .t{ font-size:12px; color:var(--text-2); margin-top:2px; }
.alert .acts{ display:flex; gap:7px; margin-top:9px; }

/* ---- buttons ---- */
.btn{ display:inline-flex; align-items:center; gap:7px; font-size:12.5px; font-weight:500; font-family:var(--sans);
  border:1px solid var(--border); background:var(--panel); color:var(--text); border-radius:var(--r-sm); padding:7px 13px;
  transition:.14s var(--ease); }
.btn:hover{ border-color:var(--text-3); background:var(--panel-2); }
.btn.sm{ padding:5px 10px; font-size:11.5px; }
.btn.primary{ background:var(--accent); color:var(--accent-on); border-color:var(--accent); font-weight:600; }
.btn.primary:hover{ background:var(--accent-2); border-color:var(--accent-2); }
.btn.ghost{ background:transparent; }
.btn svg{ width:14px; height:14px; }

/* Credit Checks: a compact overview above focused, mutually exclusive work areas. */
.credit-provider-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px; margin-top:16px; }
.credit-balance-alert{ display:grid; gap:5px; margin:14px 0; padding:12px 14px; border:1px solid var(--crit); border-radius:var(--r-sm); background:color-mix(in srgb, var(--crit) 12%, var(--panel)); line-height:1.5; }
.dash-users-range,.dash-models-range{ margin-left:auto; max-width:145px; }
.credit-balance-alert strong{ color:var(--crit); }
.credit-balance-alert small{ color:var(--text-2); }
.credit-provider-card{ min-width:0; border:1px solid var(--border); background:var(--panel-2); border-radius:var(--r-sm); padding:15px; }
.credit-provider-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.credit-provider-link{ color:var(--accent); font-weight:700; font-size:16px; text-decoration:none; }
.credit-provider-link:hover{ text-decoration:underline; }
.credit-provider-metrics{ display:grid; grid-template-columns:1fr 1fr; gap:12px; margin:16px 0 12px; }
.credit-provider-metrics>div{ display:flex; flex-direction:column; gap:4px; }
.credit-provider-metrics span,.credit-provider-foot{ color:var(--text-2); font-size:12px; }
.credit-provider-metrics strong,.credit-count{ font:700 21px var(--mono); color:var(--text); }
.credit-count{ width:max-content; padding:0; border:0; background:none; color:var(--accent); text-decoration:underline; text-underline-offset:3px; cursor:pointer; }
.credit-count:hover{ color:var(--accent-2); }
.credit-provider-foot{ border-top:1px solid var(--border-soft); padding-top:10px; line-height:1.7; overflow-wrap:anywhere; }
.credit-provider-foot>div{ margin-top:4px; }
.credit-tabs{ display:flex; gap:6px; margin:14px 0 10px; flex-wrap:wrap; }
.credit-tabs button{ border:1px solid var(--border); background:var(--panel); color:var(--text-2); border-radius:var(--r-sm); padding:9px 15px; cursor:pointer; }
.credit-tabs button.on{ border-color:var(--accent); background:var(--accent-dim); color:var(--text); font-weight:700; }
.credit-pane[hidden]{ display:none; }
.credit-balance-list{ display:grid; gap:10px; }
.credit-balance-item{ display:flex; justify-content:space-between; gap:14px; flex-wrap:wrap; padding:12px; border:1px solid var(--border-soft); border-radius:var(--r-sm); }
.credit-entry{ border-top:1px solid var(--border); margin-top:18px; padding-top:14px; }
.credit-entry summary{ width:max-content; color:var(--accent); font-weight:600; cursor:pointer; margin-bottom:12px; }
.credit-entry:not([open]) summary{ margin-bottom:0; }
@media(max-width:850px){ .credit-provider-grid{ grid-template-columns:1fr; } }

/* ---- tables ---- */
.tbl{ width:100%; border-collapse:collapse; font-size:13px; }
.tbl th{ text-align:left; font-family:var(--mono); font-size:10.5px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--text-3); font-weight:500; padding:0 10px 10px; border-bottom:1px solid var(--border); }
.tbl td{ padding:11px 10px; border-bottom:1px solid var(--border-soft); }
/* Sortable headers (Providers). Plain th is --text-3; a sortable one is brighter
   and bolder, and carries a permanent dim ⇅ so it reads as clickable before you
   hover. The active column goes accent-coloured with a solid arrow and an accent
   underline, so which column is driving the order is unmistakable. */
.tbl th.sortable{ color:var(--text-2); font-weight:700; cursor:pointer; user-select:none;
  white-space:nowrap; transition:color .12s, border-color .12s; }
.tbl th.sortable .sarr{ display:inline-block; margin-left:6px; font-weight:400; opacity:.4; }
.tbl th.sortable:hover{ color:var(--accent); }
.tbl th.sortable:hover .sarr{ opacity:.9; }
.tbl th.sortable:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:3px; }
.tbl th.sortable.on{ color:var(--accent); border-bottom:2px solid var(--accent); }
.tbl th.sortable.on .sarr{ opacity:1; }
.tbl tr:last-child td{ border-bottom:0; }
.vt-table{ min-width:1050px; table-layout:fixed; }
.vt-table th:nth-child(1){ width:150px; }
.vt-table th:nth-child(2){ width:175px; }
.vt-table th:nth-child(3){ width:220px; }
.vt-table th:nth-child(4){ width:300px; }
.vt-table th:nth-child(5){ width:92px; }
.vt-table th:nth-child(6){ width:110px; }
.vt-table th:nth-child(7){ width:105px; }
.vt-table td{ vertical-align:top; overflow-wrap:anywhere; }
.vt-table td small{ display:block; margin-top:5px; color:var(--text-3); font-size:11px; line-height:1.4; }
.vt-table td .btn{ margin-top:6px; }
.vm-table{ min-width:1250px; table-layout:fixed; }
.vm-table th{ white-space:nowrap; }
.vm-table th:nth-child(1){ width:8%; }
.vm-table th:nth-child(2){ width:17%; }
.vm-table th:nth-child(3){ width:10%; }
.vm-table th:nth-child(4){ width:15%; }
.vm-table th:nth-child(5){ width:13%; }
.vm-table th:nth-child(6){ width:12%; }
.vm-table th:nth-child(7){ width:18%; }
.vm-table th:nth-child(8){ width:7%; }
.vm-table td{ vertical-align:top; overflow-wrap:anywhere; }
.vm-table td .chip{ margin:0 4px 5px 0; text-decoration:none; }
.vm-table th:last-child,.vm-table td:last-child{position:sticky;right:0;z-index:1;min-width:105px;background:var(--panel);box-shadow:-1px 0 0 var(--border)}
.vm-table th:last-child{z-index:2}
.vm-table [data-vm-save]{white-space:nowrap}
.vm-options{display:flex;flex-wrap:wrap;gap:4px 10px;margin-top:7px}
.vm-options label{white-space:nowrap;font-size:12px}
.vm-duration{width:74px;display:inline-block;margin:4px 0}
.tbl tbody tr{ transition:background .12s; }
.tbl tbody tr.click:hover{ background:var(--panel-2); cursor:pointer; }
/* Client API keys: draggable column edges, scoped so other tables keep their layout. */
.key-table-tools{ display:flex; align-items:center; justify-content:flex-end; gap:12px; margin-top:12px; font-size:11.5px; }
.keys-resizable{ table-layout:fixed; }
.keys-resizable th{ position:relative; padding-right:17px; }
.keys-resizable td{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.keys-resizable td:last-child{ overflow:visible; }
.key-col-handle{ position:absolute; top:0; right:-5px; bottom:0; width:11px; z-index:2; cursor:col-resize; touch-action:none; }
.key-col-handle::after{ content:''; position:absolute; top:2px; bottom:8px; left:5px; width:2px; border-radius:2px; background:var(--border); }
.key-col-handle:hover::after,.key-col-handle:focus-visible::after,.key-col-dragging .key-col-handle::after{ background:var(--accent); }
.key-col-handle:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }
.key-col-dragging,.key-col-dragging *{ user-select:none!important; }
/* Supported Versions: fixed column layout so all four platform tables align */
.vtbl{ table-layout:fixed; }
.vtbl .vc-ver{ width:150px; } .vtbl .vc-stat{ width:130px; } .vtbl .vc-date{ width:120px; }
.vtbl td{ word-break:break-word; }
.tbl .u{ display:flex; align-items:center; gap:9px; }
.tbl .u .ua{ width:24px; height:24px; border-radius:50%; background:var(--panel-2); border:1px solid var(--border);
  display:grid; place-items:center; font-size:10px; color:var(--text-2); font-family:var(--mono); }

.minibar{ height:7px; border-radius:4px; background:var(--panel-2); overflow:hidden; min-width:80px; }
.minibar i{ display:block; height:100%; background:var(--accent); border-radius:4px; }
.minibar i.warn{ background:var(--warn); } .minibar i.over{ background:var(--crit); }

/* chips */
.chip{ display:inline-flex; align-items:center; gap:6px; font-size:11.5px; font-family:var(--mono);
  padding:3px 9px; border-radius:20px; border:1px solid var(--border); color:var(--text-2); }
.chip .d{ width:6px; height:6px; border-radius:50%; }
.chip.ok{ color:var(--ok); border-color:color-mix(in oklch,var(--ok) 45%,var(--border)); background:var(--ok-dim); }
.chip.ok .d{ background:var(--ok); }
.chip.warn{ color:var(--warn); border-color:color-mix(in oklch,var(--warn) 45%,var(--border)); background:var(--warn-dim); }
.chip.warn .d{ background:var(--warn); }
.chip.crit{ color:var(--crit); border-color:color-mix(in oklch,var(--crit) 50%,var(--border)); background:var(--crit-dim); }
.chip.crit .d{ background:var(--crit); }
/* Providers: a key whose recent calls are failing in a row. Yellow at 3+, red at 6+
   (vendor/key failures only — a client's bad request never colours a key). */
tr.pk-warn>td{ background:color-mix(in srgb, var(--warn) 14%, transparent); }
tr.pk-crit>td{ background:color-mix(in srgb, var(--crit) 16%, transparent); }
.pk-note{ font-size:11px; margin-top:4px; white-space:normal; font-family:var(--sans); }
.pk-note.pk-warn-t{ color:var(--warn); }
.pk-note.pk-crit-t{ color:var(--crit); font-weight:600; }
.pk-twin{ margin-left:6px; font-size:10.5px; }
/* Backup key line under the master. In failover the line carries the warn tint
   so the eye lands on the key that is actually being sent. */
.pk-backup{ margin-top:6px; padding-top:6px; border-top:1px dashed var(--border-soft); font-size:11.5px; white-space:normal; display:flex; flex-wrap:wrap; align-items:center; gap:5px; }
.pk-bk-lbl{ font-family:var(--sans); font-size:11px; color:var(--text-3); margin-right:2px; }
.pk-backup.pk-failover{ background:color-mix(in srgb, var(--warn) 12%, transparent); border-radius:6px; padding:6px 8px; border-top:0; }
.pk-backup.pk-failover .pk-bk-lbl{ color:var(--warn); font-weight:700; }
.pk-backup.pk-bk-warn{ background:color-mix(in srgb, var(--warn) 14%, transparent); border-radius:6px; padding:6px 8px; border-top:0; }
.pk-backup.pk-bk-crit{ background:color-mix(in srgb, var(--crit) 16%, transparent); border-radius:6px; padding:6px 8px; border-top:0; }
.pk-failover-note{ flex:1 1 100%; font-family:var(--sans); font-size:11px; color:var(--warn); line-height:1.5; }
.chip.info{ color:var(--info); border-color:color-mix(in oklch,var(--info) 45%,var(--border)); background:var(--info-dim); }
.chip.info .d{ background:var(--info); }

/* misc */
.muted{ color:var(--text-2); } .faint{ color:var(--text-3); }
.empty{ padding:60px 20px; text-align:center; color:var(--text-3); }
.empty .e-ic{ width:44px; height:44px; margin:0 auto 14px; border-radius:12px; background:var(--panel-2);
  border:1px solid var(--border); display:grid; place-items:center; color:var(--accent); }
.empty .e-ic svg{ width:22px; height:22px; }

.lvar.hidden, .variant{ display:none; }
.variant.on{ display:block; }

/* load-in motion */
@keyframes rise{ from{ opacity:0; transform:translateY(10px); } to{ opacity:1; transform:none; } }
.rise{ animation:rise .5s var(--ease) both; }

@media (max-width:1180px){ .kpis{ grid-template-columns:repeat(3,1fr); } .dash-mid{ grid-template-columns:1fr 1fr; } }

/* ---- console screen forms (Logs/Users/Policies/Notifications) ---- */
.inp{ font:500 12.5px var(--sans); color:var(--text); background:var(--panel-2); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:7px 10px; min-width:0; transition:border-color .14s; }
.inp:focus{ outline:none; border-color:var(--accent); }
.inp::placeholder{ color:var(--text-3); }
select.inp{ appearance:auto; cursor:pointer; }
.inp.sm{ padding:4px 8px; font-size:12px; }
.inp.num{ width:110px; font-family:var(--mono); }
.toolbar{ display:flex; gap:9px; align-items:center; flex-wrap:wrap; }
.tbl .inp{ width:100%; }
.tbl select.inp{ width:auto; }
.scr-err{ color:var(--crit); font-size:12.5px; padding:14px 8px; }

/* ---- Integration Guide screens ---- */
.guide .panel + .panel{ margin-top:16px; }
.guide .g-lead{ font-size:13px; color:var(--text-2); margin:0 2px 14px; line-height:1.6; }
.guide .g-note{ font-size:12px; color:var(--text-2); margin:12px 2px 2px; line-height:1.6; }
.guide code.mono, .guide .mono{ font-family:var(--mono); }
.guide .g-note code, .guide .g-lead code, .tbl code{ font-family:var(--mono); font-size:11.5px;
  background:var(--panel-2); border:1px solid var(--border-soft); border-radius:5px; padding:1px 5px; color:var(--text); }
.tbl.kv td:first-child{ color:var(--text-2); width:200px; }

.guide-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:12px; }
@media (max-width:1100px){ .guide-grid{ grid-template-columns:repeat(2,1fr); } }
.dev-card{ display:flex; flex-direction:column; gap:3px; align-items:flex-start; cursor:pointer;
  padding:16px; border:1px solid var(--border); border-radius:var(--r); background:var(--panel-2);
  transition:.14s var(--ease); }
.dev-card:hover{ border-color:var(--accent); transform:translateY(-2px); }
.dev-card b{ font-size:14px; }
.dev-card small{ font-size:11px; color:var(--text-3); font-family:var(--mono); }
.dev-card .dc-ic{ width:34px; height:34px; border-radius:9px; background:var(--accent-dim); color:var(--accent);
  display:grid; place-items:center; margin-bottom:8px; }
.dev-card .dc-ic svg{ width:19px; height:19px; }

/* Releases: release-note list + client-version status pills */
.rel-list{ margin:4px 0 2px; padding-left:20px; }
.rel-list li{ font-size:13px; line-height:1.6; color:var(--text-2); margin:3px 0; }
.vstat{ display:inline-block; font-size:11px; font-weight:600; padding:2px 9px; border-radius:999px;
  border:1px solid var(--border); color:var(--text-2); text-transform:capitalize; }
.vstat.ok{ color:var(--ok); border-color:transparent; background:var(--ok-dim); }
.vstat.warn{ color:var(--warn); border-color:transparent; background:var(--warn-dim); }
.vstat.err{ color:var(--crit); border-color:transparent; background:var(--crit-dim); }

.code-wrap{ position:relative; }
pre.code{ background:var(--bg-2); border:1px solid var(--border); border-radius:var(--r-sm);
  padding:14px 16px; margin:0; overflow-x:auto; }
pre.code code{ font-family:var(--mono); font-size:12px; line-height:1.65; color:var(--text);
  white-space:pre; display:block; }
.code-actions{ position:absolute; top:8px; right:8px; display:flex; gap:6px; }
.copy-btn{ font:500 11px var(--sans); color:var(--text-2);
  background:var(--panel); border:1px solid var(--border); border-radius:6px; padding:4px 9px;
  cursor:pointer; opacity:0; transition:.14s var(--ease); }
.code-wrap:hover .copy-btn{ opacity:1; }
.copy-btn:hover{ border-color:var(--text-3); color:var(--text); }
.copy-btn.done{ color:var(--accent); border-color:var(--accent); opacity:1; }

/* ---- Integration Guide: AI-prompt vs manual-reference split ---- */
.prompt-panel{ border-color:color-mix(in oklch,var(--accent) 42%,var(--border)); background:var(--accent-dim); }
.prompt-panel .panel-h h3::before{ content:"✦ "; color:var(--accent); }
.prompt-panel pre.code{ background:var(--bg-2); border-color:color-mix(in oklch,var(--accent) 25%,var(--border)); }
pre.code.prompt{ max-height:480px; overflow:auto; }
pre.code.prompt code{ font-size:11.5px; line-height:1.6; }
.copy-btn.always{ opacity:1; background:var(--accent); color:var(--accent-on); border-color:var(--accent); font-weight:600; }
.copy-btn.always:hover{ background:var(--accent-2); border-color:var(--accent-2); color:var(--accent-on); }
.ref-head{ display:flex; align-items:baseline; gap:11px; flex-wrap:wrap; margin:26px 2px 14px; padding-top:16px; border-top:1px dashed var(--border); }
.ref-head h3{ font-size:13.5px; color:var(--text-2); margin:0; font-weight:600; }
.ref-head span{ font-size:12px; color:var(--text-3); }

/* ---- API Keys: created-key reveal box ---- */
.key-reveal{ margin-top:14px; border:1px solid color-mix(in oklch,var(--accent) 45%,var(--border));
  background:var(--accent-dim); border-radius:var(--r-sm); padding:14px 16px; }
.key-reveal .kr-head{ font-size:13px; font-weight:600; color:var(--text); }
.key-reveal .kr-warn{ font-size:12px; color:var(--warn); margin:6px 0 10px; }
.key-reveal .kr-key{ display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
.key-reveal .kr-key code{ flex:1; min-width:240px; font-family:var(--mono); font-size:13px; background:var(--bg-2);
  border:1px solid var(--border); border-radius:6px; padding:8px 12px; word-break:break-all; color:var(--text); }

/* ---- key reveal: informational note (keys are viewable anytime) ---- */
.key-reveal .kr-note{ font-size:12px; color:var(--text-2); margin:6px 0 10px; }
.keytxt{ cursor:default; word-break:break-all; }

/* ---- keys: show-revoked toggle ---- */
.kshow{ display:inline-flex; align-items:center; gap:6px; font-size:12px; color:var(--text-2); cursor:pointer; user-select:none; }
.kshow input{ accent-color:var(--accent); cursor:pointer; }

/* ---- Provider Test · Chat (Providers → Test) ---- */
.pt-form{ display:flex; flex-direction:column; gap:10px; margin:4px 2px 6px; }
.pt-row{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.pt-lbl{ font-size:12px; color:var(--text-2); min-width:110px; }
.pt-hint{ font-size:11.5px; margin:-4px 0 2px 120px; }
.pt-actions{ margin-top:4px; }
.pt-out{ margin-top:14px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--bg-2); padding:12px 14px; }
.pt-out-h{ display:flex; align-items:center; gap:10px; margin-bottom:8px; flex-wrap:wrap; }
.pt-resp{ margin:0; white-space:pre-wrap; word-break:break-word; font:500 12.5px var(--mono); color:var(--text);
  background:var(--panel); border:1px solid var(--border); border-radius:var(--r-sm); padding:12px; max-height:360px; overflow:auto; }
.pt-note{ margin:0 2px 12px; padding:10px 12px; border:1px solid var(--border); border-radius:var(--r-sm);
  background:var(--bg-2); color:var(--text-2); font-size:12px; }
.pt-form:has(#ptKey:disabled){ opacity:.6; }

/* ---- Provider Test · Image (tabs + gallery) ---- */
.it-tabs{ display:flex; gap:6px; margin:2px 2px 4px; border-bottom:1px solid var(--border); }
.it-tab{ border:1px solid transparent; border-bottom:none; background:transparent; color:var(--text-2);
  font:500 12.5px var(--sans); padding:7px 14px; border-radius:var(--r-sm) var(--r-sm) 0 0; cursor:pointer; position:relative; top:1px; }
.it-tab:hover{ color:var(--text); }
.it-tab.on{ color:var(--text); background:var(--panel); border-color:var(--border); }
.it-src{ max-width:160px; max-height:160px; border:1px solid var(--border); border-radius:var(--r-sm); margin:6px 0 2px; display:block; }
.it-gallery{ display:flex; flex-wrap:wrap; gap:10px; }
/* multi 多图生图 source thumbnails with per-image remove button */
.it-srcs{ display:flex; flex-wrap:wrap; gap:10px; margin-top:6px; }
.it-src-wrap{ position:relative; display:inline-block; }
.it-src-wrap .it-src{ max-width:108px; max-height:108px; margin:0; }
.it-src-rm{ position:absolute; top:-7px; right:-7px; width:20px; height:20px; padding:0; border-radius:50%;
  border:1px solid var(--border); background:var(--bg); color:var(--crit, #f0626b); font-size:11px; line-height:1;
  cursor:pointer; display:flex; align-items:center; justify-content:center; }
.it-out-img{ max-width:320px; max-height:320px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--panel); }

/* ===================== Analyst / Gallery / DB-size ===================== */
/* Analyst selection chips */
.asel{ display:flex; flex-direction:column; gap:10px; }
.asel-row{ display:flex; align-items:flex-start; gap:12px; flex-wrap:wrap; }
.asel-lbl{ min-width:72px; font-size:12.5px; color:var(--text-2); padding-top:6px; }
.msel-wrap{ display:flex; flex-wrap:wrap; gap:6px; flex:1; }
.msel{ border:1px solid var(--border); background:var(--panel-2); color:var(--text-2);
  font-size:12px; padding:5px 10px; border-radius:999px; cursor:pointer; transition:.15s var(--ease); }
.msel:hover{ border-color:var(--accent-dim); color:var(--text); }
.msel.on{ background:var(--accent); border-color:var(--accent); color:var(--accent-on); font-weight:600; }
/* Status chips (Analyst Selection): tint unselected chips by HTTP class so the
   2xx / 4xx / 5xx grouping reads at a glance; the selected state stays accent. */
.msel.st-ok:not(.on){ color:var(--ok); border-color:color-mix(in oklch,var(--ok) 40%,var(--border)); }
.msel.st-warn:not(.on){ color:var(--warn); border-color:color-mix(in oklch,var(--warn) 40%,var(--border)); }
.msel.st-crit:not(.on){ color:var(--crit); border-color:color-mix(in oklch,var(--crit) 45%,var(--border)); }

/* Multi-series chart legend */
.chart-legend{ display:flex; flex-wrap:wrap; gap:14px; margin-top:10px; }
.chart-legend .lg{ display:inline-flex; align-items:center; gap:6px; font-size:11.5px; color:var(--text-2); }
.chart-legend .lg i{ width:11px; height:11px; border-radius:3px; display:inline-block; }

/* Size badge on a gallery tile (相片庫 → Image size / Entry size).
   Bottom-left so it never covers the ★ favourite marker (top-right) or the
   selection check. Two chips, colour-separated, because "the picture" and "the
   whole record" are different numbers and must not be mistaken for each other. */
.gal-cell.selectable{ user-select:none; -webkit-user-select:none; }
.gal-size{ position:absolute; left:6px; bottom:6px; display:flex; gap:4px; flex-wrap:wrap;
  max-width:calc(100% - 12px); pointer-events:auto; }
.gal-size span{ font-family:var(--mono); font-size:10px; line-height:1.6; padding:1px 5px;
  border-radius:3px; white-space:nowrap; backdrop-filter:blur(3px);
  background:rgba(12,14,12,.72); color:#fff; }
.gal-size .gs-ent{ background:rgba(245,166,35,.86); color:#1a1c1a; font-weight:600; }

/* Horizontal bar breakdown (Settings → Database size).
   Four aligned columns — name · count · bar · value. Grid rather than flex so the
   columns line up across every row; with flex the bars start at a different x on
   each row as soon as one name is longer, which makes the lengths impossible to
   compare by eye. The name column is sized in `ch` so it fits the longest model id
   this page shows (grok-imagine-image-quality) without clipping. */
.hbar-list{ display:flex; flex-direction:column; gap:7px; }
.hbar-row{ display:grid; grid-template-columns:minmax(0,30ch) minmax(72px,auto) 1fr minmax(104px,auto);
  gap:14px; align-items:center; padding:3px 6px; border-radius:6px;
  border:1px solid transparent; }
.hbar-lbl{ font-size:12.5px; color:var(--text-2); min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hbar-name{ font-family:var(--mono); color:var(--text); }
.hbar-lbl .faint{ font-size:11px; }
.hbar-meta{ font-size:11.5px; color:var(--text-3); text-align:right; white-space:nowrap;
  font-variant-numeric:tabular-nums; }
.hbar-track{ background:var(--bg-2, rgba(127,127,127,.13)); border-radius:4px; height:15px; overflow:hidden; }
.hbar-fill{ height:100%; border-radius:4px; min-width:2px; transition:width .3s ease; }
.hbar-val{ font-family:var(--mono); font-size:12px; text-align:right; white-space:nowrap;
  font-variant-numeric:tabular-nums; color:var(--text); }

/* Clickable rows (依模型 → Logs). Affordance on hover AND on keyboard focus, so
   it is discoverable without a mouse. */
.hbar-act{ cursor:pointer; }
.hbar-act:hover{ background:var(--panel-2, rgba(127,127,127,.09)); border-color:var(--border); }
.hbar-act:hover .hbar-name{ text-decoration:underline; text-underline-offset:2px; }
.hbar-act:focus-visible{ outline:2px solid var(--accent); outline-offset:1px; }

@media (max-width:760px){
  /* Name and count on one line, bar and value beneath — nothing is truncated,
     the row just becomes two lines. */
  .hbar-row{ grid-template-columns:1fr auto; gap:4px 10px; padding:6px; }
  .hbar-lbl{ white-space:normal; }
  .hbar-track{ grid-column:1; }
  .hbar-val{ grid-column:2; }
}
}

/* Usage heatmap (weekday x hour) */
.heatmap{ display:flex; flex-direction:column; gap:3px; overflow-x:auto; padding-top:4px; }
.hm-row{ display:grid; grid-template-columns:40px repeat(24,1fr); gap:3px; align-items:center; min-width:560px; }
.hm-day{ font-size:11px; color:var(--text-3); text-align:right; padding-right:6px; }
.hm-cell{ aspect-ratio:1/1; border-radius:3px; border:1px solid var(--border-soft); }
.hm-head .hm-cell{ border:0; }
.hm-hh{ font-size:9.5px; color:var(--text-3); text-align:center; aspect-ratio:auto; border:0; }
.hm-cell[data-v]:hover{ outline:1.5px solid var(--text-3); outline-offset:-1px; cursor:default; }
/* Current weekday × hour ("now") marker */
.hm-cell.hm-now{ outline:2px solid var(--accent); outline-offset:-1px; box-shadow:0 0 0 2px color-mix(in oklch, var(--accent) 35%, transparent); border-color:var(--accent); }
.hm-day-now{ color:var(--accent); font-weight:700; }
.hm-hh-now{ color:var(--accent); font-weight:700; }
/* Sub-header for the hour-of-day line chart below the heatmap */
.hm-sub{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:18px; padding-top:14px; border-top:1px solid var(--border-soft); }
.hm-sub h4{ margin:0; font-size:13.5px; font-weight:600; color:var(--text); }
.hm-sub .right{ margin-left:auto; }
.hm-tip{ position:absolute; z-index:30; pointer-events:none; background:var(--panel-2); border:1px solid var(--border);
  border-radius:var(--r-sm); box-shadow:var(--shadow); padding:5px 9px; font-size:11.5px; line-height:1.4; white-space:nowrap; }
.hm-tip b{ display:block; font-weight:600; color:var(--text); }
.hm-tip span{ color:var(--text-3); }

/* Photo gallery grid */
.gal-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:12px; margin-top:4px; }
.gal-cell{ margin:0; cursor:pointer; }
.gal-thumb{ position:relative; aspect-ratio:1/1; border:1px solid var(--border); border-radius:var(--r-sm);
  overflow:hidden; background:var(--panel-2); display:flex; align-items:center; justify-content:center; transition:.15s var(--ease); }
.gal-cell:hover .gal-thumb{ border-color:var(--accent-dim); transform:translateY(-2px); box-shadow:var(--shadow); }
.gal-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
.gal-noimg{ font-size:11px; color:var(--text-3); text-align:center; padding:10px; }
.gal-fav{ position:absolute; top:5px; right:6px; color:#ffcf5c; font-size:15px; text-shadow:0 1px 3px rgba(0,0,0,.6); }
.gal-cell figcaption{ font-size:11px; color:var(--text-2); margin-top:5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Multi-select (delete) toolbar + per-cell checkbox */
.gal-bulk{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:10px 0 2px; padding:8px 10px;
  border:1px solid var(--border); border-radius:var(--r-sm); background:var(--panel-2); }
.gal-bulk .sub{ margin-right:auto; }
.gal-cell.sel .gal-thumb{ border-color:var(--accent); box-shadow:0 0 0 2px var(--accent) inset; }
.gal-check{ position:absolute; top:5px; left:6px; width:20px; height:20px; border-radius:5px;
  border:1.5px solid #fff; background:rgba(0,0,0,.45); color:#fff; font-size:13px; font-weight:700;
  display:flex; align-items:center; justify-content:center; box-shadow:0 1px 3px rgba(0,0,0,.5); }
.gal-check.on{ background:var(--accent); border-color:var(--accent); color:var(--accent-on); }

/* Gallery detail modal */
.gal-modal{ max-width:880px; width:92vw; }
.gal-detail{ display:grid; grid-template-columns:1fr 1fr; gap:18px; }
.gal-full{ display:flex; align-items:flex-start; justify-content:center; }
.gal-full img{ max-width:100%; max-height:60vh; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--panel-2); }
.gal-meta{ display:flex; flex-direction:column; gap:12px; min-width:0; }
.gal-meta .tbl.kv th{ text-align:left; color:var(--text-3); font-weight:500; font-size:11.5px; padding:3px 10px 3px 0; white-space:nowrap; width:90px; }
.gal-meta .tbl.kv td{ font-size:11.5px; word-break:break-all; }
.gal-prompt .logtxt-body{ max-height:180px; overflow:auto; }
@media(max-width:720px){ .gal-detail{ grid-template-columns:1fr; } }

/* DB size big number */
.big-num{ font-size:13px; margin:6px 0 14px; }
.big-num .num{ font-size:30px; font-weight:700; color:var(--text); letter-spacing:-.5px; }

/* Admin image-cost report: three compact facts above one five-column table. */
.cost-kpis{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:12px; margin-bottom:14px; }
.cost-kpi{ margin:0; display:flex; flex-direction:column; gap:5px; }
.cost-kpi>span{ color:var(--text-3); font-size:11px; font-family:var(--mono); text-transform:uppercase; letter-spacing:.07em; }
.cost-kpi>b{ font-size:25px; line-height:1.1; }
.cost-kpi>small{ color:var(--text-3); font-size:10.5px; }
.image-cost-tbl th.num,.image-cost-tbl td.num{ text-align:right; white-space:nowrap; }
.cost-drill{ font-family:var(--mono); font-size:inherit; }
.cost-photo-sub{ color:var(--text-3); font-size:9.5px; line-height:1.25; margin-top:2px; white-space:nowrap; }
.cost-model-meta{ display:flex; align-items:center; gap:7px; flex-wrap:wrap; color:var(--text-3); font-size:10.5px; margin-top:5px; }
.cost-model-meta .chip{ font-size:10px; padding:2px 7px; }
.cost-zero{ color:var(--warn); }
.cost-method{ font-size:11.5px; line-height:1.6; margin:12px 10px 0; }
@media (max-width:760px){ .cost-kpis{ grid-template-columns:1fr; } }

/* ===========================================================================
 * 2026-08-27 (GA00.0.19.52) — recovered file.
 *
 * An entire HTML page had been committed into this stylesheet: a doctype on
 * line 1, the real rules wrapped in a style element, and from line 614 onward
 * page markup. A CSS parser cannot resync past that markup, so it stopped at
 * the .wrap rule and DISCARDED everything after it. Two consequences, both
 * silent: .log-code (the gateway error code under a Logs status chip) never
 * applied since the day it was added, and neither did anything added later.
 * Verified in the browser — the parsed sheet held 345 rules and ended at .wrap.
 *
 * The markup is gone. Everything below was stranded behind it and now applies.
 * =========================================================================== */

/* Gateway error code under a Logs status chip — an HTTP number alone cannot say
   whether a 503 was a 30s timeout or a missing provider key. */
.log-code{ margin-top:3px; font-family:var(--mono); font-size:10px; letter-spacing:.02em;
  color:var(--text-3); cursor:help; white-space:nowrap; }

/* Cost provenance marker in the Logs Cost column (GA00.0.19.52). A number alone
   cannot say whether it is our estimate or the provider's invoice, and those are
   worth different things — so the basis rides next to the money, never instead
   of it. est. = computed from published rates (a floor); ≈ = allocated from the
   provider's billed total; ✓ = matched to the provider's own request record. */
.cost-basis{ margin-left:5px; font-family:var(--mono); font-size:10px; letter-spacing:.02em;
  padding:1px 3px; border-radius:3px; cursor:help; vertical-align:1px; white-space:nowrap; }
.cost-basis.cb-est{ color:var(--text-3); border:1px solid var(--line); }
.cost-basis.cb-alloc{ color:var(--warn, #b3591c); border:1px solid currentColor; }
.cost-basis.cb-confirmed{ color:var(--ok, #2f6b4f); border:1px solid currentColor; }

/* ---- Preferences: who each setting is for ----
   The page carries both personal display settings and operator state, and the two
   are not the same kind of thing. Saying so in a heading beats hiding the admin half
   and leaving a regular user to wonder whether the page is incomplete.

   The admin half is gated by the `role-nonadmin` body class rather than by setting
   el.hidden from JS: it is one declarative rule that cannot lose a race with the nav
   sync, which is exactly the drift the rail already had to be rescued from. */
.pref-sec{ margin:22px 0 10px; }
.pref-sec:first-child{ margin-top:4px; }
.pref-sec-h{ margin:0; font-size:13px; font-weight:600; letter-spacing:.05em;
  text-transform:uppercase; color:var(--text-3); }
.pref-sec-sub{ margin:6px 0 0; font-size:12.5px; color:var(--text-2); line-height:1.6; max-width:70ch; }
body.role-nonadmin .js-admin-only{ display:none !important; }

/* ---- Settings → Preferences: display currency ----
   Picker and rate table sit side by side because they answer each other: the
   selector says WHICH currency, the table says at WHAT rate and from WHEN, and
   a converted figure nobody can trace back to a rate is just a number. Below
   860px the table drops under the picker rather than shrinking into columns of
   three characters. */
.cur-wrap{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:20px; align-items:start; }
@media (max-width:860px){ .cur-wrap{ grid-template-columns:1fr; } }
.cur-tbl{ border:1px solid var(--border); border-radius:10px; padding:12px 14px 6px; background:var(--bg-2, transparent); }
.cur-tbl-h{ display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; font-size:12.5px; margin-bottom:6px; }
.cur-tbl-h .faint{ font-size:11px; }
.cur-tbl .tbl th, .cur-tbl .tbl td{ font-size:11.5px; padding:5px 8px; }
/* The month in force. Bolder, not merely tinted: this is the one row that is
   actually doing arithmetic on screen, and it must survive a greyscale print. */
.cur-tbl tr.cur-on td{ font-weight:650; color:var(--text-1); background:var(--accent-dim, rgba(127,127,127,.08)); }
.cur-stale{ color:var(--warn, #b3591c); font-weight:600; }
.scroll-y-sm{ max-height:260px; overflow-y:auto; }

/* Legend for the Cost column's provenance markers, sat directly above the table
   so the key is where the codes are, not hidden behind a popover. */
.cost-legend{ display:grid; grid-template-columns:auto 1fr; gap:5px 8px; align-items:baseline;
  margin:0 0 10px; padding:10px 12px; border:1px solid var(--line); border-radius:8px;
  font-size:11.5px; line-height:1.5; color:var(--text-3); background:var(--bg-2, transparent); }
.cost-legend .cost-basis{ margin-left:0; justify-self:start; }
.cost-basis.cb-none{ color:var(--text-3); border:1px solid var(--line); }
@media (max-width:640px){ .cost-legend{ grid-template-columns:1fr; } }

/* Analyst → Spend by provider. A matrix: providers down, months across, totals on
   both edges, with the cost-basis marker riding beside each figure. */
.scroll-x{ overflow-x:auto; }
.cost-grid{ width:100%; }
.cost-grid th.num, .cost-grid td.num{ text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
.cost-grid td.tot, .cost-grid tfoot td{ font-weight:600; }
.cost-grid tfoot td{ border-top:1px solid var(--line); }
.cost-grid tfoot tr.sub-row td{ font-weight:400; color:var(--text-3); border-top:0; font-size:12px; }
.cost-grid td.mono{ font-family:var(--mono); font-size:12.5px; }
.cost-candle-scroll{ overflow-x:auto; overflow-y:hidden; max-width:100%; }
.cost-candle-currency{ display:inline-flex; align-items:center; gap:6px; color:var(--text-2); font-size:12px; white-space:nowrap; }
.cost-candle-currency select{ min-width:108px; }
.cost-candle-svg{ display:block; max-width:none; font-family:var(--mono); }
.candle-grid{ stroke:var(--border-soft); stroke-width:1; }
.candle-axis-line{ stroke:var(--text-3); stroke-width:1; }
.candle-tick,.candle-axis,.candle-model{ fill:var(--text-2); font-size:11px; }
.candle-axis{ font-size:12px; }
.candle-model{ font-size:10.5px; }
.candle-wick,.candle-cap{ stroke:var(--accent-2); stroke-width:2; }
.candle-body{ fill:var(--accent-dim); stroke:var(--accent); stroke-width:2; }
.candle-median{ stroke:var(--text); stroke-width:2.5; }
.cost-candle-note{ font-size:11.5px; margin:8px 0 0; }

/* ---------- Logs pager (GA00.0.19.70) ----------
   Centred like the Gallery's, with the row span pushed to the right. The span
   ("1–50 of 1,284") is the half that makes a page number mean something: on its
   own, "Page 3 / 26" says where you are but not how much is behind it. */
/* The one pager (renderPager in console.js). Navigation left/centre, the span
   and rows-per-page bottom-RIGHT — operator direction, 2026-09-18. */
.pager{ display:flex; align-items:center; justify-content:space-between; gap:12px 18px; margin-top:14px; flex-wrap:wrap; }
.pager .pg-nav{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.pager .pg-strip{ display:inline-flex; align-items:center; gap:2px; }
.pager .pg-n{ min-width:30px; height:28px; padding:0 6px; border:1px solid transparent; border-radius:6px; background:transparent; color:var(--text); font:inherit; font-size:12.5px; cursor:pointer; }
.pager .pg-n:hover{ border-color:var(--border); }
.pager .pg-n.on{ background:var(--accent); color:var(--accent-on); border-color:transparent; font-weight:600; cursor:default; }
.pager .pg-gap{ padding:0 4px; font-size:12px; opacity:.6; }
.pager .pg-goto{ display:inline-flex; align-items:center; gap:6px; margin-left:10px; font-size:12px; }
.pager .pg-goto input{ width:64px; text-align:center; }
.pager .pg-side{ display:flex; align-items:center; gap:10px; margin-left:auto; }
.pager .pg-of{ font-size:11.5px; }
.pager .pg-at{ font-size:12px; }
@media (max-width:720px){ .pager{ justify-content:center; } .pager .pg-side{ margin-left:0; width:100%; justify-content:flex-end; } }

/* ---------- Analyst: horizontal bar charts (GA00.0.19.70) ----------
   Two columns on a wide screen, stacked below 900px. The grid rather than flex
   so the two charts keep equal width regardless of how long the model ids run. */
.bars2{ display:grid; grid-template-columns:1fr 1fr; gap:22px; }
@media (max-width:900px){ .bars2{ grid-template-columns:1fr; } }
.bars-h{ margin:0 0 10px; font-size:12.5px; font-weight:600; color:var(--text-2); }
.hbars{ display:flex; flex-direction:column; gap:7px; }
/* Label / bar / value. The label column is fixed so every bar starts on the same
   line — a ragged left edge makes lengths impossible to compare by eye, which is
   the only thing this chart is for. */
.hbar{ display:grid; grid-template-columns:minmax(90px,30%) 1fr auto; align-items:center; gap:10px;
  padding:2px 4px; border-radius:var(--r-sm,6px); }
.hbar.click{ cursor:pointer; }
.hbar.click:hover{ background:var(--panel-2); }
.hb-lbl{ font-size:11.5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hb-track{ position:relative; height:15px; border-radius:4px; background:var(--panel-2); overflow:hidden; }
.hb-track > i{ display:block; height:100%; border-radius:4px; background:var(--accent); }
.hb-val{ font-size:11.5px; white-space:nowrap; min-width:74px; text-align:right; }
.hb-pct{ margin-left:6px; font-size:10.5px; }
.hb-unit{ margin-left:7px; font-size:10.5px; white-space:nowrap; }
.bars-hint{ font-size:10.5px; font-weight:400; margin-left:5px; }
.hb-more{ font-size:11px; margin-top:6px; padding-left:4px; }

/* Analyst #2: positive-cost model drill-downs. Keep the three distributions
   visually aligned and horizontally scrollable on a narrow viewport. */
.a2-controls{ display:flex; flex-wrap:wrap; align-items:center; gap:9px 12px; }
.a2-controls label{ display:flex; align-items:center; gap:6px; font-size:11.5px; color:var(--text-2); }
.a2-controls select{ max-width:225px; }
.a2-note{ font-size:11px; margin:12px 0; }
.a2-chip{ border:1px solid var(--line); background:var(--panel-2); color:var(--text-2); border-radius:999px; padding:5px 9px; font:inherit; font-size:11px; cursor:pointer; }
.a2-chip.on{ background:var(--accent); border-color:var(--accent); color:white; }
.a2-group{ margin:22px 0 9px; color:var(--accent); font-size:14px; text-transform:capitalize; }
.a2-model{ border:1px solid var(--line); border-radius:var(--r-md,10px); margin:8px 0; background:var(--panel-2); overflow:hidden; }
.a2-model[open]{ background:var(--panel); }
.a2-model summary{ display:flex; flex-wrap:wrap; align-items:center; gap:7px 15px; padding:14px; cursor:pointer; }
.a2-provenance{ padding:0 14px 12px; font-size:11px; color:var(--text-2); }
.a2-model-name{ font-weight:650; min-width:200px; overflow-wrap:anywhere; }
.a2-brand{ color:var(--accent); font-size:11px; }
.a2-metric{ font-size:11.5px; white-space:nowrap; }
.a2-series{ padding:4px 14px 16px; border-top:1px solid var(--line); }
.a2-chart{ margin-top:18px; }
.a2-chart h4{ font-size:12px; margin:0 0 7px; }
.a2-chart-scroll{ overflow-x:auto; max-width:100%; }
.a2-chart-scroll svg{ display:block; }
.a2-average{ fill:var(--accent); stroke:var(--panel); stroke-width:1.3; }
.a2-candle{ cursor:pointer; }
.a2-candle:focus{ outline:2px solid var(--accent); outline-offset:2px; }
.a2-rise .candle-body,.a2-rise .candle-wick{ stroke:#d97706; }
.a2-rise-label{ fill:#d97706; font-size:10px; font-weight:700; }
.a2-threshold{ stroke:#d97706; stroke-width:1.5; stroke-dasharray:5 4; }
.a2-threshold-label{ fill:#b45309; font-size:10px; }
.a2-no-token{ padding:20px 0; }
@media (max-width:720px){ .a2-model-name{ min-width:100%; } .a2-controls label{ flex-wrap:wrap; } }

/* A non-zero failure count on an API key is worth noticing without being an
   alarm — the key may simply be exercising a 404. Colour, not a chip. */
.keyfail{ color:var(--crit); }
/* Video Analysis: model/resolution comparison and daily recorded costs. */
.va-panel{margin-bottom:16px}
.va-range{display:inline-flex;margin-bottom:14px}
.va-controls{display:flex;flex-wrap:wrap;gap:12px;margin:14px 0 18px}
.va-controls label{display:flex;align-items:center;gap:8px;color:var(--text-3);font-size:13px}
.va-controls select{max-width:320px}
.va-stats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin:12px 0 18px}
.va-stats>div{border:1px solid var(--border);border-radius:12px;padding:14px;display:flex;flex-direction:column;gap:6px;min-width:0}
.va-stats small,.va-stats span{color:var(--text-3)}
.va-stats strong{font-size:22px;overflow-wrap:anywhere}
.va-group{border-top:1px solid var(--border)}
.va-group summary{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:15px 4px;cursor:pointer;list-style:none}
.va-group summary::-webkit-details-marker{display:none}
.va-toggle{display:inline-flex;align-items:center;gap:5px;white-space:nowrap;color:var(--accent);font-size:12px;font-weight:600}
.va-hide,.va-group[open] .va-show{display:none}
.va-group[open] .va-hide{display:inline}
.va-chevron{display:inline-block;font-size:18px;line-height:1;transition:transform .15s}
.va-group[open] .va-chevron{transform:rotate(180deg)}
.va-group summary:hover .va-toggle,.va-group summary:focus-visible .va-toggle{text-decoration:underline}
.va-main{display:flex;align-items:center;flex-wrap:wrap;gap:10px;min-width:0}
.va-main b{overflow-wrap:anywhere}
.va-metric{display:flex;align-items:center;gap:12px;min-width:240px;justify-content:flex-end}
.va-metric>div{display:flex;flex-direction:column;align-items:flex-end;gap:3px}.va-metric small{color:var(--text-3);font-size:11px}
.va-bar,.va-day-track{display:block;background:var(--border-soft);border-radius:8px;overflow:hidden}
.va-bar{width:150px;height:10px}.va-bar i,.va-day-track i{display:block;height:100%;background:#83b72b;border-radius:8px}
.va-detail{padding:0 4px 18px}.va-detail h4{margin:18px 0 8px}
.va-breakdown{display:flex;flex-wrap:wrap;gap:10px}.va-breakdown span{padding:6px 9px;border:1px solid var(--border);border-radius:8px;font-size:12px}
.va-days{display:grid;gap:6px}.va-day{display:grid;grid-template-columns:56px minmax(80px,1fr) 100px 74px;gap:8px;align-items:center;font-size:12px}.va-day-track{height:9px}.va-day small{text-align:right;color:var(--text-3)}
.va-scroll{overflow:auto;max-height:400px}.va-scroll table{min-width:900px}
.va-candle-scroll{overflow-x:auto;border:1px solid var(--border);border-radius:12px;background:var(--panel-2);padding:8px 4px 0}
.va-candle-chart{display:block;max-width:none}.va-grid-line{stroke:var(--border);stroke-dasharray:3 4}.va-axis-text{fill:var(--text-3);font:11px ui-monospace,SFMono-Regular,Consolas,monospace}
.va-candle line{stroke-width:2}.va-candle rect{stroke-width:1}.va-candle.up line,.va-candle.up rect{stroke:var(--crit)}.va-candle.up rect{fill:var(--crit)}.va-candle.down line,.va-candle.down rect{stroke:var(--ok)}.va-candle.down rect{fill:var(--ok)}.va-candle.flat line,.va-candle.flat rect{stroke:var(--text-3)}.va-candle.flat rect{fill:var(--text-3)}
.va-candle-legend{display:flex;flex-wrap:wrap;gap:14px;margin:8px 0 16px;color:var(--text-3);font-size:11px}.va-legend-up{color:var(--crit)}.va-legend-down{color:var(--ok)}
.va-mean-dot{fill:var(--text-1);stroke:var(--panel);stroke-width:1.5}
.va-zero-line{stroke:var(--text-2);stroke-width:1.5;stroke-dasharray:4 3}
.va-comparison-chart .candle-item{cursor:help;outline:none}
.va-comparison-chart .candle-item:focus .candle-body,.va-comparison-chart .candle-item:hover .candle-body{stroke-width:3}
.va-candle-hit{fill:transparent;pointer-events:all}
.va-chart-tooltip{position:fixed;z-index:1200;max-width:min(390px,calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:hidden;pointer-events:none;background:var(--panel);color:var(--text-1);border:1px solid var(--border);border-radius:12px;box-shadow:0 12px 36px rgba(0,0,0,.24);padding:12px 14px;font-size:12px;line-height:1.45}
.va-chart-tooltip[hidden]{display:none!important}
.va-chart-tooltip>strong{display:block;overflow-wrap:anywhere;font-size:13px;margin-bottom:3px}
.va-chart-tooltip>small{display:block;color:var(--text-3);margin-bottom:9px}
.va-chart-tooltip dl{display:grid;grid-template-columns:1fr auto;gap:2px 14px;margin:0 0 10px}
.va-chart-tooltip dt{color:var(--text-3)}.va-chart-tooltip dd{margin:0;text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
.va-tip-records{border-top:1px solid var(--border);padding-top:8px}.va-tip-records>b{display:block;margin-bottom:4px}
.va-tip-records>div{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:7px;align-items:baseline;padding:2px 0;font-variant-numeric:tabular-nums}
.va-tip-records code{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.va-tip-records small{color:var(--text-3);white-space:nowrap}
@media(max-width:900px){.va-stats{grid-template-columns:repeat(2,minmax(0,1fr))}.va-group summary{flex-direction:column;align-items:stretch}.va-metric{justify-content:flex-start}}
@media(max-width:550px){.va-stats{grid-template-columns:1fr}.va-day{grid-template-columns:45px minmax(50px,1fr) 86px 55px}.va-metric>div{align-items:flex-start}}
