/* ===========================================================
   The Work surfaces — Screen 03, `03-work.md`.

   One stylesheet for four pages: the arrival (projects.html)
   and the three sector pages (projects/schools · malls · homes,
   one template).

   The ledger, projects/list.html, was the fifth until Session
   XXI (6 Aug). It and the arrival were measured to be the same
   four-way cut of the same 47 records in two registers, so its
   columns moved inside the arrival's rooms and its page was
   deleted. Nothing here styles it any more.

   Ground: paper (E1) on every one of them; the single dark
   surface is the closing band, which shares its ground with
   the footer (E1.2a). Nothing is ever set on a photograph;
   every caption is off-image. #A6A6A6 never appears on paper —
   captions and metadata are ink-secondary (7.00:1).
   =========================================================== */

/* -----------------------------------------------------------
   Wayfinding — "← All work · Schools"
   ----------------------------------------------------------- */

.wk-way {
  display: flex;
  align-items: baseline;
  gap: var(--gap-inline);
  padding-block-start: var(--gap-component);
  text-transform: uppercase;
}

/* On the three sector pages the wayfinding line IS the arrival — it is the
   first ink on the page, ahead of the print and a long way ahead of the H1.
   The clearance belongs to whatever ink arrives first, not to whatever is
   set at display size, so this line takes the same one every other arrival
   takes. See the arrival-clearance block below the head. */
.wk-way--arrival {
  padding-block-start: var(--arrival-clearance);
}

.wk-way__back {
  color: var(--color-ink-secondary);
}

.wk-way__back:hover,
.wk-way__back:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.wk-way__here {
  color: var(--color-ink);
}

/* -----------------------------------------------------------
   Plates — the print, the studies, the room leads.
   E3.6: the image at its OWN aspect ratio, height-capped,
   never cropped. Edge-to-edge for a landscape lead, a tall
   plate for a vertical one — one rule for every proportion.
   ----------------------------------------------------------- */

/* margin-block only: a `margin: 0` here would clobber .container's
   margin-inline auto and push the print off the page's axis. */
.wk-print {
  margin-block: 0;
  padding-block-start: var(--gap-component);
}

.wk-plate__img {
  max-inline-size: 100%;
  max-block-size: 68vh;
  inline-size: auto;
  block-size: auto;
}

.wk-plate__caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--gap-inline);
  margin-block-start: var(--gap-tight);
}

.wk-plate__name {
  font-weight: var(--fw-semibold);
}

.wk-plate__name:hover,
.wk-plate__name:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

/* E9's label reads as a fact beside the name, not a caption's tail. */
.wk-plate__genre {
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caption);
  line-height: var(--lh-caption);
  text-transform: uppercase;
  color: var(--color-ink);
}

.wk-plate__place {
  text-transform: uppercase;
}

/* -----------------------------------------------------------
   The head — bare-verb H1 (Editorial, 300) and the support
   line carrying the page's one formula.
   ----------------------------------------------------------- */

.wk-head {
  padding-block-start: var(--gap-component);
}

/* ---- THE ARRIVAL CLEARANCE, for all four Work arrivals at once ----

   H2-b, measured. `--gap-component + --gap-heading` is not a new value: it
   is what Services, About, Contact, /careers and /ajman have carried since
   4f362d2, and it puts the first line's cap ink 97.6–98.4 below the trigger
   bars. These four sat at 33.9 (the arrival), 34.4 (the ledger) and 29.6
   (the three sector pages) — a third of the air, on the pages a reader
   reaches most often.

   Two of them were arrivals that had never been MARKED as one: the ledger's
   head carries no modifier, and the sector pages lead with `.wk-way`. The
   ≤1024 restatement below therefore never reached them either, which is why
   at 768 their first ink cleared the bars by 10.3–11.8px against 75.2–75.8
   everywhere else. Marking them is the fix; the value was already decided. */
.wk-head--arrival,
.wk-way--arrival {
  padding-block-start: var(--arrival-clearance);
}

/* The ≤1023 restatement that used to sit here is GONE — the value now lives in
   --arrival-clearance (tokens-layout.css), which restates itself at the gap
   tokens' own breakpoint. Seven files carried this identical block; the whole
   point of P3 is that there is one place to change it. */

