/* The public site's COMPONENT layer (AC-M1-W7b-01, -02, -03, -05).
 *
 * Ported from the layout package Marcin generated outside this repository, which is a
 * REFERENCE IMPLEMENTATION: its markup, class names and structure are the deliverable and its
 * template language is not. `main.css` owns the base layer -- reset, body, headings, focus,
 * skip link -- and its rules are under test, so the package's duplicate base was NOT brought
 * across. Only what is genuinely additive is restated below.
 *
 * "THE CSS IS ADOPTABLE AS-IS" WAS FALSE, AND THIS FILE IS WHERE IT WAS FALSE (RC-079). The
 * delivered stylesheet inlined four colour literals and six rgb() values, two of which are
 * `--color-ink` and `--color-ink-inverse` written out by hand -- which is exactly what
 * AC-M1-W7b-05's positive control plants on purpose. Every one is now derived from the token
 * it was a copy of, through color-mix() rather than a new token, because the tokens are a
 * closed SET that docs/design-system.md declares and this file may not extend it.
 *
 * EVERY VALUE COMES FROM A TOKEN. No component reads a hue and none invents a spacing value:
 * per §3.3, a value not on the scale means the scale is wrong and the DOCUMENT is amended.
 */

/* --- additive base: the parts main.css does not already own ------------------------------ */

html {
  -webkit-text-size-adjust: 100%;
}

::selection {
  background: var(--color-accent-secondary-muted);
  color: var(--color-ink);
}

/* Media never overflows its column. The image and gallery blocks depend on this. */
img,
svg,
video {
  max-width: 100%;
  height: auto;
  display: block;
}

.u-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Layout primitives (§3.4) ------------------------------------------- */

/* ⑧ "jakieś dziwne coś przyklejone do stopki" -- the last block sat hard against the footer,
   with nothing between the content and the ink panel. v3's sections carry
   `padding: var(--space-8) var(--space-5)`; ours had padding on the inline axis only. */
/* THE OUTER ELEMENT SINCE AC-M5-W6-02: it wraps the card rather than sitting inside it, and
   it is what carries the measure -- for every page since `D-108`, which is why no modifier
   widens it any more. `padding-block` IS GONE, and `AC-M5-W6-07` is why.

   IT HELD TWO DIFFERENT PROPERTIES AT TWO DIFFERENT TIMES AND THE SECOND ONE WAS NOBODY'S.
   While `.l-page` sat INSIDE the shell, this was ⑧ — the content's own inset, the thing
   keeping the last block off the footer. `-02` made `.l-page` the OUTER element, and ⑧ moved
   with the content to `main#main` below. What was left here was no longer ⑧: it was a second
   helping of ①, the space around the card, which `.c-shell`'s `margin-block` already supplies.

   SO THE GAP ABOVE THE CARD WAS THE SUM OF TWO GAPS. Measured on the rendered page at 6259d98:
   `.l-page` padding-top 32px + card margin-top 32px = 64px above, and 64 + 32 = 96px below.
   A gap that is the sum of two former gaps answers "nie powinno być marginesu od góry"
   backwards. It is ONE value now and ① carries it, which is the declaration that was ruled to
   stand. The delivery's `.l-page` has no vertical padding either.

   Content that needs vertical rhythm gets it from `main#main` below — the element that holds
   CONTENT — never from the element that positions the card. */
/* DIVERGENCE, DECLARED (`D-108`). PACKAGE 18 CAPS THIS AT `--container-default` AND WE DO NOT.
   Marcin, unprompted, looking at staging: *"pozostałe strony poza SG mają inną szerokość niż SG.
   Wszystkie mają mieć taką jak SG"*.

   `D-091` IS NOT OVERTURNED; ITS OWN CONDITION IS MET. It read "every other page keeps the
   default measure UNTIL A DELIVERY SAYS OTHERWISE", and its argument was evidential: the
   delivery is a STANDALONE HOME PAGE and says nothing about the other twenty-one, so widening
   this on its authority would have been a guess. What arrived is not a wider delivery — it is
   the person the delivery was standing in for.

   THIS IS A DIVERGENCE AND NOT A DRIFT, and the difference is the whole point: package 18
   genuinely puts the other pages at 68rem. `public-assets.test.ts` records it and cites this
   decision rather than being loosened, because a relaxed gate and a declared divergence look
   identical in a green run and are opposites.

   `--container-default` STAYS IN `tokens.css` although nothing reads it now: it is design-system
   vocabulary shared with the delivery, and dropping it would diverge the token file too, for
   nothing. It is not dead. */
.l-page {
  width: 100%;
  max-width: var(--container-wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* THE CONTENT WRAPPER INSIDE THE CARD, AND ⑧'S ONLY HOME SINCE `AC-M5-W6-07`. The delivery
   has no `<main>` and its sections carry their own padding; ours keeps the landmark, so the
   vertical rhythm `.l-page` used to supply lives here instead — on the element that holds
   CONTENT rather than the one that holds the card. The block-END padding is ⑧: "jakieś dziwne
   coś przyklejone do stopki", the last block sitting hard against the ink panel. The home page
   overrides it to nothing: its sections are full-bleed inside the card, exactly as the
   delivery draws them. */
main#main {
  padding-inline: var(--gutter);
  padding-block: var(--space-6) var(--space-10);
}
/* `--flush`, NOT `--wide`, AND THE RENAME IS THE POINT (`D-108`). This rule has never been
   about width: it is what makes the home page's sections full-bleed inside the card, and it rode
   `.l-page--wide` only because the home page happened to be the wide one. Now that EVERY page is
   that width, a rule keyed on `--wide` would either match everything — insetting nothing,
   undoing `AC-M5-W8-03` on twenty-two pages — or keep a class whose name states a width it no
   longer confers.

   MEASURED BEFORE THE RENAME: home `main#main` padding 0/0, every other page 32px/56px. Removing
   the modifier from `core/home.html` without moving this rule would have given the home page
   back the inset and the top gap Marcin has asked about three times ("NADAL jest margines od
   góry"). The brief for this wave said `.l-page--wide` had no users left; it had this one. */
.l-page--flush > .c-shell > main#main {
  padding: 0;
}

/* THE SHELL IS A CARD WITH NO PADDING, AND ONE CLASS CANNOT SAY SO (measured, not reasoned).
   `.c-shell` set `padding: 0` and `.c-card` sets `padding: var(--space-5)` 370 lines later;
   both are one class, so the LATER one won and the shell rendered with 25px of padding it
   was documented as not having. Rendering `/en/instruments/region-en/` is what found it —
   the declaration was written, the comment described it, and the cascade disagreed with both.

   Two classes, so it cannot be lost to source order again. The space inside the card belongs
   to `main#main` above, which is the element that holds CONTENT; the card is a surface. */
.c-card.c-shell {
  padding: 0;
}

/* The page shell is the box the header, hero and split actually live in — it
   is narrower than the window (835px inside 924px, straddling the breakpoint),
   so those components query the SHELL, not the viewport. Same reason as
   @container measure below. */
/* THE SHELL IS THE CARD, AND THE DELIVERED CSS CANNOT TELL YOU THAT (AC-M1-W7d-02).
 *
 * It says only `container-type` here, and W7d read that silence as "the shell is unbounded".
 * It is a GAP, not a statement: no package has ever delivered a page shell. Every one of the
 * eight ships `blocks/`, `instruments/` and `partials/` and nothing above them, so `.c-shell`
 * is a class the design NAMES and never wraps -- the delivered stylesheet was written for
 * partials dropped into a shell it does not define.
 *
 * MEASURED FROM MARCIN'S MOCKUP rather than argued. Sampling a horizontal line across the
 * header of the design canvas thumbnail:
 *
 *     x   0-105   rgb(248,239,226)   ~ --color-surface        the page ground
 *     x 124-531   rgb(255,251,243)   = --color-surface-raised the CARD
 *     x 537-639   rgb(248,239,224)   ~ --color-surface        the ground again
 *
 * A bounded panel, centred, on a distinct ground. So the shell carries the width AND the
 * raised surface -- without the background there is no card, only a narrower column, which is
 * the same page with less of it.
 *
 * BOTH BOUNDS ARE LOAD-BEARING AND NOT REDUNDANT. `.c-shell` bounds the CARD, so the Deco band
 * and the header rule span it edge to edge. `.l-page` bounds the CONTENT COLUMN inside it, and
 * its `padding-inline: var(--gutter)` is what insets the text from the band's ends. Remove
 * either and the mockup stops being reproducible: without the first the card is the viewport,
 * without the second the text runs into the band's edges. */
/* THE SHELL IS A CONTAINER AND A CARD, AND AC-M5-W6-02 SPLIT THOSE APART.
   It used to carry both: the width, the centring, the margins, the raised surface, the edge
   AND the container query, all on one class. The delivery keeps them in two —
   `div.l-page.l-page--wide` OUTER for the measure, `div.c-card.c-shell` INNER for the card —
   and `D-091` concluded the width had to ride `.c-shell` "because the nesting is inverted".
   The nesting WAS inverted; un-inverting it is the fix, and the declarations go where the
   delivery keeps them.

   WHAT LEFT AND WHERE IT WENT.  width/max-width/margin-inline -> `.l-page`, which is now the
   outer element.  background/border/radius -> `.c-card`, which the shell now carries and
   whose values ARE the delivery's.  box-shadow and margin-block -> GONE: the delivery has
   neither, and Marcin's note on the top of the page is "nie powinno być marginesu od góry, za
   to powinien być ten lekki pasek" — no top margin, the Deco band instead.

   `AC-M1-W7e-01`'S REASONING SURVIVES ITS DECLARATIONS. It copied v3's four card lines here
   because the card read as flat without them — `--color-surface-raised` and `--color-surface`
   are two per cent apart, so with no border, no radius and no edge the card and the ground are
   one surface. That is still true and `.c-card` is still what makes it false; the class simply
   says so now instead of the shell restating it.

   `padding: 0` CANCELS `.c-card`'s `--space-5`, which is what the delivery does inline
   (`style="padding: 0; overflow: hidden"`). A page shell is not a card of content.
   `overflow: hidden` is not decoration: the Deco band and the hero are square-cornered and
   full-bleed inside this box and would otherwise poke through the rounded corners. */
.c-shell {
  /* ① IS GONE, AND `AC-M5-W8-03` IS THE THIRD TIME MARCIN HAS ASKED FOR IT.
     "nie powinno być marginesu od góry", then "NADAL jest margines od góry, strona miała
     zaczynać się od samej góry". Package 18 agrees with him: its `.c-shell` is
     `container-type` and `container-name` and NOTHING else, and its `.l-page` carries
     `padding-inline` only.

     WHY THE MARGIN SURVIVED TWO ROUNDS OF THIS. ① was written when `.c-shell` was the OUTER
     element and his complaint then — "the card met the browser chrome with no breathing room"
     — was about that arrangement. `AC-M5-W6-02` made `.l-page` the outer element, and the
     sentence in the gate went on describing a page that no longer existed. The gate asserted
     the MECHANISM, so it defended the margin every time the property was questioned; ① is the
     fourth proxy in `R-164`'s sequence and the only one that was actively argued for.

     What is left here is containment and the container registration, neither of which is
     spacing: `overflow` keeps the square-cornered Deco band and the full-bleed hero inside the
     card's rounded corners, and the `container-*` pair is what every `@container shell` query
     in this file resolves against. */
  /* `clip` RATHER THAN `hidden`, AND THAT ONE WORD IS WHY THE STICKY HEADER WAS NOT
     STICKING. `overflow: hidden` makes a SCROLL CONTAINER, and `position: sticky` sticks to
     its nearest SCROLLING ancestor — so `.c-header--compact` has declared
     `position: sticky; top: 0` all along and scrolled away with the page, because this box
     was the scroller and this box never scrolls. Measured: scroll 600px and the header top
     goes to -597 under `hidden`; it holds at 0 under `clip`.
  
     `clip` CLIPS IDENTICALLY AND MAKES NO SCROLL CONTAINER, which is the whole difference
     and is why package 19 uses it. Shell box and radius unchanged at 1163x2481 / 6px.
  
     THE FALLBACK ORDER IS DELIBERATE. A browser without `clip` DROPS the declaration and
     lands on `visible` — no clipping at all, worse than where we started. `hidden` first
     means it clips correctly and merely loses the stickiness; a current browser takes the
     second line and gets both. */
  overflow: hidden;
  overflow: clip;
  container-type: inline-size;
  container-name: shell;
}

/* `.l-page--wide` IS GONE (`D-108`), because every page is that width and a modifier that
   modifies nothing is a class the next reader has to test to understand. The width lives on
   `.l-page` itself; a page that ever wants a different one gets a modifier then, named for what
   it does.

   THE PARAGRAPH THAT STOOD HERE WAS STALE AND SAID THE OPPOSITE OF THE TREE. It read "Both
   `.c-shell` and `.l-page` cap at `--container-default`, and the shell is the OUTER one, so the
   modifier has to lift both" — true when `D-091` was ruled and false since `AC-M5-W6-02`
   un-inverted the nesting. `.c-shell` carries `overflow` and the container registration and no
   width at all; `home-layout.test.ts` has asserted that for three waves. A comment describing
   the arrangement its own neighbour replaced is how a session reasons its way to the wrong fix.

   `.l-page--narrow` STAYS AND IS UNTOUCHED. It sits on an `<article>` INSIDE the card, not on
   the card, so the legal and search pages take the same page width as everything else and keep
   a 44rem reading column within it. The thing Marcin was looking at is the card. */
.l-page--narrow { max-width: var(--container-narrow); }

.l-stack { display: flex; flex-direction: column; gap: var(--space-4); }
.l-stack--lg { gap: var(--space-6); }

/* AC-M6-W16-05. A MARGIN AND A GAP WERE BOTH APPLIED AND NEITHER KNEW ABOUT THE OTHER.
   `main.css` gives `h1`–`h4` and `p` a `margin: 0 0 var(--space-4)`, written for document flow
   where adjacent margins COLLAPSE. `.l-stack` is `display: flex`, and FLEX GAP DOES NOT COLLAPSE
   MARGINS — it adds to them. Measured on the guide page before this rule:

       h2 margin-bottom 16px + .l-stack gap 16px = 32px BELOW,  0px ABOVE

   Exactly doubled, and doubled on the wrong side: Marcin's complaint is that a heading belongs to
   what FOLLOWS it, which is right and is the opposite of what the arithmetic produced.

   THE RULE IS THE FIX AND THE FIVE DEFECTS WERE ITS SYMPTOMS. Inside a gap-based container the
   CONTAINER owns the rhythm and children carry no block margins of their own. That principle was
   already written down twice in this stylesheet — `.b-heading` says "no margin of its own:
   `.l-article`'s rhythm supplies every gap in the column", and `.c-placeholder` says the same.
   Both are OUR components. The GENERIC elements never got it, so every heading and paragraph
   brought a margin into a container that had already spaced it.

   THE CHILD COMBINATOR IS WHAT MAKES THIS SAFE, and it is the whole reason `-05` has a control.
   `.c-prose` is DOCUMENT FLOW, where margins collapse correctly and are the right mechanism —
   `.c-prose > * + *` at the end of this file is that rhythm and must not change. A `.c-prose`
   nested inside a stack has only its OWN margins zeroed here; its children are not children of
   the stack, so `>` never reaches them. Without the combinator this fix would move the defect
   onto every page that renders prose.

   IT IS ALSO A DECLARED DIVERGENCE FROM `jigs_web`, WHICH HAS THIS DEFECT TOO. `jigs.css:52` and
   `:59` carry the identical `margin: 0 0 var(--space-4)`, and `jigs.css:132` the identical
   `.l-stack` gap. Nothing was mis-ported; the doubling is the source's, and this is us diverging
   to fix it rather than to differ. */
.l-stack > * { margin-block: 0; }

/* AC-M6-W16-01. THE SWAP SLOT IS NOT A BOX UNTIL IT HOLDS ONE. `#bundle-card` sits after the
   workbench and the result card lands in it by `hx-swap="outerHTML"`, so before a generate it is
   an empty `<div>` and afterwards it is `.c-result` carrying the same id.

   Measured before this: button bottom to card top was 0px at 1280 and at 1024 — the card met the
   GENERUJ button with nothing between them. The rhythm comes from the stack that now wraps both,
   per `-05`; this rule is what stops that stack's gap becoming dead space on the far commoner
   state, which is the page before anybody has generated anything.

   THE CONTROL IS WHY IT IS KEYED ON `:empty` RATHER THAN ON `.c-result`. A rule that only exists
   once a bundle has been generated reappears as the same defect the first time somebody loads
   the page without generating; this one belongs to the swap TARGET, which is always there. */
#bundle-card:empty { display: none; }
.l-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }

.l-grid { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }

/* Article beside a sidebar. Flex rather than fixed grid tracks so it collapses
   on its own content, at whatever width the host gives it. */
.l-split { display: flex; flex-wrap: wrap; gap: var(--space-8); align-items: flex-start; }
/* container-type so the image block can ask about the COLUMN's width rather
   than the window's — a float beside a 356px aside is still too narrow for a
   measure well above the 52rem breakpoint. */
.l-split__main { flex: 3 1 20rem; min-width: 0; max-width: var(--measure); container-type: inline-size; container-name: measure; }
.l-split__aside {
  flex: 1 1 21rem;
  min-width: 0;
  max-width: 25rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  position: sticky;
  top: var(--space-5);
}

.c-journal__row { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: var(--space-4); align-items: start; }

/* THE FEATURED REGION -- BETWEEN THE NAV AND THE CONTENT COLUMN (AC-M1-W11-02, RC-110).

   Marcin, on the deployed demo page: "bloczki od wyróżnionych są pod treścią, jeśli one są
   aktywne, mają być zawsze zaraz pod menu, a ew. treści dopiero niżej." v3 agrees, and is the
   reason the region is not merely REORDERED but UNMEASURED: its hero (line 57) and facet row
   (line 74) are siblings of the header inside the shell, above the body grid at line 117 and
   wider than the prose in it. Inside `.l-article` a featured block was capped at `--measure`
   like a paragraph -- the half of his complaint that is not about order.

   IT IS EMITTED CONDITIONALLY, BY THE TEMPLATES, AND NOT HIDDEN BY THIS FILE. With no featured
   block the element is ABSENT from the DOM rather than present and empty. An empty wrapper here
   would contribute its own `margin-bottom` below nothing -- `RC-103` ⑧'s stray margin, the
   "dziwne coś przyklejone do stopki", one element up the page. Hiding it in CSS instead would
   leave an element that assertions can find and that the next rule can silently give a margin
   back to, which is the same defect wearing a repair's name.

   THE INSETS ARE v3's, AND THE FIRST DRAFT OF THIS RULE HAD THEM WRONG. I reasoned that
   `.l-page`'s `padding-inline: var(--gutter)` already supplied the region's inset. Measuring
   every ancestor of v3's hero says otherwise:

       line  21 <div     padding=var(--space-6) var(--gutter) 0     <- the GROUND, outside the card
       line  23 <div     padding=(none)          max-width=var(--container-default)   <- the card
       line  49 <div     padding=(none)                             <- the band, edge to edge
       line  57 <figure  padding=(none)  margin=0                   <- THE HERO, edge to edge
       line  74 <section padding=var(--space-8) var(--space-5)      <- the row, inset by space-5

   `--gutter` lives OUTSIDE v3's card, not inside it. Ours is on `.l-page` inside the card, so
   the region inherited an inset the design gives the page ground -- and `RC-100` is a whole
   finding about how little visible difference it takes to read as wrong. So the region escapes
   that padding to span the card, and the ROW takes back v3's own `var(--space-5)`. The hero is
   edge to edge; the row is not; both match the artboard.

   THE VERTICAL IS THE SAME MEASUREMENT ON THE OTHER AXIS. v3's hero sits flush under the band,
   and `.l-page`'s `padding-block-start` would open `--space-6` of card between them, which is
   the gap "zaraz pod menu" is a complaint about. That padding starts the COLUMN, so the region
   steps back over it and the column keeps it untouched when no featured block exists.

   `--space-8` between the runs and below the region is v3's section padding spent as margin
   instead. Identical geometry, and margins cannot double against the row's own padding the way
   a second padding would.

   NO `container-type` HERE, AND THAT IS CHECKED RATHER THAN ASSUMED. The only rules querying
   `@container measure` are the two `.b-image[data-wrap="true"]` floats; nothing a featured block
   renders asks about its container, so the region losing `.l-article`'s container breaks no
   query. A container declared here for symmetry would be an unread name. */
.l-featured {
  margin-inline: calc(var(--gutter) * -1);
  margin-bottom: var(--space-8);
}
/* THE STEP-BACK IS SCOPED, AND THE SCOPE IS THE WHOLE CORRECTION (`AC-M8-W4-09`, `R-068` rule 2,
   `BT-58`'s named remedy). The negative `margin-top` above exists to cancel `.l-page`'s
   `padding-block-start` — a padding that is only there when the region is the FIRST thing in the
   column. The instrument page is the first page to render something above it: `AC-M8-W4-01` put
   the breadcrumb trail inside `main#main` above the region, so the unscoped declaration stepped
   back over the NAV instead, closing a gap that was never the complaint and pulling the hero
   onto the trail. Measured at `c40b0c2`: the scoped form was absent from this file, `grep -c` 0.
   (SAID WITHOUT SPELLING THE SELECTOR ON PURPOSE. The test decides which branch to take by
   looking for that string ANYWHERE in this file, so a comment quoting it would keep the
   scoped branch green after somebody deleted the rule — a control that cannot fail, which is
   the shape `AC-M7-W8`'s retirement grep already paid for once.)

   IT IS A CORRECTION RATHER THAN A WORKAROUND, and the difference is checkable: with something
   above the region there IS no block-start padding at that point to cancel, so the declaration
   had nothing left to do and was doing something else. `test_R068_...` reads this file and takes
   its SCOPED branch on the strength of the selector below — which is why removing it turns the
   test red rather than silently disarming rule 2 where it still binds. */
.l-featured:first-child {
  margin-top: calc(var(--space-6) * -1);
}
/* v3's facet section insets itself where its hero does not, so the inset belongs to the ROW and
   not to the region. Separate from the grid rule above so those three declarations stay the
   ones W7g-07 shipped. */
.l-featured > [data-block-run="featured_card"] { padding-inline: var(--space-5); }
/* TWO SELECTORS, FOR `.l-article`'s REASON AND WITH ITS EXCEPTION (BT-84). A block is a
   GRANDCHILD of the region -- `render_blocks` wraps each run -- so the first selector alone
   spaces the hero from the card row and leaves NOTHING between two adjacent heroes. That case
   is editor-reachable: filtering by region changes ADJACENCY, so two `featured` blocks with
   only body blocks between them arrive here as one run of two, flush, with no error. Found by
   BACKEND against the shape rather than by either of us against the page.

   AND THE `featured_card` EXCLUSION IS LIVE HERE, which is where it belongs. A run laid out as
   a grid spaces itself with `gap`, and a margin-top on a grid item would double it and push the
   item down inside its own track. It retired from `.l-article` in this same commit because no
   grid run can be drawn in the column any more; it returns here because one is drawn here. */
.l-featured > * + *,
.l-featured > [data-block-run]:not([data-block-run="featured_card"]) > * + * {
  margin-top: var(--space-8);
}

/* Article column: never wider than the measure, in either locale. */
/* THE IMAGE BLOCK'S FLOAT ASKS THIS ELEMENT HOW WIDE IT IS, so it must be a container.
   `container-name: measure` was declared only on `.l-split__main`, so an article rendered in
   any other layout -- which is every page that is not a two-column split -- had a
   `@container measure` query that could never match. The floats silently did nothing: valid
   CSS, no error, and `align: left|right` behaving exactly like `full`. */
/* THE MEASURE IS A PROPERTY OF PROSE, NOT OF THE COLUMN (AC-M1-W7f-01).
   `max-width: var(--measure)` used to sit HERE, on the container, so every block inside it was
   capped at ~66 characters -- images, galleries, video, dividers and the CTA along with the
   text. On a 1024px card the content occupied about 550px and the rest was blank, which is the
   complaint Marcin made about the built page.

   v3 caps a measure on exactly THREE elements and all three are prose: the hero `h1` and two
   `p`. Nothing else in that page is measured. So the cap moves onto the prose blocks below and
   the column keeps its full width for everything else.

   `container-type` STAYS. The image block's float asks this element how wide it is, and it is
   now asking about the real column rather than a 66ch box. */
