/* ===========================================================================
   Elasticity — shared components. Depends on tokens.css + base.css.

   Every rule reads role tokens, so each component works in both themes
   with no per-theme override. No colour literals in here — see tokens.css.
   Patterns borrowed (2026-09-24 rebrand) from dev-facing model directories:
   segmented toggles, mono tabular numbers, best-in-column highlight, flat
   status pills, quiet hairline tables.
   =========================================================================== */

/* ===== buttons ============================================================ */
/* inline-flex + text-decoration:none so this works on an <a> as well as a
   <button> -- a CTA that navigates is a link. */
.btn {
  font: inherit; font-size: 13px; font-weight: 600; padding: var(--s2) var(--s4);
  border-radius: var(--r); cursor: pointer; border: 1px solid transparent;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  text-decoration: none; transition: background-color .15s, border-color .15s, color .15s;
}
/* Action fill + --action-ink text: mint/near-black (14.3:1) in dark,
   ocean blue/white (7.0:1) in light. */
.btn.primary { background: var(--action); color: var(--action-ink); border-color: var(--action); }
.btn.primary:hover { background: var(--action-hover); border-color: var(--action-hover); }
.btn.primary:disabled { background: var(--surface-2); color: var(--fg-faint); border-color: var(--line); cursor: wait; }
.btn.ghost, a.btn.ghost { background: transparent; color: var(--fg); border-color: var(--line-strong); }
.btn.ghost:hover { background: var(--surface-2); border-color: var(--fg-faint); }
.btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* ===== theme toggle ======================================================= */
.theme-toggle {
  font: inherit; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border-radius: var(--r); cursor: pointer;
  background: transparent; color: var(--fg-muted); border: 1px solid var(--line);
}
.theme-toggle:hover { color: var(--fg); background: var(--surface-2); }
.theme-toggle:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.theme-toggle svg { width: 16px; height: 16px; }
.theme-toggle .i-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .i-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .i-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .i-sun { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .i-moon { display: none; }
}

/* ===== segmented control (Absolute | Percentage style) ==================== */
.seg { display: inline-flex; gap: 2px; padding: 2px; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface-2); }
.seg button {
  font: inherit; font-size: 12px; font-weight: 500; color: var(--fg-muted); background: transparent;
  border: 0; border-radius: 4px; padding: var(--s1) var(--s2); cursor: pointer;
}
.seg button[aria-pressed="true"], .seg button[aria-checked="true"] { background: var(--surface); color: var(--accent-text); box-shadow: var(--shadow-sm); }
.seg button:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

/* ===== form fields ========================================================= */
.field { display: grid; gap: var(--s2); }
.field label { font-size: 12px; font-weight: 500; color: var(--fg-muted); }
.field input, .field select, .field textarea {
  font: inherit; font-size: 13px; background: var(--surface-2); border: 1px solid var(--line); color: var(--fg);
  padding: var(--s2) var(--s3); border-radius: var(--r); width: 100%;
}
.field input::placeholder, .field textarea::placeholder { color: var(--fg-faint); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--focus); box-shadow: 0 0 0 3px var(--accent-wash);
}
.field .hint { font-size: 12px; color: var(--fg-faint); }

.check-row { display: flex; align-items: flex-start; gap: var(--s2); font-size: 13px; color: var(--fg-muted); }
.check-row input { margin-top: 2px; accent-color: var(--accent-text); }

.row { display: flex; gap: var(--s3); align-items: center; flex-wrap: wrap; }
/* A bare "Model: <select>" label in a row matches the .check-row beside it
   (it used to render at body size, one step larger). */
.row > label:not(.check-row):not(.btn) { display: inline-flex; align-items: center; gap: var(--s2); font-size: 13px; color: var(--fg-muted); }

/* Native file inputs (console, test UI): the browser's grey button and
   Arial label ignored the theme. Style the button like .btn.ghost. */
input[type="file"] { font: inherit; font-size: 13px; color: var(--fg-muted); }
input[type="file"]::file-selector-button {
  font: inherit; font-weight: 600; color: var(--fg); background: transparent;
  border: 1px solid var(--line-strong); border-radius: var(--r);
  padding: var(--s1) var(--s3); margin-right: var(--s3); cursor: pointer;
}
input[type="file"]::file-selector-button:hover { background: var(--surface-2); }