/* base.css still carries v1's "every h1 is uppercase Hero Display" rule.
   The Work surfaces' decided H1 is Editorial, SENTENCE CASE ("Learns." —
   03-work §4.2.3), so the inherited transform is switched off here, scoped.
   Whether base.css keeps that rule at all is a Home-session decision. */
/* The text-transform:none that used to sit here is gone with the sitewide
   h1 uppercase it was fighting (base.css, decided at the Home build). */
.wk-verb {
  margin: 0;
}

.wk-support {
  margin: var(--gap-block) 0 0;
  color: var(--color-ink-secondary);
}

/* -----------------------------------------------------------
   The studies — second and third photographs, half width,
   side by side, aspect preserved, top-aligned.
   ----------------------------------------------------------- */

.wk-studies {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--gutter-desktop);
  align-items: start;
  padding-block-start: var(--gap-component);
}

.wk-study {
  margin: 0;
}

/* -----------------------------------------------------------
   The catalogue — now the set, as photographs (7 Aug).
   It was quiet rows beside a sticky, hover-driven frame, with
   a 200px inline thumbnail replacing the frame below 1024 or
   on a coarse pointer. Both are gone: the set gives every
   record its own photograph at every width, so a frame that
   shows one record at a time has nothing left to do and the
   capability query that chose between them has nothing left
   to choose. The 38% right-hand column goes with the frame.
   ----------------------------------------------------------- */

.wk-catalogue {
  padding-block-start: var(--gap-section);
}

/* `.wk-row*` below is NOT dead with the catalogue — js/work.js builds the
   search RESULTS list out of these same classes (`wk-row` · `wk-row__link` ·
   `wk-row__name` · `wk-row__meta`). What went with the catalogue is only what
   the catalogue alone carried: the list wrapper, the inline thumbnail, the
   frame, and the genre/year cells no surface emits any more. */
.wk-row + .wk-row {
  border-block-start: 1px solid var(--color-hairline);
}

.wk-row__link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gap-inline);
  padding-block: var(--pad-table-row);
}