.l-article {
  line-height: var(--leading-loose);
  container-type: inline-size;
  container-name: measure;
}
/* THE VERTICAL RHYTHM, AND WHY IT NOW HAS TWO SELECTORS (BT-84, AC-M1-W7g-07).
   `render_blocks` groups a consecutive run of same-type blocks into one
   `[data-block-run]`, so a block is a GRANDCHILD of the article, not a child. The first
   selector alone therefore spaces runs from each other and leaves NO space between two
   paragraphs, because they are siblings inside one run rather than children of the column.
   Every SET we assert survived that change -- the types, the ids, the observation point --
   because a SET cannot see an adjacency, and `>` and `+` are adjacencies.

   THE `featured_card` EXCLUSION IS GONE, NOT RELAXED (AC-M1-W11-02). It read
   `:not([data-block-run="featured_card"])` and it was correct: a run laid out as a grid spaces
   itself with `gap`, and a margin-top on a grid item would both double that and push the item
   down inside its own track. `W11` draws every featured run OUTSIDE this element, so the clause
   can no longer match anything -- a styled selector with no producer, which is the shape this
   milestone has gated three times. Deleted rather than kept for safety, because "harmless" is
   how the other three arrived. The clause is not lost: `.l-featured` below needs exactly it,
   for exactly this reason, and gains it in this same commit -- the exception moved with the
   thing it excepts rather than being kept where nothing could trip it. */
.l-article > * + *,
.l-article > [data-block-run] > * + * {
  margin-top: var(--space-5);
}

/* THE HEADING RULE IS GONE RATHER THAN REPAIRED, and that was decided against v3 rather than
   by taste. `.l-article > * + .b-heading { margin-top: var(--space-8) }` had never matched
   anything: it needed a heading that is a direct child, and the only one is
   `page_detail.html`'s <h1>, which is the FIRST child, so `* +` could not reach it. Before
   moving the intent onto the run I checked whether the design has it, and it does not --
   v3's prose gives its <h2> `margin: 0 0 var(--space-5)`, the same rhythm as its paragraphs,
   with no extra space above. One value throughout the column; v3's only exception is its pull
   quote at --space-6. So there was nothing to keep, and a rule nobody could see was carrying
   an intent the design never had. */

/* --- Type utilities ----------------------------------------------------- */

.t-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-ink-muted);
}
.t-lead { font-size: var(--text-lg); }
.t-meta { font-size: var(--text-sm); color: var(--color-ink-muted); }
.t-data {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

/* --- Header, nav, locale switch ---------------------------------------- */

/* Deco banding under the header: the wordmark's own colour proportions. */
.c-band { display: flex; height: 6px; }
.c-band > * { display: block; }
.c-band__ochre { flex: 3; background: var(--color-accent-secondary); }
.c-band__accent { flex: 2; background: var(--color-accent); }
.c-band__rose { flex: 1; background: var(--color-accent-muted); }
.c-band__ink { flex: 2; background: var(--color-ink); }
.c-band__sand { flex: 1; background: var(--color-accent-secondary-muted); }

.c-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-5) var(--space-5) 0;
}
/* One continuous rule across the whole nav row — nav and utility sit inside
   it, so the line cannot break between them. */
.c-header__bar {
  width: 100%;
  border-top: 2px solid var(--color-ink);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4) var(--space-6);
  padding: var(--space-4) 0;
}
.c-header__utility { display: flex; align-items: center; gap: var(--space-3); }
/* The wordmark is the supplied artwork, not set type. IT SHIPS AS A 256-COLOUR PNG
   since `AC-M5-W7-01`; the SVGs stay TRACKED and are no longer SERVED. What is
   drawn, and from where:
     wordmark.png         full colour — light grounds          SERVED
     wordmark-paper.png   line cut, #F7EEDC baked — dark scheme, photos   SERVED
     wordmark*.svg        the vector source of all of the above — NOT served
   `backend/static/img/README.md` says what deleting the SVGs would cost.

   currentColor does NOT cross an <img> boundary — an image is its own document
   and resolves currentColor to black — so each cut has its colour baked, and
   that is as true of the PNGs as it was of the SVGs. Do not recolour a cut with
   filters; ask for the artwork in the colour you need. */
/* The wordmark is dense, faceted lettering with an "est. 2026" banner set at
   caption size. Scaled to a header-bar height it is illegible, so it leads the
   shell at full width and the nav sits on a rule beneath it. */
.c-header__wordmark {
  display: block;
  line-height: 0;
  width: 100%;
  max-width: 26rem;
  text-decoration: none;
}
.c-header__wordmark img { width: 100%; height: auto; display: block; }
/* THE RATIO IS THE FILE'S, AND IT IS NOT THE SVG'S (`AC-M5-W7-02`). It read
   2664 / 1180 — the SVG viewBox — while the served file is 833 x 369. Those are
   2.2576271 and 2.2574526, a disagreement of 0.012px at the widest the mark is
   ever drawn (22rem), so nothing was visibly wrong and nothing would have been
   until somebody trusted the number. A declared ratio that is ALMOST the file's
   is a wrong number that looks right, which is worse than an obviously wrong one.
   Pinned to the PNG's own dimensions, so all three — the `width`/`height`
   attributes, this rule, and IHDR — carry one value.
   (A PNG has intrinsic dimensions, so this pin is no longer load-bearing the way
   it was for a viewBox-only trace. It stays because the attributes can be lost in
   an edit and the collapse that follows is silent.) */
.c-header__wordmark img, .c-wordmark--on-dark img, .c-wordmark--ink img { aspect-ratio: 833 / 369; }
/* THE FULL-COLOUR MARK IS THE BRAND AND IS USED ON LIGHT GROUNDS (AC-M1-W7c-02).
   W7b substituted the ink line-cut for it on a byte budget — 407 KB against 111 KB — which
   was sound engineering applied to a question that was not engineering's. The mark is
   Marcin's: faceted Cubist lettering in ochre, terracotta and cream with a LUTHIER WORKSHOP
   banner, and the line cut throws away everything that makes it this workshop's. The cost is
   ~95 KB more once, on an edge that compresses SVG, and it is a price rather than an obstacle.

   The paper cut keeps its jobs: the dark scheme, --color-ink grounds and photography, where a
   colour mark on a dark field is unreadable rather than merely expensive. */

/* On --color-ink and on photography, use the paper cut directly. */
.c-wordmark--on-dark { display: block; max-width: 22rem; }
.c-wordmark--on-dark img { width: 100%; height: auto; display: block; }
/* On light grounds where colour would compete — the printed label, the QR
   card — use the ink cut.
   AC-M6-W3-03: the CHILD rule was ported and the PARENT was not, so the ink cut was inline
   and unbounded while its sibling --on-dark was block and capped. The package has both. */
.c-wordmark--ink { display: block; max-width: 22rem; }
.c-wordmark--ink img { width: 100%; height: auto; display: block; }
.c-nav { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--space-5); }
.c-nav__toggle { display: none; }

.c-nav__link {
  /* THE FLOOR IS DECLARED HERE, IN THE BASE RULE, NOT ONLY WHEN NARROW. It was set only
     inside the narrow-viewport block, as though a hit target were a small-screen concern.
     WCAG 2.5.8 is about the POINTER, not the width: a tablet in landscape is wide and is
     touched, and a wide window on a touch laptop is the same. Found by the gate below, which
     reads the base rule and did not find it. */
  display: inline-flex;
  align-items: center;
  min-height: var(--target-min);
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  text-decoration: none;
  padding-bottom: var(--space-1);
  border-bottom: 2px solid transparent;
}
.c-nav__link:hover { color: var(--color-ink); border-bottom-color: var(--color-accent-muted); }
.c-nav__link[aria-current="page"] { color: var(--color-ink); border-bottom-color: var(--color-accent); }

/* Reachable without opening a menu (AC-M0-W8-04). Sized for the longer
   locale label, never for the English one.

   AND THIS ::after ALONE NEVER DELIVERED THE TARGET, ON ANY PAGE. `.c-locale` below is
   `overflow: hidden` for its pill radius, and a 44px pseudo-element centred on a 34px box
   overflows that box by 5px at each end — so the clip removed exactly the part the repair
   added. Hit-tested with `elementFromPoint` rather than read off `getComputedStyle`, which
   reports 44px whether or not anything clips it:

       .c-locale__link   box 34px   EFFECTIVE 35px      <- before
       .c-unit__option   box 31px   EFFECTIVE 32px      <- the same shape, same cause
       .c-nav__link · .c-btn · .c-tab   box 44px   effective 45px

   `RC-088` is the finding that this control lost its target once. IT NEVER GOT IT BACK — what
   it got was a declaration `design-tokens.test.ts` can see and a browser cannot honour, because
   that gate reads the CSS text and nothing in the CSS text says an ancestor clips it.

   NOT REPAIRED HERE, AND THE REASON IS A GATE RATHER THAN A DOUBT. The house pattern is
   `min-height: var(--target-min)` on the control, and `delivered-structure.test.ts` ⑦ asserts
   this selector does NOT carry one: W7c decided the pill keeps v3's VISUAL box — about 32px —
   while a finger gets 44px from the pseudo-element. Adding `min-height` makes the box 44px and
   changes the delivered design, so it fails that gate, correctly. `AC-M6-W16-03` is about the
   `mm`/`in` pill and this is a different criterion's subject.

   THE REPAIR THAT KEEPS BOTH is to remove the clip rather than to grow the box — `.c-locale`
   below is `overflow: hidden` only so its pill radius cuts the `[aria-current]` background, and
   per-link `border-radius` on the first and last child does that without clipping anything.
   That is one decision by somebody who owns `AC-M1-W7g-01`, and it is reported rather than
   taken. `.c-unit__option` has no such gate and IS repaired, in this wave, by `-03`. */
.c-locale__link::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  height: var(--target-min);
}

/* THE CLIP IS GONE AND THE BOX IS UNCHANGED (`AC-M6-W18-01`). This carried `overflow: hidden`
   for exactly one job — its pill radius cutting the square corners off the `[aria-current]`
   background — and that clip also removed the half of `.c-locale__link::after` that sticks out
   of a 34px box to make a 44px target. Hit-tested before: box 34px, EFFECTIVE 35px, on all 24
   pages. `getComputedStyle` reported 44px throughout, because a clip is a property of the
   ANCESTOR and nothing in the rule can see it.

   TWO CONSTRAINTS THAT LOOKED OPPOSED AND WERE NOT. `W7c` decided the pill keeps v3's VISUAL box
   — about 32px — and `delivered-structure.test.ts` ⑦ asserts this control declares no
   `min-height`, so growing the box to 44px is refused, correctly; I tried that in `W16` and the
   gate caught it. The third option is to stop clipping and give the END LINKS the radius
   instead: the corners are cut by the things that have corners, the container needs no
   `overflow` at all, and the pseudo-element is free to extend past a box that is still 34px.

   `:first-child`/`:last-child` rather than `:nth-child(1)`/`(2)` because the switcher is two
   links today and the rule should not acquire a third-language bug. */
.c-locale {
  display: flex;
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-pill);
}
.c-locale__link:first-child { border-start-start-radius: var(--radius-pill); border-end-start-radius: var(--radius-pill); }
.c-locale__link:last-child { border-start-end-radius: var(--radius-pill); border-end-end-radius: var(--radius-pill); }
.c-locale__link {
  /* MEASURED BELOW THE FLOOR AND REPAIRED. At --text-xs with --leading-normal and 11px of
     vertical padding this box was 40.6px at the narrow end of the clamp — under WCAG 2.5.8's
     44px, on the control §4 requires to be reachable without opening a menu, which is exactly
     the control a thumb has to hit. The padding arithmetic said 44 and the type token it was
     computed against is not --text-sm. */
  /* ⑦ v3's VISUAL BOX, our TAP TARGET, and they are not the same box.
     v3's pill button is `padding: 7px 12px` on --text-xs -- about 32px tall. RC-088 measured
     ours at 40.6px and WCAG 2.5.8 wants 44, so W7c gave it `min-height: var(--target-min)`
     and it became visibly taller than the design.
     Neither had to lose. The visual box keeps v3's padding; the ::after below extends the
     HIT AREA past it without occupying any layout space. A finger gets 44px, an eye gets the
     pill Marcin drew. */
  position: relative;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  padding: var(--space-2) var(--space-3);
  color: var(--color-ink-muted);
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease-standard);
}
.c-locale__link:hover { background: var(--color-surface); color: var(--color-ink); }
.c-locale__link[aria-current="true"] { background: var(--color-ink); color: var(--color-ink-inverse); }

/* --- Buttons ------------------------------------------------------------ */

.c-btn {
  /* DECLARED, NOT COMPUTED. The height was `padding: 11px` chosen so that 11 + 11 + the line
     box reached 44px — arithmetic over a FLUID font size (--text-sm is a clamp), so it was
     only exactly true at one viewport width, and it silently moves whenever the type scale
     does. `min-height` states the floor instead of deriving it, and cannot drift. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--target-min);
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  padding: var(--space-2) var(--space-5);
  border: var(--border-hairline) solid transparent;
  border-radius: var(--radius-sm);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard),
              color var(--duration-fast) var(--ease-standard);
}
.c-btn--primary { background: var(--color-accent); color: var(--color-ink-inverse); }
.c-btn--primary:hover { background: var(--color-accent-hover); color: var(--color-ink-inverse); }
.c-btn--primary:active { background: var(--color-accent-active); }
.c-btn--quiet { background: transparent; color: var(--color-ink); border-color: var(--color-ink); }
.c-btn--quiet:hover { background: var(--color-ink); color: var(--color-ink-inverse); }
.c-btn--on-photo { background: transparent; color: var(--color-ink-inverse); border-color: var(--color-ink-inverse); }
.c-btn--on-photo:hover { background: color-mix(in srgb, var(--color-ink-inverse) 14%, transparent); color: var(--color-ink-inverse); }

/* --- Card, chip, panel ------------------------------------------------- */

.c-card {
  background: var(--color-surface-raised);
  border: var(--border-hairline) solid var(--color-rule);
  border-top: 3px solid var(--color-accent-secondary);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  transition: border-color var(--duration-fast) var(--ease-standard),
              box-shadow var(--duration-fast) var(--ease-standard);
}
/* A CARD THAT IS A LINK IS A CONTROL, so it declares the floor like every other one
   (`RC-088`, WCAG 2.5.8). It is comfortably over 44px today -- padding alone is two
   `--space-5` -- and the floor is DECLARED rather than computed anyway, because a computed
   check re-runs the author's arithmetic and agrees with it. A floor that does not currently
   bind is still the floor. */
a.c-card {
  display: block;
  min-height: var(--target-min);
  text-decoration: none;
  color: inherit;
}
a.c-card:hover, .c-card--interactive:hover {
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-sm);
}

/* A GRID WHOSE ITEMS ARE LIST ITEMS STILL NEEDS THE LIST RESET (AC-M2-W4-05). `.c-gallery`
   carries its own; `.l-grid` is a layout primitive used on `<div>`s until the instrument index
   put it on a `<ul>`, and a stray marker column is the whole difference between a gallery and a
   bulleted list. Element-qualified so the primitive stays a primitive. */
ul.l-grid, ol.l-grid { list-style: none; margin: 0; padding: 0; }

/* THE CARD AS A STACK. `.c-card--featured` already declares exactly these three, under a name
   that says where it is USED rather than what it DOES -- so this is the same layout, not a
   variant of it. Not consolidated here because `.c-card--featured` is named in
   `featured_card.html` and in `block-partials.test.ts`, and renaming a class across another
   wave's partial and its gate is not this criterion's business. Recorded so the duplication is
   a known one rather than a discovered one. */
.c-card--stack { display: flex; flex-direction: column; gap: var(--space-3); }
/* THE CARD'S PICTURE (`AC-M2-W4-05b`). Full bleed to the card's padding edge on the inline axis
   only -- the negative margin cancels `.c-card`'s own `var(--space-5)` -- so the photograph
   meets the card's border the way v3's facet card does, while the text keeps its inset.
   `aspect-ratio` with `object-fit: cover` because instruments are photographed portrait and
   landscape and a ragged grid reads as a mistake; the `width`/`height` attributes stop the
   reflow before the CSS loads, and this decides the shape after it. */
.c-card__media {
  display: block;
  width: calc(100% + 2 * var(--space-5));
  margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) 0;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}
.c-card--stack > * { margin: 0; }

.c-chip {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--color-accent-secondary-muted);
  color: var(--color-ink);
}

/* Rule 1: sunken is DARK. It always carries inverse ink. */
.c-panel--sunken {
  background: var(--color-surface-sunken);
  color: var(--color-ink-inverse);
  border-radius: var(--radius-lg);
  padding: var(--space-8) var(--space-6);
}
.c-panel--sunken .t-eyebrow,
.c-panel--sunken .t-meta { color: color-mix(in oklab, var(--color-ink-inverse) 78%, var(--color-surface-sunken)); }

.c-divider {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.c-divider::before, .c-divider::after {
  content: "";
  flex: 1;
  height: var(--border-hairline);
  background: var(--color-rule);
}

/* --- Data table (serials, jig parameters, BOM) ------------------------- */

.c-spec { width: 100%; border-collapse: collapse; }
.c-spec th, .c-spec td {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  text-align: left;
  padding: var(--space-3) var(--space-5) var(--space-3) 0;
  border-bottom: var(--border-hairline) solid var(--color-rule);
}
.c-spec th {
  font-weight: var(--weight-regular);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  white-space: nowrap;
}
.c-panel--sunken .c-spec th,
.c-panel--sunken .c-spec td { border-bottom-color: color-mix(in srgb, var(--color-ink-inverse) 16%, transparent); }
.c-panel--sunken .c-spec th { color: color-mix(in oklab, var(--color-ink-inverse) 72%, var(--color-surface-sunken)); }

/* --- Form (rendered generically; styled by field type, never by name) --- */

/* A FORM FIELD IS NOT PROSE, AC-M5-W2-04. `main.css` caps every `p` at `--measure`, and the
   enquiry block's fields are `<p class="c-field">` -- so the two `c-enquire__wide` rows, which
   `grid-column: 1 / -1` puts across the whole form, rendered at 544px inside a 724px form.
   Measured against the delivery: 544 | 724 on both wide rows. The package has no global `p`
   cap at all; ours predates the delivery and is right for prose, which a labelled input is not.
   Scoped to the class rather than removed from `p`, because the global cap is correct for the
   twenty-two pages that are prose -- and `c-field` is on a `p` in exactly one template. */
.c-field { display: flex; flex-direction: column; gap: var(--space-2); max-width: none; }
.c-field__label { font-size: var(--text-sm); color: var(--color-ink); }
.c-field__hint { font-size: var(--text-xs); color: var(--color-ink-muted); }

/* Rule 2 (OQ-012 A): control boundaries take --color-border, which is now the
   3:1 floor. --color-rule is decorative and is never a control's boundary. */
.c-field input,
.c-field select,
.c-field textarea {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
  background: var(--color-surface-raised);
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  width: 100%;
}
/* THE HIT TARGET IS DECLARED ON EVERY FORM CONTROL, NOT COMPUTED FROM ITS PADDING
   (`RC-088`, WCAG 2.5.8, `AC-M2-W8-04`). `--text-*` are `clamp()`, so any arithmetic over
   padding is exact at one viewport width and drifts at every other -- and a check that
   recomputed the box would re-run the author's model and agree with it (`FT-24`). Declared,
   so the runtime does the arithmetic. */
.c-field input,
.c-field select,
.c-field textarea { min-height: var(--target-min); }

.c-field input[type="number"],
.c-field input[inputmode="numeric"] { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.c-field textarea { resize: vertical; min-height: 6rem; }
.c-field input:focus-visible,
.c-field select:focus-visible,
.c-field textarea:focus-visible { border-color: var(--color-ink); }
.c-field[data-invalid] input,
.c-field[data-invalid] textarea { border-color: var(--color-accent); }

/* A CHECKBOX IS A ROW, AND THE LABEL IS THE TARGET (`AC-M2-W8-04`). The shared rule above
   makes a field a column and its control full-width, which is right for a text input and wrong
   for a consent tick. The floor goes on the LABEL rather than on the box: clicking a label
   toggles its checkbox natively, so the label IS the control surface, and a 44px checkbox
   would be a 44px checkbox. `width: auto` undoes the shared full-width. */
.c-field--check { flex-direction: row; align-items: flex-start; gap: var(--space-3); }
.c-field--check input[type="checkbox"] {
  width: auto;
  min-height: auto;
  margin-top: var(--space-1);
  accent-color: var(--color-accent);
}
.c-field--check .c-field__label {
  display: flex;
  align-items: center;
  min-height: var(--target-min);
  cursor: pointer;
}

/* --- The newsletter signup (AC-M2-W8-04) -------------------------------- */

/* A bounded column on the prose measure: a signup is read like prose and filled in like a
   form, and a full-width row of inputs on a 68rem card reads as a settings screen. */
.c-signup__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: var(--measure);
  margin-top: var(--space-5);
}

/* THE ANSWERED STATES ARE HIDDEN BY `hidden`, NOT BY A CLASS, so a state is absent from the
   accessibility tree rather than merely invisible -- `role="status"` on an element only
   `opacity: 0` would still be announced. `[hidden]` needs the explicit rule because
   `display: flex` on an ancestor does not stop a child's own display from winning. */
.c-signup__note[hidden] { display: none; }
.c-signup__note {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--color-success);
  background: var(--color-surface-raised);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.c-signup__note--bad { border-left-color: var(--color-accent); }

/* Rule 3: warning and danger are FILLS and take --color-ink, never inverse. */
.c-notice {
  display: flex;
  gap: var(--space-2);
  font-size: var(--text-sm);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-ink);
}
.c-notice--warning { background: var(--color-warning); }
.c-notice--danger { background: var(--color-danger); }
.c-notice--success { background: var(--color-success); color: var(--color-ink-inverse); }

@media (prefers-color-scheme: dark) {
  /* Binding rule 3 is written in the light scheme's terms — "a warning fill
     takes --color-ink, never --color-ink-inverse" — and inverts in the dark
     one, where --color-ink IS the light colour. Measured on the dark fills:
     --color-ink gives 1.13:1 on warning and 2.30:1 on danger, both illegal;
     --color-ink-inverse gives 12.2:1 and 6.2:1. Success needs no flip: it
     already carries --color-ink-inverse, which is the dark one here. */
  .c-notice--warning, .c-notice--danger { color: var(--color-ink-inverse); }
}

/* --- Photography ------------------------------------------------------- */

/* Hero text sits on its own opaque scrim, not on a gradient, so contrast
   does not move when the photograph changes. */
.c-hero { position: relative; display: flex; align-items: center; min-height: clamp(340px, 42vw, 500px); }
.c-hero__media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.c-hero__body {
  position: relative;
  max-width: 40rem;
  padding: var(--space-8);
  background: linear-gradient(90deg, color-mix(in srgb, var(--color-ink) 78%, transparent) 0%, color-mix(in srgb, var(--color-ink) 78%, transparent) 68%, transparent 100%);
  color: var(--color-ink-inverse);
}
.c-hero__body h1, .c-hero__body h2, .c-hero__body .t-eyebrow, .c-hero__body p { color: var(--color-ink-inverse); }

/* Captions over photography get an opaque chip, never a gradient. */
.c-caption {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
}
.c-caption--on-photo {
  color: var(--color-ink);
  background: var(--color-surface);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
}

/* image block: align left|right|full, wrap bool (architecture.md §4.2).
   Floated images never break the measure of the surrounding text. */
.b-image { margin: 0; }
/* Default is unfloated. The float is opt-in and only when the column can
   still hold a measure beside it (§3.4: a floated image never breaks the
   measure of the surrounding text). */
.b-image[data-wrap="true"] { float: none; width: 100%; max-width: none; }