/* ===== panel / block ======================================================= */
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--s5); display: grid; gap: var(--s3); }
.panel > h2, .block > h3, .model-group > h3 {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--fg-faint); font-weight: 500; margin: 0;
}
.block { background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--s3); display: grid; gap: var(--s2); }

.cols { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }
@media (max-width: 720px) { .cols { grid-template-columns: 1fr; } }

/* ===== status pill (.stamp kept as the class name for compatibility) ======
   Flat, small, tinted — the dev-tool register. Colour always pairs with a
   text label, never carries meaning alone. */
.stamp {
  display: inline-flex; align-items: center; gap: var(--s1);
  font-size: 11px; font-weight: 600; letter-spacing: .02em;
  padding: 2px var(--s2); border-radius: var(--r-pill); border: 1px solid transparent;
}
.stamp.cleared  { color: var(--pass); background: var(--pass-wash); }
.stamp.withheld { color: var(--flag); background: var(--flag-wash); }
.stamp.review   { color: var(--hold); background: var(--hold-wash); }
.stamp.idle     { color: var(--fg-faint); background: transparent; border-color: var(--line-strong); }

/* ===== chip / tag ========================================================= */
.chip { display: inline-flex; align-items: center; gap: var(--s1); font-size: 12px; font-weight: 500; padding: 2px var(--s2); border-radius: var(--r); background: var(--surface-2); color: var(--fg-muted); }
.chip.accent { background: var(--accent-wash); color: var(--accent-text); }
.chip.mono { font-family: var(--mono); font-size: 12px; }

/* ===== model cards (BL-048 Phase C) — a chip-group evolved into a grid of
   small info cards; still leans on --surface-2 for the same visual weight
   .chip already used. =====================================================
   2026-09-25, explicit direction: spacing was too tight (title/price/
   scores/meta all sat on the same --s2 rhythm with no visual grouping),
   the price line crammed three discount tiers into one wrapping sentence,
   and a card with a real license_condition (e.g. Qwen3.8-2.4T-A95B's
   revenue-gate text) grew tall enough to break the row's alignment with
   its siblings. Reworked: --s3 between logical groups (was --s2
   everywhere), price tiers as their own table (one row per tier, matching
   tools/public_demo.py's own ledger convention), and the condition text
   moved to a full-width footnote below the whole grid (see the template's
   own comment on ns.footnotes) so no card's height depends on how long
   its license text happens to be. */
.model-groups { display: grid; gap: var(--s6); }
.model-group { display: grid; gap: var(--s3); }
.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--s4); }
.model-card {
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r);
  padding: var(--s4); display: grid; gap: var(--s3); align-content: start;
}
.model-card .card-head { display: flex; align-items: flex-start; gap: var(--s2); }
.model-card .card-head-text { display: grid; gap: 2px; min-width: 0; }
/* Vendor mark, next to the model name -- same "logo beside name+price"
   convention as llm-stats/OpenRouter/Fireworks' own model listings. A real
   brand SVG (VENDOR_LOGOS[group].file) or, absent one, a plain-text
   monogram badge in the vendor's own brand color (.card-logo-fallback) --
   same graceful-degradation OpenRouter itself falls back to for a vendor
   it has no mark for. Fixed 20px box either way so card-head-text never
   shifts between cards. */
.card-logo, .card-logo-fallback {
  flex: none; width: 20px; height: 20px; border-radius: 5px; margin-top: 1px;
}
.card-logo { object-fit: contain; background: var(--surface); padding: 2px; border: 1px solid var(--line); }
/* Vendors with a file_dark mark render both; the theme picks one (same
   pairing as .logo-img-dark/.logo-img-light below). */
.card-logo-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .card-logo-dark { display: block; }
  :root:not([data-theme="light"]) .card-logo-light { display: none; }
}
:root[data-theme="dark"] .card-logo-dark { display: block; }
:root[data-theme="dark"] .card-logo-light { display: none; }
.card-logo-fallback {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--sans); font-size: 8.5px; font-weight: 700; letter-spacing: -.02em;
  color: #fff; background: var(--vendor-color, var(--fg-faint));
}
.model-card .card-title { font-size: 13px; font-weight: 600; color: var(--fg); }
.model-card .card-alias { font-family: var(--mono); font-size: 10.5px; color: var(--fg-faint); word-break: break-all; }
.model-card .price-unavailable { font-size: 11px; color: var(--fg-faint); }
/* One row per pricing tier -- ascending discount, Retail first, 90% off
   (the deepest, headline tier) last and visually emphasized. Compact:
   this sits inside a ~220px card, not the ledger's full-width table. */
