/* ============================================================================
   config.css - Config Tuner only.

   Loads AFTER ook.css (tokens, reset, nav, footer, buttons, cards, badges,
   .hero / .hero-grid / .hero-copy / .hero-art, .shead, .tile, .rail-card,
   focus, preference blocks) and after optimization/style.css (tool-step,
   inputs, drop zone, recommendation rows). Everything here is either a page
   layout the other two cannot know about, or a deliberate override of a shared
   rule for this page. No tokens are defined here except the page's single
   measure, and no shared component is redeclared - ook.css owns them.
   ========================================================================== */


/* ============================================================================
   1. PAGE FRAME
   ONE measure for the whole working column. Every direct child of the step
   column inherits it, so the callouts, the panel, the drop target, the
   recommendation rows and the "Putting it back" hairlines all close on the
   same right edge instead of the three the page used to carry.
   ========================================================================== */

main { --measure: 640px; }

/* Steps left, the download rail pinned in the right column from the first step
   down, tracking the review list for its whole length. The hero is a band
   ABOVE this grid, so the rail can never open above the headline. Source order
   is reading order - the rail follows step 3 - so the counter, the tab order
   and the small-screen stack all stay correct. */
.page-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s7);
  counter-reset: step;
}

.page-col { min-width: 0; }

/* The single width constraint for the working column: nothing inside it needs
   its own max-width, and nothing inside it may have one. */
#steps { max-width: var(--measure); }

@media (min-width: 68em) {
  .page-grid {
    grid-template-columns: minmax(0, 1fr) minmax(18rem, 22rem);
    column-gap: var(--s7);
    align-items: start;
  }

  .page-col { grid-column: 1; grid-row: 1; }

  /* The rail's grid area spans the full row, so sticky has the whole page
     length to travel; align-self keeps the card itself at the top of it. */
  .tuner-rail {
    grid-column: 2;
    grid-row: 1;
    align-self: start;
    position: sticky;
    top: calc(var(--nav-h) + var(--s5));
    max-height: calc(100dvh - var(--nav-h) - var(--s6));
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  .tuner-rail .rail-card { max-width: none; box-shadow: var(--sh-3), var(--hairline); }
}

/* One rhythm for the whole page: chapters at --section-y (the shared scale
   every other page uses), the steps inside one chapter a touch tighter. */
main > section + section { margin-top: var(--section-y); }
.tool-step + .tool-step { margin-top: clamp(56px, 6vw, 88px); }

/* Hero rhythm - the SAME two lines on all six sub-site surface pages (guide,
   config, audit, commands, binds, changes): a tighter band than the shared one,
   because every hero here is now a heading, one line and one action, and the
   tool or list under it is the point. Set page-locally rather than in
   ook.css because the gallery pages consume the shared band too. */
.hero { padding-block: clamp(32px, 3.5vw, 48px) var(--s5); }
main > .hero + section { margin-top: var(--s6); }

/* No leading offset on the working column: the rail card and the step-1
   heading start on the same y. */
#steps { margin-top: 0; }

/* Two-paragraph section decks: the shared .shead has one gap value, not two. */
.shead p + p { margin-top: var(--s3); }

.noscript-note { margin-top: var(--s5); }

/* The page's one non-obvious trust claim is said ONCE, by the eyebrow. The
   shield line under the lede repeated it in a second wording two lines later,
   so the fold is now the headline, the job, and the file - nothing else. */

/* An inline token must not push its line apart: fixed leading, padding on the
   box instead. Without this the one line carrying a code chip is visibly
   taller than its neighbours. */
code {
  line-height: 1;
  padding: .15em .4em;
  vertical-align: baseline;
}


/* ============================================================================
   2. HERO ART - the file this page writes
   Not a picture of an app: three real convars, one from each family the tool
   touches, and one real derivation. It carries the same surface recipe as the
   shared card system, and it is decorative - the copy beside it says all of
   this in prose.
   ========================================================================== */

.cfg-plate {
  background: linear-gradient(180deg, #221e1a 0%, #1b1714 100%);
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .045),
              0 10px 28px rgba(0, 0, 0, .40);
  padding: var(--s5);
}

.cfg-plate-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line-2);
}

.cfg-plate-name {
  color: var(--fg-1);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}

.cfg-plate-cap {
  color: var(--fg-3);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: var(--tk-label);
  line-height: var(--lh-label);
  text-transform: uppercase;
  white-space: nowrap;
}

.cfg-plate-body { margin-top: var(--s1); }

.cfg-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: var(--s4);
  padding-block: 9px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-label);
}

.cfg-line + .cfg-line { border-top: 1px solid var(--line-1); }

.cfg-line .ck { color: var(--fg-2); overflow-wrap: anywhere; }
.cfg-line .cv { color: var(--accent-300); font-variant-numeric: tabular-nums; }

.cfg-line .cd {
  grid-column: 1 / -1;
  justify-self: end;
  margin-top: 3px;
  color: var(--fg-3);
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
}

/* The plate stays on a phone. It is the one honest visual this page has, and
   dropping it leaves an all-text fold; it is also the answer to "what do I get
   out of this", which is worth more on a small screen than on a large one. It
   pays for the space by shedding the derivation caption, the only line that
   needs a second row it cannot afford at this width. */
@media (max-width: 47.99em) {
  .cfg-plate { padding: var(--s4); }
  .cfg-line { padding-block: 7px; font-size: var(--fs-2xs); }
  .cfg-line .cd { display: none; }
}


/* ============================================================================
   3. NUMBERED STEP HEADINGS
   Same token as ook.css's .stepnum - accent digit in a warm ring - drawn from
   a counter so the markup carries no numerals.
   ========================================================================== */

.step-head {
  counter-increment: step;
  display: flex;
  align-items: center;
  gap: var(--s3);
}

.step-head::before,
.steps-list li::before {
  content: counter(step);
  flex: none;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: var(--r-full);
  background: var(--bg-3);
  border: 1px solid var(--accent-600);
  color: var(--accent-300);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1;
}


/* ============================================================================
   4. FORM CONTROLS
   One label token for every field on the page, and the page draws its own
   checkboxes and radios: the visible box is the WRAPPER, never the input, so
   an engine that refuses to paint a border on appearance:none can still not
   leave the control invisible. Checkbox and radio are ONE family - same size,
   same 1.5px solid rest border, same fill on check. Nothing on this page uses
   a dashed control edge; dashed belongs to the drop target alone.
   ========================================================================== */