@container measure (min-width: 480px) {
  .b-image[data-align="left"][data-wrap="true"] { float: left; width: 45%; max-width: 14rem; margin: 0 var(--space-5) var(--space-4) 0; }
  .b-image[data-align="right"][data-wrap="true"] { float: right; width: 45%; max-width: 14rem; margin: 0 0 var(--space-4) var(--space-5); }
}
.b-image[data-align="full"] { width: 100%; max-width: none; }
.l-article::after { content: ""; display: block; clear: both; }

/* --- ② featured, ③ the row (AC-M1-W7g-03) ------------------------------ */

.c-hero__heading { margin: 0 0 var(--space-3); font-size: var(--text-2xl); }
.c-hero__body .t-lead { margin: 0; }
.c-hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: var(--space-5) 0 0; }

/* No asset means no photograph, and the scrim exists only to hold text off one. Over the card's
   own surface it reads as a smudge, so the flat variant is an ordinary bordered panel and the
   inverse ink goes with it. */
.c-hero--flat { min-height: 0; }
.c-hero--flat .c-hero__body {
  max-width: none;
  background: none;
  border: var(--border-hairline) solid var(--color-rule);
  border-left: 4px solid var(--color-accent);
  border-radius: var(--radius-md);
}
.c-hero--flat .c-hero__body h2,
.c-hero--flat .c-hero__body .t-eyebrow,
.c-hero--flat .c-hero__body p { color: var(--color-ink); }

/* v3's facet card is already `.c-card`; only its internal layout is new. The modifier and not
   the base, because `.c-card` is also the search result item and a flex column would change it. */
.c-card--featured { display: flex; flex-direction: column; gap: var(--space-3); }
/* h3 and p both carry `margin: 0 0 var(--space-4)` from main.css, which would add to the gap. */
.c-card--featured > * { margin: 0; }
.c-card__heading { font-size: var(--text-lg); letter-spacing: 0.04em; text-transform: uppercase; }
.c-card--featured .c-chip { align-self: flex-start; margin-top: var(--space-1); }

/* ③ THE ROW — v3'S OWN DECLARATION, ON THE RUN (AC-M1-W7g-07).

   `render_blocks` now wraps a consecutive run of same-type blocks in one `[data-block-run]`,
   which is the container three sibling cards never had. So this is v3's facet row verbatim,
   and `auto-fit` does in layout what a `:has()` lookahead chain was doing in the selector:
   one card fills the width, two take half each, three take a third, with no rule per length
   and nothing to assert structurally because there is nothing that cannot be evaluated.

   The float mechanism this replaces is gone entirely -- widths, the forwards-only clears, the
   run-edge padding and the two-step lookahead whose second step our test engine silently drops
   (FT-28). What made it necessary was the absence of a container, not a property of floats.

   THE DECLARATIONS BELOW ARE W7g-07's, UNCHANGED. THE ANCHOR IS NOT, AND THAT DISTINCTION IS
   THE WHOLE OF W11's RISK (AC-M1-W11-02). This rule was keyed
   `.l-article > [data-block-run="featured_card"]`, and `AC-M1-W11-02` draws the featured region
   outside `.l-article` -- so the ancestor stops matching the moment the region moves, and three
   cards render as three stacked blocks: valid CSS, no error, and EVERY SET we assert survives
   it, because a SET cannot see a layout. `BT-84` is the same shape one week older, and "the grid
   is unchanged" was true of these three declarations and false of the selector carrying them.
   The rule now keys on the RUN and asks nothing about its ancestor, so it holds wherever the
   region is drawn -- which is also what makes it survive the next move without a fourth reading.

   `.l-article` IS STILL A PLAIN BLOCK CONTAINER, and dropping the ancestor does not touch that:
   this rule has always applied to the run wrapper and never to the column. The image block's run
   is still an ordinary block box inside the article, and its `data-wrap` float still escapes to
   wrap the text of following blocks -- see `.l-article::after` above, which exists only because
   that float escapes today. Making the ARTICLE a grid would trap the float in a grid item and
   kill a feature `wrap` marks REQUIRED on every image, with no error. */
[data-block-run="featured_card"] {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--space-4);
}

/* ==========================================================================
   Narrow viewports
   One breakpoint at 52rem, because that is where the article column and the
   aside stop fitting side by side — not because it is a device size. Measured
   against the shell container, never the window.
   Everything above is already fluid (auto-fit tracks, flex-wrap, clamp()).
   ========================================================================== */

/* THE NAV WRAPS; IT DOES NOT COLLAPSE BEHIND A DISCLOSURE, and the toggle's rules have been
   removed rather than left unused. The delivered header bound `hidden` through Alpine to a
   `matchMedia` result evaluated once at init, which does not survive a resize or an
   orientation change -- a control that can be silently wrong is worse than no control on a
   nav this size. The LANGUAGE SWITCHER never collapsed either way: AC-M0-W8-04 requires it
   reachable without opening a menu. */

@container shell (max-width: 52rem) {
  .c-header { padding: var(--space-4) var(--gutter) 0; }
  .c-header__wordmark { max-width: 22rem; }
  .c-header__bar { justify-content: space-between; row-gap: var(--space-3); }

  /* PORTED FROM THE DELIVERY (AC-M1-W7d-01), with ONE deliberate change: the hit target is
     declared with --target-min instead of the delivered `padding: 9px 14px`. RC-088 measured
     that arithmetic below the WCAG floor on a sibling control, and this button is a thumb
     target on exactly the widths where it appears. Everything else -- the border, the radius,
     the uppercase display face, the two-bar ::before glyph -- is the delivery's. */
  .c-nav__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: var(--target-min);
    font-family: var(--font-display);
    font-weight: var(--weight-medium);
    font-size: var(--text-sm);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    background: transparent;
    color: var(--color-ink);
    border: var(--border-hairline) solid var(--color-ink);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-4);
    cursor: pointer;
  }
  .c-nav__toggle[aria-expanded='true'] {
    background: var(--color-ink);
    color: var(--color-ink-inverse);
  }
  .c-nav__toggle::before {
    content: '';
    width: var(--space-4);
    height: var(--space-2);
    border-top: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
  }

  .c-nav {
    order: 3;
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .c-nav[hidden] { display: none; }
  /* THE HIT TARGET IS DECLARED WITH --target-min, NOT COMPUTED FROM IT.
     These were `13px`/`11px` paddings chosen so padding + line box reached 44. The plan was to
     rewrite them as calc() from the token; measuring first showed why that is still wrong.
     The line box is FLUID (every --text-* token is a clamp) and the four controls use three
     different type tokens, so any padding arithmetic is right at one width and drifts at
     every other. Hand-checking it got the answer wrong twice here, and .c-locale__link was
     genuinely 40.6px — below the floor — because its arithmetic had been done against the
     wrong type token. min-height states the requirement; nothing has to be re-derived. */
  .c-nav__link {
    /* min-height comes from the base rule; this only widens the row and squares the edge. */
    display: flex;
    padding: var(--space-1);
    border-bottom: var(--border-hairline) solid var(--color-rule);
  }
  .c-nav__link[aria-current="page"] { border-bottom-color: var(--color-accent); }

  /* Hero text takes the full width, on a flat scrim rather than a horizontal
     gradient: there is no room for the gradient to resolve. */
  .c-hero__body {
    max-width: none;
    width: 100%;
    padding: var(--space-6) var(--space-5);
    background: color-mix(in srgb, var(--color-ink) 82%, transparent);
  }

  /* The article/aside pair stacks; the aside stops being sticky, or it would
     pin a card over the text it belongs to. */
  .l-split { flex-direction: column; }
  .l-split > .l-split__aside { position: static; max-width: none; width: 100%; }

  /* Tap targets and thumb reach. */
  /* Both controls now DECLARE min-height: var(--target-min), so there is nothing left for a
     breakpoint to re-derive. Only the horizontal breathing room changes. */
  .c-locale__link { padding: var(--space-2) var(--space-4); }
  .c-field input, .c-field select, .c-field textarea { font-size: var(--text-base); }
}

@container shell (max-width: 30rem) {
  /* The wordmark's "est. 2026" banner is caption-sized artwork; below this it
     stops being legible, so it gets the full column. */
  .c-header__wordmark { max-width: none; }
  .c-header__utility { width: 100%; justify-content: space-between; }
  .c-panel--sunken { padding: var(--space-6) var(--space-4); }
  .c-spec th, .c-spec td { display: block; padding-right: 0; }
  .c-spec th { padding-bottom: var(--space-1); border-bottom: 0; }
  .c-journal__row { grid-template-columns: 64px minmax(0, 1fr); }
}

/* --- Footer ------------------------------------------------------------ */

.c-footer {
  background: var(--color-ink);
  color: var(--color-ink-inverse);
  padding: var(--space-8) var(--space-5);
}
.c-footer a { color: var(--color-ink-inverse); }
.c-footer .c-wordmark--on-dark { margin-bottom: var(--space-4); }
.c-footer .t-meta { color: color-mix(in oklab, var(--color-ink-inverse) 80%, var(--color-ink)); }
.c-footer .t-eyebrow { color: var(--color-accent-secondary-muted); }

/* ===================================================================================
   THE JIG PAGE (`AC-M6-W12-02`, `-03`, `-04`). Marcin opened it and annotated it.

   THREE OF HIS FIVE NOTES ARE ANSWERED BY THE DESIGNER'S OWN STYLESHEET, WHICH WE NEVER
   PORTED. `M6-W9` brought eight templates and left `jigs_web/static/css/jigs.css` to `W10`,
   so the cards have been rendering with no `.c-card__title` or `.c-card__body` rule at all.
   What he saw is what an unstyled card does, and the rules below at `ceda0e9` are his
   designer's:

       .c-card        display: flex; flex-direction: column; gap: var(--space-3)
       .c-card__title margin: 0; font-size: var(--text-xl)
       .c-card__body  flex: 1; margin: 0

   `.c-card__body { flex: 1 }` is the whole of `-02`: the body absorbs the slack, so the row
   after it lands on the bottom edge whatever the blurb says. That is alignment as a PROPERTY
   of the card rather than a value somebody tuned once.
   =================================================================================== */

/* A MODIFIER, AND NOT `.c-card` ITSELF, WHICH WOULD HAVE BEEN A SITE-WIDE ACCIDENT.
   The delivery puts `display: flex; flex-direction: column` on `.c-card`, because in
   `jigs_web` every card is that shape. Here it cannot go there: `<div class="c-card c-shell">`
   in `base.html` is the page shell of all 24 pages, the same class, so the bare selector would
   have turned every page's shell into a flex column.

   MY FIRST ATTEMPT WAS `:has(> .c-card__body)` AND A GATE REFUSED IT. `block-partials.test.ts`
   asserts the SET of `:has()` selectors in this stylesheet is EMPTY — it records that a
   run-length lookahead chain was replaced by `auto-fit`, and its mechanism is a ban on the
   whole feature. Mine had nothing to do with block runs, but the honest move is to write the
   rule another way rather than widen somebody else's gate to admit my exception.

   A modifier is also what this stylesheet already does — `c-card--stack`, `c-card--featured` —
   and it says the shape at the point of use, where a reader of the template can see it. */
.c-card--stretch {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.c-card--stretch > .c-card__body {
  flex: 1;
  margin: 0;
}
/* The trailing row holds the OPEN button. `margin: 0` because the card's own `gap` is the
   rhythm now, and a paragraph margin would add a second one on top of it. */
.c-card--stretch > :last-child {
  margin: 0;
}

/* `-03`. OGRANICZNIK RENDERED AS OGRANICZNI, and the cause is two things, not one.
   Measured before: `scrollWidth 294` inside `clientWidth 233`, at `font-size: 39.36px`,
   `text-transform: uppercase`, `overflow-wrap: normal`. Unstyled, the title took the global
   `h2` size; at that size one Polish word is wider than a third-of-a-row card.

   THE DESIGNER'S `--text-xl` IS THE FIX FOR TODAY'S WORDS. `overflow-wrap` IS THE FIX FOR
   TOMORROW'S. A single word longer than its box overflows at ANY font size — the registry is
   a list somebody will extend, and a fourth jig with a longer name would put this straight
   back. Breaking a long word is ugly; a word sticking out of its card is a defect. */
.c-card__title {
  margin: 0;
  font-size: var(--text-xl);
  overflow-wrap: break-word;
}

/* `-04`. ONE GAP FOR THE WHOLE OVERVIEW, so no seam on this page can be zero by itself.
   Measured before: the card grid met "WHAT GOES TO WHOM" at 0px. */
.c-jig-overview {
  display: grid;
  gap: var(--space-8);
}

/* The intro and the photograph. Proportions are the delivery's own workbench — a wide column
   beside a ~22rem one — reversed, because here the prose leads and the picture follows. It
   collapses at the same `@container shell` step as everything else on the site rather than at
   `jigs_web`'s `@media (max-width: 56rem)`, since our breakpoints are the shell's. */
.c-jig-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: var(--space-6);
  align-items: start;
}

/* THE PLACEHOLDER. `AC-M5-W4-02`'s idiom, in CSS rather than in a PNG: a solid ground with a
   lighter inset frame, so it cannot be mistaken for a photograph that failed to load.

   `aspect-ratio` IS WHAT KEEPS THE EMPTY STATE FROM COLLAPSING — the box exists at its full
   height with nothing in it, which is the state this page will be in for weeks, and it is the
   same box the photograph will occupy. */
.c-jig-photo {
  position: relative;
  margin: 0;
  /* THE JIG'S PROPORTIONS, AND THE ONE LINE TO CHANGE WHEN THE PHOTOGRAPH ARRIVES. Marcin is
     still assembling the jig, so its real shape is not known yet; 4/3 is a workshop object's
     usual one. The slot is sized by `aspect-ratio`, so correcting this moves nothing around it.

     NOT A TOKEN, DELIBERATELY. `--jig-photo-ratio` was the first draft and `design-tokens.test.ts`
     refused it: token NAMES must equal the SET `docs/design-system.md` declares, which is
     ARCHITECT-owned. Making a placeholder's aspect ratio wait on a design-system amendment
     would be the wrong trade, and a literal in one rule is just as much "one value to change"
     as a custom property would have been. */
  aspect-ratio: 4 / 3;
  background: var(--color-surface-sunken);
  border-radius: var(--radius-sm);
  overflow: hidden;
  display: grid;
  place-items: center;
}
.c-jig-photo::after {
  content: '';
  position: absolute;
  inset: var(--space-4);
  border: 2px solid color-mix(in srgb, var(--color-ink-inverse) 22%, transparent);
  pointer-events: none;
}
.c-jig-photo__note {
  color: color-mix(in oklab, var(--color-ink-inverse) 70%, var(--color-surface-sunken));
  text-align: center;
  padding: var(--space-4);
}
/* A real photograph fills the slot with no inset frame over it: the frame is what marks the
   placeholder AS one, and drawn over a photograph it would say the opposite. */
.c-jig-photo--filled::after { content: none; }
.c-jig-photo > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

@container shell (max-width: 52rem) {
  .c-jig-intro { grid-template-columns: minmax(0, 1fr); }
}

/* THE HONEYPOT'S HIDING PLACE, PORTED WITH THE TEMPLATES IT BELONGS TO (`AC-M6-W9-02`).
   From `jigs_web/static/css/jigs.css` at `ceda0e9`, verbatim.

   THE REST OF THE JIG STYLESHEET IS `W10`'s AND THIS ONE RULE IS NOT WAITING FOR IT, because
   it is not appearance. `generator/_form.html` renders a `website` field that no human should
   fill; `apps/jigs/views.py` refuses any submission that carries one. Without this rule the
   field is an ORDINARY VISIBLE TEXT BOX — measured on the rendered page at 881x26 px, sitting
   between two real fields with an empty label — so a sighted visitor fills it in and has their
   submission rejected with "This request could not be accepted." The trap catches the people
   it was built to protect.

   OFF-SCREEN RATHER THAN `display: none`, which is the source's choice and worth keeping: a
   bot that skips hidden inputs is exactly the bot this is trying to catch. `aria-hidden` on the
   wrapper is what keeps it away from a screen reader.

   The other fifteen jig classes have no rule here and that is deliberate — they are layout and
   type, the page renders unstyled without them, and `W10` brings the stylesheet. This one
   changes what the form DOES. */
.c-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ===================================================================================
   THE JIG PAGES' STYLESHEET (`AC-M6-W10-07`). Marcin, on the tab bar: "na każdej stronie
   powtarza się to — paskudne".

   IT IS NOT THE BAR. TWENTY-TWO CLASSES ACROSS TEN JIG TEMPLATES HAD NO RULE ANYWHERE — the
   whole post-generate card (`c-result`, `c-facts`, `c-license-note`), every error and status
   state, the BOM table, the unit switch and the workbench columns. `M6-W9` ported eight
   templates and `W10` six more; the "1 css" in both waves' deferral lists is this, and it was
   never brought. What he is looking at is what unstyled markup does, repeated on every page.

   PORTED from `jigs_web/static/css/jigs.css` at `ceda0e9`, rule for rule.

   EVERY TOKEN THESE RULES USE IS ALREADY DECLARED IN OUR `tokens.css` — 34 of 34, differenced
   before porting. The two token sets have converged far enough that the jig stylesheet needs
   nothing new, so this adds no name to the SET `docs/design-system.md` normatively declares and
   needs no amendment to it.

   `htmx-indicator` IS NOT HERE AND IS NOT MISSING. It is in the templates and in neither
   stylesheet: htmx injects its own `.htmx-indicator { opacity: 0 }` at load. Checked in both
   trees rather than assumed from its absence here.
   =================================================================================== */

/* DIVERGENCE, DECLARED: the source's scroll shadows are `rgb(0 0 0 / 12%)` and ours are the
   same shape through the ink token. `design-tokens.test.ts` forbids a colour literal outside
   `tokens.css`, and this is the treatment this stylesheet already gives a delivered literal —
   the carousel scrim is `rgb(31 26 22 / 0.9)` in the package and
   `color-mix(in srgb, var(--color-ink) 90%, transparent)` here, which is the same value because
   `--color-ink` IS `#1f1a16`.

   IT IS ALSO A BEHAVIOUR CHANGE AND IN THE RIGHT DIRECTION. `--color-ink` flips to `#f2e9d9`
   under `prefers-color-scheme: dark`, so the shadow that marks a scrollable tab row follows the
   scheme instead of staying a black smudge nobody can see on a dark ground. */
.c-tabs { display: flex; flex-wrap: nowrap; gap: var(--space-1); margin-bottom: var(--space-6); border-bottom: var(--border-hairline) solid var(--color-rule); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; padding-bottom: 1px; background: linear-gradient(to right, var(--color-surface-raised) 30%, transparent) left center / 2.5rem 100% no-repeat, linear-gradient(to left, var(--color-surface-raised) 30%, transparent) right center / 2.5rem 100% no-repeat, radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--color-ink) 12%, transparent), transparent) left center / 1rem 100% no-repeat, radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--color-ink) 12%, transparent), transparent) right center / 1rem 100% no-repeat; background-attachment: local, local, scroll, scroll; }
.c-tab { flex: none; display: inline-flex; align-items: center; min-height: var(--target-min); padding: var(--space-2); font-family: var(--font-display); font-size: var(--text-xs); letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-ink-muted); text-decoration: none; border-bottom: 3px solid transparent; margin-bottom: -1px; }
.c-tab:hover { color: var(--color-ink); border-bottom-color: var(--color-accent-muted); }
.c-tab[aria-current="page"] { color: var(--color-ink); border-bottom-color: var(--color-accent); }

/* DIVERGENCE, DECLARED: the source sizes this with `@media (max-width: 56rem)` and ours asks the
   SHELL. `AC-M5-W8-02` measured that a media query and a container query are different
   questions — the shell is inset by two gutters and capped by a max-width, so they disagree
   across a band of widths — and every breakpoint on this site is the shell's. */
/* THE BETA NOTICE on every jig page while the panel's switch is on (`AC-M8-W13-04`): a quiet
   note under the tab row, not an alert — it describes the jig, nothing has gone wrong. */
.c-beta { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-3); margin: var(--space-4) 0 0; padding: var(--space-3) var(--space-4); border: var(--border-hairline) solid var(--color-rule); border-left: 3px solid var(--color-accent-secondary); border-radius: var(--radius-sm); background: var(--color-surface-raised); font-size: var(--text-sm); color: var(--color-ink); }
.c-beta__tag { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-ink-muted); }
.c-workbench { display: grid; gap: var(--space-6); grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); align-items: start; }
@container shell (max-width: 52rem) {
  .c-workbench { grid-template-columns: minmax(0, 1fr); }
}
/* NO PREVIEW, THE FORM TAKES THE ROOM (`AC-M8-W13-08`). One column for the workbench, and the
   form's FIELDS in two; everything in the form that is not a field — the note, the honeypot, the
   Generate row — spans both, so the button is never stranded in one half. At the shell's phone
   breakpoint it is one column again. `c-workbench--form` is set only when the view has no
   preview, so a tab with a drawing keeps exactly the layout above. */
.c-workbench--form { grid-template-columns: minmax(0, 1fr); }
.c-workbench--form #jig-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4) var(--space-6); align-items: start; }
.c-workbench--form #jig-form > :not(.c-field) { grid-column: 1 / -1; }
@container shell (max-width: 52rem) {
  .c-workbench--form #jig-form { grid-template-columns: minmax(0, 1fr); }
}

.c-preview { position: sticky; top: var(--space-4); padding: var(--space-4); background: var(--color-surface); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-md); min-height: 12rem; }

/* THE LIVE SHEET'S FRAME (`AC-M6-W10-04`). Three rules from `jigs_web/static/css/jigs.css` at
   `ceda0e9`, ported verbatim apart from the tokens, all five of which we already declare — so
   nothing here is a new name and nothing is a literal.

   `width: 100%; height: auto` ON THE SVG IS WHAT MAKES THE SHEET RESPONSIVE, and it is the rule
   doing the work rather than the figure's. The generator emits a document with its own intrinsic
   size in millimetres; left alone it would render at that size and overflow the pane on a phone.
   The caption says "1:1 on the laser bed" and that remains true of the FILE — the link beside it
   opens the drawing at its real dimensions. What is scaled is the picture of it. */
.c-preview__sheet { margin: 0; }
.c-preview__sheet svg { width: 100%; height: auto; display: block; background: var(--color-surface-raised); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-sm); }
.c-preview__sheet figcaption { margin-top: var(--space-2); }

/* The three post-generate states. One shell, three left edges — which is what makes them read
   as the same card in different conditions rather than three components. */
.c-status, .c-result, .c-error { padding: var(--space-4) var(--space-5); border-radius: var(--radius-md); border: var(--border-hairline) solid var(--color-border); background: var(--color-surface); }
.c-status { border-left: 4px solid var(--color-accent-secondary); }
.c-result { border-left: 4px solid var(--color-success); }
.c-error { border-left: 4px solid var(--color-danger); }
.c-error ul { margin: 0; padding-left: var(--space-5); }
.c-license-note { font-size: var(--text-sm); color: var(--color-ink-muted); border-top: var(--border-hairline) solid var(--color-rule); margin-top: var(--space-3); padding-top: var(--space-3); }

.c-facts { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin: var(--space-4) 0 0; }
.c-facts > div { display: flex; flex-direction: column; gap: 2px; }
.c-facts dt { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-ink-muted); }
.c-facts dd { margin: 0; }

/* The unit switch. `::after` carries the 44px hit area without changing the pill's visual box —
   the same idiom `.c-locale__link` uses here, and `RC-088` is why both have one. */
/* AC-M6-W16-03. THE PILL HUGS ITS CONTENT. It is a block-level `<form>`, so `display: flex`
   with no width filled the column — 352px at 1280 and 621px at 760, around two buttons summing
   78px. In `jigs_web` this same rule sat in a header utility row where the surrounding flex
   shrink-wrapped it; here it is divergence ⑥'s geometric consequence, not a mis-port: the rule
   is byte-identical to `jigs.css:623`.

   Marcin asked for either half-and-half or `in` narrowed to `mm`'s width. `mm` and `in` are both
   two characters in the same mono face with equal padding, so a pill that hugs its content gives
   the second exactly and the first to within a pixel — measured at 39px and 39px. No choice was
   needed and none was made. */
