/* =============================================================================
   butcher.css — the Butcher app's own skin
   _version: 1.1

   WHY THIS FILE EXISTS, stated honestly.
   The Butcher app is NOT un-styled. Every element it renders resolves to a
   reaching rule in the shared Forest grammar (`.row`, `.line`, `.chip`,
   `.view__list`, `.field__control`). That was proven from source at S27.0027
   (design/the-butcher-leg-1-probe-v1.md) and it falsified the earlier reading
   that a `grep -c butcher *.css` of 0/1/0/0 meant "no styling."

   What IS wrong is COMPOSITION, and it is four cascade facts, not missing CSS:

     1. `.row` is flex; `.row__body` carries no `min-width:0`, so it refuses to
        shrink and pushes `.row__trail` (`flex:0 0 auto`) past the card edge.
        `.row__trail` cannot wrap. -> chips clip mid-word.
     2. `.view__list` sets `overflow: hidden auto` + `border-radius`;
        `.view__region-label` sets `margin: 0 0 var(--s-2)` with NO horizontal
        padding. The label sits flush on the border box and is shaved.
     3. The lanes region is block-flow, so a tall open lane and a one-line
        resting lane share no grid and float at unrelated heights/widths.
     4. `.line` is `display:flex; align-items:baseline` over one text node, so
        "Picked up  ·  2 orders" breaks mid-phrase.

   SCOPE DISCIPLINE. Every rule below is scoped to a butcher surface. Butcher's
   composition problem must not be fixed by editing rules four apps share.

   THE LAW THIS RUNS ON (ux-evolution-plan-v1.md section 5, carried not invented):
     "The pane faces the WORK, never the worker. No praise, no confetti, no red.
      Weather is gold and quiet only. An unverifiable verify renders a loud
      honest state, never a false green."

   COLOUR VOCABULARY — operator ruling C, S27.0224. NO NEW HUE. The two hues
   that exist are assigned by documented discipline:
       gold   (--sunlight) = needs a hand   ... the aging/attention weather cue
       accent (--accent)   = active / selected / focused
       grey ramp           = resting states (picked up, cancelled, closed)
   Post-DP-017 `--bark` resolves to `--ink-soft` and `--moss` to `--ink-faint`
   -- BOTH neutral greys. Nothing below leans on bark/moss to carry meaning;
   they carry QUIET only. Rechecking that is why this comment exists.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   1 -- THE LANE GRID (defect 3)
   One layout system for both lane states. A resting lane and an open lane are
   cells in the same grid, so they cannot float at unrelated heights again.
   `align-items: start` keeps a short lane short instead of stretching it into
   a tall empty box -- 200 orders in CUTTING must not inflate `Cancelled  ·  1`.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .view[data-region="board-lanes"] {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--s-4);
  align-items: start;
}

/* A lane must be allowed to shrink inside its grid cell. Without this the
   grid track is sized by the widest unbreakable content and overflow returns
   by a different door. */
[data-kind="butcher-board"] .view__list {
  min-width: 0;
}

/* -----------------------------------------------------------------------------
   2 -- THE LANE LABEL (defect 2)
   The label is inside a rounded, `overflow:hidden` box. Give it the same
   horizontal inset the rows already get from `.row`'s `padding: var(--s-3)
   var(--s-4)`, so the caps sit ON the card, not ON the border.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .view__region-label {
  padding: var(--s-3) var(--s-4) 0;
  margin: 0 0 var(--s-2);
  min-width: 0;
  overflow-wrap: anywhere;
}

/* -----------------------------------------------------------------------------
   3 -- THE ROW ANCHOR + THE CHIP OVERFLOW (defects 1 and 5)
   `min-width: 0` is the whole fix for the clipping. A flex child's automatic
   minimum size is its content size unless told otherwise; that is why the trail
   was pushed out rather than the body compressed.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .row {
  min-width: 0;
  flex-wrap: wrap;
  row-gap: var(--s-2);
}

[data-kind="butcher-board"] .row__body {
  min-width: 0;
  flex: 1 1 12rem;
}

/* The title is the ANCHOR (section 5 addition 2: recognition over recall --
   tag AND customer name, never a bare number). It gets the weight so the chips
   read as attributes OF something rather than as three floating pills. */
[data-kind="butcher-board"] .row__title {
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--ink);
  font-weight: 500;
}

[data-kind="butcher-board"] .row__meta {
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--ink-soft);
}

/* The trail may wrap under the body instead of clipping off the card edge.
   `flex: 1 1 auto` + `justify-content: flex-start` keeps chips left-aligned
   when they drop to their own line, so they still hang off the title. */
[data-kind="butcher-board"] .row__trail {
  flex: 1 1 auto;
  flex-wrap: wrap;
  justify-content: flex-start;
  row-gap: var(--s-2);
  min-width: 0;
}

/* A chip must never render a clipped word (`Pac...`). It wraps or it sits whole. */
[data-kind="butcher-board"] .row__trail .chip {
  max-width: 100%;
  overflow-wrap: anywhere;
  white-space: normal;
}

/* -----------------------------------------------------------------------------
   4 -- THE RESTING LANE SUMMARY (defect 4)
   One quiet line carrying its count. The QUIET GRAMMAR is already the
   renderer's stated intent ("412 picked-up orders is a good season, not a
   warning") -- this only stops it breaking mid-phrase and gives it the same
   inset as a row so a collapsed lane and an open lane share an edge.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .line--clickable[data-lane-summary] {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  min-width: 0;
  color: var(--ink-soft);            /* RESTING = grey ramp. Ruling C. */
  font-family: var(--face-survey);
  font-size: var(--t-label);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  text-wrap: balance;
  overflow-wrap: anywhere;
}

