/* ============================================================
   Model Router

   Direction: precision tool wearing Apple's MECHANISMS, not its
   marketing aesthetic. The KB names the misuse explicitly — "sparse
   spectacle in operational tools" — so what is borrowed is:

     - ruthless hierarchy (one answer dominates; everything else recedes)
     - progressive disclosure (secondary controls are folded away)
     - grouped inset lists with hairline separators, not boxes-in-boxes
     - restrained colour: one accent, used for action and selection only
     - short, continuous motion; no scroll choreography

   Typography is the live system font, which resolves to SF Pro on Apple
   hardware. That is the real thing rather than an imitation, needs no
   webfont request, and avoids the look-alike defaults.

   Elevation is hairlines and tone. There are no shadows and no gradients.
   ============================================================ */

:root {
  /* --- colour: verified AA against every surface it is used on --- */
  --canvas: #f5f5f7;
  --surface: #ffffff;
  --sunken: #f0f0f2;

  --separator: #d2d2d7;
  --separator-strong: #c6c6cb;

  --text: #1d1d1f;
  --text-muted: #515154;
  --text-subtle: #6a6a6f;

  --accent: #0068d1;
  --accent-wash: #e8f1fb;
  --success: #1d7a3e;
  --success-wash: #e9f3ec;
  --warning: #8a5a00;
  --warning-wash: #fdf6e8;
  --danger: #c4271a;
  --danger-wash: #fdeeec;

  /* --- spacing: 4px scale --- */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

  /* --- shape --- */
  --r-sm: 6px;
  --r: 10px;
  --r-lg: 14px;
  --r-pill: 980px;

  /* --- motion: short and continuous --- */
  --t-instant: 100ms;
  --t-fast: 180ms;
  --t-standard: 260ms;
  --ease: cubic-bezier(.32, .72, 0, 1);

  --prose: 68ch;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;

  /* --- Apple Intelligence inspired gradient ---------------------------
     Apple publishes no official hex values for this, so these are an
     interpretation of the orange -> pink -> violet -> blue sweep.

     TWO sets, deliberately. The marketing-bright hues measure 1.51:1 to
     3.79:1 against the canvas, so they are unusable for anything anyone
     has to read. --ai-* is the bright set, used ONLY as decoration on a
     border. --aid-* is darkened until every stop clears 4.5:1, and is the
     only set allowed near text.

     Scope is deliberately narrow: the wordmark, the task field, and the
     primary action. Both knowledge bases flag page-wide purple gradients
     and glow as an AI-slop signature, and spreading this further would
     also bury the data this tool exists to show. */
  --ai-orange: #f5a623;
  --ai-pink:   #ff5f8f;
  --ai-violet: #af52de;
  --ai-teal:   #40e0d0;

  --aid-orange: #b4530a;   /* 4.61:1 */
  --aid-pink:   #c82d6b;   /* 4.77:1 */
  --aid-violet: #7a34c9;   /* 6.10:1 */
  --aid-blue:   #0f6fbf;   /* 4.77:1 */

  --ai-sweep: linear-gradient(100deg, var(--ai-orange), var(--ai-pink) 25%,
              var(--ai-violet) 50%, var(--ai-teal) 75%, var(--ai-orange));
  --ai-sweep-deep: linear-gradient(100deg, var(--aid-orange), var(--aid-pink) 30%,
              var(--aid-violet) 65%, var(--aid-blue));
  /* Same stops, looping back to the first, so a sweep has no visible seam. */
  --ai-sweep-deep-loop: linear-gradient(100deg, var(--aid-orange), var(--aid-pink) 25%,
              var(--aid-violet) 50%, var(--aid-blue) 75%, var(--aid-orange));
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--canvas);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { margin: 0; line-height: 1.2; letter-spacing: -.021em; }
p { max-width: var(--prose); }
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; inset-inline-start: var(--s4); inset-block-start: -100px;
  z-index: 100; padding: var(--s2) var(--s4);
  background: var(--accent); color: #fff; font-weight: 590;
  border-radius: 0 0 var(--r) var(--r); text-decoration: none;
  transition: inset-block-start var(--t-fast) var(--ease);
}
.skip-link:focus { inset-block-start: 0; }