.c-unit { display: flex; width: fit-content; border: var(--border-hairline) solid var(--color-border); border-radius: var(--radius-pill); overflow: hidden; }
.c-unit__option { position: relative; display: inline-flex; align-items: center; min-height: var(--target-min); font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; padding: var(--space-2) var(--space-3); color: var(--color-ink-muted); background: none; border: 0; cursor: pointer; transition: background var(--duration-fast) var(--ease-standard); }
.c-unit__option::after { content: ''; position: absolute; left: 0; right: 0; top: 50%; translate: 0 -50%; height: var(--target-min); }
.c-unit__option:hover { background: var(--color-surface); color: var(--color-ink); }
.c-unit__option[aria-current="true"] { background: var(--color-ink); color: var(--color-ink-inverse); }

.c-field--error input, .c-field--error select { border-color: var(--color-danger); }
.c-field--split { display: grid; grid-template-columns: 1fr auto; gap: var(--space-2); align-items: center; }
.c-field--split > label { grid-column: 1 / -1; }
.c-field--split > .c-field__help, .c-field--split > .c-field__error, .c-field--split > .u-visually-hidden { grid-column: 1 / -1; }
.c-field__unit { font-size: var(--text-sm); color: var(--color-ink-muted); }
.c-field__help { font-size: var(--text-xs); color: var(--color-ink-muted); }
.c-field__error { font-size: var(--text-sm); color: var(--color-danger); }

/* Rendered markdown — the assembly guide and the licence. */
.l-prose { max-width: var(--measure); }
.l-prose h2 { font-size: var(--text-xl); margin-top: var(--space-8); }
.l-prose h3 { font-size: var(--text-lg); margin-top: var(--space-6); }
.l-prose ul, .l-prose ol { padding-left: var(--space-5); }
.l-prose li { margin-bottom: var(--space-2); }
.l-prose hr { border: 0; border-top: var(--border-hairline) solid var(--color-rule); margin: var(--space-8) 0; }
.l-prose table { width: 100%; border-collapse: collapse; margin-bottom: var(--space-5); }
.l-prose :is(th, td) { text-align: left; vertical-align: top; padding: var(--space-2) var(--space-3); border-bottom: var(--border-hairline) solid var(--color-rule); }
.l-prose thead th { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-wide); border-bottom: 2px solid var(--color-ink); }
.l-prose code { font-family: var(--font-mono); font-size: 0.92em; }

/* The BOM table. `c-table-wrap` is one of exactly TWO things allowed to scroll sideways — this
   and `.c-tabs` above — and the two are the SET of scroll containers the page ever exercises.
   This comment said "three" for six waves; `admin-ui/scripts/scroll-audit.mjs` measured the
   population at 360/390/400px and found {nav.c-tabs, div.c-table-wrap}, nothing else, so the
   claim is now the measured number (`AC-M7-W9-01`). Everything else that runs off a phone's
   edge is either decoration the shell's `overflow: clip` is for, or a defect the audit prints. */
.c-table-wrap { overflow-x: auto; }
.c-table { border-collapse: collapse; width: 100%; font-size: var(--text-sm); }
.c-table th, .c-table td { text-align: left; vertical-align: top; padding: var(--space-2) var(--space-3); border-bottom: var(--border-hairline) solid var(--color-rule); }
.c-table thead th { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-ink-muted); border-bottom: 2px solid var(--color-ink); }
.c-table tbody th { font-weight: var(--weight-medium); min-width: 9rem; }
.c-table__where { display: block; margin-top: var(--space-1); }

.c-placeholder { margin: 0; padding: var(--space-6); border: 1px dashed var(--color-border); border-radius: var(--radius-md); background: var(--color-surface); text-align: center; }

/* ===================================================================================
   THE 3D VIEWER (`AC-M6-W10-05`, `D-099`). Marcin, on staging: "po wygenerowaniu nie ma
   podglądu 3d, w starych jigach był".

   Ported from `jigs_web/static/css/jigs.css` at `ceda0e9`, selectively — keyed on the SET of
   classes the two viewer templates use that had no rule here, the same method as `-07`. 18 of
   19 tokens these rules need were already declared; the nineteenth is not a token at all.

   THE SOURCE'S `--swatch` CUSTOM PROPERTY IS NOT PORTED, AND THE EFFECT IS. It wrote the
   part's colour into `style="--swatch: …"` and read it back as `var(--swatch, var(--color-border))`.
   That is a DATA CHANNEL, not a design token — three producers write it: both viewer templates
   and `viewer.js`, once per part, from the generator's own per-part colours. But
   `design-tokens.test.ts` asserts every `var(--x)` in this stylesheet names a token
   `docs/design-system.md` §3 declares, and it is right to: its control is an invented
   `--color-brand-new`, and a custom property nothing writes resolves to NOTHING.

   The gate has no category for a data channel, and `docs/design-system.md` is ARCHITECT-owned,
   so the choice was to widen somebody else's gate for the session that wants through, or to
   find a form that does not need the exception. The indirection is what the gate objects to, and
   the indirection buys nothing here: the colour is written straight into `background`, and the
   DEFAULT lives below in this rule. An empty value makes the inline declaration invalid, the
   parser drops it, and this rule stands — which is exactly what the `var(…, fallback)` did,
   with one moving part instead of two. Named in the `-05` report: if the ARCHITECT would
   rather the gate learned the category, that is their file and their call.

   ONE COLOUR LITERAL CONVERTED, as in the tab bar: the swatch border was `rgb(0 0 0 / 25%)`
   and is `color-mix(in srgb, var(--color-ink) 25%, transparent)` here. Same reasoning — the
   literal is refused outside `tokens.css`, the ink token IS `#1f1a16`, and the token follows
   `prefers-color-scheme` where a fixed black does not.
   =================================================================================== */

.c-viewer { margin: var(--space-4) 0; }
.c-viewer__controls { margin-block-start: var(--space-3); }
.c-viewer__head { position: sticky; top: var(--space-3); z-index: 1; background: var(--color-surface-raised); }
@media (max-width: 48rem) {
  .c-viewer__head { position: static; }
}
.c-viewer__stage { aspect-ratio: 16 / 9; min-height: 35rem; border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-md); overflow: hidden; background: var(--color-surface); max-inline-size: 100%; }
.c-viewer__stage[data-state="loaded"] > .t-meta { display: none; }
@media (max-width: 48rem) {
  .c-viewer__stage { aspect-ratio: auto; min-height: 16rem; height: 60vw; }
}
.c-viewer__stage canvas { display: block; width: 100%; height: 100%; }
.c-viewer__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding-block: var(--space-2); border-bottom: var(--border-hairline) solid var(--color-rule); }
.c-viewer__toolbar .c-modes { display: flex; align-items: center; gap: var(--space-2); margin: 0; padding: 0; border: 0; min-inline-size: 0; }
.c-viewer__toolbar .c-modes > legend { float: none; padding: 0; margin: 0; }
.c-viewer__toolbar .c-modes label { display: flex; align-items: center; gap: var(--space-1); font-size: var(--text-xs); }
.c-viewer__toggle { font-size: var(--text-xs); display: flex; align-items: center; gap: var(--space-1); }
.c-viewer__controls > .c-viewer__slider { padding-block: var(--space-2); max-width: 32rem; }
.c-viewer__panel { columns: 2; column-gap: var(--space-5); }
@media (max-width: 43.75rem) {
  .c-viewer__panel { columns: 1; }
}
.c-viewer__section { break-inside: avoid; page-break-inside: avoid; display: flow-root; margin-block-end: var(--space-3); }
.c-viewer__section > .t-eyebrow { display: block; margin-block-end: var(--space-1); }
.c-viewer__stage > .t-meta { padding: var(--space-4); }
/* THE LOADING NOTE IS HIDDEN ONCE THERE IS SOMETHING TO SEE. `data-state` is written by
   `viewer.js` — `element.dataset.state = 'loaded'` on success, `'error'` on failure — and the
   error branch also REWRITES the note's text, so this rule must hide it in exactly one of the
   two states and not the other.

   I DROPPED THIS RULE AND WAS WRONG. `styled-attributes.test.ts` reported no producer, I
   grepped the tree for `data-state=`, found none, and concluded it was dead in the source too.
   The producer is `element.dataset.state`, which that grep cannot match and neither can the
   gate: `hasProducer` consults the JS producer set ONLY for a selector with no class, and falls
   back to template tags the moment one is named. The gate has been widened to see the chain it
   already intended to see, with a control — not for this rule's benefit: `nav-toggle.js` was
   in its producer list from the start for exactly this reason.

   WHAT CAUGHT IT WAS NOT THE ARGUMENT, IT WAS THE BROWSER. With the rule gone the probe
   reported `status: "Loading the model…"` on a page whose model had loaded and whose canvas
   was up. A missing `display: none` is invisible to every check that reads the stylesheet. */
.c-viewer__parts { list-style: none; margin: 0; padding: 0; font-family: var(--font-mono); font-size: var(--text-xs); display: flex; flex-direction: column; gap: var(--space-1); }
.c-viewer__parts label { display: flex; gap: var(--space-2); align-items: baseline; }
.c-part { display: flex; flex-direction: column; gap: 2px; padding: var(--space-1) var(--space-2); margin-inline: calc(-1 * var(--space-2)); border-radius: var(--radius-sm); }
.c-part.is-pointed { background: var(--color-surface); }
.c-part__swatch { inline-size: 0.8em; block-size: 0.8em; flex: none; border-radius: 2px; background: var(--color-border); border: var(--border-hairline) solid color-mix(in srgb, var(--color-ink) 25%, transparent); }
.c-part__name { font-family: var(--font-body); font-size: var(--text-sm); }
.c-part__role, .c-part__note { font-family: var(--font-body); font-size: var(--text-xs); line-height: 1.45; }
.c-part__note { font-style: italic; }
.c-part--alternative .c-part__name { color: var(--color-ink-muted); }
.c-part--reference .c-part__name { color: var(--color-ink-muted); }
/* THE SOURCE WRITES THIS `.c-part--alternative:has(:checked) .c-part__name`, and
   `block-partials.test.ts` asserts the SET of `:has()` selectors here is EMPTY — it records
   that a run-length lookahead chain was replaced by `auto-fit`, and its mechanism is a ban
   on the feature. Rewritten rather than widening somebody else's gate to admit an
   exception: the checkbox and the name are SIBLINGS inside the same `<label>`, so the
   general-sibling form selects exactly the same elements. */
.c-part--alternative input:checked ~ .c-part__name { color: var(--color-ink); }
.c-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); font-size: var(--text-xs); }
.c-legend li { display: flex; align-items: center; gap: var(--space-1); }
.c-viewer__slider { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-xs); }
.c-viewer__slider input[type="range"] { flex: 1 1 auto; min-width: 0; }
.c-viewer__slider output { flex: 0 0 auto; min-width: 4.5ch; text-align: right; }
.c-viewer__readout { font-size: var(--text-xs); color: var(--color-ink-muted); min-height: 2.6em; }
.c-viewer__readout[data-named] { color: var(--color-ink); }
.c-viewer__parts input[type="checkbox"] { font-size: var(--text-xs); }
.c-viewer__parts .is-missing { color: var(--color-ink-muted); }
.c-viewer__parts li.is-missing { padding-inline-start: calc(1em + var(--space-2)); }

/* --- Print: the label and the A4 jig sheet share this vocabulary ------- */

@media print {
  .c-header, .c-locale, .c-footer, .c-btn, .c-band, .c-tabs, .c-filters, .c-pagination { display: none; }
  /* The label prints the ink cut. Nothing here relies on blend modes. */
  body { background: none; color: var(--color-ink); font-size: 12pt; }
  .l-article { max-width: none; }
}


/* --- Search results (AC-M1-W7b-03) ------------------------------------------------------- */

.c-results {
  list-style: none;
  margin: 0;
  padding: 0;
}

.c-results__link {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  text-decoration: none;
}

.c-results .t-meta {
  margin: var(--space-2) 0 0;
}

/* --- Block partials (AC-M1-W7b-01) ------------------------------------------------------
   One class per registered block type. `.l-article > * + *` already supplies the vertical
   rhythm between blocks, so these carry only what is specific to the block -- a block that
   sets its own top margin would double it. */

.b-paragraph {
  margin: 0;
  max-width: var(--measure);
}

.b-heading {
  /* Measured, because a heading is prose. Images, galleries, video, dividers and the CTA are
     NOT, and they now fill the column -- see the note on .l-article. */
  max-width: var(--measure);
  /* No margin of its own: `.l-article`'s rhythm supplies every gap in the column, and v3
     spaces its heading exactly as it spaces a paragraph. */
  margin: 0;
}

.b-quote {
  max-width: var(--measure);
  margin: 0;
  padding: var(--space-5);
  /* Ⓠ RC-100'S FAILURE ONE ELEMENT IN. This was --color-surface-raised, which is the CARD's own
     background -- so the panel vanished into the surface it sits on and only the left bar
     survived. Two per cent apart, exactly as the card was against the page ground. v3 uses
     --color-surface HERE, and a full hairline border, precisely because it is drawn on a
     raised card. */
  background: var(--color-surface);
  border: var(--border-hairline) solid var(--color-rule);
  border-left: 4px solid var(--color-accent);
  border-radius: var(--radius-md);
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
}
.b-quote p {
  margin: 0;
}
.b-quote .t-meta {
  margin-top: var(--space-3);
}

.b-cta {
  margin: 0;
}

/* ④ v3 draws this rule as `flex: 1; height: 2px; background: var(--color-ink)` -- twice, one
   either side of an optional label. Ours was a 1px --color-rule hairline: the right shape at
   a fifth of the weight and a fraction of the contrast. Marcin: "Może być bez tego tekstu" --
   the label is optional, the WEIGHT is not. */
.b-divider {
  border: 0;
  height: 2px;
  background: var(--color-ink);
  margin: 0;
}

/* The ornament is drawn entirely in CSS so the <hr> keeps its meaning and nothing decorative
   enters the accessibility tree. A faceted lozenge sitting ON the rule, per D-036: structure
   rather than period ornament applied on top.

   The first version flexed two pseudo-elements apart with a gap between them, which draws two
   short rules and no ornament -- a broken divider rather than a decorated one. The rule is now
   a background on the element itself, so the lozenge can sit over its centre. */
.b-divider--ornament {
  height: var(--space-4);
  background: linear-gradient(var(--color-ink), var(--color-ink)) 0 50% / 100% 2px no-repeat;
  position: relative;
  overflow: visible;
}
.b-divider--ornament::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--space-3);
  height: var(--space-3);
  transform: translate(-50%, -50%) rotate(45deg);
  /* Punched out of the surface so the rule appears to pass behind it. */
  background: var(--color-surface);
  border: var(--border-hairline) solid var(--color-accent);
}


/* --- gallery and video facade (AC-M1-W7b-01) --------------------------------------------- */

.c-gallery {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  gap: var(--space-3);
}

.c-gallery img {
  width: 100%;
  /* A uniform ratio, so a mixed set of portrait and landscape photographs still reads as one
     grid rather than as a ragged column. object-fit crops rather than distorts -- a stretched
     instrument is worse than a cropped one. */
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: var(--border-hairline) solid var(--color-rule);
  border-radius: var(--radius-md);
}

/* The video facade: our poster and a real button, with no third-party request until it is
   pressed. The play control sits over the poster; with no poster it sits on the surface and
   still works, because the button is the control and the poster is decoration behind it. */
.b-video {
  position: relative;
  margin: 0;
  display: grid;
  place-items: center;
  min-height: var(--space-16);
  background: var(--color-surface-sunken);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.b-video__poster {
  grid-area: 1 / 1;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.b-video__play {
  grid-area: 1 / 1;
  z-index: 1;
  max-width: calc(100% - var(--space-8));
}

/* Once loaded, the iframe replaces the facade in the same box, so the page does not jump. */
.b-video iframe {
  grid-area: 1 / 1;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  display: block;
}


/* --- Rendered markdown (AC-M1-W7b-02, D-057) --------------------------------------------- */

/* THE ONLY PLACE ON THE PUBLIC SITE WHERE ELEMENT SELECTORS ARE RIGHT. Everywhere else the
   markup is ours and carries classes; here the HTML comes from a markdown renderer and there
   are no classes to hook. Scoped under `.c-prose` so it cannot leak into the block partials. */

.c-prose > * + * {
  margin-top: var(--space-5);
}

.c-prose h2,
.c-prose h3,
.c-prose h4 {
  margin-top: var(--space-8);
}

.c-prose ul,
.c-prose ol {
  padding-left: var(--space-6);
}

.c-prose li + li {
  margin-top: var(--space-2);
}

/* The seller-identification table (compliance.md §3.1). It is a real table of real facts, so
   it is bordered and legible rather than styled away -- and it must survive the switch from
   SellerIdentity tokens to resolved values without the layout moving. */
.c-prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.c-prose th,
.c-prose td {
  text-align: left;
  vertical-align: top;
  padding: var(--space-2) var(--space-3) var(--space-2) 0;
  border-bottom: var(--border-hairline) solid var(--color-rule);
}

.c-prose th {
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  font-size: var(--text-xs);
}

/* A table of contact details and identifiers is tabular data: it uses the mono stack with
   tabular figures so a NIP and a REGON align down the column (§3.2). */
.c-prose td {
  font-variant-numeric: tabular-nums;
}

/* Long-form legal text wants the loose leading, and the measure keeps the line length
   readable however wide the window is. */
.c-prose {
  line-height: var(--leading-loose);
  max-width: var(--measure);
}

/* === HOME PAGE (D-073, AC-M5-W1-02) =======================================================
   FROM THE DESIGN PACKAGE, APPENDED RATHER THAN REPLACING THIS FILE.

   The package ships a 93-class `app.css`; ours has 84 and only 59 are shared. Replacing the
   file would have dropped 25 of ours — every CMS block, the gallery, search, the signup form
   and the article prose — unstyling 22 pages to style one. What follows is the 34 classes
   that are genuinely new, taken as one section.

   THE SHARED 59 KEEP OUR RULES, NOT THE PACKAGE'S. Its file is an older cut of this one
   (619 lines against 1151, same comments verbatim) and has not seen the CMS blocks, the
   gallery or the search results. Taking its version of a shared component would be a
   regression wearing a delivery's clothes. The tokens are what carry the new look, and
   those ARE the package's now (`D-073`). ------------------------------------------------ */
/* --- Home page (M3) ------------------------------------------------------
   Carousel, journal list, bench cards. Same tokens, same rules: sunken is
   dark and carries inverse ink; warning is a fill with --color-ink. -------- */

/* Carousel = the hero, repeated. Slides stack absolutely and cross-fade on
   opacity; only [data-active] is visible. Without JS the FIRST slide shows
   and the controls are hidden — the page still works. */
.c-carousel { position: relative; min-height: clamp(440px, 56vw, 720px); background: var(--color-surface-sunken); color: var(--color-ink-inverse); display: flex; align-items: flex-end; overflow: hidden; }
.c-carousel__slide { position: absolute; inset: 0; opacity: 0; transition: opacity var(--duration-slow) var(--ease-standard); pointer-events: none; }
.c-carousel__slide[data-active="true"] { opacity: 1; pointer-events: auto; }
.c-carousel:not([data-js]) .c-carousel__slide:first-child { opacity: 1; pointer-events: auto; }

/* AC-M5-W8-01, package 18. The active slide sits IN FLOW below 52rem so the section takes its
   natural height instead of a fixed one; the media stays absolute behind it, and the inactive
   slides stay stacked so the cross-fade still works. */
@container shell (max-width: 52rem) {
  .c-carousel { flex-direction: column; align-items: stretch; }
  .c-carousel__slide[data-active='true'],
  .c-carousel:not([data-js]) .c-carousel__slide:first-child {
    position: relative;
    inset: auto;
  }
}

.c-carousel__media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Scrim is a gradient here (unlike .c-hero) because the text block spans the
   whole width; the lower 40 % is at >= 0.88 alpha so contrast is stable. */
.c-carousel__scrim { position: absolute; inset: 0; background: linear-gradient(180deg, transparent 35%, color-mix(in srgb, var(--color-ink) 90%, transparent) 100%); }
.c-carousel__fig { position: absolute; top: var(--space-4); font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em; color: color-mix(in oklab, var(--color-ink-inverse) 78%, var(--color-surface-sunken)); }
.c-carousel__fig--left { left: var(--space-5); }
.c-carousel__fig--right { right: var(--space-5); font-variant-numeric: tabular-nums; }
.c-carousel__body { position: relative; width: 100%; padding: var(--space-8) var(--space-5); display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--space-6); align-items: end; }
/* BOTH TAGS, AND OUR OWN RULING IS WHY (`AC-M6-W12-06`). The delivery's slide heading is an
   `h1` and this selector was correct when it was ported; `AC-M5-W6-04` dropped ours to `h2` so
   the page could carry ONE visually hidden `h1` for `R-054`, and that orphaned the rule. It has
   been matching nothing ever since — the hero has had no `max-width: 18ch` and no explicit
   size, and looked right only because the generic `h2` happened to be `--text-2xl` too.
   `-06` moves the generic `h2` down a step, so the accident stops working in this very change.
   Both tags are named rather than just `h2`, so the rule survives the markup moving back. */
.c-carousel__body h1,
.c-carousel__body h2 { color: var(--color-ink-inverse); max-width: 18ch; font-size: var(--text-2xl); }
.c-carousel__body .t-eyebrow { color: var(--color-accent-secondary-hover); }
.c-carousel__lead { color: color-mix(in oklab, var(--color-ink-inverse) 88%, var(--color-surface-sunken)); max-width: 46ch; }
.c-carousel__meta { margin: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
.c-carousel__meta > div { display: flex; flex-direction: column; gap: 4px; padding: var(--space-3) var(--space-4); border-left: var(--border-hairline) solid color-mix(in srgb, var(--color-ink-inverse) 30%, transparent); }
.c-carousel__meta dt { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: color-mix(in oklab, var(--color-ink-inverse) 78%, var(--color-surface-sunken)); }
.c-carousel__meta dd { margin: 0; font-family: var(--font-mono); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
/* AC-M5-W6-03. THE CONTROLS ARE POSITIONED HERE BECAUSE THE DELIVERY POSITIONS THEM INLINE
   AND THE PORT DROPPED THE INLINE STYLE. The delivered template writes
   `style="position: absolute; right: var(--space-5); bottom: var(--space-5); left: var(--space-5)"`
   on this element, and neither its `app.css` nor ours carries it — so a port that takes the
   class and leaves the attribute gets a STATIC flex box that shrinks to its content.

   THAT IS WHY NO SET COULD SEE THIS. All five controls render, with the right counts, and
   `carousel.js` sets `data-js` so none of them is `display: none`. Measured on the live page
   with the script running: controls 178×44 — arrows 44+44, pause 38, three gaps — leaving
   16px for `.c-carousel__dots { flex: 1 }` to share between three `flex: 1 1 0` dots. Each dot
   came out 0×3. The progress bars Marcin could not find were zero pixels wide.

   `left` AND `right` together are the whole point: they stretch the bar across the carousel so
   the dots have a width to divide. `.c-carousel` is already `position: relative`. */
.c-carousel__controls {
  position: absolute;
  left: var(--space-5);
  right: var(--space-5);
  bottom: var(--space-5);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.c-carousel:not([data-js]) .c-carousel__controls { display: none; }
.c-carousel__arrow { width: 44px; height: 44px; border: var(--border-hairline) solid color-mix(in srgb, var(--color-ink-inverse) 40%, transparent); background: transparent; color: var(--color-ink-inverse); cursor: pointer; font-family: var(--font-mono); border-radius: var(--radius-sm); }
.c-carousel__arrow:hover { background: color-mix(in srgb, var(--color-ink-inverse) 14%, transparent); }
.c-carousel__dots { display: flex; gap: var(--space-2); flex: 1; align-items: center; }
.c-carousel__dot { flex: 1 1 0; height: 3px; max-width: 64px; border: none; padding: 0; cursor: pointer; background: color-mix(in srgb, var(--color-ink-inverse) 30%, transparent); }
.c-carousel__dot[aria-current="true"] { background: var(--color-accent-secondary-hover); }

/* THE 44px TARGETS FOR THE THREE CONTROLS W18 MEASURED UNDER THE FLOOR. Marcin, given the
   numbers: *"zrób 44px i ocenimy jak to wygląda"* — so this is a try-and-look, and the honest
   way to run it is to change the TARGET and not the LOOK, then show him that nothing moved.

       .c-carousel__dot     effective  4px
       .c-carousel__pause   effective 32px
       .c-section__more     effective 19px

   PSEUDO-ELEMENTS RATHER THAN `min-height`, WHICH IS THE OPPOSITE OF WHAT `.c-unit__option`
   GOT, and the reason is the dot. It is `flex: 1 1 0; height: 3px` — a 3px BAR, and package 17's
   design. A `min-height` would make it a 44px block and that is a different page. `min-height`
   is the better technique wherever the box may grow, precisely because it cannot be clipped;
   here the box may not grow, so the target has to be painted outside it.

   AND W18 IS THE WAVE THAT PROVED PAINTING OUTSIDE ONLY WORKS IF NOTHING CLIPS. Both carousel
   ancestors DO clip — `section.c-carousel` and `div.c-card` are both `overflow: hidden` — so
   whether these targets survive is a LAYOUT question that no rule and no reading of one can
   answer. Hit-tested after the fact and recorded in `design-tokens.test.ts`'s
   `HIT_TESTED_AFTER`, which is the register that exists for exactly this. */
.c-carousel__dot { position: relative; }
.c-carousel__dot::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  height: var(--target-min);
}
.c-carousel__pause { position: relative; }
.c-carousel__pause::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  height: var(--target-min);
}
.c-section__more { position: relative; }
.c-section__more::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  height: var(--target-min);
}
.c-carousel__pause { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: color-mix(in oklab, var(--color-ink-inverse) 78%, var(--color-surface-sunken)); background: transparent; border: none; cursor: pointer; padding: var(--space-2) 0; }
.c-carousel__pause:hover { color: var(--color-ink-inverse); }

/* DARK TEXT ON A PALE PHOTOGRAPH, chosen per instrument in the panel (`carousel_tone`). The scrim
   turns light so dark ink reads on it, and every colour the slide and the shared controls draw
   in --color-ink-inverse is drawn in --color-ink instead. The section's `data-tone` is the
   active slide's, set by `carousel.js`, which is what lets the controls follow it. */
.c-carousel__slide[data-tone="dark"] .c-carousel__scrim { background: linear-gradient(180deg, color-mix(in srgb, var(--color-surface) 70%, transparent) 0%, transparent 45%, color-mix(in srgb, var(--color-surface) 92%, transparent) 100%); }
.c-carousel__slide[data-tone="dark"] .c-carousel__body h1,
.c-carousel__slide[data-tone="dark"] .c-carousel__body h2,
.c-carousel__slide[data-tone="dark"] .c-carousel__body,
.c-carousel__slide[data-tone="dark"] .c-carousel__meta dd { color: var(--color-ink); }
.c-carousel__slide[data-tone="dark"] .c-carousel__lead,
.c-carousel__slide[data-tone="dark"] .c-carousel__meta dt,
.c-carousel__slide[data-tone="dark"] .c-carousel__fig { color: color-mix(in oklab, var(--color-ink) 82%, var(--color-surface)); }
.c-carousel__slide[data-tone="dark"] .c-carousel__body .t-eyebrow { color: var(--color-accent); }
.c-carousel__slide[data-tone="dark"] .c-carousel__meta > div { border-left-color: color-mix(in srgb, var(--color-ink) 30%, transparent); }
.c-carousel__slide[data-tone="dark"] .c-btn--on-photo { color: var(--color-ink); border-color: var(--color-ink); }
.c-carousel__slide[data-tone="dark"] .c-btn--on-photo:hover { background: color-mix(in srgb, var(--color-ink) 10%, transparent); color: var(--color-ink); }
.c-carousel[data-tone="dark"] .c-carousel__arrow { color: var(--color-ink); border-color: color-mix(in srgb, var(--color-ink) 40%, transparent); }
.c-carousel[data-tone="dark"] .c-carousel__arrow:hover { background: color-mix(in srgb, var(--color-ink) 10%, transparent); }
.c-carousel[data-tone="dark"] .c-carousel__dot { background: color-mix(in srgb, var(--color-ink) 30%, transparent); }
.c-carousel[data-tone="dark"] .c-carousel__dot[aria-current="true"] { background: var(--color-accent); }
.c-carousel[data-tone="dark"] .c-carousel__pause,
.c-carousel[data-tone="dark"] .c-carousel__pause:hover { color: var(--color-ink); }

/* Numbered section heading with a rule beneath — shared by home sections. */
.c-section { padding: var(--space-8) var(--space-5); }
.c-section + .c-section { border-top: var(--border-hairline) solid var(--color-ink); }
.c-section__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; padding-bottom: var(--space-3); border-bottom: var(--border-hairline) solid var(--color-ink); margin-bottom: var(--space-2); }
.c-section__head h2 { font-size: var(--text-lg); letter-spacing: 0.04em; text-transform: uppercase; }
.c-section__more { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase; }