[data-kind="butcher-board"] .line--clickable[data-lane-summary]:hover {
  color: var(--ink);
  background: color-mix(in srgb, var(--sunlight) 5%, transparent);
}

/* Focus is ACTIVE, so it is accent. Ruling C. */
[data-kind="butcher-board"] .line--clickable[data-lane-summary]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  color: var(--ink);
}

/* A resting lane is quieter than an open one at the container level too --
   the whole point of collapsing it. Quiet is a BORDER weight, never a hue. */
[data-kind="butcher-board"] .view__list[data-collapsed="true"] {
  border-color: color-mix(in srgb, var(--line-bark) 60%, transparent);
}

/* -----------------------------------------------------------------------------
   5 -- THE SEASON CARD RHYTHM (defect 6)
   Three label/value pairs in a card sized for far more. Give the pairs a
   vertical rhythm and let the card size to its content instead of holding
   ~70% empty space.
   -------------------------------------------------------------------------- */
[data-kind^="butcher-season"] .line {
  padding: var(--s-2) 0;
  gap: var(--s-3);
  align-items: baseline;
  justify-content: space-between;
  border-bottom: 1px solid color-mix(in srgb, var(--line-bark) 45%, transparent);
}
[data-kind^="butcher-season"] .line:last-child { border-bottom: none; }

[data-kind^="butcher-season"] .line__label {
  color: var(--ink-faint);
  font-family: var(--face-survey);
  font-size: var(--t-label);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}

[data-kind^="butcher-season"] .line__value {
  color: var(--ink);
  font-variant-numeric: tabular-nums;   /* figures align down the column */
  text-align: right;
}

/* The ledger regions -- `div.view__detail[data-region="season-lines"]` (glance,
   dashboard, report) and `[data-region="census-counts"]` (census).

   S27.1218 — THE GAP IS THE VARIABLE, NOT THE CONTAINER. `.line` is
   `justify-content: space-between`, so the value is pushed to the FAR EDGE of
   whatever bounds it: the container width IS the label-to-figure gap. Every
   prior fix on this surface capped the CARD at --measure and read that as
   "capped"; what it actually did was fix the gap at exactly 1080px. §11's
   premise -- "the eye can travel a label-to-figure gap of a measure" -- is
   false for a two-column ledger, and it is the reason five sessions of cap
   work produced no visible change. Bounding the REGION is what closes the gap;
   the card keeps --measure and the ledger sits left-aligned inside it, which is
   the same thing §13 already asks of the board's reading surfaces. */
[data-kind^="butcher-season"] .view__detail[data-region="season-lines"],
[data-kind^="butcher-season"] .view__detail[data-region="census-counts"] {
  display: grid;
  gap: var(--s-2);
  min-width: 0;
  max-width: var(--measure-ledger);
}

/* THE CENSUS CHAIN COLLAPSES (owed butcher-census-chain-has-no-working-collapse).
   Every order's chain renders `data-open="0|1"`; before the toggle existed there
   was NO rule here and hiding a chain no one could reopen would have made the
   record unreachable (the false-green law). butcher-renderer showCensus now wires
   the row to flip its own chain, so `data-open="0"` is an honest CLOSED state a
   click reopens — and a census of ~500 orders opens readable (each order one row)
   instead of an unbroken wall of expanded chains. The caret is the affordance:
   ▸ closed, ▾ open, following aria-expanded. Tokens only, ZERO new hue.
   LOOK-AND-FEEL — staged on main, undeployed, for the operator's eye: the
   default-closed choice, the caret glyph and any open/close motion are his to
   rule before this deploys. */
[data-kind="butcher-season-census"] .view__list[data-region="census-chain"][data-open="0"] {
  display: none;
}
[data-kind="butcher-season-census"] .row--clickable[data-order] .row__title::before {
  content: "\25B8";                 /* ▸ closed */
  display: inline-block;
  width: 1em;
  margin-right: var(--s-1);
  color: var(--ink-faint);
  transition: transform 120ms ease;
}
[data-kind="butcher-season-census"] .row--clickable[aria-expanded="true"] .row__title::before {
  content: "\25BE";                 /* ▾ open */
}
@media (prefers-reduced-motion: reduce) {
  [data-kind="butcher-season-census"] .row--clickable[data-order] .row__title::before {
    transition: none;
  }
}

/* "N orders need a hand" is a CLICKABLE census line (`data-act="season-open"`),
   and under ruling C needs-a-hand is exactly what gold means. It was crammed
   against the balance value with no separation; this gives it its own air and
   the affordance it already behaves like. It is a quiet left rule, never a
   badge count and never red -- section 3 E5 is explicit about that. */
[data-kind^="butcher-season"] .pane__census[data-act="season-open"] {
  margin-top: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-left: 3px solid var(--sunlight);
  color: var(--ink);
  cursor: pointer;
  min-width: 0;
  overflow-wrap: anywhere;
}

[data-kind^="butcher-season"] .pane__census[data-act="season-open"]:hover {
  background: color-mix(in srgb, var(--sunlight) 6%, transparent);
}

