/* SkillHub catalog — visual system per DESIGN.md, ported from the M5 run viewer
   (skillhub/viewer/static/app.css). Restrained: the surface serves the run/price data.
   One ochre brand hue, tinted-neutral architecture, and a semantic status ramp that
   only appears where state means something (the meter, the outcome, the risk chip).
   System fonts only. */

:root {
  --bg: oklch(1 0 0);
  --surface: oklch(0.984 0.002 260);
  --surface-2: oklch(0.965 0.003 260);
  --ink: oklch(0.235 0.012 260);
  --muted: oklch(0.52 0.014 260);
  --border: oklch(0.905 0.004 260);
  /* Border for custom-styled interactive controls (field inputs) — decorative --border
     is only 1.33:1 on --bg, below the WCAG 1.4.11 3:1 non-text floor; --control-border
     is ~3.2:1 for actual control edges. Keep --border for panels/cards/tiles/rails. */
  --control-border: oklch(0.65 0.01 260);
  --primary: oklch(0.68 0.132 77);
  --primary-ink: oklch(0.56 0.13 77);
  /* Text ON the ochre primary (buttons). Ochre is light in BOTH themes, so this dark
     ochre-ink is theme-independent: 6.2:1 on light primary, 8.9:1 on dark primary. */
  --on-primary: oklch(0.2 0.03 77);
  --accent: oklch(0.42 0.095 250);

  --ok: oklch(0.59 0.118 155);
  --ok-ink: oklch(0.52 0.11 155); /* 4.63:1 on --ok-bg — meets AA for --text-xs chip text */
  --warn: oklch(0.7 0.14 68);
  --danger: oklch(0.545 0.192 27);
  --danger-ink: var(--danger); /* light chip = 4.62:1, already passes */
  --ok-bg: oklch(0.955 0.03 155);
  --warn-bg: oklch(0.96 0.045 75);
  --danger-bg: oklch(0.955 0.04 27);

  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Menlo", "Cascadia Code", monospace;

  --text-xs: 0.78rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.25rem;
  --text-xl: 1.6rem;
  --text-2xl: 2rem;

  --meter-ease: cubic-bezier(0.165, 0.84, 0.44, 1); /* ease-out-quart */
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: oklch(0.17 0.006 260);
    --surface: oklch(0.215 0.007 260);
    --surface-2: oklch(0.255 0.008 260);
    --ink: oklch(0.94 0.006 260);
    --muted: oklch(0.7 0.012 260);
    --border: oklch(0.32 0.008 260);
    --control-border: oklch(0.5 0.01 260); /* ~3.2:1 on dark --bg; decorative --border is only 1.51:1 */
    --primary: oklch(0.78 0.13 77);
    --primary-ink: oklch(0.8 0.128 77);
    --accent: oklch(0.72 0.09 250);

    --ok: oklch(0.72 0.12 155);
    --ok-ink: oklch(0.72 0.12 155); /* = --ok; already 6.29:1 on dark --ok-bg */
    --warn: oklch(0.78 0.14 70);
    --danger: oklch(0.66 0.18 27);
    --danger-ink: oklch(0.7 0.18 27); /* 5.16:1 on dark --danger-bg, in-gamut */
    --ok-bg: oklch(0.27 0.045 155);
    --warn-bg: oklch(0.285 0.055 75);
    --danger-bg: oklch(0.28 0.06 27);
  }
}

* {
  box-sizing: border-box;
}

html {
  color-scheme: light dark;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.5;
  font-weight: 400;
}

h1,
h2,
h3 {
  font-weight: 600;
  margin: 0 0 0.5rem;
  text-wrap: balance;
}

p {
  margin: 0 0 0.75rem;
  text-wrap: pretty;
  max-width: 72ch;
}

a {
  color: var(--primary-ink);
}

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

.mono {
  font-family: var(--font-mono);
}

.tabular-nums {
  font-variant-numeric: tabular-nums;
}

button {
  font-family: inherit;
}