/* THE BREADCRUMB TRAIL (`AC-M6-W20-02`), ported from package 19's `app.css:667` — the same
   seven rules, the same tokens, all of which we already declare, so nothing here is a new name
   and nothing is a literal.

   ONE DIVERGENCE, AND THE PAGES DECIDED IT. 19 sets the trail in `--text-xs` mono, which reads
   as small print above a heading. On the jig pages that would be wrong: FOUR routes render the
   same `<h1>`, with the section only in `<title>`, so the leaf is not a label above the heading —
   it is the half of the heading the page does not otherwise say. It takes `--text-sm` and the
   leaf takes `--weight-medium`, which is a step up from 19 and a step below the `<h1>`.

   A SECOND DIVERGENCE, AND THE PAGE ASKED FOR IT. 19's trail carries no bottom margin because
   what follows it there is `<header class="c-article-head">`, which brings its own spacing. Ours
   is followed directly by `{% block content %}`, whose first element is an `<h1 class="b-heading">`
   — and `h1` is `margin: 0 0 var(--space-4)`, bottom only. Measured with 19's rule as written:
   the gap between the trail's bottom border and the heading was 0px, so a hairline rule sat
   directly against a 39px heading. `margin-block-end` is the component's own separation from
   whatever follows, which is what a bar with a rule under it owes the next thing.

   `overflow: hidden; text-overflow: ellipsis` ON THE LEAF ONLY is 19's, and it is right: a jig's
   name is short but an article's title is not, and the trail must not wrap to two lines above a
   heading. The LINKS wrap instead, because `ol` is `flex-wrap: wrap`. */
.c-breadcrumbs { padding: var(--space-3) var(--space-5); border-bottom: var(--border-hairline) solid var(--color-rule); margin-block-end: var(--space-5); }
.c-breadcrumbs ol { list-style: none; margin: 0; padding: 0; display: flex; gap: var(--space-2); flex-wrap: wrap; font-family: var(--font-mono); font-size: var(--text-sm); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); }
.c-breadcrumbs li { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.c-breadcrumbs li + li::before { content: "/"; color: var(--color-border); }
.c-breadcrumbs a { color: var(--color-ink-muted); text-decoration: none; }
.c-breadcrumbs a:hover { color: var(--color-ink); text-decoration: underline; }
.c-breadcrumbs [aria-current="page"] { color: var(--color-ink); font-weight: var(--weight-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Journal list: index · thumbnail · title+lead · date. Grid, so the date
   column never wraps under the title in either locale. */
.c-journal { display: flex; flex-direction: column; }
.c-journal__item { display: grid; grid-template-columns: 4ch 112px minmax(0, 1fr) auto; gap: var(--space-4); padding: var(--space-4) 0; border-bottom: var(--border-hairline) solid var(--color-rule); text-decoration: none; color: var(--color-ink); align-items: start; }
.c-journal__item:hover { background: var(--color-surface-raised); color: var(--color-ink); }
/* EXPLICIT PLACEMENT, AC-M6-W8-01. The four columns are `4ch 112px minmax(0,1fr) auto`
   and the thumbnail is OPTIONAL -- `{% templatetag openblock %} if post.thumb %}` in
   core/home.html, because emitting an <img> with no src would be worse. Under
   auto-placement an absent thumbnail slid every later sibling one column left: the title
   rendered in the thumbnail's 112px slot and the date took the 722px body slot. Measured
   live: `43.25px 112px 722.75px 0px` with the fourth column empty, against the delivery's
   `43.25px 112px 909.41px 69.34px`. That is the ten-character column Marcin saw.

   THE THREE STABLE CHILDREN ARE PLACED AND THE OPTIONAL ONE IS NOT, deliberately. With a
   thumbnail it auto-fills the only free cell in the row; without one that cell stays empty
   and nothing moves. Placing the optional child too would work for OUR markup and break the
   control: the delivery's own rendered sample uses an UNCLASSED <span> placeholder for the
   thumb, not `img.c-journal__thumb`, so a rule keyed on that class would not reach it.
   Placing what must be right, and letting the optional cell be optional, is correct for both. */
.c-journal__index { grid-column: 1; }
.c-journal__thumb { grid-column: 2; }
.c-journal__item > .l-stack { grid-column: 3; }
.c-journal__date { grid-column: 4; }
.c-journal__index { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-accent-secondary); padding-top: 4px; }
.c-journal__thumb { aspect-ratio: 4 / 3; width: 100%; object-fit: cover; border: var(--border-hairline) solid var(--color-border); display: block; }
.c-journal__title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-bold); letter-spacing: 0.03em; text-transform: uppercase; line-height: var(--leading-tight); }
.c-journal__date { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); white-space: nowrap; padding-top: 4px; font-variant-numeric: tabular-nums; }

/* THE SHELF (`AC-M6-W17-02`) — the journal row above, ported, with two of its four columns
   dropped and one refilled. Marcin named the reference: "jak z dziennika ze strony głównej".

       reference   4ch 112px minmax(0, 1fr) auto      ordinal · photo · title+lead · date
       here            minmax(0, 1fr) auto            title+summary · what it generates

   WHY IT IS NOT THE SAME CLASSES. Sharing `.c-journal__*` would make every future change to the
   home page's row a change to this one, in a file where the two are 1500 lines apart and neither
   mentions the other. The SHAPE is ported; the coupling is not. `pages/jig_index.html` carries
   the column-by-column reasoning, because the question "why is this not the journal row" belongs
   where somebody reading the markup will ask it.

   EXPLICIT PLACEMENT WITH TWO COLUMNS AND NO OPTIONAL CELL, which looks redundant and is
   `AC-M6-W8-01`'s lesson taken early. The reference places all four because an absent thumbnail
   under auto-placement slid every later sibling one column left — a bug that only appeared once a
   cell became conditional. This row has no conditional cell TODAY. Stating the placement now
   costs two declarations and means the first guarded cell somebody adds cannot cause it. */
.c-jig-list { display: flex; flex-direction: column; }
.c-jig-list__item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-4); padding: var(--space-4) 0; border-bottom: var(--border-hairline) solid var(--color-rule); text-decoration: none; color: var(--color-ink); align-items: start; }
.c-jig-list__item:hover { background: var(--color-surface-raised); color: var(--color-ink); }
.c-jig-list__item > .l-stack { grid-column: 1; }
.c-jig-list__kinds { grid-column: 2; }
.c-jig-list__title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-bold); letter-spacing: 0.03em; text-transform: uppercase; line-height: var(--leading-tight); }
.c-jig-list__kinds { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); white-space: nowrap; padding-top: 4px; }
/* AC-M8-W23-01. The coupon is a step BEFORE the jigs, so it is framed rather than ruled like a row:
   a raised ground and a full hairline, and the gap below it is the list's own distance from the lead. */
.c-jig-list--first .c-jig-list__item { padding-inline: var(--space-4); background: var(--color-surface-raised); border: var(--border-hairline) solid var(--color-rule); }
/* A JIG ROW WITH A PHOTOGRAPH (`pages/_jig_list.html`, the `jigs_showcase` block). The journal
   row's thumbnail column in front of the two the row already has, at the journal's 112px, and the
   image is `.c-journal__thumb` itself rather than a copy of it -- so the narrow step's 16/7 banner
   arrives with the class. `-2` for the kinds column is "the last track": column 3 here, and column
   1 under the narrow step's single track, so no breakpoint rule has to know this modifier exists.
   The `.l-stack` placement is overridden there by the existing rule, which is later and as specific. */
.c-jig-list__item--thumb { grid-template-columns: 112px minmax(0, 1fr) auto; }
.c-jig-list__item--thumb > .c-journal__thumb { grid-column: 1; }
.c-jig-list__item--thumb > .l-stack { grid-column: 2; }
.c-jig-list__item--thumb > .c-jig-list__kinds { grid-column: -2; }
.c-bed__coupon { margin: 0; }

/* Bench cards: progress is read from the bench log (stages done / total). */
.c-bench { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--space-8); align-items: start; }
.c-bench__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr)); gap: var(--space-3); }
.c-bench__card { border: var(--border-hairline) solid var(--color-border); background: var(--color-surface-raised); padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.c-bench__serial { display: flex; justify-content: space-between; gap: var(--space-2); font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); }
.c-bench__serial b { font-weight: var(--weight-regular); color: var(--color-accent-secondary); }
.c-bench__name { font-family: var(--font-display); font-weight: var(--weight-bold); letter-spacing: 0.03em; text-transform: uppercase; line-height: var(--leading-tight); }
.c-bench__bar { display: block; height: 4px; background: var(--color-rule); position: relative; }
.c-bench__bar > span { position: absolute; inset: 0 auto 0 0; background: var(--color-accent); display: block; }


/* Enquiry block on the home page: sunken panel → inverse ink (Rule 1).
   Controls take a translucent paper border so the 3:1 boundary holds on dark. */
.c-enquire { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--space-8); align-items: start; border-radius: 0; }
.c-enquire .c-section__head h2 { color: var(--color-ink-inverse); }
.c-enquire .c-field__label, .c-enquire .c-field__hint { color: color-mix(in oklab, var(--color-ink-inverse) 80%, var(--color-surface-sunken)); }
.c-enquire .c-field__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; }

/* THE CONSENT SENTENCE IS NOT A FIELD LABEL, THOUGH IT LIVES IN A `<label>`.
   The rule above dresses this block's labels as the delivery does — mono, uppercase, tracked —
   and that is right for `Name` and `Email`, which are one word naming a box. The consent row's
   label is a SENTENCE, and `RC-121` requires it to BE the label rather than text beside one, so
   it inherited a treatment written for the other case: 108 characters of uppercase Mono at
   11.52px. Marcin, looking at it: it should be in normal case.

   SCOPED TO `--check` RATHER THAN TO THIS ROW, because the property is about the KIND of label —
   a sentence that labels a checkbox — and the next one will not be the consent row. */
.c-enquire .c-field--check .c-field__label {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  letter-spacing: normal;
  text-transform: none;
}
.c-enquire .c-field input, .c-enquire .c-field select, .c-enquire .c-field textarea { background: color-mix(in srgb, var(--color-ink-inverse) 6%, transparent); color: var(--color-ink-inverse); border-color: color-mix(in srgb, var(--color-ink-inverse) 35%, transparent); }
.c-enquire .c-field select option { color: var(--color-ink); }
.c-enquire__form { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); gap: var(--space-4); }
.c-enquire__wide { grid-column: 1 / -1; }
.c-enquire a { color: var(--color-ink-inverse); }

@container shell (max-width: 52rem) {
  .c-carousel__body, .c-bench, .c-enquire { grid-template-columns: minmax(0, 1fr); }
  .c-carousel { min-height: 0; }
  .c-carousel__body { padding: var(--space-8) var(--space-4) var(--space-5); gap: var(--space-5); }
  .c-carousel__body h1,
  .c-carousel__body h2 { font-size: var(--text-2xl); }
  /* Two figure labels cannot share one line at this width, so the right-hand one drops
     beneath the left instead of colliding with it. */
  .c-carousel__fig--right { top: calc(var(--space-4) + 1.6em); right: auto; left: var(--space-5); }
  .c-carousel__meta { gap: var(--space-1); }
  .c-carousel__meta > div { padding: var(--space-2) var(--space-3); }
  /* THE CONTROLS LEAVE THE ABSOLUTE CORNER AND BECOME THE SLIDE'S LAST ROW, so the carousel
     grows with them instead of overlapping the CTAs — which is what Marcin was looking at.

     18 WRITES THIS `position: static !important` AND WE DO NOT NEED THE `!important`. There the
     positioning is an INLINE style on the element, and an inline style is the one thing a
     stylesheet cannot outrank without it. `AC-M5-W6-03` moved that declaration off the
     attribute and into the rule above, so plain source order settles it here. The `R-163`
     repair is what makes this line ordinary. */
  .c-carousel__controls { position: static; padding: 0 var(--space-4) var(--space-5); }
  .c-carousel__lead { font-size: var(--text-sm); }
  .c-journal__item { grid-template-columns: 4ch 88px minmax(0, 1fr); }
  /* Three columns here, so the date drops to row 2 of column 3 under the body. Both are
     placed explicitly for the same reason as the wide case — 18 leaves the stack to
     auto-placement at this width and `AC-M6-W8-01` requires it stated. */
  .c-journal__item > .l-stack { grid-column: 3; }
  .c-journal__date { grid-column: 3; padding-top: 0; }
}

/* AC-M5-W8-01, package 18's 30rem step: the journal thumbnail goes ABOVE the text, the hero's
   CTAs take the full width rather than sitting two-up, and the sections lose a step of inset. */
@container shell (max-width: 30rem) {
  /* `AC-M6-W17-02`: the kinds drop under the title rather than squeezing beside it. One
     column, both cells placed, for the reason stated where the rule is defined. */
  /* THE TRAIL'S GUTTER, AND THIS IS NOT 19'S NARROW STEP however much the declaration
     looks like it. 19 writes the identical padding at `app.css:760`, one breakpoint HIGHER
     — `shell (max-width: 52rem)` — and as one of FOUR selectors. The other three are
     `.c-breadcrumbs ol { flex-wrap: nowrap; overflow: hidden }`, `li:not(:last-child)
     { flex: none }` and `li:last-child { flex: 1 1 auto; min-width: 0 }`, and they are ONE
     change rather than three: together they turn the trail into a single line that
     truncates the current page when it runs out of room.

     WE CARRY NONE OF THOSE THREE, so ours keeps the base `flex-wrap: wrap` and a long
     trail takes a second line instead of truncating. With no wrapping change to make at
     52rem, the only thing left for a breakpoint to do to the trail is the gutter — which
     is why this sits at 30rem with the rest of this block. THE VALUE IS 19'S VERBATIM;
     THE CONDITION IS OURS, and only the second of those is a thing a reader can see by
     comparing the two declarations.

     The first version of this comment read "19's own narrow step for the trail, at
     `app.css:760`" — a true line number attached to a false implication, which is the
     worst shape a citation has. `OURS_ALONE` in `mobile-breakpoints.test.ts` carries the
     same argument, because that is where the gate sends you when it fires; this is where
     you are standing when you change the rule. */
  .c-breadcrumbs { padding: var(--space-3) var(--space-4); }
  .c-jig-list__item { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-2); }
  .c-jig-list__item > .l-stack, .c-jig-list__kinds { grid-column: 1; }
  .c-jig-list__kinds { padding-top: 0; white-space: normal; }
  .c-jig-list__title { font-size: var(--text-base); }
  .c-journal__item { grid-template-columns: 4ch minmax(0, 1fr); row-gap: var(--space-2); }
  .c-journal__thumb { grid-column: 1 / -1; aspect-ratio: 16 / 7; }
  .c-journal__item > .l-stack, .c-journal__date { grid-column: 2; }
  .c-journal__title { font-size: var(--text-base); }
  .c-carousel__cta .c-btn { flex: 1 1 100%; text-align: center; white-space: normal; }
  .c-section { padding: var(--space-6) var(--space-4); }
  .c-enquire { padding: var(--space-6) var(--space-4); }
  /* Re-asserted from 18. Our base rule already declares 44x44, so this changes nothing today;
     it is kept so the breakpoint still states the floor if the base is ever re-tokenised. */
  .c-carousel__arrow { width: var(--target-min); height: var(--target-min); }
}
@media (prefers-reduced-motion: reduce) {
  .c-carousel__slide { transition: none; }
}


/* Compact header — the home-page variant from the approved mockup: wordmark
   (colour, ~240px) left, mono nav centred, locale + Contact right, one row,
   sticky. Full-width wordmark header (.c-header) stays for instrument pages. */
.c-header--compact { flex-direction: row; flex-wrap: nowrap; align-items: center; justify-content: space-between; gap: var(--space-5); padding: var(--space-3) var(--space-5); border-bottom: var(--border-hairline) solid var(--color-ink); background: var(--color-surface-raised); position: sticky; top: 0; z-index: 2; }
.c-header--compact .c-header__wordmark { width: 200px; max-width: 200px; flex: none; margin: 0; }
.c-header--compact .c-header__bar { width: auto; min-width: 0; flex: 1 1 auto; border: none; margin: 0; padding: 0; display: flex; align-items: center; justify-content: flex-end; gap: var(--space-5); }
.c-header--compact .c-nav { flex: 1 1 auto; justify-content: center; }
.c-header--compact .c-nav__link { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-ink-muted); border-bottom: 1px solid transparent; padding-bottom: 2px; }
.c-header--compact .c-nav__link:hover { color: var(--color-ink); }
.c-header--compact .c-nav__link[aria-current="page"] { color: var(--color-ink); border-bottom-color: var(--color-accent); }
/* AC-M5-W9-03. THE BAND IS SUPPRESSED ON EVERY PAGE NOW, AND THAT IS A DECISION RATHER THAN
   A SIDE EFFECT — which is the only reason this comment is longer than the rule.

   Until `AC-M5-W9-01` exactly one page rendered `c-header--compact`, so this rule suppressed
   the band on one page and the other twelve showed it. Making the chrome uniform makes the
   band disappear from twelve pages at once, and "it vanished when we fixed the header" is how
   a designed element leaves a site with nobody deciding.

   WHAT THE DELIVERY DOES. Package 18 carries this identical rule, and every page it ships is
   compact — so the band is in the delivered markup and suppressed in every delivered render.
   The delivery has no opinion about a non-compact page because it contains none.

   WHY IT IS THE RIGHT OUTCOME AND NOT MERELY THE INHERITED ONE. The band is an EDGE
   TREATMENT, and the compact header brings its own: `border-bottom: var(--border-hairline)
   solid var(--color-ink)`. Two edges under one header is the defect, not the feature. And the
   compact header is `position: sticky` — a 6px strip below a sticky header scrolls away from
   it, leaving the band stranded up the page and the header's real edge bare. Measured:

       before   inner pages   header 310px static, no border, band 6px visible
       after    every page    header 114px sticky, 1px border, band suppressed

   THE ELEMENT STAYS IN THE MARKUP, aria-hidden, which is what makes this reversible. If
   Marcin wants the Deco band back on inner pages, the fix is to SCOPE THIS RULE rather than
   revert the header — it is one selector, and the header stays uniform either way:

       .c-header--compact + .c-band { display: none; }        <- today, all pages
       body.home .c-header--compact + .c-band { … }           <- would need a page hook

   Raised in the wave report rather than assumed. */
.c-header--compact + .c-band { display: none; }
/* AC-M5-W8-02. THE COMPACT HEADER HAD NO NAVIGATION AT ALL ON A PHONE, AND NO WAY TO GET ONE.
   This block used to read `.c-header--compact .c-nav { display: none }` AND
   `.c-header--compact .c-nav__toggle { display: none }` — the menu hidden and the button that
   opens it hidden too, on the one page that uses this header. That is the "menu rozwala się na
   telefonach" Marcin reported, and it is a state no SET of classes could have found: every
   element was present and correctly named, and two of them were invisible.

   Package 18's arrangement: the wordmark and the utility row stay on line one, the toggle
   joins them, and the nav becomes a full-width list on line three, separated by a rule.

   `Kontakt` HIDES HERE AND THE LANGUAGE SWITCHER DOES NOT. The enquiry block is further down
   this same page, so the button is a duplicate of something already reachable by scrolling.
   The switcher is not reachable any other way — `AC-M0-W8-04` — so it stays at every width,
   and `.c-locale__link` below only ever changes its padding. */