[data-kind^="butcher-season"] .pane__census[data-act="season-open"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* -----------------------------------------------------------------------------
   6 -- THE MONEY PANEL
   `butcher__money-error` was re-pointed `pane__absent` -> `pane__error` at
   S27.0027 Item A (the vocabulary half). The APPEARANCE half was deliberately
   filed, NOT shipped: `.pane__error` exists Forest-wide only as a co-listed
   selector with `pane__absent`/`pane__pending`, so all three render identically
   in every app. Giving the error a face is a FOREST-WIDE change touching parent
   section 5 -- out of scope for a butcher sheet, and Renata's call was right.

   What is in scope here: the money panel's own geometry, so an error and a note
   are at least not crammed against the balance value. NO new hue is introduced
   and no error-specific colour is asserted -- doing that here would silently
   fork the Forest's error grammar from one app.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .butcher__money-panel,
.butcher__money-panel {
  display: grid;
  gap: var(--s-3);
  min-width: 0;
}

.butcher__money-note,
.butcher__money-error {
  min-width: 0;
  overflow-wrap: anywhere;
  margin: 0;
}

/* -----------------------------------------------------------------------------
   7 -- THE AGING CUE (section 3, E5: "a quiet gold weather cue on the card --
   never red, never a badge count")
   This is the ONLY place gold carries meaning, and it is opt-in from the
   renderer via a data attribute. Nothing paints gold today; the hook exists so
   the aging signal has somewhere to land WITHOUT a second stylesheet pass.
   Ruling C: gold = needs a hand.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .row[data-aging="true"] {
  box-shadow: inset 3px 0 0 var(--sunlight);
}

[data-kind="butcher-board"] .row[data-aging="true"] .row__title {
  color: var(--ink);
}

/* =============================================================================
   PASS 2 (_version 1.1) — HIERARCHY AND DENSITY

   Pass 1 fixed COMPOSITION: nothing clipped, nothing floating, nothing shaved.
   It was correct and it is retained above unchanged. What it did not do — and
   did not claim to do — is answer the operator's actual finding, which the
   design plan v2 §7 states plainly and honestly:

     "'Ugly as sin' is the operator's finding and this plan does not confirm it.
      It proves only that the ugly is not made of missing CSS. Whether the
      RESULT looks right is unanswered."

   This pass answers it. The result did not look right, and the reason is not
   composition — it is that every element on a butcher surface is rendered at
   the same weight, so nothing tells Rick where to look. Three named faults,
   each traced to a carrier, none invented here:

     1. NO PRIMARY ACT. ux-evolution-plan-v1.md §5 addition 1: "One primary act
        per surface. The next thing to do is always the biggest thing on
        screen." Today the biggest thing on screen is the words "This season."
        The advance button — the whole point of E1, the verb Rick presses two
        hundred times in three weeks with a knife in his hand — renders as a
        small pill identical to every other control.
     2. NO ORDINAL EXPRESSION. Design plan v2 §4 (Sol/Vee/Kira, Item C): the
        rite has seven stations and the surface has one face. Item C is routed
        out as a design project and is NOT built here. What IS built here is
        the part that needs no new design: the STAGE gets a face, so a lane
        reads as a station rather than as a box of text.
     3. THE SUMMARY OUTWEIGHS THE WORK. The season glance is a summary and the
        board is the work, and they render at identical weight — same title
        size, same card, same padding. §5: the pane faces the WORK.

   DISCIPLINE, unchanged from pass 1: tokens only, zero new hue, every rule
   scoped to a butcher surface. Gold = needs a hand / the primary act (ruling C
   extended by one noun: the act is what needs a hand NEXT). Accent = active,
   selected, focused. Grey ramp = resting. No red, no confetti, no badge counts.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   8 — PANE RHYTHM. A butcher pane is a WORKING surface, not an article.
   The shared `.pane--live` padding (--s-5 / --gutter) and `.pane__title` scale
   (--t-title, which clamps up to 2.1rem) are tuned for reading. On a board
   holding two hundred orders they spend the screen on air. Tightened here only,
   for butcher, so four apps keep the rule they were tuned for.
   -------------------------------------------------------------------------- */
[data-kind^="butcher-"] {
  padding: var(--s-4) var(--s-5);
}

[data-kind^="butcher-"] .pane__title {
  font-size: var(--t-h);
  letter-spacing: 0.01em;
  margin: 0 0 var(--s-3);
}

/* -----------------------------------------------------------------------------
   9 — THE SUMMARY RECEDES (fault 3).
   The glance answers "how is the season going". It is context, not work, so it
   reads at survey scale and steps back. Its numbers stay legible — they are the
   only thing on it worth a glance — and the card stops spending 700px on four
   lines.
   -------------------------------------------------------------------------- */
/* S27.1145 — THE CARD IS ALSO A THING THE EYE TRAVELS.
   §11 capped the glance's CONTENTS (.line, .pane__title, .view__detail) and
   left the card itself unbounded, so on a 2500px display the ledger sat capped
   at a measure against the left edge of a hall-wide card. Capping the contents
   of an uncapped card fixes the label-to-figure gap and leaves the surface
   still reading as full-bleed — which is what it kept looking like. The pane is
   three lines and a sentence; it is a card, not a hall. */
[data-kind="butcher-season-glance"] {
  padding: var(--s-3) var(--s-5) var(--s-4);
}

/* S27.1218 — THE CAP FAMILY NAMES THE FAMILY, LIKE THE STYLE FAMILY ALWAYS DID.
   The measured fault (owed `butcher-season-caps-exact-match-where-prefix-was-meant`):
   every STYLE above is written `[data-kind^="butcher-season"]` and reaches all
   three season panes, while every CAP was written
   `[data-kind="butcher-season-glance"]` and reached exactly one. So
   `butcher-season-dashboard` inherited the whole look and almost none of the
   measure, and four sessions hunted the ONE cap that used the prefix
   (`.view__detail`, §11 below) — the one cap that was working. The operator's
   live-DOM measurement settled it: computed max-width 1080px, rendered
   1079.9998px. It was never broken. Its neighbours were.

   WHY `.pane[data-kind^=...]` AND NOT A BARE PREFIX. The prefix family has four
   members, not two: glance, dashboard, census, and `butcher-season-report`. The
   first three are `section.pane`; the report is `article.record` — a PRINTED
   artifact. `--measure` is a screen-reading token, and capping a print surface
   with it is a category slip, so the `.pane` qualifier excludes the report BY
   CONSTRUCTION rather than by a maintained exception list. The report's own
   lines keep their measure through §11's `.view__detail` rule, which is
   deliberately left on the bare prefix. */
.pane[data-kind^="butcher-season"] {
  max-width: var(--measure);
}

[data-kind="butcher-season-glance"] .pane__title {
  font-family: var(--face-survey);
  font-size: var(--t-label);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 var(--s-2);
}

/* The figures are the payload. Give them the weight the heading gave up, and
   put them on one baseline so ORDERS / HANGING WEIGHT / BALANCE DUE scan as a
   column rather than as three unrelated sentences. */
[data-kind="butcher-season-glance"] .line__value {
  font-family: var(--face-survey);
  font-size: var(--t-body);
  color: var(--ink);
}

[data-kind="butcher-season-glance"] .line {
  padding: var(--s-1) 0;
}

/* -----------------------------------------------------------------------------
   10 — THE LANE IS A STATION (fault 2, the part that needs no new design).
   The lane label was a floating caps string sitting on a border. It becomes a
   header: its own band, a hairline under it, and the count riding with it. A
   resting lane gets the SAME header so a collapsed lane and an open lane read
   as the same kind of object at different states — which is what they are.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .view__list {
  background: color-mix(in srgb, var(--paper) 10%, transparent);
}

[data-kind="butcher-board"] .view__region-label {
  padding: var(--s-3) var(--s-4);
  margin: 0;
  border-bottom: 1px solid var(--line-bark);
  background: color-mix(in srgb, var(--paper) 14%, transparent);
  color: var(--ink-soft);
  font-size: var(--t-label);
  letter-spacing: var(--tracking-caps);
}

/* The rows sit under the header with no double edge. */
[data-kind="butcher-board"] .view__list .row:first-of-type {
  border-top: none;
}

/* A resting lane is one line and should not pretend to be a card with nothing
   in it. Same header treatment, no body. Quiet is weight and inset, never hue. */
[data-kind="butcher-board"] .line--clickable[data-lane-summary] {
  padding: var(--s-3) var(--s-4);
  background: color-mix(in srgb, var(--paper) 14%, transparent);
}

/* -----------------------------------------------------------------------------
   11 — THE PRIMARY ACT (fault 1). §5 addition 1, made literal.
   `butcher__advance` is E1's one button — the verb of the next stage. It shares
   `pane__connect` with every other control today, so the act Rick came to the
   app to perform is the same size as "Season census". It gets the screen.

   NO NEW HUE: this is the SAME gold wash and gold border `.pane__connect`
   already carries, at a larger size with more weight. Fitts's Law is the stated
   argument in §3 E1 ("the target must be thumb-sized on a phone"), so the size
   is the design, not decoration.
   -------------------------------------------------------------------------- */
[data-kind^="butcher-"] .butcher__advance {
  display: block;
  width: 100%;
  padding: var(--s-3) var(--s-4);
  margin: var(--s-3) 0 var(--s-2);
  border-radius: var(--r-m);
  background: color-mix(in srgb, var(--sunlight) 18%, transparent);
  border: 1px solid var(--line-gold);
  font-family: var(--face-survey);
  font-size: var(--t-body);
  letter-spacing: 0.02em;
  text-align: center;
  color: var(--ink);
}

[data-kind^="butcher-"] .butcher__advance:hover {
  background: color-mix(in srgb, var(--sunlight) 28%, transparent);
}

/* The secondary verbs stay secondary — they are the out-of-order case (§3 E1:
   "the full event list behind a secondary control"). Quiet, inline, smaller. */
[data-kind^="butcher-"] .butcher__correct,
[data-kind^="butcher-"] .butcher__resume,
[data-kind^="butcher-"] .butcher__tell,
[data-kind^="butcher-"] .butcher__money-open {
  font-size: var(--t-small);
  padding: var(--s-1) var(--s-3);
  background: transparent;
  border-color: var(--line-bark);
  color: var(--ink-soft);
}

[data-kind^="butcher-"] .butcher__correct:hover,
[data-kind^="butcher-"] .butcher__resume:hover,
[data-kind^="butcher-"] .butcher__tell:hover,
[data-kind^="butcher-"] .butcher__money-open:hover {
  color: var(--ink);
  border-color: var(--line-gold);
  background: color-mix(in srgb, var(--sunlight) 8%, transparent);
}

/* -----------------------------------------------------------------------------
   12 — THE ROW READS AS A RECORD.
   `.row__title` is the anchor (tag AND customer name — §5 addition 2), so it
   carries the survey face for the tag portion's figures and does not truncate
   to a nowrap ellipsis inside a narrow lane. The meta line drops back.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .row {
  padding: var(--s-3) var(--s-4);
}

[data-kind="butcher-board"] .row__title {
  font-size: var(--t-body);
  font-variant-numeric: tabular-nums;
  white-space: normal;
  text-overflow: clip;
}

[data-kind="butcher-board"] .row__meta {
  white-space: normal;
  font-size: var(--t-label);
  color: var(--ink-faint);
}

/* The board's own census line ("5 ORDERS · 1 CUTTING, …") is orientation, not
   work. It sits under the search field with air, not crammed against it. */
[data-kind="butcher-board"] .pane__census {
  margin: var(--s-3) 0 var(--s-3);
}

/* -----------------------------------------------------------------------------
   13 — THE FIELD. The search field is the recognition-over-recall affordance
   (§3 E5, "nobody remembers tag 2026-114"). It renders at full pane width with
   a serif placeholder, which reads as prose. Survey face, sized to the work.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .field__control {
  font-family: var(--face-survey);
  font-size: var(--t-small);
  padding: var(--s-2) var(--s-3);
}

[data-kind="butcher-board"] .field__label {
  font-size: var(--t-label);
  letter-spacing: var(--tracking-caps);
  color: var(--ink-faint);
}

/* =============================================================================
   PASS 3 (S27.1101-sunny-wizard-ef24bd) — WHAT THE RAIL CHANGED, AND THE
   MEASURE PROBLEM THE FIRST WIDE SCREENSHOT MADE VISIBLE.

   Passes 1 and 2 were both repairs to a pane that was missing its left half.
   The structural fix is in `butcher-renderer.js`: Butcher now fills
   `ctx.menuBody` like every other Forest app, so `+ New order` and the three
   view verbs are `.rail__compose` / `.rail__slot` in the left column instead of
   a pill strip across the top of the work. Nothing below re-skins that — the
   rail wears the shared vocabulary and needs no butcher rules at all.

   What IS below is the fault the operator's screenshot showed that no probe
   could: on a real 2500px display every butcher surface is set to the FULL pane
   width, so `ORDERS` and `5` sit two thousand pixels apart with nothing between
   them. That is not a hierarchy defect and pass 2 could not have caught it —
   pass 2 was reasoning about weight, and this is about MEASURE.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   11 — THE GLANCE IS A LEDGER, AND A LEDGER HAS A MEASURE.
   `.line` is `display:flex` with the label `flex: 0 0 auto` and the value
   pushed right, which is correct at a card's width and absurd at a hall's. The
   Forest already owns the answer: `--measure` (1080px), the token the rest of
   the shell reads by. The eye can travel a label-to-figure gap of a measure;
   it cannot travel a pane.
   -------------------------------------------------------------------------- */
/* S27.1218: `.line` and `.pane__title` were glance-EXACT while `.view__detail`
   beside them was prefixed — the same rule, two selector shapes, which is the
   whole fault. All three now name the family. `.view__detail` deliberately
   keeps the BARE prefix (no `.pane`): it is the one subject the printed report
   also carries, and a printed ledger wants its measure too. */
.pane[data-kind^="butcher-season"] .line,
.pane[data-kind^="butcher-season"] .pane__title,
[data-kind^="butcher-season"] .view__detail {
  max-width: var(--measure);
}

/* The anomaly line ("N orders need a hand") is a sentence, not a ledger row —
   it holds its gold left rule but stops stretching to the horizon with it.
   S27.1145: this rule named `.pane__note` and reached NOTHING. The renderer
   emits the sentence as `p.pane__census[data-act="season-open"]`
   (butcher-surfaces.js renderSeasonGlance) — `.pane__note` appears exactly
   once in the served client tree, here, as this selector, with no counterpart
   anywhere. So the cap was byte-present and dead, which is the whole reason
   the glance still measured wrong one session after the cap was written.
   `.line--clickable` is kept: it is real, but it lives on the BOARD lane
   summary and never inside the glance, so it too was dead IN CONTEXT. */
.pane[data-kind^="butcher-season"] .pane__census,
.pane[data-kind^="butcher-season"] .line--clickable {
  max-width: var(--measure);
}

/* -----------------------------------------------------------------------------
   12 — THE LANES ARE A SEQUENCE, NOT A MASONRY WALL.
   `repeat(auto-fit, minmax(20rem, 1fr))` fits as many columns as the pane will
   hold, so on a wide display three lanes sat in a row and the fourth orphaned
   onto a second row underneath the first — the stages of the rite rendered in
   an order the grid chose. Capping the track count keeps the lanes reading
   left-to-right in the order the surface emits them, which is the order Rick
   works them.

   This is NOT the ordinal expression design-plan v2 §4 routed out (owed
   `butcher-rite-has-no-ordinal-expression`) — that project has to decide what a
   station IS. This only stops the grid from scrambling the sequence it is
   handed, which it should never have been doing.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .view[data-region="board-lanes"] {
  grid-template-columns: repeat(auto-fit, minmax(20rem, 24rem));
  justify-content: start;
}

/* A resting lane is a header band with nothing under it. Give it a floor so it
   reads as a CLOSED station rather than as a heading whose content failed to
   render — the difference between "nothing is cancelled" and "something broke".
   Weight and a hairline, no new hue. */
[data-kind="butcher-board"] .view__list:not(:has(.row)) {
  min-height: 4.5rem;
  opacity: 0.72;
}

/* -----------------------------------------------------------------------------
   13 — THE BOARD'S OWN WORK KEEPS THE MEASURE TOO.
   The row list, the census line and the honest-state notes are all reading
   surfaces. Left-aligned at a measure, they scan; full-bleed at 2500px they are
   a line of text with a continent after it.
   -------------------------------------------------------------------------- */
[data-kind="butcher-board"] .pane__census,
[data-kind="butcher-board"] .pane__absent,
[data-kind="butcher-board"] .pane__connect {
  max-width: var(--measure);
}

/* -----------------------------------------------------------------------------
   14 — THE BACK STRIP STEPS BACK.
   `.butcher__nav` used to carry the app's primary verbs; the rail carries those
   now, and all this strip does on a sub-view is walk back one step. A back link
   that renders with the same weight as a primary action is the exact
   undifferentiation pass 2 was chasing, one level up. It is a quiet control on
   a quiet surface, and it is the only thing left in the strip.
   -------------------------------------------------------------------------- */
[data-kind^="butcher-"] .butcher__nav {
  background: transparent;
  border: 0;
  padding: 0 0 var(--s-3);
  max-width: var(--measure);
}

/* -----------------------------------------------------------------------------
   15 — THE SEASON FAMILY GETS THE BOARD'S COMPOSITION FIXES (S27.1336).

   THIS FILE ALREADY DIAGNOSED THIS. Defect 2 in the header — `.view__list` sets
   `overflow: hidden auto` + `border-radius` while `.view__region-label` carries
   NO horizontal padding, so the label sits flush on the border box and is
   shaved — was fixed in section 2, scoped `[data-kind="butcher-board"]`, and
   never extended to the season family. So the same defect kept rendering on
   every season surface: "NEEDS A HAND" sits ON the panel's top hairline, and
   the census chain's "WHAT HAPPENED, AND WHEN" overflows its own rounded box.

   This is the SAME SHAPE as the 1.50 selector fault — a rule written for ONE
   `data-kind` where the FAMILY was meant. The fix there was the prefix; it is
   the prefix here. Prefix, not exact, is the default on this surface now.

   THE CENSUS ROW, and it is a composition fault not a missing feature. The row
   appends `.row__body` AND the chain `.view__list` as SIBLINGS of a
   `display:flex` row, so the chain becomes a second flex item sitting BESIDE
   the body at content width — about 8rem — and everything inside it clips:
   `HANGING (SUPERSED`, `PICKED UP (SUPERS`, and the region label spilling left
   across the customer's name. A record of what happened to an order is a
   READING surface; it belongs UNDER the row it describes, at a ledger measure,
   not crushed into a gutter beside it.

   WHAT IS DELIBERATELY NOT DONE HERE. `data-region="census-chain"` carries
   `data-open="0|1"` and there is NO `data-open` rule anywhere in this app, so
   the attribute is inert and every chain paints open. The obvious "fix" is to
   hide the closed ones — and it is wrong: nothing wires a toggle (the renderer
   is called with `{}`, `opts.expanded` is never passed, and no handler sets
   `data-open`). Hiding them would make the record UNREACHABLE, and adding a
   disclosure caret would draw an affordance that cannot fire — the false-green
   this file's own law forbids ("an unverifiable verify renders a loud honest
   state, never a false green"). So the chain stays VISIBLE and is made
   LEGIBLE. The missing toggle is a real gap; it is a behaviour gap, and it is
   named here rather than papered over.
   -------------------------------------------------------------------------- */

/* 15a — the region label sits ON the card, not ON the border. Section 2's rule,
   owed to the whole family. Fixes "Needs a hand" and the chain's caption. */
[data-kind^="butcher-season"] .view__region-label {
  padding: var(--s-3) var(--s-4) 0;
  margin: 0 0 var(--s-2);
  min-width: 0;
  overflow-wrap: anywhere;
}

/* 15b — the census row stacks. A two-column grid holds the body; the chain
   spans the full track on its own line, so it reads UNDER the order it
   describes instead of fighting it for horizontal room. */
[data-kind="butcher-season-census"] .row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-3);
  align-items: start;
  min-width: 0;
}

