/* ============================================================================
   binds.css - the Bind Builder only.

   Loads AFTER ook.css (tokens, reset, nav, footer, buttons, cards, badges,
   .hero / .hero-grid / .hero-copy / .hero-art, .shead, .tile, .rail-card,
   .note, .more, .q, focus, preference blocks) and after optimization/style.css
   (.tool-step, .inp / .inp-help, the base .drop, .paste-alt, .file-status,
   .count, .slabel / .glabel, .noscript-note). Nothing shared is redeclared
   here: ook.css owns its components and this file only adds what a page with a
   key picker, a chain builder and a five-bucket file reader needs on top.

   ONE DELIBERATE DUPLICATION, and it is worth naming. The form recipe
   (.field-label, .pick / .pick-box / .pick-mark, .pick-group, .inp-sub), the
   cfg plate, the step counter and the load-control block are declared in
   config/config.css and audit/audit.css, which this page does not load - a
   stylesheet is per page, and copying two other pages' stylesheets in for four
   components would be worse than copying the four components. They are copied
   VERBATIM in behaviour and class name rather than reinvented under new names,
   so a reader meets one checkbox, one drop target and one status line across
   all three tools, and so the day a third page needs them the move into
   style.css is a cut and paste rather than a redesign. Do not "clean this up"
   by renaming anything here.
   ========================================================================== */


/* ============================================================================
   1. PAGE FRAME
   ONE measure for the working column, as on the tuner: every direct child of
   the step column inherits it, so the panels, the pickers and the section
   decks all close on the same right edge.
   ========================================================================== */

main { --measure: 640px; }

/* The second skip link, same offset the Guide and the Command Reference use for
   theirs: this page opens with a picker made of a hundred small targets, so a
   keyboard reader gets a way past it to the file reader in one press. */
.skip-2:focus { left: calc(var(--s3) + 10.5rem); }

/* Steps left, the line you are building pinned in the right column and tracking
   the three steps for their 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 the last step - so the step 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. */
#build-tool { 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. */
  .bd-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;
  }

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

/* One rhythm for the whole page: chapters at --section-y, the steps inside one
   chapter a touch tighter. The hero band owns its own closing space. */
.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); }

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

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

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


/* ============================================================================
   2. HERO ART - two lines in the shape this page writes
   config.css's component, copied per the note at the top of this file. Not a
   picture of an app and not anybody's config: the example is invented, and the
   caption says so where the reader can see it. The evidence caption (.cd), the
   quiet fourth row (.cfg-rest) and their rules went with the declutter - the
   plate is two lines and a caption now, so nothing here styles them.
   ========================================================================== */

.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); }

/* The plate stays on a phone: it is the one honest visual this page has, and
   it is the answer to "what do I get out of this". Two rows at this size cost
   almost nothing. */
@media (max-width: 47.99em) {
  .cfg-plate { padding: var(--s4); }
  .cfg-line { padding-block: 7px; font-size: var(--fs-2xs); }
}


/* ============================================================================
   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 and a step can be added, removed
   or reordered without a single number needing an edit.
   ========================================================================== */

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

.step-head::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;
}

/* "Build a bind" names the chapter; "Pick a key" is the thing a reader acts on.
   With the chapter's deck gone the head sits closer to the first step - same
   weight as the #read and #how chapter heads, so the three chapters agree. */
#build > .wrap > .shead { margin-bottom: var(--s4); }


/* ============================================================================
   4. FORM CONTROLS
   config.css's recipe. One label token for every field, 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 still cannot
   leave the control invisible. Checkbox and radio are ONE family - same size,
   same rest border, same fill on check, differing in shape alone. Dashed edges
   belong to the drop target and to nothing else.
   ========================================================================== */

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

.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="text"],
input[type="search"] {
  display: block;
  width: 100%;
  max-width: 22rem;
  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="text"]:hover,
input[type="search"]:hover { border-color: var(--fg-3); }