@container shell (max-width: 52rem) {
  .c-header--compact { flex-wrap: wrap; padding: var(--space-3) var(--space-4); gap: var(--space-3); }
  .c-header--compact .c-header__wordmark { width: 150px; max-width: 150px; }
  .c-header--compact .c-header__bar {
    flex: 1 1 auto;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-3);
    border: none;
    padding: 0;
    margin: 0;
  }
  .c-header--compact .c-nav__toggle { display: inline-flex; order: 1; }
  .c-header--compact .c-header__utility { order: 2; width: auto; }
  /* The contact CTA, and ONLY the contact CTA. Scoped to the utility row so it cannot reach
     the locale links, which are `.c-locale__link` and sit in the same container. */
  .c-header--compact .c-header__utility .c-btn { display: none; }
  .c-header--compact .c-nav {
    order: 3;
    display: flex;
    width: 100%;
    flex-direction: column;
    gap: 0;
    padding-top: var(--space-2);
    border-top: var(--border-hairline) solid var(--color-rule);
  }
  .c-header--compact .c-nav[hidden] { display: none; }
  /* min-height comes from the base `.c-nav__link`; this widens the row and squares the edge,
     the same way the standard header's block does. 18 writes `13px 2px` here and we do not,
     for `RC-088`'s reason: padding arithmetic against a fluid line box is right at one width. */
  .c-header--compact .c-nav__link {
    font-size: var(--text-sm);
    padding: var(--space-1);
    border-bottom: var(--border-hairline) solid var(--color-rule);
  }
  .c-header--compact .c-nav__link[aria-current='page'] { border-bottom-color: var(--color-accent); }
}

/* AC-M5-W8-01, 18's narrowest step. The wordmark gives up more width and the locale links
   tighten horizontally — they do not shrink vertically, because their height is
   `--target-min` and that is the floor, not a starting point. */
@container shell (max-width: 24rem) {
  .c-header--compact .c-header__wordmark { width: 120px; max-width: 120px; }
  .c-locale__link { padding: var(--space-2) var(--space-3); }
}


/* --- THE CONTACT PAGE (package 20, `AC-M6-W23-01`) -------------------------
   Marcin: *"strona kontaktu nadal nie jest zgodna z szablonem który Ci wysłałem."*
   The page it replaces is BACKEND's minimal markup (`AC-M6-W20-04`) and was
   always going to be — a stub, correctly described as ugly.

   WHAT PACKAGE 20 ACTUALLY IS: 19 plus 49 lines, one contiguous block, purely
   additive. `tokens.css` is BYTE-IDENTICAL to 19's (same sha256), which is worth
   recording because the wave brief said it differed and a token difference would
   have changed everything taken from here. Every token these rules reference is
   already defined in ours; the SET was checked rather than assumed.

   `.c-article-head` AND `.c-ph` ARE 19's, NOT 20's, and are pulled in because the
   contact page is the first page of ours to use the article-head component. Only
   the three rules this page needs are taken: `__byline` is the article's date and
   author row and has no equivalent here.

   DIVERGENCE ① — NO `min-height` ON THE FIELDS. 20 writes `min-height: 48px` on
   every control. Our `.c-field input, select, textarea` already declares
   `min-height: var(--target-min)`, so the floor holds at every width and there is
   nothing for this block to re-derive. Same argument as `.c-btn` in
   `mobile-breakpoints.test.ts`'s NOT_ADOPTED, and the same reason: a second
   declaration of a floor is a second place to get it wrong.

   DIVERGENCE ② IS DISCHARGED (`AC-M7-W24-01`). It said 20 ships a counter "fed by
   `data-counter` and a script we do not have" — the script was in the tree the
   whole time, in package 22's vendored `carousel.js`, and is in `forms.js` now.
   The rule is 22's, value for value (`app.css:794`), below the form's fields.

   DIVERGENCE ④ — NO MAP. 22 closes the contact aside with `<figure><img class="c-ph
   c-map" src="img/map-krakow.png"…><figcaption class="c-caption">Map, not live —
   no third-party embed.</figcaption></figure>` and `.c-map { aspect-ratio: 4 / 3 }`
   (22 `app.css:809`, top level). Marcin, `OQ-061`, 2026-09-20: *rezygnujemy z mapy*
   — declined, `W24-04` dropped; neither the figure nor the rule is ported. (Not in
   `mobile-breakpoints.test.ts`'s NOT_ADOPTED: that register is per-`@container`
   condition and 22 declares `.c-map` under none, so the row would read as spent.)

   DIVERGENCE ③ — `.c-contact-form .c-field` KEEPS ONLY `margin: 0`. 20 restates
   `display: flex; flex-direction: column; gap: var(--space-2)`, which is our
   `.c-field` base rule character for character. Restating it would mean two
   places to change it. ---------------------------------------------------- */
.c-contact-form__counter { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); font-variant-numeric: tabular-nums; text-align: right; }
.c-article-head { padding: var(--space-8) var(--space-5) var(--space-6); border-bottom: var(--border-hairline) solid var(--color-ink); display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
.c-article-head h1 { max-width: 22ch; }
.c-article-head__standfirst { font-size: var(--text-lg); color: var(--color-ink-muted); max-width: var(--measure); }

.l-contact { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: var(--space-10); padding: var(--space-8) var(--space-5) var(--space-10); align-items: start; }
.l-contact > aside { position: sticky; top: calc(var(--space-8) + 56px); display: flex; flex-direction: column; gap: var(--space-6); }

.c-contact-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5) var(--space-4); }
.c-contact-form .c-field { margin: 0; }
.c-contact-form .c-field--wide { grid-column: 1 / -1; }

/* THE COMMISSION CHOICE (`AC-M8-W6-09`): a checkbox that reveals a fieldset of four fields. The
   toggle is the whole row as its target, like the consent row; the fieldset loses its UA frame and
   lays its fields out like the form around it. The two radio rows (currency, timeframe) are chips
   with visually hidden radios, the view switch's idiom, `:checked + span` and no `:has()`. */
.c-commission { display: flex; flex-direction: column; gap: var(--space-4); }
.c-commission__toggle { display: inline-flex; align-items: center; gap: var(--space-3); min-height: var(--target-min); cursor: pointer; }
.c-commission__toggle input { width: 1.1rem; height: 1.1rem; margin: 0; }
.c-commission__fields { display: grid; gap: var(--space-4); min-width: 0; margin: 0; padding: var(--space-4); border: var(--border-hairline) solid var(--color-border); border-radius: var(--radius-sm); }
.c-commission__fields[hidden] { display: none; }
.c-commission [data-commission-date][hidden] { display: none; }
.c-commission__currency,
.c-commission__timeframe { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.c-commission__currency label,
.c-commission__timeframe label { position: relative; display: inline-flex; }
.c-commission__currency input,
.c-commission__timeframe input { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); }
.c-commission__currency span,
.c-commission__timeframe span { display: inline-flex; align-items: center; min-height: var(--target-min); padding: 0 var(--space-3); border: var(--border-hairline) solid var(--color-border); border-radius: var(--radius-sm); font-size: var(--text-sm); cursor: pointer; }
.c-commission__currency input:checked + span,
.c-commission__timeframe input:checked + span { border-color: currentColor; box-shadow: inset 0 0 0 1px currentColor; }
.c-commission__currency input:focus-visible + span,
.c-commission__timeframe input:focus-visible + span { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.c-contact-form .c-field__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); display: flex; justify-content: space-between; gap: var(--space-2); }
.c-contact-form .c-field__label .req { color: var(--color-accent); }
.c-contact-form .c-field__hint { font-family: var(--font-body); font-size: var(--text-xs); letter-spacing: 0; text-transform: none; }
.c-contact-form input, .c-contact-form select, .c-contact-form textarea { width: 100%; font-size: var(--text-base); padding: 13px var(--space-4); border: var(--border-hairline) solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface-raised); color: var(--color-ink); }
.c-contact-form input { font-family: var(--font-body); }
.c-contact-form input[type="email"], .c-contact-form select { font-family: var(--font-mono); font-size: var(--text-sm); }
.c-contact-form textarea { font-family: var(--font-body); line-height: var(--leading-normal); min-height: 16rem; resize: vertical; }
.c-contact-form :is(input, select, textarea):focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; border-color: var(--color-ink); }

/* Consent: checkbox + running text; the label is the hit target. */
.c-consent { grid-column: 1 / -1; display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: var(--space-3); align-items: start; padding: var(--space-4); border: var(--border-hairline) solid var(--color-rule); background: var(--color-surface-raised); font-size: var(--text-sm); line-height: var(--leading-normal); }
.c-consent input { width: 20px; height: 20px; margin: 2px 0 0; accent-color: var(--color-accent); min-height: 0; padding: 0; }
.c-contact-form__actions { grid-column: 1 / -1; display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; padding-top: var(--space-2); }
.c-contact-form__actions .c-btn { padding: 14px var(--space-6); }

/* Aside: the workshop's details as a definition list. */
.c-details { margin: 0; border-top: var(--border-hairline) solid var(--color-ink); }
.c-details > div { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: var(--space-3); padding: var(--space-3) 0; border-bottom: var(--border-hairline) solid var(--color-rule); }
.c-details dt { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); padding-top: 3px; }
.c-details dd { margin: 0; font-size: var(--text-sm); line-height: var(--leading-normal); }
.c-details dd a { text-decoration: none; border-bottom: 1px solid var(--color-accent-muted); }
.c-details dd a:hover { border-bottom-color: var(--color-accent); }

@container shell (max-width: 52rem) {
  .c-article-head { padding: var(--space-6) var(--space-4) var(--space-5); }
  .l-contact { grid-template-columns: minmax(0, 1fr); gap: var(--space-8); padding: var(--space-6) var(--space-4) var(--space-8); }
  .l-contact > aside { position: static; }
}
@container shell (max-width: 30rem) {
  .c-contact-form { grid-template-columns: minmax(0, 1fr); }
  .c-contact-form textarea { min-height: 12rem; }
  .c-details > div { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
  .c-contact-form__actions .c-btn { width: 100%; text-align: center; }
}

/* THE ENQUIRY CONFIRMATION SPANS ITS GRID (`AC-M6-W22-02`). It is the first child of whatever
   carries the fragment, and on BOTH pages that element is a grid: `.c-enquire` is
   `minmax(0, 1fr) minmax(0, 2fr)` on the home page and `.c-contact-form` is `repeat(2, ...)` on
   the contact page. Without this the notice takes ONE column — a full-width sentence rendered in
   a third of the width, directly above the form it is about. One rule rather than two, because
   the property is the same on both and the class is the confirmation's own. */
.c-notice--enquiry { grid-column: 1 / -1; }
/* --- THE INSTRUMENT CATALOGUE (package 21, `AC-M6-W24-01`) -----------------
   Package 21 is package 20 plus 94 lines, one contiguous block, purely additive, with
   `tokens.css` byte-identical for the third delivery running. Every token these rules
   reference is already defined in ours; the SET was checked rather than assumed.

   DIVERGENCE (a) -- `.c-results` IS RENAMED TO `.c-catalog-summary`, AND IT IS A LIVE
   COLLISION RATHER THAN A PREFERENCE. We already have `.c-results`, and it is something else:

       ours   cms/search.html:45   <ul class="l-stack c-results">   the SEARCH RESULTS LIST
       21's                        <p class="c-results">            the FILTER RESULT LINE

   21's rule is `display: flex; justify-content: space-between; border-bottom: ...`, so taking
   the name verbatim would turn our search results list into a flex row with a rule under it --
   a regression on a page this wave does not touch. THEIRS is renamed rather than ours because
   ours is landed and live and theirs is used nowhere yet.

   THE PREDICTION THAT USED TO END THIS PARAGRAPH HAS COME TRUE AND HAS MOVED (`AC-M6-W33-06`).
   It read: *somebody differencing our stylesheet against 21 will find a missing `.c-results` and
   an invented `.c-catalog-summary`*. `AC-M6-W33-02` pointed that check at package 22 and it found
   exactly that, so the sentence now lives in `mobile-breakpoints.test.ts`'s `RENAMED` register,
   where a reader meets it as a DECLARED divergence with a liveness rule rather than as a warning
   with no way to tell whether it ever happened.

   DIVERGENCE (b) IS OVER, AND THE PARAGRAPH IS KEPT BECAUSE IT IS THE REASON IT ENDED
   (`AC-M6-W33-04`). It read: *21's `@container shell (max-width: 60rem)` STEP IS FOLDED INTO OUR
   52rem BLOCK*, because our condition SET had to EQUAL package 18's and "introducing a condition
   is a change to that gate, and it is not one to make for one's own work."

   THAT WAS THE RIGHT REFUSAL AND THE WRONG OUTCOME, and it took three waves to say so: the gate
   was pinned to a delivery with no catalogue in it, so a BASELINE decided a DESIGN question it
   was never asked. `AC-M6-W33-02` moved the baseline to the newest vendored delivery, `-03` gave
   conditions a register in both directions, and the two rules are now at 60rem where they were
   drawn. Measured after: the row relieves from four columns to three between shell 997 and 942
   -- at 960 -- where the fold had it at 832.

       THE COST, STATED: between 60rem and 52rem of shell width the row keeps four columns
       where the designer relieved it to three, so the description column is tighter there
       than intended. Nothing breaks and nothing overflows; it is a refinement we decline
       rather than a step we need. If the fifth condition is wanted, the gate is the thing
       to amend, deliberately, and that is the ARCHITECT's call rather than a side effect
       of this port.

   `sort` IS NOT A FACET and carries none of the derivation rules -- see the template. -- */

/* --- Instrument catalogue (M3) -------------------------------------------
   Same shell, compact header, breadcrumbs, footer. Filter bar (type,
   availability, sort) is a GET form — works without JS, URL is shareable.
   List rows: photo · text · availability; 10 per page, numbered pager. --- */

/* Filter bar: one row of fieldsets, each a label + control group. Type and
   availability are toggle groups (radio inputs with visible labels), sort is
   a select. Submit button is visible only without JS (auto-submit on change). */
.c-filters { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-5) var(--space-8); padding: var(--space-5); border-bottom: var(--border-hairline) solid var(--color-ink); background: var(--color-surface-raised); }
.c-filters fieldset { border: 0; margin: 0; padding: 0; min-width: 0; display: flex; flex-direction: column; gap: var(--space-2); }
/* `AC-M6-W26`. Marcin: the sort control does not sit on the availability row's line. MEASURED:
   sort bottom 539px, toggle bottom 555px -- 16px out, with `.c-filters` already `align-items:
   flex-end`. The cause is not the alignment: the sort is a `<p class="c-field">` and keeps the
   USER AGENT's `margin-block` on the paragraph, so flex-end aligns a box that has a margin
   under it. `.c-contact-form` zeroes the same margin for the same reason; this is the second
   place `.c-field` has been put inside a flex row and the first where it showed. */
.c-filters .c-field { margin: 0; }
.c-filters legend, .c-filters .c-field__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); padding: 0; margin-bottom: var(--space-2); }
.c-toggle { display: flex; border: var(--border-hairline) solid var(--color-border); border-radius: var(--radius-sm); overflow: hidden; }
.c-toggle label { position: relative; display: flex; border-left: var(--border-hairline) solid var(--color-border); }
.c-toggle label:first-child { border-left: 0; }
.c-toggle label > span { display: flex; align-items: center; gap: var(--space-2); padding: 11px var(--space-4); font-family: var(--font-display); font-size: var(--text-sm); font-weight: var(--weight-medium); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); cursor: pointer; min-height: var(--target-min); }
.c-toggle label:hover > span { color: var(--color-ink); background: var(--color-surface); }
.c-toggle input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.c-toggle input:checked + span { background: var(--color-ink); color: var(--color-ink-inverse); }
.c-toggle input:focus-visible + span { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.c-toggle .count { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0; opacity: 0.8; }
.c-filters select { font-family: var(--font-mono); font-size: var(--text-sm); padding: 11px var(--space-4); padding-right: var(--space-8); min-height: var(--target-min); border: var(--border-hairline) solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface-raised); color: var(--color-ink); appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--color-ink) 50%), linear-gradient(-45deg, transparent 50%, var(--color-ink) 50%); background-position: calc(100% - 18px) 50%, calc(100% - 12px) 50%; background-size: 6px 6px; background-repeat: no-repeat; }
.c-filters__submit { align-self: flex-end; }
.c-filters[data-js] .c-filters__submit { display: none; }
/* `min-height` AND `inline-flex` ARE OURS; 21 HAS NEITHER, AND IT MEASURED 55x36. WCAG
   2.5.8 wants 44. The delivery gives this `padding: 11px 0` and no floor, which lands
   eight pixels short — the inline-link exception does not cover it, because this is a
   standalone control in a bar rather than a link inside a sentence. Declared rather than
   padded to it, so the floor is readable as a floor (`AC-M6-W16`).

   AND 21's `padding: 11px 0` GOES WITH IT, because the two together measured 55x66 -- the
   min-height applies to the CONTENT box here, so the padding stacks on top of the floor rather
   than being absorbed by it. The floor alone is the height. Re-measured: 55x44 at 1280 and at
   390, which is the number this comment first claimed before it had been read. */
.c-filters__reset { margin-left: auto; align-self: flex-end; display: inline-flex; align-items: center; min-height: var(--target-min); font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase; }

/* Result line: "12 instruments · Acoustic · Available · newest first". */
.c-catalog-summary { display: flex; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; padding: var(--space-4) var(--space-5); font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); border-bottom: var(--border-hairline) solid var(--color-rule); }
.c-catalog-summary b { font-weight: var(--weight-regular); color: var(--color-ink); }

/* Catalogue row: index · photo 4:3 · text · availability + year. The whole
   row is a link. Availability is text + a square swatch — never colour alone. */
/* A `<ul>`, so the list affordances go -- see the template for why it is a list at all.
   21 draws this as a `<div>` of anchors and needs neither. */
.c-catalog { display: flex; flex-direction: column; list-style: none; margin: 0; padding: 0; }
.c-catalog__item { display: grid; grid-template-columns: 4ch 15rem minmax(0, 1fr) 11rem; gap: var(--space-5); padding: var(--space-5); border-bottom: var(--border-hairline) solid var(--color-rule); text-decoration: none; color: var(--color-ink); align-items: start; }
.c-catalog__item:hover { background: var(--color-surface-raised); color: var(--color-ink); }
.c-catalog__index { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-accent-secondary); padding-top: 4px; }
/* THE COVER. Dropped from this block once, on the grounds that no instrument has an
   image -- which was wrong: `services.attach_covers` resolves one per row and has since
   `AC-M2-W4-05b`. The markup came back and `AC-M2-W4-04/-05` named the class as styled by
   nothing, which is the same gate that caught the opposite mistake an hour earlier.
   21 writes `.c-catalog__photo, .c-catalog__photo.c-ph`; we have no `.c-ph`, so the
   second half of that selector would match nothing here. */
.c-catalog__photo { aspect-ratio: 4 / 3; width: 100%; object-fit: cover; display: block; border: var(--border-hairline) solid var(--color-border); }
/* `AC-M6-W26`, AND IT IS `AC-M6-W8-01`'s LESSON A THIRD TIME. The photograph is GUARDED --
   an instrument with no cover emits no `<img>` -- so under auto-placement every later sibling
   slid one column left. MEASURED: the availability badge at 1152px on the three rows with a
   photograph and at 582px on the one without, which is what Marcin's arrow points at. Placing
   both cells explicitly is what the journal row and the jig row already do, for this exact
   reason; the difference here is that the conditional cell is real today rather than
   hypothetical. */
.c-catalog__text { grid-column: 3; display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.c-catalog__kicker { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); display: flex; gap: var(--space-3); flex-wrap: wrap; }
.c-catalog__title { font-family: var(--font-display); font-size: var(--text-xl); font-weight: var(--weight-bold); letter-spacing: 0.02em; text-transform: uppercase; line-height: var(--leading-tight); }
.c-catalog__desc { font-size: var(--text-sm); line-height: var(--leading-normal); color: var(--color-ink-muted); max-width: 52ch; }
.c-catalog__specs { display: flex; gap: var(--space-4); flex-wrap: wrap; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); font-variant-numeric: tabular-nums; margin-top: var(--space-1); }
.c-catalog__side { grid-column: 4; display: flex; flex-direction: column; gap: var(--space-3); align-items: flex-start; min-width: 0; font-family: var(--font-mono); font-size: var(--text-xs); font-variant-numeric: tabular-nums; color: var(--color-ink-muted); }
.c-catalog__side time { padding-top: 4px; }

/* Availability tag: swatch + text. Available = ink on ochre-muted; reserved
   = ink on warning; sold = inverse on ink. */