.wk-row__link:hover .wk-row__name,
.wk-row__link:focus-visible .wk-row__name {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.wk-row__meta {
  display: flex;
  align-items: baseline;
  gap: var(--gap-inline);
  text-transform: uppercase;
}

.wk-row__meta span + span::before {
  content: "\00B7\00A0";
}

/* -----------------------------------------------------------
   THE SET — every record in a room or a catalogue, as a
   photograph (03-work §4.1.4).

   THE RULE, in one sentence: each row fills the column
   exactly; within a row every photograph shares a height; the
   height is whatever makes that row fit. Nothing is cropped,
   so the variation the eye reads is the buildings' own
   proportions — 41 landscape frames, 6 portrait, aspects from
   0.605 to 2.184.

   🔴 THE JUSTIFICATION IS THESE FOUR DECLARATIONS AND NOTHING
   ELSE, and it is why no pixel value appears in the markup.
   Each tile takes `flex-grow` equal to its own aspect ratio
   against `flex-basis: 0`, so the row's free width — its own
   width minus the gaps, which flex subtracts before it
   distributes — is shared in proportion to the aspects:
   w(i) = free · a(i) / Σa. `aspect-ratio` then makes every
   height in the row free / Σa, IDENTICAL by construction
   rather than by arithmetic. The same rule therefore re-fits
   at every viewport width, at any zoom, and in RTL, none of
   which the build ever hears about.

   `min-inline-size: 0` is load-bearing: a flex item's default
   `min-width: auto` is its CONTENT's width, and an image's
   content width is its intrinsic 800px. Without it the widest
   tiles refuse to shrink and the row overflows its column —
   silently, because overflow on a flex row looks like a
   design decision.

   WHICH records share a row is decided in build/lib/work.js
   (§ THE BAND): a fixed beat of 2 · 3 · 4 · 3, clamped so no
   row exceeds 340px at the reference column. Bare, the beat
   put two portrait heroes together and `homes` produced rows
   of 683px.
   ----------------------------------------------------------- */

.wk-set {
  margin-block-start: var(--gap-component);
}

/* -----------------------------------------------------------
   THE FOUND SET (Session XXXVII) — a band with no heading above it

   `[data-found]` carries no heading, because no heading is TRUE
   of a free-text set: `al jurf` reaches seven records across two
   rooms and the mosque.

   🔴 IT IS NOT A `.wk-room` AND MUST NOT BORROW THE CLASS. It
   did, for the arrival spacing, and that made it a fifth room to
   every selector that counts them — p27's delta, `sweep.js`'s
   split, three x-probes. It restates the one gap instead.

   🔴 Measured, not guessed. A room's first INK is its verb,
   which sits directly after the section's 200px — 200 from the
   control. The found band's first ink is a PHOTOGRAPH, which
   arrives after the section's 200 AND the set's own 64, so the
   reader met 264px of white where a room gives 200 and the band
   read as detached from the control that produced it.

   The rule is the one already on the page rather than a new
   number: the found band's first ink sits where a room's first
   ink sits. That is the set's lead removed, not a value invented
   — the section already holds the arrival gap.
   ----------------------------------------------------------- */
/* 🔴 THE ARRIVAL UNDER THE CONTROL IS NOT A SECTION GAP (Mahesh, 9 Aug,
   reading /projects.html?q=malls). --gap-section is the distance between two
   BANDS the reader scrolls past. The first band under the sector control is
   not that: the reader has just PRESSED something and is looking for its
   answer, and 200px of white is the page appearing not to have responded.
   Measured before: filter row bottom 514, the answer's first ink at 714.

   The composition is `--gap-component + --gap-heading`, which is the site's
   own arrival-clearance formula rather than an invented number — §"Spacing"
   in CLAUDE.md bars a value that is not a token, and this is the one
   composition the system already makes out of these two. 200 -> 128.

   The ROOMS' own rhythm is untouched: see .wk-room below, where the general
   sibling rule gives every room AFTER the first visible one the full section
   gap back. */
.wk-found {
  padding-block-start: calc(var(--gap-component) + var(--gap-heading));
}

.wk-found .wk-set {
  margin-block-start: 0;
}

.wk-set__row {
  display: flex;
  gap: var(--gap-block);
  align-items: flex-start;
  margin: 0 0 var(--gap-block);
  padding: 0;
  list-style: none;
}

.wk-set__row:last-child {
  margin-block-end: 0;
}

.wk-tile {
  flex: var(--a) 1 0;
  min-inline-size: 0;
}

.wk-tile__link {
  display: block;
  color: inherit;
}

/* 🔴 A SOLO ROW IS CAPPED, and the mosque is the only one on the site.
   A lone tile in a justified row fills the column, so its height is the
   column divided by its aspect and nothing else — and this record's hero is
   PORTRAIT at 0.667, which renders 1,440px tall at a 960 column. Capped at
   the set's OWN maximum row height it is 227 x 340, inside the family every
   other tile belongs to (200-677px wide), so the page's one Religious record
   never outweighs a room.

   The cap is the same 340 the build clamps rows to, named here rather than
   repeated as a bare number, because the two must move together: if the
   grouping's maximum row height changes, this is the other half of it. */
.wk-set {
  --set-solo-cap: 340px;
}

.wk-set__row--solo .wk-tile {
  flex: 0 1 auto;
}

.wk-set__row--solo .wk-tile__img {
  block-size: var(--set-solo-cap);
  inline-size: auto;
  max-inline-size: 100%;
}

.wk-tile__img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: var(--a);
  object-fit: cover;
}

/* 🔴 `break-word` IS NOT A TIDY-UP — it is the lesser of two evils, and the
   probe chose it. A portrait record in a justified row is inherently narrow:
   its width is the row's height times its own aspect, so Rose Tower at 0.605
   renders 95px wide at 768 while its neighbours are 300. A single word longer
   than that has two possible behaviours and no third — break, or stick out
   over the tile beside it. Measured at 768, one caption run escaped its tile
   by 5.1px, which reads as a typo rather than as a layout. It only ever fires
   on a word that cannot fit; every name that can wrap normally still does. */
.wk-tile__cap {
  display: block;
  margin-block-start: var(--gap-inline);
  overflow-wrap: break-word;
}

.wk-tile__name {
  display: block;
  color: var(--color-ink);
}