/* The engines draw a clear affordance inside a type=search that differs three
   ways and eats part of the declared width; the field is a plain text box on
   all of them, and the value is cleared with the keyboard like any other. */
input[type="search"] { appearance: none; -webkit-appearance: none; }
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }

textarea { resize: vertical; }

.inp + .inp,
.inp + fieldset.inp,
fieldset.inp + .inp,
fieldset.inp + fieldset.inp { margin-top: var(--s5); }

.inp-wide { width: 100%; max-width: none; }

/* No second card inside the panel: the fieldset keeps its grouping semantics
   and loses its chrome, so the 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);
}

/* Three options that are each a sentence about consequences, not a word: side
   by side they wrap into an unreadable ladder, so this group stacks. */
.pick-stack { flex-direction: column; gap: 0; }

.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 links inside it are not nested
   interactive content and the field's accessible name is just its name. */
.inp-help { max-width: none; }

.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 {
  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 it. */
.pick-box input {
  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 { border-color: var(--accent-400); }

.pick-box:has(input:checked) {
  background: var(--accent-500);
  border-color: var(--accent-500);
}

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

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


/* -- Focus: the ring traces the control you can SEE -------------------------
   Every tickable control here is an appearance:none input lying on top of a
   wrapper that paints the box, so the ring goes on the WRAPPER too. Same 3px
   offset as everywhere else on the site. */
.pick-box:has(input:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-color: var(--accent-400);
}

.paste-alt > summary:focus-visible,
.rail-disc > summary:focus-visible,
.more > summary:focus-visible,
.bd-line > summary:focus-visible,
.bd-form > summary:focus-visible,
.textlink:focus-visible,
.rail-link:focus-visible,
.bd-key:focus-visible,
.bd-act:focus-visible,
.btn:focus-visible,
.dl-btn:focus-visible,
input[type="text"]:focus-visible,
input[type="search"]:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

.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;
  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; }

.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); }


/* ============================================================================
   5. THE KEY PICKER
   A grid of small targets, grouped, with the state of our evidence ON the
   target rather than in a tooltip: three dot colours, one legend, and the
   unconfirmed ones are dimmed but never disabled - "we could not confirm this
   name" is not "you may not use it", and the picker must not silently enforce
   a stronger claim than the data makes.
   ========================================================================== */