.field-label {
  display: block;
  margin-bottom: var(--s2);
  color: var(--fg-3);
  font-size: var(--fs-2xs);
  font-weight: 600;
  line-height: var(--lh-label);
  text-transform: uppercase;
  letter-spacing: var(--tk-label);
}

input[type="number"],
input[type="text"] {
  background: var(--bg-1);
  border: 1px solid var(--stroke);
  border-radius: var(--r-sm);
  color: var(--fg-1);
  min-height: 36px;
  padding: 0 var(--s3);
  font-size: var(--fs-sm);
  transition: border-color var(--dur-base) var(--ease-std),
              background-color var(--dur-base) var(--ease-std);
}

input[type="number"]:hover,
input[type="text"]:hover { border-color: var(--fg-3); }

/* Spinners differ in metric and chrome across all three engines and eat part
   of the declared width; the field is a plain text box on every one of them. */
input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

input[aria-invalid="true"] { border-color: var(--warn-line); }

textarea { resize: vertical; }

/* -- Custom checkbox / radio -------------------------------------------- */
.pick,
fieldset.inp label.pick {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  column-gap: var(--s3);
  align-items: start;
  min-height: 32px;
  margin-right: 0;
  padding-block: 5px;
  cursor: pointer;
  color: var(--fg-1);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.pick-box,
.rec-check {
  grid-column: 1;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  flex: none;
  border: 1.5px solid var(--stroke);
  border-radius: var(--r-sm);
  background: var(--bg-1);
  cursor: pointer;
  transition: background-color var(--dur-base) var(--ease-std),
              border-color var(--dur-base) var(--ease-std),
              opacity var(--dur-base) var(--ease-std);
}

.pick-box:has(input[type="radio"]) { border-radius: var(--r-full); }

/* The input keeps the whole hit area and all its semantics, and paints
   nothing: every pixel of the control comes from the wrapper above. The focus
   ring is ook.css's, drawn on this input - it is what a keyboard reader
   follows down a page that is nothing but checkboxes. */
.pick-box input,
.rec-check input[type="checkbox"] {
  grid-area: 1 / 1;
  appearance: none;
  -webkit-appearance: none;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 0;
  border-radius: inherit;
  background: transparent;
  cursor: inherit;
}

.pick-mark {
  grid-area: 1 / 1;
  width: 16px;
  height: 16px;
  color: #1b1410;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-base) var(--ease-std);
}

.pick-text { grid-column: 2; }

.pick:hover .pick-box,
.rec-row:hover .rec-check { border-color: var(--accent-400); }

/* One checked state for both: the control fills with the brand and the mark
   is cut out of it dark. A radio differs from a checkbox in shape only. */
.pick-box:has(input:checked),
.rec-check:has(input:checked) {
  background: var(--accent-500);
  border-color: var(--accent-500);
}

input:checked ~ .pick-mark { opacity: 1; }

.pick-box:has(input:disabled),
.rec-check:has(input:disabled) { opacity: .5; cursor: not-allowed; }


/* ============================================================================
   4b. FOCUS - the ring traces the control you can SEE
   Every tickable control on this page is an appearance:none input lying on top
   of a wrapper that paints the box. ook.css rings the input; these rules put
   the same ring on the WRAPPER too, so a keyboard reader following seventeen
   checkboxes down the page sees a ring around the painted control rather than
   around a transparent square inside it. The offset is the shared 3px, and the
   wrapper's edge warms at the same time - two signals for one event.
   ========================================================================== */

.pick-box:has(input:focus-visible),
.rec-check:has(input:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-color: var(--accent-400);
}

.rec-row:has(.rec-check input:focus-visible) { border-color: var(--accent-600); }

/* Same ring, same offset, on everything else that takes focus in the working
   column and in the rail: the disclosures, the free-text values, the two
   downloads and the two selection actions. */
.rec-why > summary:focus-visible,
.rail-disc > summary:focus-visible,
.paste-alt > summary:focus-visible,
.others > summary:focus-visible,
.yourcall > summary:focus-visible,
.more > summary:focus-visible,
.q > summary:focus-visible,
.textlink:focus-visible,
.rail-link:focus-visible,
.jump-dl:focus-visible,
.btn:focus-visible,
.dl-btn:focus-visible,
input[type="number"]:focus-visible,
input[type="text"]:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

/* The file input is visually hidden but stays focusable, so its ring is drawn
   on the visible affordance instead - the button inside the drop target. */
.drop:has(input:focus-visible) { outline: none; border-color: var(--accent-500); }

.drop:has(input:focus-visible) .drop-btn {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-color: var(--accent-400);
}


/* ============================================================================
   5. STEP 1 - one panel, one grid, everything top-aligned
   ========================================================================== */

.panel { padding: var(--s5); }

.inputs-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--s5) var(--s6);
  align-items: start;
}

.inp { max-width: none; }
.inp-wide { grid-column: 1 / -1; }

.inp input[type="number"],
.inp input[type="text"] {
  margin-top: 0;
  padding: 0 var(--s3);
  min-height: 36px;
  font-size: var(--fs-sm);
  width: 9rem;
}

/* No second card inside the panel: the fieldset keeps its grouping semantics
   and loses its chrome, so the three controls share one visual surface. The
   float is what stops the legend cutting a notch through anything. */
fieldset.inp {
  border: 0;
  border-radius: 0;
  padding: 0;
}

fieldset.inp legend {
  float: left;
  width: 100%;
  padding: 0;
}

.pick-group {
  clear: both;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s5);
}

.inp-sub {
  clear: both;
  margin-top: var(--s4);
  padding-top: var(--s4);
  border-top: 1px solid var(--line-1);
}

/* Help text lives OUTSIDE its label, so the links inside it are not nested
   interactive content and the field's accessible name is just its name. */
.inp-help { max-width: none; }
.inp-help-indent { padding-left: calc(20px + var(--s3)); }

/* The advanced opt-in and its "when?" mark on one line. The mark is a sibling
   of the label, never a child: a <details> inside a <label> would be a second
   interactive target inside the checkbox's own hit area. Open on a narrow
   screen the popover goes static, so it takes a full row of its own rather
   than squeezing the label. */
.pick-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s1) var(--s3);
}

/* The same arrangement one level up, for a field whose depth belongs beside its
   LABEL rather than beside a checkbox: the mark is a sibling of the label, so
   the help span the input names by aria-describedby stays a plain span. */