/* 15c — the chain is a ledger, so it takes the LEDGER measure (1.51's finding:
   `.line` is space-between, so the container width IS the label-to-figure gap).
   Full-bleed here would re-open the exact trip 1.51 just closed. */
[data-kind="butcher-season-census"] [data-region="census-chain"] {
  width: 100%;
  min-width: 0;
  max-width: var(--measure-ledger);
  overflow: visible;
  background: color-mix(in srgb, var(--paper) 10%, transparent);
}

/* 15d — nothing inside a chain clips mid-word. `.line` is flex over text nodes,
   which is defect 4 of the header list one level down: a stage label long
   enough to need room takes it by wrapping, never by being shaved. */
[data-kind="butcher-season-census"] [data-region="census-chain"] .line {
  min-width: 0;
  overflow-wrap: anywhere;
}
[data-kind="butcher-season-census"] [data-region="census-chain"] .line__label,
[data-kind="butcher-season-census"] [data-region="census-chain"] .line__value {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* 15d-ii — THE ROWS GET THE PADDING THE CAPTION GOT (S27.1528, owed 530).
   15a gave `padding: var(--s-3) var(--s-4) 0` to `.view__region-label` and
   stopped there. But the defect this file diagnoses in its own header is a
   property of the BORDER BOX, not of one element inside it: `.view__list` is
   `border + border-radius + overflow:hidden` with `padding: 0` (block.css
   :1147), so EVERY child sits flush on the border line. The caption was
   indented and every `INTAKE … Jul 25, 3:53 PM` under it was not — visible in
   the operator's own screenshots as content pressed against the glass.

   Same sentence as 1.50 and 1.52, new axis: those scoped a rule to one
   `data-kind` where the FAMILY of kinds was meant; this scoped a rule to one
   ELEMENT where the family of elements sharing one border box was meant.
   Padding goes on the ROWS, not the container, so the row hairlines keep
   running full-bleed (a list separator that stops short reads as a broken
   rule) while the text inside them sits off the border. */
[data-kind="butcher-season-census"] [data-region="census-chain"] .line {
  padding-left: var(--s-4);
  padding-right: var(--s-4);
}

/* 15e — one measure per card. The anomalies panel ("Needs a hand") was the last
   full-bleed region on a card whose every other reading surface now stops at
   the ledger measure; a single left column is what makes the card scan as one
   object instead of two stacked ones of different widths. */
[data-kind^="butcher-season"] [data-region="season-anomalies"],
[data-kind^="butcher-season"] [data-region="season-groups"] {
  max-width: var(--measure-ledger);
  min-width: 0;
}

/* -----------------------------------------------------------------------------
   16 — THE CENSUS IS A LIST, NOT A PAGE (S27.1336, after 1.52 by eye).

   `renderSeasonCensus` builds its rows region as `el(doc, "view", ...)` — but
   `.view` is the THREE-REGION PAGE TEMPLATE (`grid-template-columns:
   minmax(16rem,24rem) minmax(0,1fr) minmax(0,18rem)`), the shell that lays out
   LIST | DETAIL | CONTEXT for a whole surface. Used as a row container it makes
   every order a CELL in a page grid, which is why:
     - six orders tiled into three ragged columns,
     - `align-items: start` left a canyon of dead space under the short cards
       whenever one neighbour carried an eight-entry chain,
     - `margin: 0 auto` centred the block at --measure while every reading
       surface above it sits left-aligned at --measure-ledger.

   Same family of fault as 15 and as 1.50: a rule (there a selector, here a
   class) applied where its actual contract does not hold. The renderer's class
   choice is the root; this corrects the composition without touching a pure
   render function that 171 tests stand on.

   A census is "every order on file". The honest shape for that is ONE COLUMN,
   scanned top to bottom, each order's record directly beneath it — long is
   correct here, ragged is not.
   -------------------------------------------------------------------------- */
   RETIRED AT SHELL 1.56 — and the retirement is the point. This block was
   correct and it was the fifth of its kind, each one scoped to the exact
   `data-kind` that happened to get photographed that session. Naming the family
   was owed every time and paid none. `renderSeasonCensus` now builds its rows
   region as `view__rows` (block.css), the grammar class that did not exist when
   this was written, so these two rules are the grammar's job and are deleted
   rather than left to be cargo-culted into a sixth copy. Nothing about the
   census's rendered shape changes: `.view__rows` carries the identical
   `display:block; max-width:var(--measure); margin:0` and the same last-row
   border cleanup.
   -------------------------------------------------------------------------- */

/* -----------------------------------------------------------------------------
   16b — THE FAMILY GUARD (SHELL 1.56).
   The renderers are fixed and the grammar now has the class they were missing.
   This is the net under both: ANY butcher `.view` holding rows directly is a
   LIST that got handed the PAGE template, and it renders as a stack instead of
   shredding its rows into grid cells.

   WHY A SHAPE PREDICATE AND NOT A KIND LIST. Every prior fix in this family
   matched on `data-kind` — the one surface in front of the author — so the next
   surface with the same defect matched nothing and shipped broken. `:has(> .row)`
   matches the FAULT rather than the location, so a renderer written next month
   that reaches for `.view` on a list is caught without anyone editing this file.
   That exact-vs-shape choice is the 1.50/1.52 fault, stated here so it is not
   made a seventh time.

   IT DOES NOT CATCH `board-lanes`, AND THAT IS CORRECT. The board appends LANES
   (`.view__list`) to its region, never bare rows, so the predicate cannot match
   it — and the board's grid is deliberate (rules 1 and 13), not this defect.
   Verified against the renderer at `butcher-surfaces.js` (`lanesRegion.appendChild(lane)`).

   HONEST CEILING: this is a net, not a proof. It catches a `.view` that holds
   rows; it cannot see a list that clips for some other reason, and NOTHING in
   the 101-assertion butcher suite tests geometry at all — every assertion here
   checks content. The detector this family actually needs is a Tier-1 render
   proof over the butcher panes (`verify-fit-render.cjs`, which has never run on
   this app). Routed as owed, not claimed as done.
   -------------------------------------------------------------------------- */
[data-kind^="butcher-"] .view:has(> .row) {
  display: block;
  max-width: var(--measure);
  margin: 0;
}
[data-kind^="butcher-"] .view:has(> .row) > .row:last-child {
  border-bottom: none;
}

/* -----------------------------------------------------------------------------
   13 — THE PRIMARY KEY SURVIVES ON EVERY RECORD PANE (the family, named).
   The base `.row__title` policy (block.css) is overflow:hidden / nowrap /
   ellipsis — correct for a mail folder name, WRONG for a butcher record whose
   title IS the primary key (a date; a customer + #order). `[data-kind="butcher-
   board"]` un-did it one pane ago (§12: white-space:normal, the anchor wraps);
   the three OTHER record-list panes — the season census, the cooler log, the
   worker dashboard — never got that fix, so their key still truncated at phone
   width. The Tier-1 render proof (verify-fit-render.cjs, run for the first time
   this session) caught it: census + worker shredded "Katherine Vanderberg-
   Holloway · #10428" at 375px, worker worst (the .row__trail advance control
   squeezes the title lane to 48px).

   This names the FAMILY instead of fixing a fourth pane one-at-a-time — the exact
   trail block.css:1234 complained about. Same anchor policy butcher-board already
   uses: the key WRAPS (survives) rather than ellipsis-truncating (shredded), and
   overflow-wrap:anywhere lets a long word break inside the worker's tight lane
   rather than paint past it. The pane's row list already carries max-width:var(
   --measure), so wrapping does not blow the column. Additive — the board pane is
   already handled by §12 and is untouched.
   -------------------------------------------------------------------------- */
[data-kind="butcher-season-census"] .view__rows .row__title,
[data-kind="butcher-cooler-log"]    .view__rows .row__title,
[data-kind="butcher-worker"]        .view__rows .row__title {
  min-width: 0;
  white-space: normal;
  text-overflow: clip;
  overflow-wrap: anywhere;
}

/* -----------------------------------------------------------------------------
   THE WORKER ROW REFLOWS ON A PHONE (owed butcher-worker-row-trail-crowds-title-
   on-phone; operator ruling A1, S07.1441).

   The title-wrap fix above stops the key TRUNCATING, but the worker pane's
   `.row__trail` (the single primary advance control) is base-`flex: 0 0 auto`
   beside `.row__body`, so at 375px it still claims its width first and squeezes
   the title lane to ~48px — the key wraps into a tall skinny sliver, still
   unreadable. The board pane already solved this by letting the trail WRAP under
   the body when space is tight (§ butcher-board above); the worker pane never
   got that half. This applies the SAME proven pattern, scoped to the worklist
   rows. Fluid, not a breakpoint: on a wide screen nothing moves (body + trail
   share one line); on a phone the advance control drops to its own line beneath
   the name, which reclaims the full title lane. Additive — census/cooler carry
   no trail, so they are untouched.
   -------------------------------------------------------------------------- */
[data-kind="butcher-worker"] .view__rows .row {
  min-width: 0;
  flex-wrap: wrap;
  row-gap: var(--s-2);
}

[data-kind="butcher-worker"] .view__rows .row__body {
  min-width: 0;
  flex: 1 1 12rem;
}

/* `flex: 1 1 auto` lets the trail take the remaining inline space on a wide row
   and wrap to its own full line under the body when the row is too narrow to
   hold both — the board's exact trail rule, one pane over. */
[data-kind="butcher-worker"] .view__rows .row__trail {
  min-width: 0;
  flex: 1 1 auto;
  row-gap: var(--s-2);
}

/* On a phone the advance control is the thing a worker taps all day. Once it has
   wrapped below the name (above), stretch it to a full-width tap target so it is
   an easy thumb hit rather than a small button hanging off the left. Phone-only
   (<=40rem, the codebase's narrow breakpoint): on desktop it stays inline at its
   natural width, so A1's "nothing changes on a wide screen" promise holds. */
@media (max-width: 40rem) {
  [data-kind="butcher-worker"] .view__rows .row__trail {
    flex-basis: 100%;
  }
  [data-kind="butcher-worker"] .view__rows .row__trail > * {
    width: 100%;
  }
}

/* -----------------------------------------------------------------------------
   THE COOLER SAFETY MARK (S08.1239, decision #1 SURFACED).

   The per-reading alarm rides `data-butcher-mark` on the reading `.line` plus a
   spoken `.line__safety` sentence the renderer appends. DP-017: gold (--sunlight)
   = needs a hand. `warn` gets the quiet gold left-rule + faint wash; `danger` and
   a sustained-danger `discardRisk` get a FIRMER gold — heavier rule, stronger
   wash, weight on the words. ZERO NEW HUE: no red badge, no scolding (law 1); the
   firmer tier is MORE gold, never a different colour. Scoped to the cooler log so
   the mark cannot leak onto another pane's lines (butcher.css never edits shared
   block.css/shell.css to fix a butcher problem).
   -------------------------------------------------------------------------- */
[data-kind="butcher-cooler-log"] .line[data-butcher-mark="warn"] {
  border-left: 3px solid var(--sunlight);
  padding-left: var(--s-3);
  background: color-mix(in srgb, var(--sunlight) 6%, transparent);
}

[data-kind="butcher-cooler-log"] .line[data-butcher-mark="danger"] {
  border-left: 4px solid var(--sunlight);
  padding-left: var(--s-3);
  background: color-mix(in srgb, var(--sunlight) 14%, transparent);
}

/* The spoken sentence — words a health inspector reads, not only an attribute a
   stylesheet paints. Quiet by default; the danger tier takes ink + weight. */
[data-kind="butcher-cooler-log"] .line__safety {
  display: block;
  margin-top: var(--s-2);
  font-size: 0.85em;
  color: var(--ink-soft);
}

[data-kind="butcher-cooler-log"] .line__safety[data-butcher-mark="danger"] {
  color: var(--ink);
  font-weight: 600;
}