.bd-legend {
  list-style: none;
  display: grid;
  gap: var(--s1);
  margin: 0 0 var(--s4);
  padding: 0;
  max-width: var(--measure);
  color: var(--fg-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.bd-legend li {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr);
  gap: var(--s2);
  align-items: baseline;
}

.bd-dot {
  width: 6px;
  height: 6px;
  align-self: center;
  border-radius: var(--r-full);
  background: var(--fg-3);
}

.at-wiki { background: var(--ev-consensus-fg); }
.at-wild { background: var(--ev-inference-fg); }
.at-unconfirmed { background: var(--fg-3); }

#key-count,
#action-count { margin: 0 0 var(--s3); }

.bd-keygroup + .bd-keygroup { margin-top: var(--s4); }
.bd-keygroup > .glabel { display: block; margin-bottom: var(--s2); }

.bd-keys {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

/* A real button, and the smallest one on the site that is still a target: 32px
   tall, 32px wide at minimum, so a row of digits does not become a row of
   pinpricks. */
.bd-key {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 32px;
  min-width: 32px;
  padding-inline: var(--s3);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  background: var(--bg-1);
  color: var(--fg-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  cursor: pointer;
  transition: border-color var(--dur-base) var(--ease-std),
              background-color var(--dur-base) var(--ease-std),
              color var(--dur-base) var(--ease-std);
}

.bd-key::before {
  content: "";
  width: 5px;
  height: 5px;
  flex: none;
  border-radius: var(--r-full);
  background: var(--ev-consensus-fg);
}

.bd-key[data-attested="wild"]::before { background: var(--ev-inference-fg); }
.bd-key[data-attested="unconfirmed"]::before { background: var(--fg-3); }
.bd-key[data-attested="unconfirmed"] { color: var(--fg-3); }

.bd-key:hover { border-color: var(--stroke); background: var(--bg-2); color: var(--fg-0); }

.bd-key[aria-pressed="true"] {
  border-color: var(--accent-500);
  background: var(--bg-3);
  color: var(--fg-0);
}

.bd-picked {
  margin: var(--s4) 0 0;
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-picked:empty { margin: 0; }
.bd-picked b { color: var(--fg-0); }

/* The honest empty state. It is prose, not a shrug: it says what we do not
   have and what the reader can do anyway. */
.bd-empty {
  margin: var(--s3) 0 0;
  padding-left: var(--s4);
  border-left: 2px solid var(--line-2);
  max-width: var(--measure);
  color: var(--fg-3);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-empty[hidden] { display: none; }

.bd-combo { margin-top: var(--s5); }


/* ============================================================================
   6. THE ACTION PICKER AND THE CHAIN
   A list, not a grid: an action is a name plus a sentence, and a sentence needs
   a line. The kind chip is the one piece of state that decides what the next
   control does, so it rides at the end of the row where the eye lands last.
   ========================================================================== */

#action-list {
  display: grid;
  gap: var(--s1);
  max-height: 22rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: var(--s2);
}

.bd-act {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 2px var(--s3);
  width: 100%;
  padding: var(--s2) var(--s3);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg-2);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-base) var(--ease-std),
              background-color var(--dur-base) var(--ease-std);
}

.bd-act:hover { background: var(--bg-2); border-color: var(--line-2); }

.bd-act[aria-pressed="true"] {
  border-color: var(--accent-500);
  background: var(--bg-3);
}

.bd-act .an {
  min-width: 0;
  color: var(--fg-1);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  overflow-wrap: anywhere;
}

.bd-act .ak {
  flex: none;
  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);
  white-space: nowrap;
}

.bd-act .aw {
  grid-column: 1 / -1;
  color: var(--fg-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.bd-detail {
  margin-top: var(--s4);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-detail:empty { margin: 0; }
.bd-detail p { margin: 0 0 var(--s2); }
.bd-detail p:last-child { margin-bottom: 0; }
/* The record's own "not for a key" line, in the same voice as a refusal. */
.bd-detail .bd-nokey { color: var(--warn-fg); }

.bd-ref { margin: var(--s2) 0 0; font-size: var(--fs-xs); }
.bd-ref:empty { margin: 0; }

.bd-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s3) var(--s5);
  margin-top: var(--s5);
}

/* The chain. Numbered, because with the cycle form the order IS the content:
   step one, step two, step three, then round again. */
.bd-chain {
  counter-reset: bstep;
  list-style: none;
  display: grid;
  gap: var(--s2);
  margin: 0;
  padding: 0;
}

.bd-chain:empty { display: none; }

.bd-step {
  counter-increment: bstep;
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  background: var(--bg-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-1);
}

.bd-step::before {
  content: counter(bstep);
  color: var(--fg-3);
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.bd-step .bs-text { min-width: 0; overflow-wrap: anywhere; }

.bd-step-del,
.bd-kept-del {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex: none;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg-3);
  cursor: pointer;
  transition: color var(--dur-base) var(--ease-std),
              border-color var(--dur-base) var(--ease-std);
}

.bd-step-del:hover,
.bd-kept-del:hover { color: var(--warn-fg); border-color: var(--line-2); }

.bd-step-del:focus-visible,
.bd-kept-del:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

#chain-empty { margin-top: 0; }


/* ============================================================================
   7. PATTERNS - a shape with holes in it
   The card carries the form; the slot list carries what the reader has to
   supply and where each value comes from. That second list is the whole reason
   this page can refuse to publish a bind pack and still be useful, so it is
   never the small print: it sits directly under the syntax, in the same
   register as the syntax.
   ========================================================================== */

#pattern-list { display: grid; gap: var(--s4); }

.bd-pattern {
  padding: var(--s5);
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background: var(--bg-2);
}

.bd-pattern h3 {
  margin: 0 0 var(--s2);
  font-size: var(--fs-h3);
  letter-spacing: var(--tk-h3);
}

.bd-pattern p {
  margin: 0 0 var(--s3);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-pattern .bd-syntax {
  display: block;
  margin: 0 0 var(--s3);
  padding: var(--s3);
  border: 1px solid var(--line-1);
  border-radius: var(--r-sm);
  background: var(--bg-1);
  color: var(--accent-300);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
  overflow-wrap: anywhere;
}

.bd-slots {
  list-style: none;
  display: grid;
  gap: var(--s2);
  margin: 0 0 var(--s4);
  padding: 0;
}

.bd-slot {
  display: grid;
  gap: 2px;
  padding-left: var(--s4);
  border-left: 2px solid var(--accent-500);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-slot b { color: var(--fg-0); font-family: var(--font-mono); font-size: var(--fs-xs); }
.bd-slot span { color: var(--fg-2); }

.bd-pat-foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s3) var(--s4);
}


/* ============================================================================
   8. THE OUTPUT RAIL
   The line is the deliverable, so it is the loudest thing in the card and it
   never leaves the screen while the steps are being answered. Everything under
   it is for the reader doing several at once.
   ========================================================================== */

.rail-card { max-width: 30rem; }
.rail-card > h2 { margin-bottom: var(--s4); }

.bd-placeholder {
  margin: 0;
  color: var(--fg-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.bd-placeholder[hidden] { display: none; }

.bd-linebox {
  margin-top: var(--s2);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  background: var(--bg-1);
}

/* Empty, the box would be a 40px empty frame under a placeholder that already
   says there is nothing yet - so it is absent until there is a line, and the
   :empty test is on the code element rather than a class the script has to
   remember to toggle. */
.bd-linebox:has(#bind-line:empty) { display: none; }

#bind-line {
  display: block;
  padding: 0;
  background: none;
  color: var(--accent-300);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
  overflow-wrap: anywhere;
}

.bd-copyrow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s2) var(--s3);
  margin-top: var(--s3);
}

.bd-copyrow .copy-msg { margin-top: 0; }

.bd-read {
  margin: var(--s4) 0 0;
  color: var(--fg-1);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-read:empty { margin: 0; }

/* The validations. One tone per consequence, and the tone is carried by the
   left rule, not by a fill: a card of four filled warning blocks reads as a
   page-wide alarm when three of them are just things to know. */
.bd-flags {
  list-style: none;
  display: grid;
  gap: var(--s2);
  margin: var(--s4) 0 0;
  padding: 0;
}

.bd-flags:empty { margin: 0; }

.bd-flag {
  padding: var(--s1) 0 var(--s1) var(--s4);
  border-left: 2px solid var(--line-2);
  color: var(--fg-2);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.bd-flag b { color: var(--fg-0); }
.bd-flag.is-stop { border-left-color: var(--warn-line); }
.bd-flag.is-stop b { color: var(--warn-fg); }
.bd-flag.is-warn { border-left-color: var(--imp-high-line); }
.bd-flag.is-warn b { color: var(--imp-high-fg); }
.bd-flag.is-note { border-left-color: var(--accent-500); }

#keep-add { width: 100%; margin-top: var(--s5); }

.bd-kept {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line-1);
}

.bd-kept .rail-count {
  margin: 0 0 var(--s3);
  color: var(--fg-1);
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: var(--lh-snug);
}

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

.bd-keptlist {
  list-style: none;
  display: grid;
  gap: var(--s1);
  margin: 0;
  padding: 0;
}

.bd-keptlist:empty { display: none; }

.bd-keptlist li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s2);
  padding: var(--s1) 0;
  border-bottom: 1px solid var(--line-1);
  color: var(--fg-2);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  line-height: var(--lh-snug);
  overflow-wrap: anywhere;
}

.bd-keptlist li:last-child { border-bottom: 0; }

#kept-empty { margin-top: 0; }
#kept-empty[hidden] { display: none; }

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

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

.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); }