:focus-visible {
  /* --primary-ink (4.8:1 on bg) not --primary (2.9:1) so the ring clears the WCAG
     3:1 non-text contrast floor in light mode. */
  outline: 2px solid var(--primary-ink);
  outline-offset: 2px;
}

/* --- shell: top nav + main panel --------------------------------------------------- */

.app {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.topnav {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 0.75rem 1.5rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

.topnav__brand {
  font-weight: 600;
  font-size: var(--text-base);
  text-decoration: none;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.topnav__links {
  display: flex;
  gap: 1rem;
  flex: 1 1 auto;
}

.topnav__link {
  font-size: var(--text-sm);
  text-decoration: none;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 0.5rem;
  transition: color 150ms ease;
}

.topnav__link:hover {
  color: var(--ink);
}

.topnav__right {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-left: auto;
}

.topnav__logout {
  margin: 0;
}

.balance-chip {
  display: inline-block;
  padding: 0.25rem 0.65rem;
  border-radius: 4px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: var(--text-sm);
  font-weight: 600;
}

.main {
  flex: 1;
  min-width: 0;
  padding: 2rem 1.5rem;
}

.main__inner {
  max-width: 960px;
  margin: 0 auto;
}

@media (max-width: 640px) {
  .topnav {
    flex-wrap: wrap;
    padding: 0.75rem 1rem;
  }

  .main {
    padding: 1.25rem 1rem;
  }

  .account-summary {
    flex-wrap: wrap;
    gap: 1rem;
  }
}

.back-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--text-sm);
  text-decoration: none;
  margin-bottom: 0.5rem;
}

/* --- status dot (always paired with a text label — never color alone) ------------ */

.dot {
  display: inline-block;
  width: 0.55em;
  height: 0.55em;
  border-radius: 50%;
  background: var(--muted);
  flex: 0 0 auto;
}

.dot[data-outcome="ok"] {
  background: var(--ok);
}

.dot[data-outcome="cost_cap"],
.dot[data-outcome="skill_error"],
.dot[data-outcome="internal_error"],
.dot[data-outcome="invalid_output"],
.dot[data-outcome="failed"],
.dot[data-outcome="dead"] {
  background: var(--danger);
}

.dot[data-outcome="running"] {
  background: var(--primary);
}

[data-run-status] {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

/* --- empty states (no runs / no skills / not found / no result / in progress) ---- */

.empty-state {
  padding: 3rem 1rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
}

.empty-state--inline {
  padding: 1.5rem 1rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
}

.empty-state__hint {
  background: var(--surface-2);
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  display: inline-block;
}

/* --- run detail header ------------------------------------------------------------ */

.run-detail__header {
  margin-bottom: 1.5rem;
}

.run-detail__id {
  font-size: var(--text-lg);
  font-weight: 600;
}

.run-detail__status {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--text-sm);
  margin-top: 0.25rem;
}

.run-detail__live-tag {
  font-size: var(--text-xs);
}

.run-detail__settled {
  margin-top: 1.5rem;
}

.section-heading {
  font-size: var(--text-sm);
  font-weight: 600;
  margin-top: 2rem;
  margin-bottom: 0.5rem;
}

/* --- skill card: a compact definition grid, no icon-heading-text cards ----------- */

.skill-card {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 6px;
  padding: 1.25rem;
}

.skill-card__title {
  font-size: var(--text-lg);
}

.skill-card__outcome {
  margin-bottom: 1rem;
}

.skill-card__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.75rem 1.5rem;
  margin: 0;
}