.label-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s1) var(--s3);
  margin-bottom: var(--s2);
}

.label-row .field-label { margin-bottom: 0; }

/* A convar chip inside a 38ch popover has room to break mid-token, and a
   wrapped "-cpu_affinity" reads as a typo rather than a name. It always fits
   on a line of its own. */
.q-pop code { white-space: nowrap; }

@media (max-width: 40em) {
  .pick-row .q[open],
  .label-row .q[open] { flex: 1 0 100%; }
}

.inp-err {
  display: block;
  margin-top: var(--s2);
  color: var(--warn-fg);
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: var(--lh-snug);
}


/* ============================================================================
   6. STEP 2 - drop zone as a real label, on the column measure
   ========================================================================== */

.drop {
  position: relative;
  display: grid;
  justify-items: center;
  gap: var(--s1);
  width: 100%;
  max-width: none;
  padding: var(--s7) var(--s5);
  transition: border-color var(--dur-base) var(--ease-std),
              background-color var(--dur-base) var(--ease-std),
              color var(--dur-base) var(--ease-std),
              transform var(--dur-fast) var(--ease-std);
}

/* Visually hidden but still focusable: display:none would drop the only file
   picker on the page out of the tab order entirely. */
.drop input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: 0;
  opacity: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.drop .icon {
  margin: 0 0 var(--s2);
  transition: transform var(--dur-base) var(--ease-out),
              color var(--dur-base) var(--ease-std);
}

.drop:hover .icon { color: var(--accent-400); }
.drop.over { transform: scale(1.005); }
.drop.over .icon { transform: translateY(-2px); color: var(--accent-400); }

.drop-title { color: var(--fg-1); font-weight: 500; }

/* The only click affordance in this step was a clause inside a sentence. It is
   a control now: its own line, its own edge. The whole target is still a
   label, so this stays a span - a nested button would be a second, competing
   hit area inside the first. */
.drop-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  margin-top: var(--s2);
  padding-inline: var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  color: var(--fg-1);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: border-color var(--dur-base) var(--ease-std),
              background-color var(--dur-base) var(--ease-std);
}

.drop:hover .drop-btn { border-color: var(--stroke); background: var(--bg-2); }

/* The keys.cfg aside: a real question, asked by a minority, answered without
   standing between the Steam path and the file picker - so it sits below the
   picker with the other two asides, not above it. */
.step-more { margin-top: var(--s3); }

.drop.loaded { border-style: solid; border-color: var(--ok); }
.drop.loaded .icon { color: var(--ok); }

.paste-alt > summary { gap: var(--s2); }
.paste-body { margin-top: var(--s3); }
.paste-alt textarea { width: 100%; max-width: none; margin-bottom: var(--s3); }

/* Touching the target it answers for: "did that work?" is answered where the
   question was asked, not three blocks further down the step. */
.file-status {
  margin-top: var(--s3);
  color: var(--ok);
  line-height: var(--lh-snug);
}

/* Empty it occupies no space, but it is never display:none - a live region
   removed from the tree is a live region a screen reader may not announce
   when the answer finally arrives. */
.file-status:empty { margin: 0; min-height: 0; }

.file-status.is-error { color: var(--warn-fg); }


/* ============================================================================
   7. STEP 3 - the review list
   Three tracks and nothing else: control, content, state. Every checkbox,
   every convar, every value label and every status chip therefore lands on one
   x down the whole list, however long a name or a label runs.
   ========================================================================== */

/* Below the two-column breakpoint the download is not beside this list, it is
   after it: eight rows and a summary stand between the reader and the button.
   One line at the top of the list carries the same count and the way down to
   it. Above 68em the sticky rail is on screen the whole way, so this would be
   a second copy of a number already in view. */
.jump-dl {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  margin-bottom: var(--s5);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  background: var(--bg-2);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  text-decoration: none;
  transition: border-color var(--dur-base) var(--ease-std),
              color var(--dur-base) var(--ease-std);
}

.jump-dl b { color: var(--accent-300); font-weight: 600; }
.jump-dl:hover { border-color: var(--stroke); color: var(--fg-0); }

.jump-go {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  flex: none;
  color: var(--fg-1);
  font-weight: 500;
}

.jump-go svg { color: var(--fg-3); }

@media (min-width: 68em) {
  .jump-dl { display: none; }
}

/* Appears the instant a file loads, i.e. at peak impatience - so it appears
   as one line, not as a paragraph. */
#loaded-hint { margin: 0 0 var(--s5); }

/* No filled control in this cluster: the one loud button on the page is the
   download in the rail. "Clear selection" is the undo of a thing you just
   did, not a peer of the action that does it. The cluster itself is absent
   until there is a selection to sweep - display:flex would otherwise beat the
   UA's [hidden] rule and paint an already-satisfied button. */
.review-actions {
  display: flex;
  align-items: center;
  gap: var(--s5);
  margin-bottom: var(--s5);
}

.review-actions[hidden] { display: none; }

.textlink {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 32px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--fg-2);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--dur-base) var(--ease-std);
}

.textlink:hover { color: var(--fg-0); }
.textlink:hover > span { text-decoration: underline; text-underline-offset: 3px; }
.textlink svg { color: var(--fg-3); transition: color var(--dur-base) var(--ease-std); }
.textlink:hover svg { color: var(--accent-400); }

.rec-row {
  padding: var(--s4);
  transition: border-color var(--dur-base) var(--ease-std),
              background-color var(--dur-base) var(--ease-std),
              box-shadow var(--dur-base) var(--ease-std),
              opacity var(--dur-base) var(--ease-std);
}

/* No left bar on a row. An accent bar down the left edge is callout language
   on this site, and a row wearing it reads as a notice rather than as a state.
   What a row wants is already said, in words, by its status chip; what a row
   IS is said by its own edge, below. */
.rec-row.st-diff,
.rec-row.st-missing,
.rec-row.st-baseline { border-left: 1px solid var(--line-2); }

.rec-row:hover { border-color: var(--line-2); background-color: var(--bg-3); }
.rec-row:focus-within { border-color: var(--accent-600); }
.rec-row.st-ok { opacity: .82; }
.rec-row.st-ok:hover,
.rec-row.st-ok:focus-within { opacity: 1; }

/* Ticked: the whole edge warms and the whole surface takes a faint wash, so
   "chosen" is a property of the card rather than a mark pinned to its side.
   The wash is weak on purpose - eight consecutive selections still have to
   read as eight rows and not as one orange slab. */