#kept-text {
  width: 100%;
  margin-top: var(--s2);
  padding: var(--s2) var(--s3);
  background: var(--bg-1);
  border: 1px solid var(--stroke);
  border-radius: var(--r-sm);
  color: var(--fg-1);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

/* Stacked (below the two-column breakpoint) the rail sits directly above the
   next section, so a link to it would point at the next thing on the screen.
   It exists only where the rail is a sticky column beside the steps. */
.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); }

@media (min-width: 68em) {
  .rail-link { display: inline-flex; }
}


/* ============================================================================
   9. THE READER - the load control and the five buckets
   The load control is the Config Tuner's and the PC Audit's, copied unchanged,
   because a reader who has met one of them has met this one. The buckets are
   the audit review's shape: findings first, counts on the heading, and an empty
   state that says which question was asked and came back clean.
   ========================================================================== */

.review-grid {
  display: grid;
  gap: var(--s6);
  align-items: start;
}

@media (min-width: 62em) {
  .review-grid {
    grid-template-columns: minmax(0, 1fr) var(--aside);
    gap: var(--s7);
  }
}

.bd-where {
  margin: 0 0 var(--s4);
  max-width: var(--measure);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.drop {
  position: relative;
  display: grid;
  justify-items: center;
  gap: var(--s1);
  width: 100%;
  padding: var(--s7) var(--s5);
  background: var(--bg-1);
  border: 1px dashed var(--stroke);
  border-radius: var(--r-lg);
  cursor: pointer;
  transition: border-color var(--dur-base) var(--ease-std),
              background-color var(--dur-base) var(--ease-std),
              transform var(--dur-fast) var(--ease-std);
}

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

/* Visually hidden but still focusable: display:none would drop the only file
   picker in this section 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);
  color: var(--fg-3);
  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); border-color: var(--accent-400); }
.drop.over .icon { transform: translateY(-2px); color: var(--accent-400); }

.drop-title { color: var(--fg-1); font-weight: 500; text-align: center; }
.drop-title code { font-size: .875em; }

/* The only click affordance in this block was a clause inside a sentence. It is
   a control now: its own line, its own edge. The whole target is 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 file input is visually hidden but stays focusable, so its ring is drawn
   on the visible affordance instead. */
.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);
}

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