:is(a, button, select, textarea, input, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* ---------------- header ---------------- */
/* Large title, stacked. At 21px the h1 was smaller than an h3 further down
   the page, which inverted the hierarchy. Baseline-aligning it beside the
   tagline also wrapped awkwardly at narrow widths. */
.topbar {
  padding: var(--s6) clamp(var(--s4), 4vw, var(--s7)) var(--s5);
  max-width: 1320px; margin-inline: auto;
}
.topbar h1 {
  font-size: clamp(27px, 3.2vw, 33px);
  font-weight: 620; letter-spacing: -.028em;
  color: var(--text);            /* fallback if background-clip is unsupported */
}
/* Gradient text is normally a tell, and it is used here exactly once, on the
   wordmark. Every stop is the darkened set, so the title stays AA-legible
   along its whole length rather than fading into the background mid-word. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .topbar h1 {
    background-image: var(--ai-sweep-deep);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
}
/* In forced-colors mode, clipped text would render invisible. */
@media (forced-colors: active) {
  .topbar h1 { -webkit-text-fill-color: CanvasText; color: CanvasText; background-image: none; }
}
.sub {
  margin: var(--s1) 0 0; font-size: 17px;
  color: var(--text-subtle); max-width: var(--prose);
}

/* ---------------- layout ---------------- */
.layout {
  display: grid;
  grid-template-columns: minmax(280px, 330px) minmax(0, 1fr);
  gap: var(--s6);
  padding: 0 clamp(var(--s4), 4vw, var(--s7)) var(--s8);
  align-items: start;
  max-width: 1320px; margin-inline: auto;
}

/* Controls defer: no panel border, no card. Grouping is done with
   space and hairlines so the answer is the only thing with weight. */
/* The scrollbar used to sit on top of the text, because this scroll
   container had no inline-end padding. scrollbar-gutter reserves the track
   in modern browsers; the padding guarantees a gap in the ones that ignore
   it, and gives the column room to breathe either way. */
.controls {
  position: sticky; inset-block-start: var(--s5);
  max-height: calc(100vh - var(--s7));
  overflow-y: auto;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: var(--separator-strong) transparent;
  /* overflow-y: auto makes the OTHER axis compute to auto as well, so this
     container clips horizontally. Without inline-start padding it sliced off
     the task box's left edge and its focus ring. The negative margin cancels
     the padding visually, so content stays aligned with the page while the
     container still has room to paint rings and outlines. */
  padding-inline: var(--s3) var(--s4);
  margin-inline-start: calc(var(--s3) * -1);
}
.controls::-webkit-scrollbar { width: 8px; }
.controls::-webkit-scrollbar-thumb { background: var(--separator-strong); border-radius: var(--r-pill); }
.controls::-webkit-scrollbar-track { background: transparent; }

/* Roomier rhythm inside the sidebar only. */
.controls .block { margin-block-end: var(--s7); }
.controls .field { margin-block-end: var(--s5); }
.controls .field:last-child { margin-block-end: 0; }
.controls .fieldHead { margin-block-end: var(--s2); }
.controls .hint { margin-block-start: var(--s3); }
.controls details.fold { padding-block-start: var(--s4); margin-block-start: var(--s4); }
.controls details.fold > .foldBody { padding-block-start: var(--s5); }
.controls .chips { margin-block-start: var(--s3); }
.controls .preset-btns { margin-block-start: var(--s4); }

/* The live figures are the thing people watch while dragging, so they
   carry the accent and flash once when the value actually changes.
   That is motion as feedback, and it is killed by reduced-motion below. */
.controls .fieldHead output {
  color: var(--accent);
  padding-inline: var(--s2);
  border-radius: var(--r-sm);
}
.controls .fieldHead output.changed { animation: valueChanged var(--t-standard) var(--ease); }
@keyframes valueChanged {
  from { background: var(--accent-wash); }
  to   { background: transparent; }
}

.block { margin-block-end: var(--s6); }
.blockTitle {
  font-size: 13px; font-weight: 590; color: var(--text-subtle);
  margin-block-end: var(--s3); letter-spacing: 0;
}

/* ---------------- grouped inset list ---------------- */
.group {
  background: var(--surface);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.group-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s4); padding: var(--s3) var(--s4);
  position: relative;
}
/* Separator inset from the leading edge, as in a native grouped list. */
.group-row + .group-row::before {
  content: ''; position: absolute; inset-block-start: 0;
  inset-inline: var(--s4) 0; height: 1px; background: var(--separator);
}
.group-row .k { font-size: 15px; color: var(--text-muted); }
.group-row .v { font-size: 15px; font-weight: 590; font-variant-numeric: tabular-nums; text-align: end; }
.group-row .v small { display: block; font-size: 13px; font-weight: 400; color: var(--text-subtle); }