.c-avail { display: inline-flex; align-items: center; gap: var(--space-2); padding: 6px 10px; border-radius: var(--radius-sm); font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; max-width: 100%; }
.c-avail::before { content: ""; width: 8px; height: 8px; display: block; flex: none; }
.c-avail[data-state="available"] { background: var(--color-accent-secondary-muted); color: var(--color-ink); }
.c-avail[data-state="available"]::before { background: var(--color-success); }
.c-avail[data-state="reserved"] { background: var(--color-warning); color: var(--color-ink); }
.c-avail[data-state="reserved"]::before { background: var(--color-ink); clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.c-avail[data-state="sold"] { background: var(--color-ink); color: var(--color-ink-inverse); }
.c-avail[data-state="sold"]::before { background: var(--color-ink-inverse); border-radius: 50%; }
/* Personal (not for sale): the sold tag's ink, with a hollow swatch -- it was never on offer. */
.c-avail[data-state="personal"] { background: var(--color-ink); color: var(--color-ink-inverse); }
.c-avail[data-state="personal"]::before { border: 1px solid var(--color-ink-inverse); border-radius: 50%; }

/* Empty state when filters match nothing. */
.c-empty { padding: var(--space-10) var(--space-5); text-align: center; display: flex; flex-direction: column; gap: var(--space-3); align-items: center; }

/* Pagination: prev · numbered · next; current page is ink-filled; 44px targets. */
.c-pagination { display: flex; justify-content: space-between; align-items: center; gap: var(--space-4); flex-wrap: wrap; padding: var(--space-6) var(--space-5); }
.c-pagination ol { list-style: none; margin: 0; padding: 0; display: flex; gap: var(--space-2); }
.c-pagination a, .c-pagination [aria-current], .c-pagination .gap { display: inline-flex; align-items: center; justify-content: center; min-width: var(--target-min); min-height: var(--target-min); padding: 0 var(--space-3); font-family: var(--font-mono); font-size: var(--text-sm); font-variant-numeric: tabular-nums; text-decoration: none; color: var(--color-ink); border: var(--border-hairline) solid var(--color-border); border-radius: var(--radius-sm); }
.c-pagination a:hover { border-color: var(--color-ink); color: var(--color-ink); }
.c-pagination [aria-current="page"] { background: var(--color-ink); color: var(--color-ink-inverse); border-color: var(--color-ink); }
.c-pagination .gap { border: 0; min-width: 0; color: var(--color-ink-muted); }
/* `min-height` RESTATED ON THE CLASS, deliberately. `.c-pagination a` already supplies it
   and hit-tests at 46px — but that is an ELEMENT selector, and a floor readable only by
   knowing the tag is a floor the next reader has to rediscover. `.c-btn--primary` versus
   `.c-btn` is the same shape, and it cost nineteen good controls once. */
.c-pagination__step { font-family: var(--font-display) !important; font-size: var(--text-sm) !important; letter-spacing: 0.08em; text-transform: uppercase; padding: 0 var(--space-4) !important; min-height: var(--target-min); }
.c-pagination__step[aria-disabled="true"] { color: var(--color-ink-muted); pointer-events: none; border-color: var(--color-rule); }

/* UNFOLDED TO THE CONDITION THE DESIGNER WROTE (`AC-M6-W33-04`). These two were at 52rem because
   this file had no 60rem step and introducing one turned `mobile-breakpoints.test.ts` red — a gate
   pinned to package 18, which has no catalogue. `AC-M6-W33-02` moved that baseline to the newest
   vendored delivery, so the fold is no longer required and is no longer paid for.

   VALUE FOR VALUE, MEASURED BEFORE THE MOVE: `.c-catalog__item`'s
   `grid-template-columns: 4ch 11rem minmax(0, 1fr)` and the whole of `.c-catalog__side` are
   byte-equal to 22's at 60rem. Only the CONDITION changes.

   `padding: var(--space-4)` STAYS AT 52rem and that is 22's own split, not a leftover: 22 relieves
   the row from four columns to three at 60rem and tightens its inset a step later. Our fold had
   both happening together. */
@container shell (max-width: 60rem) {
  .c-catalog__item { grid-template-columns: 4ch 11rem minmax(0, 1fr); }
  .c-catalog__side { grid-column: 3; flex-direction: row; align-items: center; gap: var(--space-4); }
}

@container shell (max-width: 52rem) {
  .c-filters { padding: var(--space-4); gap: var(--space-4) var(--space-6); }
  .c-filters__reset { margin-left: 0; }
  .c-catalog-summary, .c-pagination { padding-inline: var(--space-4); }
  .c-catalog__item { padding: var(--space-4); }
}
@container shell (max-width: 30rem) {
  /* `AC-M6-W29`. THE SORT CONTROL GOES FULL WIDTH WITH THE GROUPS, AND IT WAS NOT.
     `.c-filters select { width: 100%; }` below has been here since the port and resolves against
     `.c-field`, which is a flex ITEM sized to its content — so on a phone the two toggle groups
     spanned the bar and the sort sat 120px short of them with the same left edge. Measured at
     400px: toggle 37..348, select 37..228. The fieldsets carry `width: 100%` and the paragraph
     holding the select did not, which is the whole of it. */
  .c-filters fieldset,
  .c-filters .c-field { width: 100%; }
  /* `AC-M6-W29`. Marcin: *"W wersji mobilnej daj poziome linie rozdzielające opcje
     filtrowania, bo bez nich źle to wygląda."* A wrapped toggle group reads as one
     undifferentiated block, and his screenshot draws a line across every wrap point.

     THE LINE IS A ROW GAP SHOWING THE CONTAINER'S BACKGROUND, WHICH IS THE ONLY ONE OF THE THREE
     CANDIDATES THAT CANNOT DRAW WHEN NOTHING WRAPPED. `row-gap` exists between ROWS and nowhere
     else: one row has no row gap, so there is no line to suppress and no width at which a stray
     one appears. A border on every item would need a negative offset to hide the first row's,
     against a container that has its own border and a radius clipping it; a container query at
     the wrap width would be a second breakpoint that has to track the content, and the content
     is DERIVED — how many options exist is a function of the data.

     AND IT IS INSIDE THE WRAP BLOCK ON PURPOSE, WHICH IS THE STRUCTURAL HALF. `flex-wrap` is set
     here and NOWHERE else, so above 30rem the property is its initial `nowrap` and the group is
     one row by construction rather than by fitting. The separator rule living in the same block
     means the desktop SET of drawn separators is EMPTY because the rule does not exist there, not
     because it evaluates to nothing. Measured: shell 425px wraps to [3, 1]; shell 500px is one
     row of [4], and 30rem is 480px.

     THE SPAN TAKES THE SURFACE COLOUR so the container's border-colour background shows ONLY in
     the gap. Every row fills its width — the labels are `flex: 1 1 auto`, so a row holding one
     option grows to the full width rather than leaving a bar of border colour beside it. The
     checked and hover rules are both more specific than this and are unaffected. */
  .c-toggle { flex-wrap: wrap; row-gap: var(--border-hairline); background: var(--color-border); }
  .c-toggle label { flex: 1 1 auto; justify-content: center; }
  .c-toggle label > span { background: var(--color-surface-raised); }
  .c-filters select { width: 100%; }
  /* ONE COLUMN AT 30rem, AND THE ORDINAL MOVES INTO THE KICKER (`AC-M6-W33-04`).
     THIS IS A REVISION, NOT A FOLD, WHICH IS WHY A UNION BASELINE COULD NEVER HAVE FOUND IT.
     Our register entry said *"at 30rem it drops to `4ch 1fr`, which IS 21's own step"* — true of
     package 21 and no longer true of 22, which collapses the row to one column, HIDES
     `.c-catalog__index` and re-renders the ordinal as generated content on the kicker. A baseline
     that unioned every delivery would still be holding us to 21's two columns.
     `.c-catalog__index` IS THE LOOP POSITION, so moving it out of the accessibility tree at this
     width costs nothing a reader needs — the same information is the row's own order. */
  .c-catalog__item { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-3); }
  .c-catalog__index { display: none; }
  .c-catalog__kicker::before { content: attr(data-index); color: var(--color-accent-secondary); }
  /* `grid-column: 1 / -1` IS GONE. It existed to make the cover span a TWO-column row; the row
     is ONE column at this width now, so it spans nothing. 22 dropped it for that reason, and our
     entry was citing 21 for a rule 22 has since retracted. */
  .c-catalog__photo { aspect-ratio: 16 / 9; }
  .c-catalog__text, .c-catalog__side { grid-column: 1; }
  .c-catalog__side { flex-wrap: wrap; }
  .c-catalog__title { font-size: var(--text-lg); }
  .c-pagination { justify-content: center; }
}

/* --- THE JOURNAL INDEX (package 22, `AC-M6-W32`) ---------------------------
   Ported from `dist/home/backend/static/css/app.css`. Four departures, each measured rather
   than preferred, and each one a thing the delivery could not know about our tree.

   ① `.l-page--wide` IS NOT PORTED. Its whole body is `max-width: var(--container-wide)`, which
      `D-108` already gave `.l-page` itself. See the note at the top of this file: a modifier
      that modifies nothing is a class the next reader has to test to understand.

   ② THE STICKY YEAR LABEL'S OFFSET IS OURS, NOT THEIRS, AND THE NUMBER IS THE WHOLE POINT.
      22 writes `top: calc(56px + var(--space-5))`, where 56px is ITS compact header. Measured
      on our tree, on a page that already renders that header:

          .c-header--compact height   1280px viewport -> 114px      (22 assumes 56)
                                       400px viewport -> 331px

      Porting the literal would stick the year label 58px UP INTO the header at desktop and
      275px behind it on a phone — the label would be invisible exactly while scrolling, which
      is the only time it does anything. Below 60rem the label is `position: static` in 22's
      design too (at 52rem here — see the divergence note below), so only the desktop value
      matters and it is declared once, here, beside the
      rule that consumes it.

      WHAT IS AND IS NOT GUARDED, SAID PLAINLY BECAUSE THE DIFFERENCE MATTERS. `journal-index.test.ts`
      asserts the SHAPE — that 22's `56px` literal is absent and that the offset is this one
      variable. It does NOT assert the RELATIONSHIP, because that suite renders nothing. The
      relationship was MEASURED on a fixture render: header bottom 114, label top 138, after a
      900px scroll, and `position: static` at 900 and 400 where the query takes over. **So this
      constant can drift out of date without any gate noticing**, and the wave that gives the
      entry page a browser — it needs one for `l-article-page` — is where the scrolling assertion
      belongs. Named here rather than left for somebody to discover.

   ③ `.c-ph` IS DROPPED FROM TWO SELECTORS. 22 writes `.c-entry__thumb, .c-entry__thumb.c-ph`
      and the same for `.c-featured__photo`; we have no `.c-ph`, so the second half of each
      matches nothing here. Same call `.c-catalog__photo` made in `AC-M6-W24`.

   ④ `:last-child` MOVES OUT ONE LEVEL. 22 writes `.c-entry:last-child { border-bottom: 0 }`
      over a `<div>` of anchors. Ours is a `<ul>` of `<li>`, because BACKEND's reachability test
      matches `<li data-journal-entry>` literally — so every `.c-entry` is the only child of its
      `<li>` and the delivery's selector would strip the rule from EVERY row rather than the
      last. It is `li:last-child > .c-entry` here.

   The lists carry their own reset, as `.c-catalog` does: 22 draws these as `<div>`s and needs
   neither. --------------------------------------------------------------- */

ul[data-journal-index] { list-style: none; margin: 0; padding: 0; }

/* The featured entry: the LATEST, and deliberately repeated in the list below (`D-112`,
   Marcin's emphasis). Photo 16:9 beside a 2xl title. */
.c-featured { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--space-8); padding: var(--space-8) var(--space-5); border-bottom: var(--border-hairline) solid var(--color-ink); text-decoration: none; color: var(--color-ink); align-items: center; background: var(--color-surface-raised); }
.c-featured:hover { color: var(--color-ink); }
.c-featured:hover .c-featured__title { color: var(--color-accent); }
.c-featured__photo { aspect-ratio: 16 / 9; width: 100%; object-fit: cover; display: block; border: var(--border-hairline) solid var(--color-border); }
.c-featured__text { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.c-featured__title { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: 0.02em; text-transform: uppercase; line-height: var(--leading-tight); }
.c-featured__lead { font-size: var(--text-base); line-height: var(--leading-normal); color: var(--color-ink-muted); max-width: 46ch; }

/* A year section: sticky year in the left column, its entries on the right. */
.c-year { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: var(--space-8); padding: var(--space-8) var(--space-5) 0; }
.c-year + .c-year { border-top: var(--border-hairline) solid var(--color-rule); }
.c-year__label { position: sticky; top: calc(114px + var(--space-5)); align-self: start; font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: 0.02em; line-height: 1; color: var(--color-ink); display: flex; flex-direction: column; gap: var(--space-2); }
.c-year__label small { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); font-weight: var(--weight-regular); }

/* An entry row: thumb 4:3 · kicker · title · lead · meta. The whole row is a link. */
.c-entries { display: flex; flex-direction: column; list-style: none; margin: 0; padding: 0; }
.c-entry { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-5); padding: var(--space-5) 0; border-bottom: var(--border-hairline) solid var(--color-rule); text-decoration: none; color: var(--color-ink); align-items: start; }
.c-entries > li:last-child > .c-entry { border-bottom: 0; }
.c-entry:hover { color: var(--color-ink); }
.c-entry:hover .c-entry__title { color: var(--color-accent); }
/* THE THUMBNAIL IS GUARDED IN THE TEMPLATE, SO THE COLUMN HAS TO ANSWER FOR ITS ABSENCE
   (`AC-M6-W8-01`, and `AC-M6-W17-02` where it cost a whole column). An entry with no image
   under a 12rem grid leaves 12rem of nothing and slides its text right.

   ONE COLUMN IS THE BASE AND THE THUMBNAIL ADDS ONE, rather than two columns with the empty
   case subtracted. The first draft wrote `.c-entry:not(:has(.c-entry__thumb))`, and
   `block-partials.test.ts` refused it: that suite asserts the SET of `:has()` selectors in this
   stylesheet is EMPTY, because `auto-fit` replaced the block run's lookahead chain. Narrowing
   somebody else's control so my rule fits is the one move this project does not allow — and the
   modifier is better anyway, because THE TEMPLATE ALREADY KNOWS. It is a fact about the data,
   not something to re-derive from the DOM.

   There are no journal images in the tree today, so the base branch is the only one the fixture
   renders — which is why both are declared now rather than after somebody sees the hole. */
.c-entry--thumbed { grid-template-columns: 12rem minmax(0, 1fr); }
.c-entry__thumb { aspect-ratio: 4 / 3; width: 100%; object-fit: cover; display: block; border: var(--border-hairline) solid var(--color-border); }
.c-entry__text { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
/* `gap` AND NO SEPARATOR CHARACTERS, which is what makes an untagged entry safe (`D-112`,
   `R-259`). A kicker built from "· ".join() leaves a leading dot when the first part is
   absent; this one just has one flex child fewer. */
.c-entry__kicker { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); display: flex; gap: var(--space-3); flex-wrap: wrap; font-variant-numeric: tabular-nums; }
.c-entry__kicker .cat { color: var(--color-accent-secondary); }
.c-entry__title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-bold); letter-spacing: 0.03em; text-transform: uppercase; line-height: var(--leading-tight); }
.c-entry__lead { font-size: var(--text-sm); line-height: var(--leading-normal); color: var(--color-ink-muted); max-width: 60ch; }
.c-entry__meta { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-1); }

/* The feed link sits at the end of the filter row, pushed right until the row wraps. */
/* `min-height` DECLARED, NOT REACHED BY PADDING. 22 writes `padding: 11px 0` and arrives at 44px
   by arithmetic; `design-tokens.test.ts` requires every interactive control to DECLARE
   `var(--target-min)`, because arithmetic that happens to reach the target is not a guarantee
   that survives a font-size change. WCAG 2.5.8. */
.c-filters__rss { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase; align-self: flex-end; padding: 11px 0; margin-left: auto; display: inline-flex; align-items: center; min-height: var(--target-min); }

/* 52rem, AND 22 WRITES 60rem — A DECLARED DIVERGENCE, NOT A TRANSCRIPTION SLIP.

   `mobile-breakpoints.test.ts` asserts the SET of `@container` conditions in this file EQUALS
   package 18's, exactly, with no register for a condition we have and they do not. Measured:

       18 (the gate's baseline)  4 conditions   {measure 480px, shell 52/30/24rem}
       22 (this delivery)        6 conditions   {+ measure 640px, + shell 60rem}
       ours                      4, and this block is the first thing that wanted a fifth

   So a new breakpoint is not mine to add quietly: the gate would go red and the only ways out
   are changing the design or changing the gate, and the second one is changing a parity
   assertion so that my own wave passes.

   WHAT IT COSTS, MEASURED RATHER THAN WAVED AT: the stack happens at shell 832px instead of
   960px, so between those two widths the featured entry stays two-column where 22 stacks it.
   Measured at shell 900: 540 + 360, which reads correctly — not a defect, a different choice.

   RAISED WITH THE ARCHITECT, because the real question is whether the gate's baseline should
   still be package 18 when the delivery in hand is 22. Every future port from 22 hits this. */
/* 60rem, AS DELIVERED (`AC-M6-W33-04`). `AC-M6-W32` shipped these at 52rem and said so in the
   file: *"a new breakpoint is not mine to add quietly: the gate would go red and the only ways out
   are changing the design or changing the gate."* The gate was the thing that was wrong, it was
   fixed as its own change with its own control, and the design comes back to where it was drawn.

   All five are byte-equal to 22's declarations; only the condition moves. The featured entry now
   stacks at shell 960 as delivered rather than at 832 — `R-172`, a page that looks better than the
   source is as much a defect as one that looks worse. */
@container shell (max-width: 60rem) {
  .c-featured { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); padding: var(--space-6) var(--space-4); }
  .c-featured__title { max-width: none; }
  .c-year { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); padding-inline: var(--space-4); }
  .c-year__label { position: static; flex-direction: row; align-items: baseline; gap: var(--space-3); font-size: var(--text-xl); padding-bottom: var(--space-3); border-bottom: var(--border-hairline) solid var(--color-ink); }
  .c-filters__rss { margin-left: 0; }
}

@container shell (max-width: 30rem) {
  .c-featured__title { font-size: var(--text-xl); }
  .c-entry { grid-template-columns: minmax(0, 1fr); gap: var(--space-3); }
  .c-entry__thumb { aspect-ratio: 16 / 9; }
  .c-entry__title { font-size: var(--text-base); }
}

/* --- THE REMEMBERED PRINTER (`AC-M7-W1-04`) --------------------------------
   Beside `.c-unit` and deliberately quieter than it: the unit toggle is two states a visitor
   flips while reading numbers, this is a machine they own and set once. Same row, same target
   height, no pill — a pill of five printer names would read as a filter. */
.c-bed { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); width: fit-content; max-width: 100%; }
.c-bed__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); }
/* NEVER WIDER THAN THE COLUMN (`AC-M8-W6-06`): a printer name is data, and the longest one made
   this select 452 px on a 360 px phone — the jig form tabs scrolled sideways, 36 route×width
   pairs of `scroll-audit` on staging. A select truncates its own text; the page must not. */
.c-bed__select { max-width: 100%; min-width: 0; text-overflow: ellipsis; min-height: var(--target-min); font-family: var(--font-mono); font-size: var(--text-xs); padding: 0 var(--space-3); color: var(--color-ink); background: var(--color-surface); border: var(--border-hairline) solid var(--color-border); border-radius: var(--radius-sm); }
.c-bed__save { min-height: var(--target-min); }

/* ===================================================================================
   THE JOURNAL ENTRY PAGE (`AC-M7-W21-02`) — package 22's `journal/detail.html`, ported.

   WHAT IS TAKEN AND WHAT IS NOT. The article head's base rules arrived with the contact page
   (`AC-M6-W23-01`, above); only `__byline` is new here. The lead figure, the article + aside
   grid, the table of contents, the related-instrument card and the pager are 22's, value for
   value, at 22's own `@container` conditions — which is what lets `mobile-breakpoints.test.ts`
   move ten of its NOT_ADOPTED entries to adopted and delete the `measure (min-width: 640px)`
   condition from its not-adopted register. `.b-image-pair` is NOT taken: it is a block type
   the registry does not have, and a rule with no markup to match is the thing that register
   refuses (`OQ-054`).

   THE ONE VALUE THAT IS OURS: `.l-article-page > aside { top }`. 22 writes `calc(var(--space-8)
   + 56px)` where 56px is ITS compact header; ours measures 114px at 1280 (`.c-year__label`,
   above, made the same correction for the same reason). `article-audit.mjs` holds the
   relationship — aside top == header bottom + space-8 after a scroll — so the literal cannot
   drift out of date without a run going red.

   THE HEADING LEVELS ARE SCOPED TO THE ENTRY PAGE, not to `.l-article`, which `page_detail.html`
   shares: 22's chapter rule (numbered h2 with a rule above it) is the entry's, and a CMS page
   keeps the rhythm `.b-heading` already gives it. Declared divergence, same selector family.

   THE TABLE OF CONTENTS IS A GRID CHILD, NOT THE ASIDE'S (`D-116`, `OQ-058`, mechanism B —
   `AC-M7-W25-03`). A divergence from 22's STRUCTURE in service of 22's INTENT: its
   `.c-toc { order: -1 }` at 52rem reorders the nav among the aside's flex children, where it is
   already first, so on 22's own page the TOC follows the article at every phone width (measured
   at 900/700/400, `W21-04` (b)). The nav is `.l-article-page`'s first child now: on desktop it
   takes the sidebar column's first row, sticky at the same offset the aside had, with the aside
   (the related card and its label, so the `complementary` landmark survives) in the row below
   and the article spanning both; below 52rem everything is `auto`/static and the nav precedes
   the article in the flow — and in the accessibility tree at every width, which `order` could
   never do. 22's `.c-toc { order: -1 }` is therefore NOT ported (`mobile-breakpoints.test.ts`
   says why), and the two placement selectors are ours alone.
   =================================================================================== */
.c-article-head__byline { display: flex; gap: var(--space-4); flex-wrap: wrap; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); font-variant-numeric: tabular-nums; }
.c-article-head__byline b { font-weight: var(--weight-regular); color: var(--color-ink); }

/* The image pair: two 4:5 frames beside each other, one caption across both; one under the
   other at 30rem, each 4:3 (`AC-M7-W28-04`). 22's `app.css:734–736` and `766–767`, value for
   value, including the `.c-ph` placeholder selector 22 pairs with `img` — we render no `.c-ph`,
   but a rule taken verbatim is a rule the register can hold to the delivery. */
.b-image-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
.b-image-pair .c-ph, .b-image-pair img { aspect-ratio: 4 / 5; width: 100%; object-fit: cover; display: block; border: var(--border-hairline) solid var(--color-border); }
.b-image-pair figcaption { grid-column: 1 / -1; }

/* The lead figure: 21:9 across the shell, caption set right. */
.c-article-lead { margin: 0; padding: var(--space-5) var(--space-5) 0; }
.c-article-lead img, .c-article-lead .c-ph { width: 100%; aspect-ratio: 21 / 9; object-fit: cover; display: block; border: var(--border-hairline) solid var(--color-border); }
.c-article-lead figcaption { margin-top: var(--space-2); text-align: right; }

/* Body layout: article + sticky aside. Column = measure + room for a floated figure (~14rem +
   gutter); the aside sits right after it, not at the far edge, so there is no dead band. */
.l-article-page { display: grid; grid-template-columns: minmax(0, calc(var(--measure) + 14rem + var(--space-5))) 17rem; justify-content: space-between; gap: var(--space-10); padding: var(--space-8) var(--space-5) var(--space-10); align-items: start; }
.l-article-page > .l-article { grid-column: 1; grid-row: 1 / span 2; container-type: inline-size; container-name: measure; min-width: 0; max-width: none; }
.l-article-page > .l-article > * { max-width: none; }
.l-article-page > .l-article .c-notice { max-width: none; }
@container measure (min-width: 640px) {
  .l-article-page .b-image[data-align="left"][data-wrap="true"], .l-article-page .b-image[data-align="right"][data-wrap="true"] { width: 40%; max-width: 18rem; }
}
.l-article-page > .c-toc { grid-column: 2; grid-row: 1; position: sticky; top: calc(114px + var(--space-8)); }
.l-article-page > aside { grid-column: 2; grid-row: 2; position: sticky; top: calc(114px + var(--space-8)); display: flex; flex-direction: column; gap: var(--space-5); }

/* In this entry: numbered h2 list, h3s indented, the current one accented. */
.c-toc { border-top: var(--border-hairline) solid var(--color-ink); padding-top: var(--space-3); }
.c-toc__label { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-ink-muted); display: block; margin-bottom: var(--space-2); }
.c-toc ol { list-style: none; margin: 0; padding: 0; counter-reset: toc; }
.c-toc li { counter-increment: toc; }
.c-toc a { display: grid; grid-template-columns: 3ch minmax(0, 1fr); gap: var(--space-2); padding: 7px 0; font-family: var(--font-display); font-size: var(--text-sm); font-weight: var(--weight-medium); letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-ink); text-decoration: none; }
.c-toc a::before { content: counter(toc, decimal-leading-zero); font-family: var(--font-mono); font-weight: var(--weight-regular); color: var(--color-accent-secondary); }
.c-toc li li { counter-increment: none; }
.c-toc li li a { grid-template-columns: minmax(0, 1fr); padding-left: calc(3ch + var(--space-2)); font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--weight-regular); letter-spacing: 0; text-transform: none; color: var(--color-ink-muted); }
.c-toc li li a::before { content: none; }
.c-toc a:hover, .c-toc a[aria-current="true"] { color: var(--color-accent); }

/* Chapter headings inside the ENTRY: h2 numbered with a rule above; a step down each level. */
.l-article-page .l-article h2 { font-size: var(--text-xl); letter-spacing: 0.03em; text-transform: uppercase; margin: var(--space-10) 0 var(--space-4); padding-top: var(--space-4); border-top: 2px solid var(--color-ink); }
/* THE MARKER IS NOT THE ENTRY PAGE'S, AND IT WAS SCOPED AS THOUGH IT WERE (`AC-M8-W4-05`).
   `cms/blocks/heading.html` emits `<span class="n">` for EVERY level-2 heading block that
   carries an index, so the marker reaches every template that draws a block stream in
   `.l-article` — the instrument page, `page_detail`, `legal_detail`. Only the entry page styled
   it, so everywhere else it rendered as an unspaced, uncoloured `01` run into the heading's
   first word: measured on the instrument page at 1280 as `01THE BRIEF`. The h2 BOX rules above
   stay scoped — the rule above the heading is the entry page's chapter treatment — but the
   marker's own appearance belongs wherever the marker is. */
.l-article h2 > .n { font-family: var(--font-mono); font-weight: var(--weight-regular); font-size: var(--text-sm); color: var(--color-accent-secondary); margin-right: var(--space-3); vertical-align: 0.15em; }
.l-article-page .l-article h3 { font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-bold); letter-spacing: 0.04em; text-transform: uppercase; line-height: var(--leading-tight); margin: var(--space-8) 0 var(--space-3); }
.l-article-page .l-article h4 { font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--weight-medium); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-ink-muted); margin: var(--space-6) 0 var(--space-2); display: flex; align-items: center; gap: var(--space-3); }
.l-article-page .l-article h4::after { content: ""; flex: 1; border-top: var(--border-hairline) solid var(--color-rule); }