.rec-row:has(.rec-check input:checked) {
  border-color: rgba(216, 112, 60, .45);
  background-color: rgba(216, 112, 60, .06);
}

.rec-row:has(.rec-check input:checked):hover { background-color: rgba(216, 112, 60, .10); }

.rec-head {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  column-gap: var(--s4);
  row-gap: var(--s1);
  align-items: start;
}

.rec-check { align-self: start; margin-top: 1px; }

/* A row nobody can tick still shows its control, greyed: an empty column is
   how a page tells the reader its own premise is broken. */
.rec-row.no-tick .rec-check { opacity: .45; }

/* Already correct: a quiet check, so "done" is visible at a glance. */
.rec-row.st-ok .rec-check {
  border-color: var(--dif-easy-line);
  background: var(--bg-3);
  opacity: .8;
}

.rec-row.st-ok .rec-check .pick-mark { opacity: 1; color: var(--dif-easy-fg); }

.rec-name,
.rec-label { cursor: pointer; }
.rec-row.no-tick .rec-name,
.rec-row.no-tick .rec-label { cursor: default; }

/* The convar chip sizes off its label, not off body copy: at body size a
   36-character name overruns its column and breaks mid-word. */
.rec-name {
  grid-column: 2;
  min-width: 0;
  margin: 0;
  font-size: var(--fs-xs);
  line-height: var(--lh-label);
}

.rec-label {
  grid-column: 2;
  margin: 0;
  color: var(--fg-1);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-snug);
}

/* Evidence is a label, not a badge: one filled pill per row, and it is the
   one that says what to do about the row. Stacked, the cluster spans the
   content column and pushes the chip to its right edge, so the chips still
   read as one straight column on a phone. */
.rec-meta {
  grid-column: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-width: 0;
}

/* The evidence label is the site-wide dot-label: one hue dot from the shared
   evidence ramp, then uppercase text, and no pill of its own - the guide
   renders the identical component. The ev-* classes are ook.css's; the fill
   and border they carry in their badge form are stripped here so the only
   thing that crosses over is the hue, and it lands in the dot. */
.claim {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--fg-3);
  font-size: var(--fs-2xs);
  font-weight: 500;
  line-height: var(--lh-label);
  text-transform: uppercase;
  letter-spacing: var(--tk-label);
  white-space: nowrap;
}

.claim.ev-measured,
.claim.ev-consensus,
.claim.ev-vendor,
.claim.ev-inference {
  background: none;
  border: 0;
  padding: 0;
  color: var(--fg-3);
}

.claim .dot {
  width: 5px;
  height: 5px;
  flex: none;
  border-radius: var(--r-full);
  background: var(--fg-3);
}

.claim.ev-measured  .dot { background: var(--ev-measured-fg); }
.claim.ev-consensus .dot { background: var(--ev-consensus-fg); }
.claim.ev-vendor    .dot { background: var(--ev-vendor-fg); }
.claim.ev-inference .dot { background: var(--ev-inference-fg); }


/* -- Group headers: the list changes character halfway down ------------------
   Above, every row has a recommended value and a tick box. Below, every row
   has a direction and an empty field. A hairline, a micro-label and a live
   count mark the seam, so seventeen cards read as two blocks. */
.rec-group {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4);
  margin: var(--s6) 0 var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--line-1);
}

.rec-group:first-child { margin-top: 0; }