/* ---------------- form ---------------- */
.lbl { display: block; font-size: 15px; font-weight: 510; margin-block-end: var(--s2); color: var(--text); }
.lbl.sm { font-size: 14px; color: var(--text-muted); font-weight: 400; }

textarea, select {
  width: 100%; background: var(--surface); color: var(--text);
  border: 1px solid var(--separator); border-radius: var(--r);
  padding: var(--s3); font: inherit; font-size: 15px; resize: vertical;
  transition: border-color var(--t-fast) var(--ease);
}
textarea::placeholder { color: var(--text-subtle); }
textarea:hover, select:hover { border-color: var(--separator-strong); }

/* Task field. Apple puts the gradient on the prompt input, and here that
   doubles as the signal for the one required control. The ring animates
   ONLY while the field is empty: motion carrying a status, which stops as
   soon as the status changes. Bright stops are fine here because this is a
   border, not text, and it is never the only indicator of the state (the
   label is marked Required and the results pane says what is missing). */
.taskField {
  position: relative;
  border-radius: calc(var(--r) + 2px);
  padding: 2px;
  background: var(--separator);
  transition: background-color var(--t-standard) var(--ease);
}
.taskField:hover { background-color: var(--separator-strong); }

/* The focus ring goes on the WRAPPER, outside the gradient. On the textarea
   it inherited outline-offset: 2px, which is exactly this wrapper's padding,
   so the blue ring landed on top of the gradient and hid it. Offsetting
   outward lets both read at once: gradient ring, gap, then focus ring. */
.taskField textarea:focus-visible { outline: none; }
.taskField:focus-within {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}
.taskField textarea {
  border: 0; display: block;
  position: relative; z-index: 1;   /* sits above the gradient layer */
  border-radius: calc(var(--r) - 1px);
}
/* Gradient is visible whenever the field is still empty, but it holds
   STILL. The sweep runs only while the field is hovered or focused, so the
   motion is a response to the user rather than a loop playing at nobody. */
/* Absent at rest, fades in on hover or focus. It lives on a pseudo-element
   because background-image cannot transition between "none" and a gradient,
   whereas opacity can, so this arrives smoothly instead of snapping on. */
.taskField::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  background-image: var(--ai-sweep);
  background-size: 300% 100%;
  opacity: 0;
  transition: opacity var(--t-standard) var(--ease);
  pointer-events: none;
}
.taskField:hover::before,
.taskField:focus-within::before {
  opacity: 1;
  animation: aiSweep 4s linear infinite;
}
/* First and last stop match, so the sweep loops without a seam. */
@keyframes aiSweep { to { background-position: 300% 0; } }
@media (forced-colors: active) {
  .taskField::before { content: none; }
}
select { cursor: pointer; }
.row { margin-block-start: var(--s3); }

.field { margin-block-end: var(--s4); }
.fieldHead { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s2); margin-block-end: var(--s1); }
.fieldHead label { font-size: 15px; color: var(--text); }
.fieldHead output { font-size: 15px; font-weight: 590; font-variant-numeric: tabular-nums; }
.hint { margin-block: var(--s2) 0; font-size: 13px; color: var(--text-subtle); line-height: 1.45; max-width: var(--prose); }