/* The related instrument card in the aside (mirrors the bench card). */
.c-related { border: var(--border-hairline) solid var(--color-border); background: var(--color-surface-raised); padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); text-decoration: none; color: var(--color-ink); min-height: var(--target-min); }
.c-related:hover { border-color: var(--color-ink); color: var(--color-ink); }
.c-related img { aspect-ratio: 4 / 3; width: 100%; object-fit: cover; display: block; border: var(--border-hairline) solid var(--color-border); }

/* Prev / next entry at the foot of the article. */
.c-pager { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-top: var(--border-hairline) solid var(--color-ink); margin-top: var(--space-10); }
.c-pager a { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-5); text-decoration: none; color: var(--color-ink); }
.c-pager a + a { border-left: var(--border-hairline) solid var(--color-rule); text-align: right; align-items: flex-end; }
.c-pager a:hover { background: var(--color-surface-raised); color: var(--color-ink); }
.c-pager__dir { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-ink-muted); }
.c-pager__title { font-family: var(--font-display); font-size: var(--text-base); font-weight: var(--weight-bold); letter-spacing: 0.03em; text-transform: uppercase; line-height: var(--leading-tight); }

@container shell (max-width: 52rem) {
  .l-article-page { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); padding: var(--space-6) var(--space-4) var(--space-8); }
  .l-article-page > aside { position: static; }
  /* THE ASIDE'S DESKTOP CELL RESETS TOO, or the grid keeps an implicit second column for it and
     auto-placement drops the article beside the TOC: measured at 400 and 900 with the aside left
     at `grid-column: 2` — toc.top == article.top, the TOC beside the article, not above it. */
  .l-article-page > .c-toc, .l-article-page > .l-article, .l-article-page > aside { grid-column: auto; grid-row: auto; position: static; }
  .c-article-lead { padding: var(--space-4) var(--space-4) 0; }
  .c-article-lead img, .c-article-lead .c-ph { aspect-ratio: 16 / 10; }
}
@container shell (max-width: 30rem) {
  .b-image-pair { grid-template-columns: minmax(0, 1fr); }
  .b-image-pair .c-ph, .b-image-pair img { aspect-ratio: 4 / 3; }
  .c-pager { grid-template-columns: minmax(0, 1fr); }
  .c-pager a + a { border-left: 0; border-top: var(--border-hairline) solid var(--color-rule); text-align: left; align-items: flex-start; }
}

/* ── The truss-rod guide's diagrams (`AC-M7-W17-04`) ─────────────────────────────────────────

   TWO INLINE SVGs IN `pages/guides/truss-rod.html`, drawn in millimetres times a scale the
   markup declares. Every colour is a token through these classes — the SVG writes none — and
   the drawing sits in the same surface-raised, hairline-ruled frame the generator's preview
   sheet uses, so a diagram and a live drawing read as the same kind of object on the same site.
   Muted ink for the material, ink for the tool, the accent for what is being measured, and the
   secondary accent for the two corners the chisel takes: four roles, four tokens. */
.c-diagram { margin: 0; }
.c-diagram__svg { width: 100%; height: auto; display: block; max-width: 40rem; background: var(--color-surface-raised); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-sm); color: var(--color-ink); }
.c-diagram figcaption { margin-top: var(--space-2); max-width: 40rem; }
.c-diagram__part { fill: var(--color-surface); stroke: var(--color-border); stroke-width: 1; }
.c-diagram__void { fill: var(--color-surface-raised); stroke: var(--color-ink); stroke-width: 1.5; }
.c-diagram__bushing { fill: var(--color-accent-muted); stroke: var(--color-ink); stroke-width: 1.5; }
.c-diagram__bit { fill: var(--color-ink-muted); stroke: var(--color-ink); stroke-width: 1; }
.c-diagram__rod { fill: var(--color-ink-muted); fill-opacity: 0.55; stroke: var(--color-ink); stroke-width: 1; }
.c-diagram__chisel { fill: var(--color-accent-secondary); stroke: var(--color-accent-secondary); stroke-width: 1; }
.c-diagram__dim { stroke: var(--color-accent); stroke-width: 1.5; fill: none; }
.c-diagram__dim--offset { stroke-width: 3; }
.c-diagram__dim--leader { stroke-width: 0.75; stroke-dasharray: 3 3; }
.c-diagram__mark { fill: var(--color-accent); }
.c-diagram__label { font-family: var(--font-mono); font-size: 12px; fill: currentColor; }
/* The drawing scales with the column and its type scales with it — 12 units on a 640px-wide
   drawing is 16px of text, and on the 318px drawing a phone gets it would be 8px. So the label's
   unit size rises at the shell's phone breakpoint, the one every other phone rule here uses:
   16 units at that scale is 10px, and the viewBoxes carry the room the wider labels need —
   measured on the 400px render, 18 units clipped four labels at the frame's edges. Declared in
   `mobile-breakpoints.test.ts`: package 22 has no diagram and so no rule to adopt. */
@container shell (max-width: 30rem) { .c-diagram__label { font-size: 16px; } }
.c-diagram__label--muted { fill: var(--color-ink-muted); }
.c-diagram__label--on-rod { fill: var(--color-ink-inverse); }

/* ── The generator pane's verdict row and the form's combination note (`AC-M7-W17-04`) ──────

   THE BED-FIT LINE IS A VERDICT, NOT A NUMBER. The preview fragment's facts are label/value
   pairs; the truss rod's bed-fit line arrives with a third element naming which way it went, and
   the fragment writes it as `data-verdict`. It takes the whole row of the fact list, so it reads
   as the sentence under the four numbers rather than as a fifth number, and it carries a mark in
   the colour the result deserves — the card's own success green when it fits, the secondary
   accent when it splits, because a split is a designed outcome and not a failure. */
.c-facts__verdict { flex-basis: 100%; }
.c-facts__verdict dd { font-weight: 600; }
.c-facts__verdict dd::before { content: ""; display: inline-block; width: 0.6em; height: 0.6em; border-radius: 50%; margin-right: var(--space-2); vertical-align: 0.05em; background: var(--color-ink-muted); }
.c-facts__verdict[data-verdict="fits"] dd::before { background: var(--color-success); }
.c-facts__verdict[data-verdict="splits"] dd::before { background: var(--color-accent-secondary); }

/* The form's one note that is about a combination rather than a field: set like help text,
   above the fields, so it is read before the bushing and the bit are chosen. */
.c-form-note { font-size: var(--text-sm); color: var(--color-ink-muted); max-width: var(--measure); }

/* ===================================================================================
   THE INSTRUMENT PAGE (`AC-M8-W4-05`) — package 23's `instruments/detail_v2.html`, ported.

   Value for value at 23's own conditions (`shell 60rem`, `shell 30rem`), with three declared
   divergences from its STRUCTURE (`D-121`): the photo switch is by `:target` — the eight
   `.c-gallery:has(…)` rules are not taken, `block-partials.test.ts` holds our `:has()` SET
   empty — and the component is `.c-photos`, because `.c-gallery` is the gallery BLOCK's class;
   23's `.c-facts` is `.c-instrument-facts`, because `.c-facts` is the generator's read-out list
   (`mobile-breakpoints.test.ts` RENAMED carries both). The title block's sticky top is our
   measured 114px header + space-8, the relationship `instrument-audit.mjs` holds, as the entry
   page's aside and the year label do. The current thumbnail is `[aria-current="true"]`, set by
   the template for the first and by `carousel.js` on every hash change — 23 styled it through
   `:has(input:checked)`. The bench log's rules ride along, for `W5`.

   DECLARED NON-ADOPTION — `c-btn--secondary` (ARCHITECT's ruling, 2026-09-22). 23 puts the
   Specification button in `c-btn c-btn--secondary` and STYLES THAT CLASS NOWHERE: it is not in
   23's stylesheet at all, so there is no appearance to port. `instrument-pages.test.ts` refuses
   a class styled by nothing, and the answer is to declare rather than to widen the gate —
   inventing a secondary-button appearance would be choosing one we have no design authority
   for. It ships as the plain `c-btn`, our un-filled button, and the click script asks Marcin
   about the distinction against something he can see.

   DECLARED NON-ADOPTION — 23's *Bench hours* fact row (`OQ-066`, answered NO, `D-125`). 23
   shows `Godziny pracy · 412 h` in the quick facts; there is no field behind it and there will
   not be one. The row is not rendered, and no row is left holding a place for it.
   =================================================================================== */
.l-instrument-top { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--space-8); padding: var(--space-6) var(--space-5) var(--space-8); align-items: start; }
.l-instrument-top--solo { grid-template-columns: minmax(0, 1fr); }

/* The photos: one large 4:3 frame + a strip of thumbnails that are links; the frame's children
   are stacked, the first shown by default, the `:target` one raised above it. */
.c-photos { display: flex; flex-direction: column; gap: var(--space-3); }
.c-photos__main { position: relative; aspect-ratio: 4 / 3; border: var(--border-hairline) solid var(--color-border); background: var(--color-surface-sunken); overflow: hidden; }
.c-photos__main > * { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity var(--duration-fast) var(--ease-standard); }
.c-photos__main > :first-child { opacity: 1; }
.c-photos__main > :target { opacity: 1; z-index: 1; }
.c-photos__main:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.c-photos__thumbs { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--space-2); }
.c-photos__thumb { position: relative; display: block; aspect-ratio: 4 / 3; min-height: var(--target-min); border: var(--border-hairline) solid var(--color-border); overflow: hidden; }
.c-photos__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; border: 0; }
.c-photos__thumb[aria-current="true"] { border-color: var(--color-ink); outline: 2px solid var(--color-ink); outline-offset: -2px; }
.c-photos__thumb:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.c-photos__caption { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); display: flex; justify-content: space-between; gap: var(--space-3); margin: 0; }

/* The title block: kicker, h1, standfirst, the availability line, the CTA row, the quick facts. */
.c-instrument-head { display: flex; flex-direction: column; gap: var(--space-4); position: sticky; top: calc(114px + var(--space-8)); }
.c-instrument-head h1 { font-size: var(--text-2xl); }
.c-instrument-head__standfirst { font-size: var(--text-base); color: var(--color-ink-muted); }
.c-instrument-head__status { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; padding: var(--space-3) 0; border-top: var(--border-hairline) solid var(--color-ink); border-bottom: var(--border-hairline) solid var(--color-rule); font-family: var(--font-mono); font-size: var(--text-sm); }
.c-instrument-head__status .note { width: 100%; font-size: var(--text-xs); color: var(--color-ink-muted); }
.c-instrument-head__cta { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.c-instrument-facts { margin: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
.c-instrument-facts > div { display: flex; flex-direction: column; gap: 3px; padding: var(--space-3); border: var(--border-hairline) solid var(--color-rule); background: var(--color-surface-raised); }
.c-instrument-facts dt { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); }
.c-instrument-facts dd { margin: 0; font-family: var(--font-mono); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }

/* The numbered sections, like the home page's. */
.c-instrument-section { padding: var(--space-8) var(--space-5); border-top: var(--border-hairline) solid var(--color-ink); }
.c-instrument-section .c-section__head { margin-bottom: var(--space-5); }

/* 01 — the description beside the maker's notes. */
.l-description { display: grid; grid-template-columns: minmax(0, 1fr) 18rem; gap: var(--space-10); align-items: start; }
.l-description .l-article { max-width: none; }
.c-notes { border-top: 2px solid var(--color-accent-secondary); padding-top: var(--space-3); display: flex; flex-direction: column; gap: var(--space-3); font-size: var(--text-sm); line-height: var(--leading-normal); }
.c-notes .t-eyebrow { color: var(--color-accent-secondary); }

/* 02 — the specification: groups per type, two columns on a wide shell. */
.c-specs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6) var(--space-10); }
.c-specs__lead { margin: 0 0 var(--space-5); font-size: var(--text-lg); line-height: var(--leading-normal); }
.c-specs__group { display: flex; flex-direction: column; }
.c-specs__group h3 { font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--weight-medium); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--color-ink-muted); margin: 0 0 var(--space-2); padding-bottom: var(--space-2); border-bottom: var(--border-hairline) solid var(--color-ink); display: flex; gap: var(--space-2); }
.c-specs__group h3 .n { color: var(--color-accent-secondary); }
.c-specs table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.c-specs th { text-align: left; font-family: var(--font-mono); font-weight: var(--weight-regular); font-size: var(--text-xs); letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-ink-muted); padding: 9px var(--space-3) 9px 0; border-bottom: var(--border-hairline) solid var(--color-rule); vertical-align: top; width: 40%; }
.c-specs td { padding: 9px 0; border-bottom: var(--border-hairline) solid var(--color-rule); font-family: var(--font-mono); font-variant-numeric: tabular-nums; vertical-align: top; }
.c-specs td small { display: block; font-family: var(--font-body); font-size: var(--text-xs); color: var(--color-ink-muted); margin-top: 2px; }
.c-specs__foot { grid-column: 1 / -1; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); display: flex; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }

/* 03 — the bench log (W5): a compact three-column table. */
.c-log { width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-size: var(--text-xs); font-variant-numeric: tabular-nums; }
.c-log th { text-align: left; font-weight: var(--weight-regular); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); padding: 6px 8px 6px 0; border-bottom: var(--border-hairline) solid var(--color-ink); }
.c-log td { padding: 8px 8px 8px 0; border-bottom: var(--border-hairline) solid var(--color-rule); vertical-align: top; }
.c-log td.action, .c-log th.action { font-family: var(--font-body); font-size: var(--text-sm); line-height: 1.4; padding-left: 8px; }
.c-log td.date { white-space: nowrap; }
.c-log td.rh, .c-log th.rh { text-align: right; }
.l-log { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: var(--space-10); align-items: start; }
.l-log .t-meta { max-width: 36ch; }

/* 04 — the related journal entries, up to three cards. */
.c-related-entries { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); gap: var(--space-3); }
.c-related-entries .c-related img { aspect-ratio: 16 / 9; }

@container shell (max-width: 60rem) {
  .l-instrument-top { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); padding-inline: var(--space-4); }
  .c-instrument-head { position: static; }
  .l-description, .l-log { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
  .c-specs { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
  .c-instrument-section { padding-inline: var(--space-4); }
}
@container shell (max-width: 30rem) {
  .c-photos__thumbs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .c-instrument-facts { grid-template-columns: minmax(0, 1fr); }
  .c-instrument-head h1 { font-size: var(--text-xl); }
  .c-instrument-head__cta .c-btn { flex: 1 1 100%; text-align: center; }
  .c-specs th { width: 48%; }
}

/* ===================================================================================
   THE ROSETTE MAKER'S WORKBENCH (`AC-M8-W3a-05`, `D-119`, `D-124`)

   EVERY RULE HERE IS `OURS_ALONE` AND THE REGISTER SAYS SO. Packages 22 and 23 have no rosette
   maker, so there is no delivered counterpart to adopt, decline or rename — this is the first
   screen in the site with no baseline behind it. The upstream tool's own inline stylesheet is
   NOT taken (`§A.6`): system fonts, one breakpoint and colours written as literals, against our
   tokens, our type scale and the container SET the rest of the site already queries.

   THE LAYOUT FAMILY IS THE JIG PAGES', deliberately: a controls column beside a working area,
   the same card surface, the same rhythm. A visitor who has used the fret-slotting page should
   read this as another tool of the same workshop rather than as a different site.

   NO `:has()` — `block-partials` holds our SET empty and the upstream CSS has none either; the
   swatch's checked state is `:checked + span`, which is what theirs uses too.
   =================================================================================== */
/* `[hidden]` LOSES TO A CLASS THAT SETS `display`, AND ONLY A SCREENSHOT SHOWS IT. The UA sheet
   says `[hidden] { display: none }` at its own low weight, so `.l-workbench { display: grid }`
   and `.c-rosette-banner { display: flex }` override it: the element reports `hidden === true`,
   every test that asks the DOM agrees, and the thing is on the page. Measured here — the
   storage-full banner rendered on a first visit with nothing wrong. The rule is scoped to this
   screen's own boxes rather than made global, because a site-wide `!important` is a bigger
   decision than this defect. */
.l-workbench[hidden], .c-rosette-banner[hidden], .c-rosette-empty[hidden] { display: none; }
.l-workbench { display: grid; grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); gap: var(--space-8); align-items: start; padding-block: var(--space-6); }
.l-workbench__controls { display: flex; flex-direction: column; gap: var(--space-5); }
/* The preview follows the page while the controls scroll, as the instrument page's title block
   does — the same `114px + space-8` expression, so the two agree by construction. */
.l-workbench__preview { position: sticky; top: calc(114px + var(--space-8)); display: flex; flex-direction: column; gap: var(--space-4); }
/* THE COLUMN SCROLLS ON ITS OWN WHEN IT IS TALLER THAN THE SCREEN (`AC-M8-W8-01`). A sticky box
   taller than the viewport never shows its bottom until the page ends — measured at 1280x900:
   the column 1393 px, the selected piece's form first on screen at scrollY 3360 of 3851, so a
   chip picked at the top filled a form nobody could see. Capped at what is left under the
   header, it scrolls inside itself instead; the one-column layout below lifts the cap, because
   a nested scroll on a phone is a trap for the thumb. */
.l-workbench__preview { max-height: calc(100vh - 114px - var(--space-8) - var(--space-4)); overflow-y: auto; overscroll-behavior: contain; }
/* AND THE PICTURE INSIDE IT DOES NOT STICK. `.c-preview` is the jig pages' pane and is
   `position: sticky` there; inside a column that now scrolls, it pinned itself over the piece's
   form and covered its first three fields (screenshot, 1280x900). The column sticks; the
   picture scrolls with it. */
.l-workbench__preview .c-preview { position: relative; top: auto; }

.c-panel { padding: var(--space-5); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-md); background: var(--color-surface); }
.c-panel > h2 { font-family: var(--font-display); font-size: var(--text-sm); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-ink-muted); margin: 0 0 var(--space-4); }
.c-panel .c-field + .c-field { margin-top: var(--space-3); }

/* One fieldset per band (`§A.9`), its legend the band's name, its own controls inside.
   `c-rosette-band` AND NOT `c-band` (`AC-M8-W3c-01`): `.c-band` is the base layout's decorative
   strip (`display: flex; height: 6px`), and a fieldset carrying that class became a six-pixel
   row wider than the column, its labels landing on *Selected elements*. Measured at 1280: the
   fieldset 1247 px wide in a 352 px column. `min-width: 0` because a fieldset's UA minimum is
   its content's, which is the other way a row of inputs pushes past its column. */
.c-rosette-band,
.c-rosette-add,
.c-rosette-element { min-width: 0; margin: 0 0 var(--space-4); padding: var(--space-4); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-sm); display: flex; flex-direction: column; gap: var(--space-3); }
.c-rosette-add { margin: var(--space-4) 0 0; }
.c-rosette-band legend,
.c-rosette-add legend,
.c-rosette-element legend { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink-muted); padding-inline: var(--space-2); }
.c-rosette-band .c-field input:not([type="checkbox"]),
.c-rosette-element .c-field input:not([type="checkbox"]),
.c-rosette-add .c-field input:not([type="color"]) { width: 100%; min-width: 0; }
.c-rosette-band .c-btn { align-self: flex-start; }
.c-rosette-add p { margin: 0; }
.c-rosette-add input[type="color"] { width: 4rem; min-height: var(--target-min); padding: 0; border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-sm); background: none; }
.c-rosette-element { margin: var(--space-4) 0 0; }
.c-rosette-element__id { font-family: var(--font-mono); text-transform: none; letter-spacing: 0; color: var(--color-ink); }
.c-rosette-element[hidden] { display: none; }
/* THE FILE INPUTS ARE VISUALLY HIDDEN AND STILL FOCUSABLE; their `<label class="c-btn">` is what
   is seen. `display: none` would take them out of the tab order, and the pickers must be
   reachable from the keyboard like every other control. */
.c-rosette-file { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.c-rosette-file:focus-visible + .c-btn { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* THE SWATCHES: a radiogroup whose radios are visually hidden, so the state is the input's and
   the appearance is the span's. `:checked + span` needs no `:has()` and no JavaScript. */
.c-swatches { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.c-swatches label { position: relative; display: inline-flex; }
.c-swatches input { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.c-swatches span { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--target-min); padding: var(--space-2) var(--space-3); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-sm); font-size: var(--text-sm); cursor: pointer; }
.c-swatches input:checked + span { border-color: var(--color-ink); box-shadow: inset 0 0 0 1px var(--color-ink); }
.c-swatches input:focus-visible + span { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.c-swatches .c-swatch__chip { width: 1rem; height: 1rem; border: var(--border-hairline) solid var(--color-ink); border-radius: 2px; }

.c-rosette-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.c-rosette-actions + .c-rosette-actions { margin-top: var(--space-3); }

.c-preview__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
.c-preview__head h2 { font-family: var(--font-display); font-size: var(--text-lg); margin: 0; }
.c-view-switch { display: inline-flex; gap: var(--space-1); }
.c-view-switch label { position: relative; display: inline-flex; }
.c-view-switch input { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); }
.c-view-switch span { display: inline-flex; align-items: center; min-height: var(--target-min); padding: 0 var(--space-3); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-sm); font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.06em; text-transform: uppercase; cursor: pointer; }
.c-view-switch input:checked + span { background: var(--color-ink); color: var(--color-surface); border-color: var(--color-ink); }
.c-view-switch input:focus-visible + span { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* The pane keeps its box while a render is in flight, so the page does not jump on every
   keystroke — the SVG is replaced inside a box whose size is the aspect ratio, not the content. */
.c-preview { aspect-ratio: 1 / 1; display: grid; place-items: center; padding: var(--space-4); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-md); background: var(--color-surface-sunken); }
.c-preview svg { width: 100%; height: auto; }
.c-preview__status { min-height: 1.5em; margin: 0; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-ink-muted); }

.c-selected__list { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.c-selected__list button { min-height: var(--target-min); padding: var(--space-1) var(--space-3); border: var(--border-hairline) solid var(--color-rule); border-radius: var(--radius-sm); font-family: var(--font-mono); font-size: var(--text-xs); background: var(--color-surface); cursor: pointer; }
.c-selected__list button[aria-pressed="true"] { border-color: var(--color-ink); box-shadow: inset 0 0 0 1px var(--color-ink); }
/* A CHIP AND ITS ×, side by side (`AC-M8-W8-01`): the chip picks, the × removes. The × keeps the
   floor from the rule above; it is narrower, never shorter. */
.c-selected__list li { display: inline-flex; gap: 2px; }
.c-selected__list .c-selected__remove { padding-inline: var(--space-2); font-family: var(--font-body); font-size: var(--text-sm); }

/* The two states that are COPY rather than error handling (`§A.2`). */
.c-rosette-empty { padding: var(--space-8) var(--space-5); border: var(--border-hairline) dashed var(--color-rule); border-radius: var(--radius-md); text-align: center; }
.c-rosette-empty__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-3); margin-top: var(--space-5); }
.c-rosette-banner { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); padding: var(--space-4) var(--space-5); border: var(--border-hairline) solid var(--color-accent); border-radius: var(--radius-md); background: var(--color-surface-raised); }
.c-rosette-banner p { margin: 0; flex: 1 1 24rem; }

@container shell (max-width: 60rem) {
  /* ONE COLUMN, AND THE PREVIEW GOES FIRST. A controls column above a picture means scrolling
     past every field to see what a change did; the picture leads and the controls follow it. */
  .l-workbench { grid-template-columns: minmax(0, 1fr); }
  .l-workbench__preview { position: static; order: -1; max-height: none; overflow: visible; }
}

@container shell (max-width: 30rem) {
  .c-panel { padding: var(--space-4); }
  .c-rosette-actions .c-btn { flex: 1 1 100%; text-align: center; }
  .c-rosette-empty { padding: var(--space-6) var(--space-4); }
}