.rec-group-title {
  margin: 0;
  color: var(--fg-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: var(--lh-label);
  text-transform: uppercase;
  letter-spacing: var(--tk-label);
}

.rec-group-count {
  margin: 0;
  color: var(--fg-3);
  font-size: var(--fs-2xs);
  font-weight: 500;
  line-height: var(--lh-label);
  text-transform: uppercase;
  letter-spacing: var(--tk-label);
  white-space: nowrap;
}

.rec-group-count b { color: var(--accent-300); font-weight: 600; }

/* -- The advisory block: one summary, not seven rows ------------------------
   The tool cannot act on any of these - no tick box, no computed value, just a
   direction and a field to type your own number in. Left inline they were a
   third of the mobile page standing between the diff the reader came for and
   the download button. Collapsed, the surface of step 3 is the ten rows the
   page can actually do something about, and the seam still carries its live
   count so nothing looks hidden. */
.yourcall {
  margin-top: var(--s6);
  padding-top: var(--s3);
  border-top: 1px solid var(--line-1);
}

.yourcall > summary {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: 34px;
  color: var(--fg-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: var(--lh-label);
  text-transform: uppercase;
  letter-spacing: var(--tk-label);
}

.yourcall > summary b { color: var(--accent-300); font-weight: 600; }
.yourcall-body { margin-top: var(--s3); }

.yourcall-note {
  margin: 0 0 var(--s4);
  color: var(--fg-3);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

/* -- The values: label and value sized to their content, never to a track ---
   Fixed offsets left ~180px of every row empty and forced a sentence into a
   30px slot. Both pairs size themselves and sit next to each other; anything
   that is a sentence rather than a value takes its own full-width line. */
.rec-vals {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s2) var(--s6);
  margin: var(--s3) 0 0 calc(20px + var(--s4));
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}

.rec-vals .val {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  column-gap: var(--s3);
  row-gap: var(--s1);
  align-items: baseline;
  min-width: 0;
}

.vlabel {
  color: var(--fg-3);
  font-size: var(--fs-2xs);
  font-weight: 600;
  line-height: var(--lh-label);
  text-transform: uppercase;
  letter-spacing: var(--tk-label);
}

.vbody { min-width: 0; color: var(--fg-1); }

/* A value the file does not have is still a value, not disabled chrome: one
   step below the values around it, not three. Same for the placeholder in the
   free-text fields, one step below that again. */
.none { color: #a79684; font-weight: 400; }
input::placeholder, textarea::placeholder { color: #8b7b6b; opacity: 1; }
.deriv { color: var(--fg-2); font-variant-numeric: tabular-nums; }

/* Not italics: a slanted system face in a dense table reads as an accident.
   These two carry no label, so they run the full width instead of the pair. */
.rec-vals .v-pending,
.rec-vals .dup-warn {
  display: block;
  grid-template-columns: none;
}

.v-pending {
  color: var(--accent-300);
  font-size: var(--fs-xs);
  font-weight: 500;
}

.dup-warn { color: var(--imp-med-fg); font-size: var(--fs-xs); }

/* A sentence, not a value: its own line, at meta size. */
.rec-vals .v-dir { font-size: var(--fs-xs); }
.rec-vals .v-dir .vbody { color: var(--fg-2); line-height: var(--lh-snug); }

.custom-val { align-items: center; }
.custom-val input { width: 8rem; }

/* The chevron's ink starts 6px inside its 16px box, so a summary flush with
   the column would hang 6px right of the code chip above it. Pulled back by
   exactly that, the arrow's optical left edge lands on the column. */
.rec-why { margin: var(--s2) 0 0 calc(20px + var(--s4)); }

.rec-why > summary {
  gap: var(--s2);
  min-height: 28px;
  margin-left: -6px;
  padding-left: 6px;
}

.rec-why > summary:hover { color: var(--fg-0); }

/* Above this width the state chip moves to a third track and pins itself to
   the right edge, so the whole column of chips reads as one straight edge. */
@media (min-width: 48em) {
  .rec-head { grid-template-columns: 20px minmax(0, 1fr) auto; }
  .rec-label { grid-column: 2 / -1; }
  .rec-meta { grid-column: 3; grid-row: 1; justify-self: end; width: auto; }

  .rec-vals { grid-template-columns: max-content minmax(0, 1fr); }
  .rec-vals > .v-cur { grid-column: 1; }
  .rec-vals > .v-rec { grid-column: 2; }

  /* With no file there is no Yours track, so the recommended value takes the
     row back instead of sitting one gap in from an empty column. */
  #review.no-file .rec-vals > .v-rec { grid-column: 1 / -1; }

  .rec-vals > .v-dir,
  .rec-vals > .v-pending,
  .rec-vals > .custom-val,
  .rec-vals > .dup-warn { grid-column: 1 / -1; }
}

/* At desktop the list is most of the page, and fifteen cards of one uniform
   height is a wall. The convar, its title and its two values cannot share a
   line at this measure without something wrapping, so the height comes out of
   the padding, the interline air, and the Why disclosure - which moves up onto
   the values line and pins itself to the row's right edge, giving the list a
   second straight column. Opened, it takes the full width back. */
@media (min-width: 64em) {
  .rec-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    padding: 14px 18px;
  }

  .rec-head { grid-column: 1 / -1; row-gap: 2px; }
  .rec-vals { grid-column: 1; margin-top: var(--s2); }
  .rec-why { grid-column: 2; margin: var(--s2) 0 0 var(--s5); }
  .rec-why > summary { min-height: 24px; }

  .rec-row:has(.rec-why[open]) .rec-why {
    grid-column: 1 / -1;
    margin-left: calc(20px + var(--s4));
  }
}

/* -- Status chips: one warm ramp, filled only where there is something to do */
.st-chip.st-diff,
.st-chip.st-missing,
.st-chip.st-baseline {
  background: var(--imp-high-bg);
  color: var(--imp-high-fg);
  border-color: var(--imp-high-line);
}

/* "Your call" is not a warning - it is the absence of a default. A neutral
   warm outline, so the filled orange stays reserved for the states that have
   something for the reader to do. */
.st-chip.st-advisory {
  background: transparent;
  color: #cdbba8;
  border-color: rgba(205, 187, 168, .35);
}

.st-chip.st-pending {
  background: var(--bg-3);
  color: var(--accent-300);
  border-color: var(--accent-600);
}

.st-chip.st-ok {
  background: transparent;
  color: var(--dif-easy-fg);
  border-color: var(--dif-easy-line);
}

/* -- Fixes for your file ----------------------------------------------------
   Present only when a loaded file contradicts the client's own defaults, so it
   never appears on a first visit and never appears for a clean config. It is
   the one block on the page that is about the reader's file rather than about
   Rust, which is why it is bounded: a marked edge, not a heading in the same
   flow as the recommendations above it. */
.rec-fixes {
  margin-top: var(--s6);
  padding-left: var(--s4);
  border-left: 2px solid var(--warn-line);
}

.rec-fixes[hidden] { display: none; }

.rec-fixes > .rec-group { margin-top: 0; }

/* The block leads the list now, so it opens the column rather than closing a
   run of rows. `:first-child` cannot do this job on its own: hidden, the
   section is still the first CHILD, so the group after it would inherit a
   seam that has nothing above it. */
.rec-fixes:first-child { margin-top: 0; }
.rec-fixes[hidden] + .rec-group { margin-top: 0; }

.rec-fixes-note {
  margin: 0 0 var(--s4);
  max-width: 62ch;
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}


/* -- Other settings ---------------------------------------------------------
   No longer a name dump, so no longer a multi-column grid of names: each line
   in the reader's file is read back against the shared dataset, so a row now
   carries what the setting IS and a route to its full record. One column, and
   the row wraps rather than truncating - the description is the payload. */
.others ul {
  display: grid;
  gap: var(--s2);
  list-style: none;
  margin: var(--s3) 0 0;
  padding: 0;
}

.others li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s1) var(--s2);
  break-inside: avoid;
  font-size: var(--fs-xs);
  color: var(--fg-3);
}

.others li code { color: var(--fg-2); }
.others .ov { color: var(--fg-3); font-variant-numeric: tabular-nums; }
.others .od { flex: 1 1 18rem; min-width: 0; }
.others .od-quiet { color: var(--fg-4, var(--fg-3)); font-style: italic; }
.others .oref { flex: 0 0 auto; font-size: var(--fs-xs); }

/* A name that is not a setting in this client is the one finding in this list
   worth interrupting for, so it is the one thing here that carries colour. */
.others .oflag {
  color: var(--warn-fg);
  font-weight: 600;
  white-space: nowrap;
}

/* Set away from the value the client ships. Deliberately NOT the warning
   colour: a difference from a default is a fact about the file, and half of
   them are somebody's field of view. The reader gets both values and decides. */
.others .odef {
  color: var(--fg-1);
  font-weight: 600;
  white-space: nowrap;
}

.others .oth-dead code { color: var(--warn-fg); }
.others .oclaim { color: var(--fg-3); }

.others > summary { gap: var(--s2); }

.oth-alert {
  border: 1px solid var(--warn-line);
  border-radius: 999px;
  background: var(--warn-bg);
  color: var(--warn-fg);
  font-size: var(--fs-xs);
  padding: 1px var(--s2);
  white-space: nowrap;
}

.others-note {
  margin: var(--s3) 0 0;
  font-size: var(--fs-xs);
  color: var(--fg-3);
}

.others-note:empty { display: none; }

/* -- Both routes out of a row, on one line -------------------------------- */
.rec-routes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s4);
  margin: var(--s2) 0 0;
  font-size: var(--fs-xs);
}