.skill-card__fact {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.skill-card__fact dt {
  font-size: var(--text-xs);
  color: var(--muted);
}

.skill-card__fact dd {
  margin: 0;
  font-size: var(--text-sm);
}

.skill-card__fact dd.mono {
  overflow-wrap: anywhere;
}

.skill-card__fact--price {
  grid-column: 1 / -1;
}

.chip {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  border-radius: 4px;
  border: 1px solid var(--border);
  font-size: var(--text-xs);
  background: var(--surface-2);
}

/* Text label is always present; a restrained tint reinforces it, graded up the
   risk ladder (bundle-spec §2). Low tiers stay neutral so a high-risk skill is
   triageable at a glance. Same pattern as the outcome chips below. */
.chip--risk {
  border-color: var(--border);
  color: var(--muted);
}

.chip--risk[data-risk="credentialed"] {
  border-color: var(--warn);
  color: var(--warn);
  background: var(--warn-bg);
}

.chip--risk[data-risk="acts_as_user"] {
  border-color: var(--danger);
  color: var(--danger);
  background: var(--danger-bg);
}

.chip--danger {
  border-color: var(--danger);
  color: var(--danger-ink);
  background: var(--danger-bg);
}

.chip[data-outcome="ok"] {
  border-color: var(--ok);
  color: var(--ok-ink);
  background: var(--ok-bg);
}

.chip[data-outcome="cost_cap"],
.chip[data-outcome="skill_error"],
.chip[data-outcome="internal_error"],
.chip[data-outcome="invalid_output"],
.chip[data-outcome="failed"],
.chip[data-outcome="dead"] {
  border-color: var(--danger);
  color: var(--danger-ink);
  background: var(--danger-bg);
}

/* --- the cost meter: a designed gauge, not a rounded gradient progress bar ------- */

.cost-meter {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 6px;
  padding: 1.25rem;
  margin-top: 1.5rem;
}

.cost-meter__label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}

.cost-meter__title {
  font-weight: 600;
  font-size: var(--text-sm);
}

.cost-meter__zone-label {
  font-size: var(--text-xs);
  color: var(--muted);
  text-transform: lowercase;
}

.cost-meter__track {
  position: relative;
  height: 1.15rem;
  border-radius: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  overflow: hidden;
  /* Tick marks every 10% — read as an instrument, not a rounded gradient bar. */
  background-image: repeating-linear-gradient(
    to right,
    var(--border) 0,
    var(--border) 1px,
    transparent 1px,
    transparent 10%
  );
}

/* A heavier notch at the 100%/cap end. */
.cost-meter__track::after {
  content: "";
  position: absolute;
  inset: 0 0 0 auto;
  width: 2px;
  background: var(--muted);
}

/* Reserved-vs-settled ghost fill (DESIGN.md's cost-meter spec): a lighter fill behind
   the solid spent fill, showing the hold (reserved_peak) vs the settled spend. Painted
   BEFORE .cost-meter__fill in the DOM so the solid fill overlays it. */
.cost-meter__ghost {
  position: absolute;
  inset: 0 auto 0 0;
  height: 100%;
  border-radius: 0;
  background: var(--primary);
  opacity: 0.35;
}

.cost-meter__fill {
  position: absolute;
  inset: 0 auto 0 0;
  height: 100%;
  border-radius: 0;
  background: var(--primary);
  transition: width 450ms var(--meter-ease), background-color 450ms var(--meter-ease);
}

.cost-meter[data-zone="warn"] .cost-meter__fill {
  background: var(--warn);
}

.cost-meter[data-zone="at-cap"] .cost-meter__fill {
  background: var(--danger);
}

/* Width steps in 5% increments — CSP forbids `style-src 'unsafe-inline'`, so the fill
   is driven by swapping this class (server-rendered on first paint, JS-toggled live)
   rather than an inline `style="width: …"`. Shared by the ghost fill (.cost-meter__ghost)
   so a single pct-N bucket set drives both layers. */