.wk-tile__link:hover .wk-tile__name,
.wk-tile__link:focus-visible .wk-tile__name {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

/* E9.3 governs index rows with "Exempt: none" — a Visualisation says so here
   exactly as it did in the row this replaced. */
.wk-tile__genre {
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caption);
  text-transform: uppercase;
  color: var(--color-ink);
}

.wk-tile__meta {
  display: block;
  text-transform: uppercase;
  color: var(--color-ink-secondary);
  font-variant-numeric: tabular-nums;
}

/* -----------------------------------------------------------
   The "also" line, and the mosque line
   ----------------------------------------------------------- */

.wk-also {
  margin-block: 0;
  padding-block-start: var(--gap-component);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--color-ink-secondary);
}

.wk-also__link {
  font-weight: var(--fw-semibold);
  color: var(--color-ink);
}

.wk-also__link:hover,
.wk-also__link:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.wk-mosque {
  margin-block: 0;
  padding-block-start: var(--gap-section);
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  line-height: var(--lh-body-lg);
  max-inline-size: var(--measure-body-lg);
  color: var(--color-ink);
}

/* -----------------------------------------------------------
   The arrival's rooms
   ----------------------------------------------------------- */

/* 🔴 KEYED ON THE FIRST *VISIBLE* ROOM, NOT THE FIRST IN THE DOM. Under a
   sector filter the room that answers can be the third one — `?q=malls`
   shows Shops, which is room 2 — so `:first-of-type` would put the tightened
   arrival on a room the reader cannot see and leave the answer at 200.

   Read it as: every room takes the tightened gap, and a room that has a
   VISIBLE room before it takes the section gap back. `~` is the general
   sibling, so this is true whichever rooms the filter has hidden, and it
   needs no JavaScript to maintain — the same doctrine as the rest of this
   page, where the control changes attributes and CSS decides the shape. */
.wk-room {
  padding-block-start: calc(var(--gap-component) + var(--gap-heading));
}

.wk-room:not([hidden]) ~ .wk-room {
  padding-block-start: var(--gap-section);
}

.wk-room__verb {
  margin: 0;
}

.wk-room__verblink {
  color: inherit;
}

.wk-room__verblink:hover,
.wk-room__verblink:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 8px;
}

.wk-room__opener {
  margin: var(--gap-block) 0 0;
  color: var(--color-ink-secondary);
}

/* 🔴 THE ROOM'S TABLE IS GONE, AND THE TABLE IS WHAT PAID FOR THE SET.
   Measured on the live page at 1440: the set with its captions adds 1,066px
   and removing the table takes 2,544px away, so every record gains a
   photograph and the page gets SHORTER — 8,072px to 6,864 for the shape
   alone. What went with it: `.wk-room__table`, its `<colgroup>` widths,
   `.wk-table*`, and the <=767 block that re-laid the rows as blocks. The one
   datum lost is the type noun, which ROOM_UNSAID_NOUNS already suppressed on
   32 of the 46 rows and which the search index still carries. */


/* -----------------------------------------------------------
   Search — the field's border is E6.1's #595959 on both
   grounds (ink-secondary IS that value); the tally is data
   furniture at caption size.
   ----------------------------------------------------------- */

.wk-search {
  margin-block-start: var(--gap-heading);
}

.wk-search__label {
  display: block;
  margin-block-end: 4px;
  text-transform: uppercase;
}

.wk-search__field {
  inline-size: min(100%, 40ch);
  padding: var(--gap-inline);
  border: 1px solid var(--color-ink-secondary);
  background: var(--color-surface);
  font-family: inherit;
  font-size: var(--fs-body);
  color: var(--color-ink);
  border-radius: 0;
  appearance: none;
}

.wk-search__field:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 2px;
}

/* The hint sits under the field and is permanent — it is not a placeholder.
   A placeholder vanishes at the first keystroke, which is precisely when a
   reader who mistyped a type most needs to see what the field accepts, and
   it cannot be read by anything but the eye. This is a real element wired
   with `aria-describedby`, so it survives typing and reaches a screen
   reader. Ink-secondary is 7.00:1 on paper (§5) — not a hierarchy made of
   opacity, which §9.16 bars. */
.wk-search__hint {
  margin: var(--gap-inline) 0 0;
  color: var(--color-ink-secondary);
}