/* ============================================================================
   7b. THE VERDICT - what a loaded file says, above what we would do to it
   Findings lead. The block only exists with a file in, and it is bounded the
   same way "Fixes for your file" is: this is about the reader's file, not
   about Rust. Same left rule, so the two read as one argument.
   ========================================================================== */

.verdict {
  margin-bottom: var(--s6);
  padding-left: var(--s4);
  border-left: 2px solid var(--warn-line);
}

.verdict[hidden] { display: none; }

.verdict-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s2) var(--s4);
  margin-bottom: var(--s3);
}

.verdict-top h3 {
  margin: 0;
  color: var(--fg-0);
  font-size: var(--fs-h3);
  letter-spacing: var(--tk-h3);
}

/* Same pill the "other settings" summary uses for its own alarm, so one
   warning shape covers the page. */
.verdict-flag {
  border: 1px solid var(--warn-line);
  border-radius: var(--r-full);
  background: var(--warn-bg);
  color: var(--warn-fg);
  font-size: var(--fs-xs);
  padding: 1px var(--s2);
  white-space: nowrap;
}

.verdict-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s3);
}

.verdict-list li {
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

/* The numeral is the payload here as everywhere else on this page. */
.verdict-list b {
  color: var(--accent-300);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.verdict-list .v-bad b { color: var(--warn-fg); }
.verdict-list .v-quiet { color: var(--fg-3); }
.verdict-list .v-ok b { color: var(--ok); }

/* The names are the part a reader screenshots, so they get their own line
   rather than being folded into the sentence. */
.v-names {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s2);
  margin-top: var(--s2);
}

.v-names code { font-size: var(--fs-xs); }

/* A tweak pack can push fifty settings off their shipped value. The chips stop
   at twelve and this says how many are behind the link. */
.v-more {
  align-self: center;
  color: var(--fg-3);
  font-size: var(--fs-xs);
}

.v-go {
  display: inline-block;
  margin-top: var(--s1);
  font-size: var(--fs-xs);
}

.verdict-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s2) var(--s4);
  margin-top: var(--s4);
}

.verdict-actions .copy-msg { min-height: 0; margin-top: 0; }


/* ============================================================================
   7c. THE CHECK-MY-CONFIG BAND
   Shown only on config/?check, where the HERO now carries the framing and the
   file step comes first. What is left for the band is the one orientation
   neither of them gives: which of this site's two tools the reader is in.
   ========================================================================== */

.check-lead {
  margin-bottom: var(--s6);
  padding: var(--s4) var(--s5);
  border: 1px solid var(--line-2);
  border-left: 2px solid var(--accent-500);
  border-radius: 0 var(--r-lg) var(--r-lg) 0;
  background: var(--bg-2);
}

.check-lead[hidden] { display: none; }

.check-lead p {
  margin: 0;
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
}


/* ============================================================================
   7d. THE DIFF - the page's central promise, made checkable
   No <pre> treatment exists in the design system and this is the only place
   that needs one, so it is built here out of shared tokens. Three fixed
   tracks: line number, marker, text. The text never wraps - a wrapped config
   line stops being checkable against the file it came from - so the BLOCK
   scrolls sideways inside its own box and the page body never does.
   ========================================================================== */

.diff-summary {
  margin: 0 0 var(--s3);
  color: var(--fg-1);
  font-size: var(--fs-sm);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-snug);
}

.diff-note {
  margin: 0 0 var(--s3);
  color: var(--accent-300);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.diff-note[hidden] { display: none; }

/* The legend marks in the deck, at the same weight they carry in the block. */
.dm-legend {
  display: inline-block;
  min-width: 1.1em;
  text-align: center;
  font-family: var(--font-mono);
  font-weight: 700;
}

.dm-del { color: var(--warn-fg); }
.dm-add { color: var(--ok); }

/* The frame exists for the edge fades: they must sit OVER the scrolling
   content and stay put while it moves, which a background on the scroller
   itself cannot do. config.js measures the overflow and toggles each side, so
   a fade only ever appears where there is genuinely more line to read. */
.diff-frame { position: relative; }

.diff-frame::before,
.diff-frame::after {
  content: "";
  position: absolute;
  top: 1px;
  bottom: 1px;
  width: 28px;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) ease;
}

.diff-frame::before {
  left: 1px;
  border-radius: var(--r-md) 0 0 var(--r-md);
  background: linear-gradient(to right, var(--bg-1), rgba(0, 0, 0, 0));
}

.diff-frame::after {
  right: 1px;
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: linear-gradient(to left, var(--bg-1), rgba(0, 0, 0, 0));
}

.diff-frame.more-left::before,
.diff-frame.more-right::after { opacity: 1; }

.diff-scroll {
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  background: var(--bg-1);
}

/* A scroll container that only some engines make focusable, made focusable
   everywhere: without this the clipped half of a long line is unreachable by
   keyboard in Safari. */
.diff-scroll:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* As wide as the longest line, and never narrower than the box: a changed
   line's tint has to reach the right edge on a short file, and has to keep
   going past it on a long one. */
.diff-body {
  width: max-content;
  min-width: 100%;
  padding-block: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 1.6;
}

.dline {
  display: flex;
  align-items: baseline;
  padding-right: var(--s4);
}

.dnum {
  flex: none;
  width: 3.75em;
  padding-right: var(--s3);
  color: var(--fg-4);
  text-align: right;
  font-variant-numeric: tabular-nums;
  user-select: none;
}

.dmark {
  flex: none;
  width: 1.25em;
  color: var(--fg-3);
  font-weight: 700;
  text-align: center;
  user-select: none;
}

/* pre, never wrap: a config line broken across two rows cannot be compared
   with the file it came from by eye. */
.dtext {
  white-space: pre;
  color: var(--fg-2);
  tab-size: 4;
}

.dl-del { background: rgba(194, 69, 47, .14); }
.dl-del .dmark { color: var(--warn-fg); }
.dl-del .dtext { color: var(--warn-fg); }