.cost-meter__fill.pct-0,
.cost-meter__ghost.pct-0 { width: 0%; }
.cost-meter__fill.pct-5,
.cost-meter__ghost.pct-5 { width: 5%; }
.cost-meter__fill.pct-10,
.cost-meter__ghost.pct-10 { width: 10%; }
.cost-meter__fill.pct-15,
.cost-meter__ghost.pct-15 { width: 15%; }
.cost-meter__fill.pct-20,
.cost-meter__ghost.pct-20 { width: 20%; }
.cost-meter__fill.pct-25,
.cost-meter__ghost.pct-25 { width: 25%; }
.cost-meter__fill.pct-30,
.cost-meter__ghost.pct-30 { width: 30%; }
.cost-meter__fill.pct-35,
.cost-meter__ghost.pct-35 { width: 35%; }
.cost-meter__fill.pct-40,
.cost-meter__ghost.pct-40 { width: 40%; }
.cost-meter__fill.pct-45,
.cost-meter__ghost.pct-45 { width: 45%; }
.cost-meter__fill.pct-50,
.cost-meter__ghost.pct-50 { width: 50%; }
.cost-meter__fill.pct-55,
.cost-meter__ghost.pct-55 { width: 55%; }
.cost-meter__fill.pct-60,
.cost-meter__ghost.pct-60 { width: 60%; }
.cost-meter__fill.pct-65,
.cost-meter__ghost.pct-65 { width: 65%; }
.cost-meter__fill.pct-70,
.cost-meter__ghost.pct-70 { width: 70%; }
.cost-meter__fill.pct-75,
.cost-meter__ghost.pct-75 { width: 75%; }
.cost-meter__fill.pct-80,
.cost-meter__ghost.pct-80 { width: 80%; }
.cost-meter__fill.pct-85,
.cost-meter__ghost.pct-85 { width: 85%; }
.cost-meter__fill.pct-90,
.cost-meter__ghost.pct-90 { width: 90%; }
.cost-meter__fill.pct-95,
.cost-meter__ghost.pct-95 { width: 95%; }
.cost-meter__fill.pct-100,
.cost-meter__ghost.pct-100 { width: 100%; }

.cost-meter__readout {
  margin-top: 0.6rem;
  /* Scale down on narrow viewports so `$spent / $cap` never overflows its container. */
  font-size: clamp(1.35rem, 5.5vw, var(--text-2xl));
  font-weight: 600;
  white-space: nowrap;
}

.cost-meter__sep {
  color: var(--muted);
  margin: 0 0.25rem;
}

.cost-meter__cap {
  color: var(--muted);
}

.cost-meter__cap-note {
  margin: 0.6rem 0 0;
  font-size: var(--text-sm);
  color: var(--danger);
  font-weight: 500;
}

/* --- event stream: a monospace log, newest last ----------------------------------- */

.event-stream__log {
  border: 1px solid var(--border);
  background: var(--surface-2);
  border-radius: 6px;
  padding: 0.75rem 1rem;
  max-height: 360px;
  overflow-y: auto;
  font-size: var(--text-sm);
}

.event-stream__empty {
  margin: 0;
}

.event-line {
  display: flex;
  gap: 0.75rem;
  padding: 0.15rem 0;
  border-bottom: 1px solid var(--border);
}

.event-line:last-child {
  border-bottom: none;
}

.event-line[data-flagged="true"] {
  background: var(--danger-bg);
}

.event-line__time {
  color: var(--muted);
  flex: 0 0 auto;
}

.event-line__type {
  flex: 0 0 auto;
  min-width: 13ch;
  color: var(--accent);
}

.event-line__detail {
  flex: 1 1 auto;
  word-break: break-word;
}

.event-line--enter {
  animation: event-line-in 220ms ease-out;
}

@keyframes event-line-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* --- the result: pretty JSON in a --surface-2 block, plus the failure panels ----- */

.result__panel {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 6px;
  overflow: hidden;
}

.result__panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0.9rem;
  border-bottom: 1px solid var(--border);
}

.result__panel-title {
  font-size: var(--text-xs);
  color: var(--muted);
}

.result__json {
  margin: 0;
  padding: 0.9rem;
  background: var(--surface-2);
  font-size: var(--text-sm);
  overflow-x: auto;
  white-space: pre;
  border-radius: 6px;
}

.result__panel--danger {
  border-color: var(--danger);
  background: var(--danger-bg);
}