.wk-search__tally {
  margin: var(--gap-inline) 0 0;
  font-variant-numeric: tabular-nums;
}

/* -----------------------------------------------------------
   The sector row (Session XXIV) — bare type on its own ground
   under the search island. No border, no fill, no radius: the
   record page's relation chooser is a bordered, uppercase,
   fill-on-active button and that role is assigned for BLACK
   ground under E2, where roles are assigned and never derived
   by inversion. The paper role is assigned here, in the other
   direction, so a later pass does not "harmonise" the two into
   the chip row §4.1 refuses.

   Active is weight 700 + underline — the site's decided active
   idiom, and the only state signal permitted: never colour
   (rule 3), never opacity (§9.16, rule 11).
   ----------------------------------------------------------- */

.wk-sectors {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--gap-tight) var(--gap-block);
  margin-block-start: var(--gap-block);
}

/* 🔴 ONE PIXEL DECIDED THIS, AND ONLY A TRUE 375 COULD SEE IT. The five words
   measure 240px of ink; at --gap-block the row wants 336 against a 335px
   column, so it wrapped and left "Homes" alone on a second line. Headless
   clamps to a 500px minimum, so every resize-based check reported one line —
   it took the iframe harness (x29) to render the width the fault lives at.
   The column gap steps to --gap-tight at the type tokens' own breakpoint,
   which is what sets the item widths: 240 + 4x16 = 304, and the row holds
   one line. Keyed at 767 because that is where the tokens step; a rule made
   of tokens inherits THOSE tokens' breakpoints. */
@media (max-width: 767px) {
  .wk-sectors {
    column-gap: var(--gap-tight);
  }
}

.wk-sector {
  display: inline-grid;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  color: var(--color-ink-secondary);
  text-align: start;
  cursor: pointer;
}

/* 🔴 RESERVE THE BOLD METRICS, OR THE ROW RE-LAYS OUT ON EVERY PRESS.
   Measured before this rule existed: pressing one item moved every item
   after it by 2-3px, because 400 -> 700 is wider — five states rendering
   as five slightly different arrangements of the same five words. The
   hidden twin is set at the pressed weight and shares the grid cell, so
   the button is always as wide as its widest state and nothing moves.
   `visibility: hidden` keeps it out of the accessibility tree, so the
   label is not announced twice. It reads `data-label`, so a copy change
   cannot leave a hardcoded width behind. */
.wk-sector::before {
  content: attr(data-label);
  grid-area: 1 / 1;
  font-weight: var(--fw-bold);
  visibility: hidden;
}

.wk-sector__t {
  grid-area: 1 / 1;
}

.wk-sector[aria-pressed='true'] {
  color: var(--color-ink);
  font-weight: var(--fw-bold);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.wk-sector:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 2px;
}

.wk-results {
  margin: var(--gap-block) 0 0;
  padding: 0;
  list-style: none;
}

/* -----------------------------------------------------------
   The table — the arrival's four room tables and the sector
   pages' catalogues.

   🔴 THE LEDGER'S CHROME WAS DELETED HERE (Session XXI, 6 Aug):
   `.wk-controls`, `.wk-chips`, `.wk-chip`, `.wk-chip__tally`,
   `.wk-sort`, `.wk-sort__select`, `.wk-ledger__body` and
   `.wk-ledger-line`, together with `.wk-table__h` (the visible
   column header) and `.wk-table__grouphead` (newest-first's
   group head). They styled projects/list.html, which retired
   into the arrival's rooms — the two pages were rendering the
   same 47 records under the same four-way cut. The chips died
   because §4.1 always said the rooms are the filter; the sort
   died with the flat run it ordered. The header row is now a
   visually-hidden <thead> per room, so its widths come from a
   <colgroup> instead — see .wk-room__table.
   ----------------------------------------------------------- */


/* -----------------------------------------------------------
   The closing band — the same object as the project page's
   (project.css .pd-band); repeated here because a page loads
   exactly one page stylesheet.
   ----------------------------------------------------------- */

.wk-band {
  margin-block-start: var(--gap-section);
  padding-block: calc(var(--gap-section-major) / 2) var(--gap-component);
}