.dl-add { background: rgba(134, 201, 142, .12); }
.dl-add .dmark { color: var(--ok); }
.dl-add .dtext { color: var(--fg-1); }

/* A folded run of untouched lines. It is a disclosure, never a deletion: the
   promise is that every line survives, so every line stays readable. */
.dfold { margin: 0; }

.dfold > summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) var(--s4);
  color: var(--fg-3);
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  cursor: pointer;
  user-select: none;
}

.dfold > summary::-webkit-details-marker { display: none; }
.dfold > summary:hover { color: var(--fg-1); }
.dfold > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.dfold + .dfold > summary,
.dline + .dfold > summary { border-top: 1px solid var(--line-1); }
.dfold[open] > summary { border-bottom: 1px solid var(--line-1); }
/* Closed, the fold's summary sits flush against the next real line - the seam
   marks where the hidden run ends. */
.dfold + .dline { border-top: 1px solid var(--line-1); }

.diff-empty {
  margin: 0;
  padding: var(--s4);
  color: var(--fg-3);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
}

.diff-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s2) var(--s4);
  margin-top: var(--s4);
}

.diff-actions .copy-msg { min-height: 0; margin-top: 0; }

/* At 390px the gutter is the first thing to pay: the payload is the line. */
@media (max-width: 30em) {
  .diff-body { font-size: var(--fs-2xs); }
  .dnum { width: 2.75em; padding-right: var(--s2); }
  .dmark { width: 1em; }
}

/* A hidden step generates no box, so it also increments no counter - the diff
   is the last numbered step and disappears cleanly without a file. */
#step-diff[hidden] { display: none; }


/* ============================================================================
   8. STEP 4 - the download rail
   Header per the shared rail-card pattern: eyebrow, then the heading at card
   scale. A support panel does not get to shout at section volume, and the
   useful line - how many changes are selected - is the one that grows.
   ========================================================================== */

/* In flow (below the two-column breakpoint) the card must not stretch to the
   full container, or the two CTAs become 700px-wide bars. Surface, padding and
   the eyebrow/heading pattern are ook.css's - this adds width and rhythm only. */
.rail-card { max-width: 30rem; }
.rail-card > h2 { margin-bottom: var(--s4); }

.rail-count {
  color: var(--fg-1);
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: var(--lh-snug);
  margin-bottom: var(--s4);
}

.rail-count b { color: var(--accent-300); font-weight: 600; }

/* The missing input, said before the press. It is a next step, not an error -
   so it reads as secondary prose, not in the accent, which on the first screen
   would be the loudest sentence there for an instruction. It closes up under
   the count it qualifies. */
.rail-count:has(+ .rail-need:not([hidden])) { margin-bottom: var(--s2); }

.rail-need {
  margin: 0 0 var(--s4);
  color: var(--fg-2);
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: var(--lh-snug);
}

/* config/?check before a file is in: the card says what it is waiting for
   instead of shouting a download that route did not come for. */