/* Touching the target it answers for. 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 {
  margin-top: var(--s3);
  color: var(--ok);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.file-status:empty { margin: 0; min-height: 0; }
.file-status.is-error { color: var(--warn-fg); }

.paste-alt { margin-top: var(--s4); }
.paste-alt > summary { display: inline-flex; align-items: center; gap: var(--s2); min-height: 32px; color: var(--fg-2); font-size: var(--fs-sm); }
.paste-body { margin-top: var(--s3); }

.paste-alt textarea {
  width: 100%;
  margin-bottom: var(--s3);
  padding: var(--s3);
  background: var(--bg-1);
  border: 1px solid var(--stroke);
  border-radius: var(--r-sm);
  color: var(--fg-1);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

/* -- the output ----------------------------------------------------------
   One attribute drives the whole block: read.js flips data-state and nothing
   else has to be shown or hidden by hand. Before a file there is a single
   honest line; after one, the buckets. */
.review-out { margin-top: var(--s7); }

.review-out[data-state="empty"] > *:not(#read-placeholder) { display: none; }
.review-out[data-state="done"] > #read-placeholder { display: none; }

.rv-placeholder {
  margin: 0;
  max-width: var(--measure);
  padding-left: var(--s4);
  border-left: 2px solid var(--line-2);
  color: var(--fg-3);
  font-size: var(--fs-sm);
}

.rv-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s5);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line-1);
}

.rv-top h3 { margin: 0; font-size: var(--fs-h2); }
.rv-top h3:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; }