.wk-band__line {
  margin: 0 0 var(--gap-block);
  font-size: var(--fs-h2);
  font-weight: var(--fw-light);
  letter-spacing: var(--ls-h2);
  line-height: var(--lh-h2);
  max-inline-size: var(--measure-h2);
  color: var(--color-on-dark);
}

.wk-band__action {
  display: inline-block;
  padding-block: var(--gap-tight);
  padding-inline: var(--gap-heading);
  border: 1px solid var(--color-on-dark);
  font-size: var(--fs-metadata);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-nav);
  text-transform: uppercase;
  color: var(--color-on-dark);
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.wk-band__action:hover,
.wk-band__action:focus-visible {
  background: var(--color-on-dark);
  color: var(--color-surface-dark);
}

/* -----------------------------------------------------------
   Utility (shared shape with project.css)
   ----------------------------------------------------------- */

.u-visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* -----------------------------------------------------------
   Breakpoints
   ----------------------------------------------------------- */

@media (max-width: 1024px) {
  .wk-studies {
    column-gap: var(--gutter-tablet);
  }

}

/* -----------------------------------------------------------
   THE CAPABILITY QUERY IS GONE WITH THE FRAME (7 Aug).

   A whole block lived here: `(max-width: 1024px), (hover: none),
   (pointer: coarse)` chose between a sticky hover-driven frame
   and a 200px inline thumbnail, because a frame that only
   works with a mouse must retire where there is no mouse. The
   set retires both — every record now carries its own
   photograph at every width and on every pointer — so the
   query has nothing left to choose between.

   📌 Its reasoning is kept in the record rather than here:
   the De Morgan form of the disjunction, the iPad-with-
   trackpad case, and 🔴 the finding that a capability query
   CANNOT be emulated by resizing a window — `setEmulatedMedia`
   accepts `hover`/`pointer` and changes nothing, and
   `--touch-events` is a different thing. Only Blink's own
   `--blink-settings=primaryPointerType=…` works. That is worth
   more than the rules were: it is why `p26-frame-capability.js`
   exists, and it applies to the next capability query anyone
   writes. The probe itself is now obsolete — it is off-board,
   so nothing goes red, but it measures an element that no
   longer ships.
   ----------------------------------------------------------- */

@media (max-width: 767px) {
  .wk-studies {
    grid-template-columns: 1fr;
    row-gap: var(--gap-component);
  }

  /* 🔴 THE SET GOES TWO-UP, AND THE ORPHAN TAKES THE WHOLE WIDTH.
     The row's grouping is markup — decided once, at build, against a
     960px reference column — so CSS cannot regroup it here. What it can
     do is stop justifying: below 767 the row becomes a two-column grid,
     which holds at a true 375 (a 335px column gives ~155px tiles) where
     a justified row of four would give 55px.

     A row of three or of five then leaves its last tile alone on a line,
     and `:last-child:nth-child(odd)` is exactly the test for that — the
     last tile sits at an odd position only when nothing shares its line.
     It spans both columns rather than sitting beside a hole, so every
     line is full at every width and the phone gets a large closing
     photograph instead of a gap. */
  .wk-set__row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--gap-block);
  }

  .wk-tile:last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }

  /* The solo row's cap is a DESKTOP proportion, not a mobile one: 340px in a
     335px column is the whole column and then some. Below the break it joins
     the grid on the same terms as every other lone tile — full width, its own
     height — so the cap is released rather than fought with max-inline-size. */
  .wk-set__row--solo .wk-tile__img {
    block-size: auto;
    inline-size: 100%;
  }
}

/* -----------------------------------------------------------
   Print — the tender view (§4.3): the table with all rows in
   the current filter/sort; chrome, controls, frames, thumbs
   and the band suppressed.
   ----------------------------------------------------------- */

@media print {
  .chrome-trigger,
  .chrome-plate,
  .menu-nib,
  .menu-overlay,
  .wk-band,
  .site-footer {
    display: none !important;
  }

}

/* -----------------------------------------------------------
   Reduced motion — the frame swap is already instant; the one
   transition on these pages is the band action. Durations AND
   delays: a zero duration does not cancel a delay.
   ----------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .wk-band__action {
    transition-duration: 0s;
    transition-delay: 0s;
  }
}