.rail-idle {
  margin: 0 0 var(--s4);
  color: var(--fg-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.rail-idle[hidden] { display: none; }

.rail-card .dl-row { display: block; }
.rail-card .dl-btn { width: 100%; }
.rail-card .dl-btn[hidden] { display: none; }

/* Whichever download the page cannot deliver yet is the quiet one. It is never
   disabled: pressing it explains what is missing, which is more use than a
   dead button, and the page's loudest control is always one that works. */
.rail-card .dl-btn.secondary {
  border-color: var(--line-2);
  color: var(--fg-1);
  font-weight: 500;
}

.rail-card .dl-btn.secondary:hover { border-color: var(--stroke); }

/* Before a file is in, the one button on the first screen writes a FRESH
   client.cfg - the minority path, and not what the reader came here to do. So
   it keeps its place and its wording and loses the fill: nothing on the fold
   is louder than the file picker the page is actually waiting for. The moment
   a file is loaded the same button becomes the tuned download and the fill
   comes back. The state is read from the review list, which is what the script
   marks when there is no file - the button itself carries no class. */
.page-grid:has(#review.no-file) #dl-primary {
  background-image: none;
  background-color: var(--bg-2);
  border-color: var(--line-2);
  color: var(--fg-1);
  font-weight: 500;
  box-shadow: var(--sh-1), var(--hairline);
}

.page-grid:has(#review.no-file) #dl-primary:hover {
  background-color: var(--bg-3);
  border-color: var(--stroke);
  color: var(--fg-0);
  box-shadow: var(--sh-2), var(--hairline);
}

.rail-hint {
  margin-top: var(--s2);
  color: var(--fg-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.rail-hint + .dl-btn { margin-top: var(--s5); }

.dl-note {
  margin-top: var(--s3);
  color: var(--ok);
  line-height: var(--lh-snug);
}

.dl-note.is-error { color: var(--warn-fg); }

/* -- Two disclosures, one treatment: the explanation and the escape hatch --
   Both are asides to the two buttons above them, so neither is allowed to be
   a wall of 13px prose sitting open in the rail. */
.rail-disc { margin-top: var(--s4); }

.rail-disc + .rail-disc { margin-top: var(--s2); }

.rail-disc > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 32px;
  color: var(--fg-2);
  font-size: var(--fs-sm);
}

.rail-disc > .rail-hint { margin-top: var(--s1); }

.copy-body { margin-top: var(--s2); }

/* #copy-out is a <details class="rail-disc">, not a .copy-out - as a class
   selector this rule matched nothing and the escape hatch rendered as a
   browser-default grey box next to the themed paste field. */
#copy-out textarea {
  width: 100%;
  margin: var(--s2) 0 var(--s3);
  background: var(--bg-1);
  border: 1px solid var(--stroke);
  border-radius: var(--r-sm);
  color: var(--fg-1);
  padding: var(--s2) var(--s3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.copy-msg {
  display: block;
  min-height: 1.2em;
  margin-top: var(--s2);
  color: var(--ok);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.copy-msg.is-error { color: var(--warn-fg); }

/* Stacked (below the two-column breakpoint) the rail sits directly above
   "Putting it back", so this would be a jump link to the next thing on the
   screen. It exists only where the rail is a sticky column beside the list -
   there, the section it points at is genuinely far below the fold. */
.rail-link {
  display: none;
  align-items: center;
  gap: var(--s2);
  min-height: 32px;
  margin-top: var(--s4);
  padding-top: var(--s4);
  border-top: 1px solid var(--line-1);
  width: 100%;
  color: var(--fg-2);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
  transition: color var(--dur-base) var(--ease-std);
}

.rail-link:hover { color: var(--fg-0); }
.rail-link svg { color: var(--fg-3); transition: color var(--dur-base) var(--ease-std); }
.rail-link:hover svg { color: var(--accent-400); }

@media (min-width: 68em) {
  .rail-link { display: inline-flex; }
  /* The diff link is absent without a file, and [hidden] must beat the
     display above it or an empty row of chrome appears on first paint. */
  .rail-link[hidden] { display: none; }
}


/* ============================================================================
   9. PUTTING IT BACK - a designed ordered list, numbers from a counter
   ========================================================================== */

/* Below the rail the page stops being a two-column tool, so these last two
   sections take the whole container: their right edge lands on the same grid
   line as the footer's instead of stopping at the working measure and leaving
   a third of the viewport empty. The four steps become a strip of columns
   rather than a 1040px-wide list of one-line paragraphs. */
.steps-list {
  counter-reset: pb;
  list-style: none;
  margin: 0;
  padding: 0;
}

.steps-list li {
  counter-increment: pb;
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  column-gap: var(--s4);
  padding-block: var(--s4);
  border-top: 1px solid var(--line-1);
}

.steps-list li::before { content: counter(pb); grid-area: 1 / 1; }
.steps-list li:first-child { border-top: 0; padding-top: 0; }
.steps-list li:last-child { padding-bottom: 0; }

.steps-list h3 {
  grid-column: 2;
  font-size: var(--fs-body);
  letter-spacing: var(--tk-h3);
  margin-bottom: var(--s1);
}

.steps-list p {
  grid-column: 2;
  margin: 0;
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

/* The traps - a rename that silently becomes .bak.cfg, a second download that
   becomes client (1).cfg - are read-when-it-bites content. The strip states
   the four moves; these hold the caveat for the reader it happens to. */
.steps-list .more { grid-column: 2; margin-top: 0; }
.steps-list .more > summary { font-size: var(--fs-xs); }
.steps-list .more-body { margin-top: var(--s2); font-size: var(--fs-sm); }

/* Two up, then four up: every step keeps the same hairline over it, so the
   strip reads as one rule broken into columns rather than as stacked rows. */
@media (min-width: 48em) {
  .steps-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--s7);
    row-gap: var(--s5);
  }

  .steps-list li,
  .steps-list li:first-child,
  .steps-list li:last-child {
    border-top: 1px solid var(--line-1);
    padding-top: var(--s4);
    padding-bottom: 0;
  }
}

@media (min-width: 62em) {
  .steps-list { grid-template-columns: repeat(4, minmax(0, 1fr)); column-gap: var(--s6); }

  /* Side by side, a one-line title would start its paragraph a line above its
     neighbours'. Two lines of room for every title puts all four bodies on one
     baseline without a subgrid. */
  .steps-list h3 { min-height: 2.3em; }

  /* Three destinations since the Command Reference joined, so the band rides
     the shared tile-grid tracks: three across at this width. */
}


/* ============================================================================
   10. STATUS ENTRANCE
   A message written into a region the reader may not be looking at replays a
   short cue, so the change is noticed without any layout shift.
   ========================================================================== */

@keyframes cfg-status-in {
  from { opacity: 0; transform: translateY(-3px); }
}

.flash { animation: cfg-status-in var(--dur-slow) var(--ease-out); }


/* ============================================================================
   11. SMALL SCREENS
   ========================================================================== */

@media (max-width: 40em) {
  .rec-vals,
  .rec-why { margin-left: 0; }
  .drop { padding: var(--s6) var(--s4); }
  .inputs-row { gap: var(--s5); }
  .rec-row { padding: var(--s3); }
  .review-actions { gap: var(--s4); }
}

@media (pointer: coarse) {
  .pick { min-height: 44px; padding-block: var(--s3); }
}


/* ============================================================================
   12. USER PREFERENCE BLOCKS
   ========================================================================== */

@media (forced-colors: active) {
  .pick-box,
  .rec-check {
    border: 1px solid CanvasText;
    forced-color-adjust: none;
    background: Canvas;
  }

  .pick-box:has(input:checked),
  .rec-check:has(input:checked) { background: Highlight; }
  .pick-mark { color: HighlightText; }

  .panel,
  .rail-card,
  .cfg-plate,
  .drop,
  .drop-btn,
  .st-chip { border: 1px solid CanvasText; }

  .step-head::before,
  .steps-list li::before { border: 1px solid CanvasText; }

  .rec-row.st-ok { opacity: 1; }

  /* The tint that carries "chosen" everywhere else is dropped in this mode, so
     the edge has to carry it alone. */
  .rec-row:has(.rec-check input:checked) { border: 2px solid Highlight; }

  /* The diff's two tints go the same way. The -/+ markers are TEXT, so they
     survive on their own and the block stays readable without them. */
  .diff-scroll { border: 1px solid CanvasText; }
  /* A gradient cannot be trusted to render in this mode, and the scrollbar is
     forced visible anyway - so the edge cue is dropped rather than faked. */
  .diff-frame::before,
  .diff-frame::after { display: none; }
  .dl-del,
  .dl-add { background: none; }
  .dl-del .dtext,
  .dl-add .dtext,
  .dl-del .dmark,
  .dl-add .dmark { color: CanvasText; }
  .verdict-flag { border: 1px solid CanvasText; }
}

@media print {
  .page-grid { display: block; }
  .tuner-rail { position: static; max-height: none; overflow: visible; margin-top: var(--s6); }
  .hero-art,
  .dl-row,
  .rail-need,
  .rail-idle,
  .jump-dl,
  .rail-disc,
  .review-actions,
  .diff-actions,
  .verdict-actions,
  .drop,
  .paste-alt { display: none !important; }
  .rec-row { break-inside: avoid; }

  /* On paper the diff is the record of what was changed, so nothing about it
     may depend on a scrollbar or on a disclosure being open. */
  .diff-scroll { overflow: visible; }
  .diff-frame::before,
  .diff-frame::after { display: none; }
  .diff-body { width: auto; min-width: 0; }
  .dtext { white-space: pre-wrap; overflow-wrap: anywhere; }
  .dline { break-inside: avoid; }
  .dl-del,
  .dl-add { background: none; }
  .dl-del .dmark,
  .dl-del .dtext,
  .dl-add .dmark,
  .dl-add .dtext { color: inherit; }
}