.result__panel--danger .result__panel-header {
  border-bottom-color: var(--danger);
  background: transparent;
}

.result__error-message {
  padding: 0 0.9rem 0.9rem;
  margin: 0.5rem 0 0;
}

/* --- buttons ------------------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  border: 1px solid var(--primary);
  background: var(--primary);
  color: var(--on-primary);
  border-radius: 4px;
  padding: 0.45rem 0.9rem;
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  transition: filter 150ms ease, background-color 150ms ease, border-color 150ms ease;
}

.btn:hover {
  filter: brightness(0.95);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn--ghost {
  background: transparent;
  color: var(--primary-ink);
  border-color: var(--border);
  min-height: 44px;
  padding: 0.3rem 0.6rem;
  font-size: var(--text-xs);
}

/* --- panels (login error, insufficient balance, refusals) ------------------------ */

.panel {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.9rem 1rem;
  margin-bottom: 1rem;
}

.panel--danger {
  border-color: var(--danger);
  background: var(--danger-bg);
}

.panel__message {
  margin: 0;
}

/* --- forms: login, input, consent -------------------------------------------------- */

.field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-bottom: 1rem;
}

.field__label {
  font-size: var(--text-sm);
  font-weight: 500;
}

.field__required {
  color: var(--danger);
}

.field__hint {
  font-size: var(--text-xs);
}

.field__input,
.field__textarea {
  border: 1px solid var(--control-border);
  border-radius: 4px;
  background: var(--bg);
  color: var(--ink);
  min-height: 44px;
  padding: 0.5rem 0.6rem;
  font-size: var(--text-sm);
  font-family: inherit;
}

.field__textarea {
  resize: vertical;
  min-height: 8rem;
}

.field__checkbox {
  width: 1.1rem;
  height: 1.1rem;
  align-self: flex-start;
}

.input-form__fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0 1.5rem;
}

/* --- auth (login) ------------------------------------------------------------------- */

.auth {
  max-width: 32rem;
  margin: 3rem auto 0;
  text-align: center;
}

.auth__form {
  text-align: left;
  margin-top: 1.5rem;
}

/* --- catalog index: card grid ------------------------------------------------------- */

.catalog-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.25rem;
  margin-top: 1.5rem;
}

.tile {
  display: block;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 6px;
  padding: 1.25rem;
  text-decoration: none;
  color: inherit;
  transition: border-color 150ms ease;
}

.tile:hover {
  border-color: var(--accent);
}

.tile__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}

.tile__title {
  font-size: var(--text-base);
  margin: 0;
}

.tile__outcome {
  font-size: var(--text-sm);
  margin-bottom: 0.75rem;
}

.tile__price {
  font-size: var(--text-sm);
  margin-bottom: 0.4rem;
}

.tile__stats {
  font-size: var(--text-xs);
  margin: 0;
}

/* --- consent: the honest price screen ----------------------------------------------- */

.price-panel {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 6px;
  padding: 1.25rem;
  margin-bottom: 1.5rem;
}

.price-panel__headline {
  margin-bottom: 0.5rem;
}

.price-panel__balance {
  margin: 0;
}

/* --- account: balance summary + receipts -------------------------------------------- */

.account-summary {
  display: flex;
  gap: 2rem;
  margin: 0 0 1.5rem;
}

.account-summary__fact dt {
  font-size: var(--text-xs);
  color: var(--muted);
}

.account-summary__fact dd {
  margin: 0;
  font-size: var(--text-xl);
  font-weight: 600;
}

.table-scroll {
  overflow-x: auto;
}

.receipts {
  width: 100%;
  min-width: 32rem;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.receipts th,
.receipts td {
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
}

.receipts th {
  color: var(--muted);
  font-weight: 500;
  font-size: var(--text-xs);
}

/* --- motion: calm by default, snap when reduced ----------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .cost-meter__fill {
    transition: none;
  }

  .event-line--enter {
    animation: none;
  }
}

.run-detail__settled--hold { color: var(--warn); }