.card-price-table { width: 100%; border-collapse: collapse; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.card-price-table caption {
  caption-side: top; text-align: left; font-family: var(--sans); font-size: 10.5px;
  color: var(--fg-faint); font-weight: 400; padding-bottom: var(--s1);
}
.card-price-table th, .card-price-table td { padding: 3px 0; font-size: 12px; font-weight: 400; text-align: left; color: var(--fg-muted); }
.card-price-table th { padding-right: var(--s2); white-space: nowrap; }
.card-price-table td { text-align: right; width: 100%; color: var(--fg); }
.card-price-table tr.headline th, .card-price-table tr.headline td { color: var(--fg); font-weight: 600; }
.card-price-table tr.headline { border-top: 1px solid var(--line); }
.card-price-table tr.headline th, .card-price-table tr.headline td { padding-top: var(--s2); }
.model-card .card-scores { display: flex; gap: var(--s3); flex-wrap: wrap; font-family: var(--mono); font-size: 11px; color: var(--fg-muted); }
/* Only shown for a model with no llm-stats.com composite rank (blank
   Reasoning/Coding/Agent above) -- a different metric on a different
   scale, so deliberately its own line rather than folded into
   .card-scores' "pts" row. */
.model-card .card-benchmark-fallback { font-size: 10.5px; color: var(--fg-faint); }
.model-card .card-meta {
  display: flex; justify-content: space-between; gap: var(--s2); font-size: 11px; color: var(--fg-muted);
  border-top: 1px solid var(--line); padding-top: var(--s3);
}
.model-card .card-meta sup a { color: var(--fg-faint); text-decoration: none; }
.model-card .card-meta sup a:hover { text-decoration: underline; }
/* Full page width, below the whole card-grid -- not a card's own child --
   same role tools/public_demo.py's own #licenseFootnotes plays for its
   ledger table. */
.model-footnotes {
  margin: 0; padding: 0 0 0 var(--s4); font-size: 12px; color: var(--fg-faint);
  display: grid; gap: var(--s1);
}

/* ===== ledger — hairline rows, no cell borders ============================ */
.ledger-wrap { overflow-x: auto; }
table.ledger { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 480px; }
table.ledger th {
  text-align: left; font-family: var(--mono); font-weight: 500; font-size: 10.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--fg-faint);
  padding: 0 var(--s3) var(--s2); border-bottom: 1px solid var(--line);
}
table.ledger td { padding: var(--s3); border-bottom: 1px solid var(--line); color: var(--fg-muted); }
table.ledger tr:last-child td { border-bottom: 0; }
table.ledger tbody tr { transition: background-color .15s; }
table.ledger tbody tr:hover td { background: var(--surface-2); }
table.ledger .m { font-family: var(--mono); font-size: 12px; color: var(--fg); font-variant-numeric: tabular-nums; white-space: nowrap; }
table.ledger .num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--fg); white-space: nowrap; }
table.ledger td .stamp { font-size: 10.5px; }
/* best value in a column — the one highlight a scanning eye should land on */
table.ledger .best { display: inline-block; padding: 1px var(--s2); border-radius: 4px; background: var(--accent-wash); color: var(--accent-text); font-weight: 600; }
/* A closed/proprietary model shown as a full-retail reference point, never
   something Elasticity subsidizes -- shaded so it reads as context. */
table.ledger tbody tr.row-closed td { background: var(--surface-2); }

/* ===== stats / KPI strip ================================================== */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--s4); }
.stat .v { font-family: var(--mono); font-size: 30px; font-weight: 500; font-variant-numeric: tabular-nums; letter-spacing: -.02em; color: var(--fg); }
.stat .v .u { font-size: 16px; color: var(--fg-faint); margin-left: 1px; }
.stat .l { font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--fg-faint); margin-top: 2px; }
.stat .d { font-size: 12px; color: var(--fg-muted); margin-top: var(--s1); }
.stat .d .up { color: var(--pass); }