.rv-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3); }
.rv-actions .btn { min-height: 36px; font-size: var(--fs-sm); }
.rv-actions .copy-msg { margin-top: 0; }

.rv-lede {
  margin: 0;
  max-width: var(--measure);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

/* File-scope findings: the ones that are about the file as a whole rather than
   about one line, so they sit above the buckets and outside them. */
.rv-flags {
  list-style: none;
  display: grid;
  gap: var(--s3);
  margin: var(--s5) 0 0;
  padding: 0;
}

.rv-flags:empty { margin: 0; }

.rv-flags li {
  max-width: var(--measure);
  padding: var(--s1) 0 var(--s1) var(--s4);
  border-left: 2px solid var(--line-2);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.rv-flags li b { color: var(--fg-0); }
.rv-flags .is-warn { border-left-color: var(--warn-line); }
.rv-flags .is-warn b { color: var(--warn-fg); }
.rv-flags .is-ok { border-left-color: var(--ok); }
.rv-flags .is-ok b { color: var(--ok); }
.rv-flags .is-note { border-left-color: var(--accent-500); }

.bd-bucket { margin-top: var(--s8); }
.bd-bhead { margin-bottom: var(--s4); }

.bd-bhead h4 {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin: 0;
  font-size: var(--fs-h3-lg);
  letter-spacing: var(--tk-h2);
}

.bd-bhead p {
  margin: var(--s2) 0 0;
  max-width: var(--measure);
  color: var(--fg-3);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 24px;
  padding-inline: 8px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-full);
  background: var(--bg-1);
  color: var(--fg-2);
  font-size: var(--fs-2xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Only the bucket that means something is wrong gets a colour. "Could not tell"
   deliberately does not: it is an admission, not an alarm, and dressing it as
   one would push readers to ignore it. */
.bd-bucket[data-bucket="broken"] .bd-count {
  border-color: var(--imp-crit-line);
  background: var(--imp-crit-bg);
  color: var(--imp-crit-fg);
}

.bd-bucket[data-bucket="risky"] .bd-count {
  border-color: var(--imp-high-line);
  background: var(--imp-high-bg);
  color: var(--imp-high-fg);
}

.bd-bempty {
  margin: 0;
  max-width: var(--measure);
  padding-left: var(--s4);
  border-left: 2px solid var(--line-2);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-bempty[hidden] { display: none; }

.bd-rows { display: grid; gap: var(--s3); }
.bd-rows:empty { display: none; }

/* A finding is a card the reader opens: the summary is the key, the form and
   the one-line finding; the body is what we detected, why it matters and what
   to do instead. Same shape as a guide entry and an audit finding, because it
   is the same kind of object. */
.bd-line {
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background: var(--bg-2);
  transition: border-color var(--dur-base) var(--ease-std);
}

.bd-line > summary {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr) max-content;
  grid-template-areas:
    "mark title badges"
    "mark sum   sum";
  align-items: center;
  gap: var(--s1) var(--s3);
  padding: var(--s3) var(--s4);
  min-height: 56px;
  border-radius: var(--r-lg);
  cursor: pointer;
}

.bd-line > summary > .marker { grid-area: mark; align-self: center; }
.bd-line > summary:hover > .marker,
.bd-line[open] > summary > .marker { color: var(--accent-400); }

.bd-line .etitle {
  grid-area: title;
  margin: 0;
  min-width: 0;
  color: var(--fg-0);
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: var(--lh-snug);
}

.bd-line .etitle code { font-size: .875em; background: var(--bg-1); color: var(--accent-300); }

.bd-line .entry-badges {
  grid-area: badges;
  display: inline-flex;
  align-items: center;
  gap: var(--s3);
}

.bd-line .esum {
  grid-area: sum;
  margin: 0;
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-line .esum code { font-size: .875em; background: var(--bg-1); color: var(--accent-300); }

.bd-line[open] { border-color: var(--accent-600); }
.bd-line[open] > summary { border-bottom: 1px solid var(--line-1); border-radius: var(--r-lg) var(--r-lg) 0 0; }
.bd-line .entry-body { padding: var(--s4) var(--s5) var(--s5); }
.bd-line .entry-body p { margin: 0 0 var(--s3); font-size: var(--fs-sm); color: var(--fg-2); }
.bd-line .entry-body p:last-child { margin-bottom: 0; }
.bd-line .entry-body b { color: var(--fg-0); }

/* Every line of the file, in order, behind a disclosure: the buckets are the
   findings, this is the receipt. Monospace for the line itself, body face for
   what we made of it. */
#read-all { margin-top: var(--s8); }

.bd-readlines {
  display: grid;
  gap: var(--s2);
  margin: 0;
  padding-left: var(--s5);
}

/* `overflow-wrap: anywhere` on both the row and the code inside it, like every
   other block on this page that renders a line out of somebody's file. Without
   it one unbroken run - a merged pack's chat macro, a pasted token - stretches
   the <li>, and because the rows are block siblings the whole page goes with
   it: measured at 26,501px wide from a single 4,000-character line. */
.bd-readline {
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  min-width: 0;
  overflow-wrap: anywhere;
}
.bd-readline::marker { color: var(--fg-3); font-variant-numeric: tabular-nums; }
.bd-readline code { font-size: .875em; overflow-wrap: anywhere; }
.bd-readline .rl-what {
  display: block;
  color: var(--fg-3);
  font-size: var(--fs-xs);
  min-width: 0;
  overflow-wrap: anywhere;
}


/* ============================================================================
   10. THE REFERENCE
   Forms, then the file's own lifecycle, then the holes. The gaps block is
   bounded and marked: it is the page arguing against itself, and it should
   look deliberate rather than like a run of ordinary entries.
   ========================================================================== */

/* The evidence legend, in the same shape the Command Reference gives it (that
   file's .ev-legend is page-scoped, so this is the recipe rather than a shared
   component). Static markup, no counts: this page prints a label on every
   record and had nowhere to define the four words. */
.ev-legend {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s3) var(--s5);
  margin: var(--s2) 0 0;
}

@media (min-width: 40em) {
  .ev-legend { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.ev-legend .val { display: grid; gap: 2px; align-content: start; min-width: 0; }
.ev-legend dt { display: flex; align-items: center; gap: var(--s2); }
.ev-legend dd { margin: 0; color: var(--fg-2); font-size: var(--fs-sm); line-height: var(--lh-snug); }

#ev-legend-disc { margin-bottom: var(--s6); }

#forms-list { display: grid; gap: var(--s4); }

.bd-form {
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background: var(--bg-2);
}

.bd-form > summary {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  padding: var(--s4) var(--s5);
  border-radius: var(--r-lg);
  cursor: pointer;
}

.bd-form[open] > summary { border-bottom: 1px solid var(--line-1); border-radius: var(--r-lg) var(--r-lg) 0 0; }
.bd-form[open] { border-color: var(--accent-600); }

.bd-form .ftitle {
  margin: 0;
  color: var(--fg-0);
  font-size: var(--fs-body);
  font-weight: 600;
}

.bd-form .fsyntax {
  color: var(--accent-300);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  overflow-wrap: anywhere;
}

.bd-form-body { padding: var(--s4) var(--s5) var(--s5); }

.bd-form-body p {
  margin: 0 0 var(--s3);
  max-width: var(--measure);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
}

.bd-form-body p:last-child { margin-bottom: 0; }

.bd-example {
  display: block;
  margin: 0 0 var(--s3);
  padding: var(--s3);
  border: 1px solid var(--line-1);
  border-radius: var(--r-sm);
  background: var(--bg-1);
  color: var(--accent-300);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
  overflow-wrap: anywhere;
}

/* The traps are the half of a syntax record that a reader actually needs, so
   they are not folded away inside it. */
.bd-traps {
  list-style: none;
  display: grid;
  gap: var(--s2);
  margin: 0 0 var(--s3);
  padding: 0;
}

.bd-traps li {
  padding-left: var(--s4);
  border-left: 2px solid var(--imp-high-line);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.bd-facts { margin-top: var(--s8); }
.bd-facts h3,
.bd-gaps h3 { margin-bottom: var(--s4); font-size: var(--fs-h3-lg); letter-spacing: var(--tk-h2); }

#facts-list,
#gaps-list { display: grid; gap: var(--s5); }

.bd-fact,
.bd-gap { max-width: var(--measure); }

.bd-fact h4,
.bd-gap h4 {
  margin: 0 0 var(--s2);
  color: var(--fg-0);
  font-size: var(--fs-body);
  font-weight: 600;
}

.bd-fact p,
.bd-gap p {
  margin: 0 0 var(--s2);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
}

.bd-gaps {
  margin-top: var(--s8);
  padding-left: var(--s5);
  border-left: 2px solid var(--accent-500);
}

.bd-gaps-lede {
  margin: 0 0 var(--s5);
  max-width: var(--measure);
  color: var(--fg-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

#sourcing { margin-top: var(--s7); }
#sourcing .more-body p { max-width: var(--measure); font-size: var(--fs-sm); color: var(--fg-2); }
#sourcing .more-body p + p { margin-top: var(--s3); }


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

@media (max-width: 47.99em) {
  .panel { padding: var(--s4); }
  .drop { padding: var(--s6) var(--s4); }
  #action-list { max-height: 18rem; }
  .bd-pattern { padding: var(--s4); }
  .bd-line > summary { grid-template-columns: 16px minmax(0, 1fr); grid-template-areas: "mark title" "mark badges" "mark sum"; }
  .bd-line .entry-body { padding: var(--s4); }
  .bd-bucket { margin-top: var(--s7); }
}

/* A key is a tap target before it is a chip. */
@media (pointer: coarse) {
  .pick { min-height: 44px; padding-block: var(--s3); }
  .bd-key { min-height: 40px; min-width: 40px; }
  .bd-step-del,
  .bd-kept-del { width: 36px; height: 36px; }
}


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

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

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

  .panel,
  .rail-card,
  .cfg-plate,
  .drop,
  .drop-btn,
  .bd-key,
  .bd-count,
  .bd-linebox,
  .bd-line,
  .bd-form,
  .bd-pattern { border: 1px solid CanvasText; }

  .step-head::before { border: 1px solid CanvasText; }

  /* The tint that carries "chosen" everywhere else is dropped in this mode, so
     the edge has to carry it alone. */
  .bd-key[aria-pressed="true"],
  .bd-act[aria-pressed="true"] { border: 2px solid Highlight; }

  /* The dots are the only thing saying which evidence a claim carries and how
     well attested a key name is, and a background colour is not guaranteed to
     render here - so they take a border as well, which is. */
  .ev-label .dot,
  .bd-dot,
  .bd-key::before { border: 1px solid CanvasText; }
}

@media print {
  .page-grid { display: block; }
  .bd-rail { position: static; max-height: none; overflow: visible; margin-top: var(--s6); }

  /* On paper this page is the reference and the review, not the pickers: a key
     grid and a drop target are controls, and a control printed on paper is
     ink spent on something nobody can press. */
  .hero-art,
  #key-groups,
  #key-legend,
  #action-list,
  #action-filter,
  .bd-actions,
  .bd-copyrow,
  #keep-add,
  .rail-disc,
  .rail-link,
  .rv-actions,
  .drop,
  .paste-alt { display: none !important; }

  .bd-line,
  .bd-form,
  .bd-pattern,
  .bd-fact,
  .bd-gap { break-inside: avoid; }

  /* Every finding open on paper: a printed review with half its rows collapsed
     is a printed review missing half its content. */
  .bd-line > .entry-body,
  .bd-form > .bd-form-body,
  #read-all > .more-body,
  #sourcing > .more-body { display: block !important; }
}