input[type=range] {
  width: 100%; -webkit-appearance: none; appearance: none;
  background: transparent; cursor: pointer; height: 22px;
}
input[type=range]::-webkit-slider-runnable-track { height: 4px; background: var(--separator); border-radius: var(--r-pill); }
input[type=range]::-moz-range-track { height: 4px; background: var(--separator); border-radius: var(--r-pill); }
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 20px; height: 20px; margin-block-start: -8px;
  border-radius: 50%; background: var(--surface); border: 1px solid var(--separator-strong);
  transition: transform var(--t-instant) var(--ease);
}
input[type=range]::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--separator-strong);
}
input[type=range]:active::-webkit-slider-thumb { transform: scale(1.12); }

/* Segmented control: white thumb on a tinted track. */
.segmented {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px;
  background: var(--sunken); padding: 2px; border-radius: var(--r);
}
.segmented button {
  font: inherit; font-size: 14px; font-weight: 400; padding: var(--s2) var(--s1);
  background: transparent; color: var(--text-muted); border: 1px solid transparent;
  border-radius: var(--r-sm); cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.segmented button:hover { color: var(--text); }
.segmented button[aria-checked=true] {
  background: var(--surface); color: var(--text);
  font-weight: 590; border-color: var(--separator);
}

.check { display: flex; align-items: center; gap: var(--s3); padding-block: var(--s2); font-size: 15px; color: var(--text-muted); cursor: pointer; }
.check input { accent-color: var(--accent); width: 17px; height: 17px; cursor: pointer; }
.check:hover span { color: var(--text); }

.modalities { margin-block-start: var(--s3); border: 0; padding: 0; margin-inline: 0; }
.modalities legend { padding: 0; }
.modChips { display: flex; gap: var(--s2); margin-block-start: var(--s2); flex-wrap: wrap; }
.modChips label {
  font-size: 14px; padding: var(--s1) var(--s3); border-radius: var(--r-pill);
  border: 1px solid var(--separator); background: var(--surface);
  color: var(--text-muted); cursor: pointer;
  transition: border-color var(--t-fast) var(--ease);
}
.modChips input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.modChips label:has(input:focus-visible) { outline: 3px solid var(--accent); outline-offset: 2px; }
.modChips label:has(input:checked) { border-color: var(--accent); color: var(--accent); background: var(--accent-wash); }

.chips { display: flex; gap: var(--s2); flex-wrap: wrap; margin-block-start: var(--s2); min-height: 22px; }
.chip { font-size: 13px; padding: 2px var(--s2); border-radius: var(--r-sm); background: var(--accent-wash); color: var(--accent); }
.chip.muted { background: var(--sunken); color: var(--text-subtle); }

.preset-btns { display: flex; flex-wrap: wrap; gap: var(--s2); margin-block-start: var(--s2); }
.preset-btns button {
  font: inherit; font-size: 13px; padding: var(--s1) var(--s3); cursor: pointer;
  background: var(--surface); color: var(--text-muted);
  border: 1px solid var(--separator); border-radius: var(--r-pill);
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.preset-btns button:hover { border-color: var(--accent); color: var(--accent); }

/* Progressive disclosure: native details, keyboard-operable for free. */
details.fold { border-block-start: 1px solid var(--separator); padding-block-start: var(--s3); margin-block-start: var(--s3); }
details.fold > summary {
  cursor: pointer; list-style: none; font-size: 15px; color: var(--text-muted);
  display: flex; align-items: center; gap: var(--s2); border-radius: var(--r-sm);
}
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary::before {
  content: ''; width: 6px; height: 6px; flex: none;
  border-inline-end: 1.5px solid currentColor; border-block-end: 1.5px solid currentColor;
  transform: rotate(-45deg); margin-inline-start: 2px;
  transition: transform var(--t-fast) var(--ease);
}
details.fold[open] > summary::before { transform: rotate(45deg); }
details.fold > summary:hover { color: var(--text); }
details.fold > .foldBody { padding-block-start: var(--s4); }

/* ---------------- results ---------------- */
.results { min-width: 0; }

.tabs { display: flex; gap: var(--s1); margin-block-end: var(--s5); flex-wrap: wrap; }
.tabs button {
  font: inherit; font-size: 14px; font-weight: 400; white-space: nowrap;
  padding: var(--s2) var(--s4); background: transparent; color: var(--text-muted);
  border: 1px solid transparent; border-radius: var(--r-pill); cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tabs button:hover { color: var(--text); background: var(--sunken); }
.tabs button[aria-selected=true] { background: var(--text); color: var(--surface); font-weight: 510; }
.tabpane:focus-visible { outline-offset: 4px; }

/* The answer. One element dominates; the rest is quiet. */
.verdictName {
  font-size: clamp(28px, 4vw, 38px); font-weight: 620;
  letter-spacing: -.028em; line-height: 1.08;
}
.verdictSub { margin-block: var(--s2) 0; font-size: 17px; color: var(--text-muted); max-width: var(--prose); }
.verdictWhy { margin-block: var(--s3) 0; font-size: 15px; color: var(--text-subtle); max-width: var(--prose); }

.hero {
  display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap;
  margin-block: var(--s5) var(--s2);
}
.hero .figure { font-size: clamp(34px, 5vw, 46px); font-weight: 620; letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1; }
.hero .unit { font-size: 16px; color: var(--text-subtle); }

.subhead { font-size: 13px; font-weight: 590; color: var(--text-subtle); margin-block: var(--s6) var(--s3); }

/* score bars inside a grouped card */
.barRow { display: grid; grid-template-columns: 1fr 96px 60px; align-items: center; gap: var(--s3); padding: var(--s3) var(--s4); position: relative; }
.barRow + .barRow::before {
  content: ''; position: absolute; inset-block-start: 0; inset-inline: var(--s4) 0;
  height: 1px; background: var(--separator);
}
.barRow .n { font-size: 15px; color: var(--text-muted); }
.barRow .track { height: 6px; background: var(--sunken); border-radius: var(--r-pill); overflow: hidden; }
.barRow .fill {
  display: block; height: 100%; width: 100%; border-radius: var(--r-pill);
  transform: scaleX(var(--v, 0)); transform-origin: left center;
  transition: transform var(--t-standard) var(--ease);
}
.barRow .p { font-size: 13px; color: var(--text-subtle); text-align: end; font-variant-numeric: tabular-nums; }

ul.pts { margin-block: 0; padding-inline-start: var(--s5); font-size: 15px; color: var(--text-muted); max-width: var(--prose); }
ul.pts li { margin-block-end: var(--s2); }

/* ---------------- alerts ---------------- */
.alerts { display: flex; flex-direction: column; gap: var(--s2); }
.alert { padding: var(--s3) var(--s4); border-radius: var(--r); font-size: 14px; line-height: 1.5; max-width: var(--prose); }
.alert b { font-weight: 590; display: block; }
.alert.high { background: var(--danger-wash); color: var(--danger); }
.alert.med  { background: var(--warning-wash); color: var(--warning); }
.alert.low  { background: var(--sunken); color: var(--text-muted); }

/* ---------------- ranked rows ---------------- */
.rankRow { display: grid; grid-template-columns: 1fr auto; gap: var(--s4); align-items: baseline; padding: var(--s3) var(--s4); position: relative; }
.rankRow + .rankRow::before {
  content: ''; position: absolute; inset-block-start: 0; inset-inline: var(--s4) 0;
  height: 1px; background: var(--separator);
}
.rankName { font-size: 15px; font-weight: 510; }
.rankMeta { font-size: 13px; color: var(--text-subtle); }
.rankCost { font-size: 15px; font-weight: 590; font-variant-numeric: tabular-nums; text-align: end; }
.rankCost small { display: block; font-size: 13px; font-weight: 400; color: var(--text-subtle); }
.blockReason { font-size: 13px; color: var(--danger); }

/* ---------------- waiting / first run ---------------- */
.waiting { padding-block: var(--s5) var(--s6); max-width: var(--prose); }
.waiting h3 { font-size: 24px; font-weight: 620; letter-spacing: -.022em; }
.waiting p { font-size: 17px; color: var(--text-muted); margin-block: var(--s3) 0; }
.primaryBtn {
  font: inherit; font-size: 15px; font-weight: 510; cursor: pointer;
  margin-block-start: var(--s5); padding: var(--s3) var(--s5);
  background: var(--accent); color: #fff; border: 0; border-radius: var(--r-pill);
  /* Deep stops: white clears 5.02:1 against the lightest of them. One sweep
     on hover, driven by a transition rather than a loop, so the motion ends
     instead of running for as long as the pointer happens to rest there. */
  background-image: var(--ai-sweep-deep-loop);
  background-size: 200% 100%;
  background-position: 0 0;
  transition: background-position var(--t-standard) var(--ease), opacity var(--t-fast) var(--ease);
}
.primaryBtn:hover, .primaryBtn:focus-visible { background-position: 100% 0; }
.waitingAlt { font-size: 14px; color: var(--text-subtle); margin-block-start: var(--s3); }

/* Marks an answer as belonging to a built-in example, not the user's task. */
.exampleTag {
  font-size: 14px; color: var(--text-muted);
  background: var(--sunken); border-radius: var(--r);
  padding: var(--s2) var(--s3); margin-block-end: var(--s4);
  display: inline-block; max-width: var(--prose);
}
.exampleTag strong { color: var(--text); font-weight: 590; }

/* "Required" marker on the one input the page cannot work without. */
.req {
  font-size: 12px; font-weight: 510; color: var(--accent);
  background: var(--accent-wash); border-radius: var(--r-sm);
  padding: 1px var(--s2); margin-inline-start: var(--s1); vertical-align: 2px;
}

/* ---------------- chart ---------------- */
.chart { margin: 0 0 var(--s5); }
.chartSvg {
  width: 100%; height: auto; display: block;
  background: var(--surface); border-radius: var(--r-lg);
}
.cGrid { stroke: var(--separator); stroke-width: 1; }
.cAxis { stroke: var(--separator-strong); stroke-width: 1; }
.cTick { font-size: 11px; fill: var(--text-subtle); font-family: var(--sans); }
.cAxisTitle { font-size: 11px; fill: var(--text-subtle); font-family: var(--sans); }
.cLabel { font-size: 12px; font-family: var(--sans); }
.cNote { font-size: 10px; fill: var(--text-subtle); font-family: var(--sans); }
/* The current call size, marked so the chart relates to the sidebar. */
.cNow { stroke: var(--text); stroke-width: 1; stroke-dasharray: 2 3; opacity: .45; }
.cNowLabel { font-size: 10px; fill: var(--text-muted); font-family: var(--sans); }

.chartCap {
  font-size: 14px; color: var(--text-muted); line-height: 1.55;
  max-width: var(--prose); margin-block-start: var(--s3);
}
.chartCap strong { color: var(--text); font-weight: 590; }
.chartKey, .chartDrop { display: block; margin-block-start: var(--s2); font-size: 13px; color: var(--text-subtle); }
.kSolid, .kDash { font-weight: 590; color: var(--text-muted); }
.kDash { border-block-end: 2px dashed var(--text-subtle); }
.kSolid { border-block-end: 2px solid var(--text-subtle); }

/* ---------------- table ---------------- */
.tblWrap { overflow-x: auto; background: var(--surface); border-radius: var(--r-lg); }
table { width: 100%; border-collapse: collapse; font-size: 14px; min-width: 780px; }
caption { text-align: start; font-size: 13px; color: var(--text-subtle); padding: var(--s3) var(--s4); }
th, td { padding: var(--s2) var(--s4); text-align: start; border-block-start: 1px solid var(--separator); white-space: nowrap; }
thead th { font-size: 13px; color: var(--text-subtle); font-weight: 400; }
tbody th { font-weight: 510; }
td.num { text-align: end; font-family: var(--mono); font-size: 13px; font-variant-numeric: tabular-nums; }
tbody tr:hover { background: var(--sunken); }
tbody tr.out { color: var(--text-subtle); }

.tag { font-size: 12px; padding: 1px var(--s2); border-radius: var(--r-sm); margin-inline-start: var(--s2); white-space: nowrap; font-weight: 400; }
.tag.kb { background: var(--success-wash); color: var(--success); }
.tag.web { background: var(--accent-wash); color: var(--accent); }
.tag.assumed { background: var(--warning-wash); color: var(--warning); }
.tag.derived { background: var(--sunken); color: var(--text-muted); }
.tag.family { background: var(--sunken); color: var(--text-subtle); }

/* ---------------- code ---------------- */
.codeHead { display: flex; justify-content: space-between; align-items: center; gap: var(--s3); margin-block-end: var(--s3); flex-wrap: wrap; }
.codeHead .lbl { margin: 0; font-family: var(--mono); font-size: 13px; color: var(--text-subtle); }
.copyBtn {
  font: inherit; font-size: 14px; padding: var(--s2) var(--s4); cursor: pointer;
  background: var(--text); color: var(--surface); border: 0; border-radius: var(--r-pill);
  transition: opacity var(--t-fast) var(--ease);
}
.copyBtn:hover { opacity: .82; }
.copyBtn.done { background: var(--success); }
pre {
  margin: 0; padding: var(--s4); background: var(--surface);
  border-radius: var(--r-lg); overflow-x: auto; font-family: var(--mono);
  font-size: 13px; line-height: 1.7; color: var(--text);
}
pre:focus-visible { outline-offset: -3px; }
pre .c { color: var(--text-subtle); }
pre .k { color: #9a3fb0; }
pre .s { color: var(--success); }
pre .n { color: var(--danger); }

.note { font-size: 14px; color: var(--text-muted); line-height: 1.55; max-width: var(--prose); margin-block-end: var(--s4); }
.note strong { color: var(--text); font-weight: 590; }
.note code { font-family: var(--mono); font-size: 13px; }
.note.warnNote { background: var(--warning-wash); color: #6b4700; padding: var(--s3) var(--s4); border-radius: var(--r); }
.note.warnNote strong { color: #4d3300; }

.legend { display: flex; gap: var(--s4); flex-wrap: wrap; margin-block-start: var(--s3); font-size: 13px; color: var(--text-subtle); }

.empty { padding-block: var(--s6); color: var(--text-muted); max-width: var(--prose); }
.empty h3 { font-size: 21px; color: var(--text); margin-block-end: var(--s2); }
.empty ul { padding-inline-start: var(--s5); }

.errorState { background: var(--danger-wash); border-radius: var(--r-lg); padding: var(--s5); max-width: var(--prose); }
.errorState h3 { font-size: 19px; color: var(--danger); margin-block-end: var(--s2); }
.errorState p { font-size: 15px; color: var(--text-muted); }
.errorState code { font-family: var(--mono); font-size: 13px; }

ol.checklist { margin: 0; padding-inline-start: var(--s5); font-size: 14px; color: var(--text-muted); columns: 2; column-gap: var(--s6); }
ol.checklist li { margin-block-end: var(--s1); break-inside: avoid; }

.footnote { margin-block-start: var(--s6); font-size: 13px; color: var(--text-subtle); }

/* ---------------- responsive ---------------- */
@media (max-width: 1000px) {
  .layout { grid-template-columns: 1fr; gap: var(--s5); }
  .controls { position: static; max-height: none; }
}
@media (max-width: 620px) {
  .topbar { padding: var(--s4) var(--s4) var(--s3); }
  .layout { padding: 0 var(--s4) var(--s7); }
  .hero { margin-block-start: var(--s4); }
  .barRow { grid-template-columns: 1fr 64px 48px; }
  .rankRow { grid-template-columns: 1fr; gap: var(--s1); }
  .rankCost { text-align: start; }
  ol.checklist { columns: 1; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}