/* ===== issued-key line ===================================================== */
.keyline { display: flex; align-items: center; gap: var(--s2); background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r); padding: var(--s2) var(--s3); font-family: var(--mono); font-size: 12px; }
.keyline .k { color: var(--accent-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ===== app shell (tabs + appbar), used by admin console + portal ========== */
.app { border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; background: var(--surface); }
.appbar { display: flex; align-items: center; gap: var(--s4); padding: var(--s3) var(--s4); border-bottom: 1px solid var(--line); background: var(--bg); flex-wrap: wrap; }
.appbar .brand { font-family: var(--display); font-weight: 600; font-size: 14px; letter-spacing: -.01em; display: flex; align-items: center; gap: var(--s2); }
.appbar .brand .bar { display: inline-block; width: 22px; height: 10px; background: var(--accent); border-radius: 2px; }
.tabs { display: flex; gap: var(--s5); margin-left: auto; }
.tabs button {
  font: inherit; font-size: 13px; font-weight: 500; color: var(--fg-muted); background: none; border: 0; cursor: pointer;
  /* pull the underline onto the appbar's bottom border: its --s3 padding + 1px rule */
  padding: var(--s1) 0; border-bottom: 2px solid transparent; margin-bottom: calc(-1 * var(--s3) - 1px);
}
.tabs button[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--accent-text); }
.tabs button:hover { color: var(--fg); }
.tabs button:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.appbody { padding: var(--s5) var(--s4); display: grid; gap: var(--s5); }
.tabpanel { display: none; }
.tabpanel.active { display: block; }

/* ===== topbar (site header: wordmark + nav) ================================ */
.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s3) 0; margin-bottom: var(--s6); border-bottom: 1px solid var(--line); flex-wrap: wrap;
}
.topbar .wordmark { display: flex; align-items: center; gap: var(--s2); text-decoration: none; color: var(--fg); font-weight: 600; font-size: 16px; letter-spacing: -.02em; }
/* 36px: the PNGs are trimmed to the wordmark's ink (~84px tall), so this
   is the visible letter height and stays sharp on 2x screens up to ~42px. */
.topbar .wordmark .logo-img { height: 36px; }

/* ===== brand wordmark image, swapped by theme (2026-09-26) =================
   Two renders of the "elasticity" mark -- mint-on-transparent for dark,
   solid Ocean Blue for light -- shown/hidden rather than recoloured, since
   neither is a simple tint of the other. Same not-[data-theme="light"]
   vs [data-theme="dark"] pairing tokens.css itself uses for every colour
   role, so this follows the OS preference and the toggle exactly like
   everything else does. Any page dropping in the wordmark just needs both
   <img class="logo-img logo-img-dark"|"logo-img-light"> elements; size is
   set per-context (e.g. .topbar .wordmark .logo-img above). */
.logo-img { display: block; width: auto; }
.logo-img-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .logo-img-dark { display: block; }
  :root:not([data-theme="light"]) .logo-img-light { display: none; }
}
:root[data-theme="dark"] .logo-img-dark { display: block; }
:root[data-theme="dark"] .logo-img-light { display: none; }
.topbar nav { display: flex; align-items: center; gap: var(--s5); flex-wrap: wrap; }
.topbar nav a:not(.btn) { font-size: 13px; font-weight: 500; color: var(--fg-muted); text-decoration: none; }
.topbar nav a:not(.btn):hover { color: var(--fg); }
.topbar .btn { font-size: 13px; padding: var(--s2) var(--s3); }
@media (max-width: 640px) { .topbar nav a:not(.btn) { display: none; } }

/* ===== icons ============================================================== */
/* Lucide sprite (static/img/icons.svg). Stroke-only, colour from
   currentColor, so an icon inherits whatever text colour it sits in:
     <svg class="icon" aria-hidden="true"><use href="{{ url_for('static', filename='img/icons.svg') }}#shield-check"/></svg>
   Decorative icons get aria-hidden; an icon-only button carries its own
   aria-label. .icon-tile is the 44px accent-wash square used on stat and
   pipeline cards. */
.icon { width: var(--icon); height: var(--icon); flex: none; display: inline-block; vertical-align: -0.2em;
  fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.icon-sm { width: 16px; height: 16px; }
.icon-tile {
  width: var(--icon-tile); height: var(--icon-tile); flex: none;
  display: inline-grid; place-items: center;
  border-radius: var(--r-lg); background: var(--accent-wash); color: var(--accent-text);
}
