/* ==========================================================================
   Wild Sheep — brochure
   An A4 document rendered from the same games.json the site runs on, laid out
   in HTML/CSS so the design is editable without touching a PDF library.
   The browser's print engine turns it into a vector PDF with live fonts.

   WordPress port: this exact stylesheet + markup is what the server-side
   renderer (Dompdf / mPDF / headless Chrome) consumes for one-click download.
   See wp/HANDOVER.md.
   ========================================================================== */

/* MARGIN ZERO, AND THAT IS THE FIX FOR THE BROWSER'S PRINT FURNITURE.
   Safari and Chrome draw their own header and footer — document title, date,
   page URL, "Page 7 of 29" — INSIDE the @page margin. With a 14mm/15mm margin
   there was room for them, which is where the white border with a localhost
   link in the corner came from. At margin 0 there is nowhere to draw them, so
   they are suppressed, and the sheets bleed to the paper edge as intended.
   The page's own inset moves into .sheet__pad instead. */
@page {
  size: A4 portrait;
  margin: 0;
}

.brochure {
  /* The FULL page, not the old 180mm content box — the sheet now is the paper,
     so the on-screen preview is the same geometry as the print. */
  --sheet-w: 210mm;
  background: #8A8A8A;
  padding: 10mm 0;
}

/* ---- One sheet = one printed page --------------------------------------- */
.sheet {
  width: var(--sheet-w);
  min-height: 297mm;
  margin: 0 auto 8mm;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.sheet--dark { background: var(--ink); color: var(--white); }
.sheet--cover { background: var(--purple); color: var(--white); justify-content: space-between; }
/* The Classic edition's cover takes the range's own colour. White type on
   #FF932E is the brand's call — the site's Classic footer does the same. */
.sheet--cover[data-scope='classic'] { background: var(--orange); }

/* Carries the page inset that used to live on @page. */
.sheet__pad { padding: 14mm 15mm; flex: 1; display: flex; flex-direction: column; }

/* ---- Cover -------------------------------------------------------------- */
/* Three bands: the lockup at the top, the type and figures pulled up under it,
   and the cast lineup filling the foot of the page. */
.sheet--cover { justify-content: flex-start; }
.cover__top { padding: 12mm 12mm 0; }
/* Inline SVG (see inlineMark() in brochure.js) rather than the site's masked
   .mark — the mask does not survive Safari's print pipeline and lands in the
   PDF as a solid white rectangle. */
.cover__mark { width: 72mm; color: var(--white); }
.cover__mark svg { display: block; width: 100%; height: auto; fill: currentColor; }

/* The gap under the lockup — this is what drops the title down the page; the
   lockup itself does not move. */
.cover__head { padding: 0 12mm; margin-top: 24mm; }
.cover__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 47mm;
  line-height: 0.8;
  text-transform: uppercase;
  margin: 0;
  color: var(--white);
}
/* Bold, and it carries the full sentence — this is the line that says what the
   document actually is. */
.cover__sub {
  /* NEGATIVE, and it has to be. The visible gap is not this margin — at 47mm
     with line-height 0.8 the title's line box still runs ~5.6mm below the cap
     baseline, and that dead space is what separates the two lines. Closing it
     means pulling up INTO the title's box. The heading is all caps with no
     descenders, so there is nothing down there to collide with. */
  margin: -2.5mm 0 0;
  font-size: 5.7mm;
  font-weight: 700;
  line-height: 1.3;
  /* One line, never two — the three blurbs are all about the same length and
     `nowrap` is what guarantees none of them folds under itself. */
  white-space: nowrap;
}
/* Dropped toward the artwork, but not onto it — .cover__base is pushed to the
   foot by margin-top:auto, so any more here closes the gap to zero. */
.cover__stats { display: flex; gap: 16mm; margin: 10mm 0 0; }
.cover__stat b {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 24mm;
  /* Tight, so the label sits right under the figure rather than a line away —
     at 24mm a line-height of 1 left a visible gap between the pair. The negative
     margin halves what the line box still leaves (measured 1.32mm). */
  line-height: 0.82;
  margin-bottom: -0.66mm;
}
.cover__stat span { font-size: 3mm; letter-spacing: 0.14em; text-transform: uppercase; }
/* Smaller than the old 3.4mm — it is the imprint, not copy anyone reads. */
.cover__foot {
  margin: 0;
  font-size: 2.6mm;
  line-height: 1.5;
  color: var(--white);
  opacity: 0.75;
}

/* The cast lineup closes the cover. It runs WIDER than the page so the outermost
   characters are cropped by the paper edge — at 100% it would be a strip of
   thumbnails. `margin-inline: auto` cannot centre a box wider than its
   container (auto resolves to 0 and the whole overflow lands on one side), so
   the offset does it.
   -47.22%, not -50%: that puts the SHEEP dead centre rather than the file's
   bounding box. Its hooves sit at x=1071 and x=1634 of 2864, so the sheep's axis
   is 1352 against the file's 1432 — 2.78% of the width left of centre, which
   this adds back. Same figure as the landing page's hero, and for the same
   reason. */
/* The lineup and the dark table it stands on, pushed to the foot of the page. */
.cover__base { margin-top: auto; }
.cover__art {
  width: 137%;
  position: relative;
  left: 50%;
  transform: translateX(-47.22%);
}
.cover__art picture { display: block; }
/* The artwork is cut flat at y=1207 of 1307 and the hooves, two bottles and a
   hand hang below that line. 100/1307 of the height, and the image is 1307/2864
   as tall as it is wide, so the overhang is 3.49% OF ITS OWN WIDTH — which is
   why the negative margin sits on the img inside a wrapper that is the image's
   width. That makes the table's edge land on the cut at any size, rather than
   being a tuned guess. */
/* EXACTLY the landing page's relation, and the figure is measured, not tuned.
   The artwork is cut flat at y=1207 of 1307 and the sheep's hooves, two bottles
   and a hand hang below that line. 100/1307 of the height, and the image is
   1307/2864 as tall as it is wide, so the overhang is 3.49% OF ITS OWN WIDTH —
   which is why the negative margin sits on the img inside a wrapper that is the
   image's width, making it exact at any size.
   The table's top therefore lands ON the cut: the flat edge disappears behind it
   and only the overhang laps over, so the cast reads as standing on a surface.
   The extra 0.4mm is the print equivalent of the site's 3px — it hides the
   hairline of paper that subpixel rounding can otherwise leave at the join. */
.cover__art img {
  display: block; width: 100%; height: auto;
  margin-bottom: calc(-3.49% - 0.4mm);
}

/* THE ARTWORK PAINTS OVER THE TABLE, which is the landing page's arrangement and
   the whole point of the overhang: .hero__art carries z-index 2 there for exactly
   this reason. Without it the table — later in the DOM and positioned — painted
   on top and simply covered the 3.49% that was supposed to lap over it, leaving
   a hard flat cut where the sheep's arms and the bottles should cross onto the
   dark. The table's top padding clears the overhang so the imprint stays legible
   underneath it. */
.cover__art { z-index: 2; }
.cover__table {
  position: relative;
  z-index: 1;
  padding: 15mm 15mm 11mm;
  color: var(--white);
}

/* ---- Shared document furniture ------------------------------------------ */
.doc-h1 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--purple);
  font-size: 26mm;
  line-height: 0.84;
  text-transform: uppercase;
  margin: 0 0 7mm;
}
.doc-h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 9mm;
  line-height: 0.9;
  text-transform: uppercase;
  margin: 0 0 2mm;
}
.doc-body { font-size: 3.4mm; line-height: 1.45; font-weight: 400; margin: 0 0 3.5mm; }
.doc-rule { border: 0; border-top: 0.4mm solid var(--rule); margin: 4.5mm 0; }
.sheet--dark .doc-rule { border-top-color: var(--rule-invert); }
/* On the dark closing sheet the heading stays white — purple on ink is 2.95:1,
   the same reason the site's spec-band heading has to lighten. */
.sheet--dark .doc-h1 { color: var(--white); }

.doc-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 6mm; }
.doc-cols--3 { grid-template-columns: repeat(3, 1fr); }

.b-prop { break-inside: avoid; }
.b-prop h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 6mm; line-height: 0.9; text-transform: uppercase; margin: 0 0 1.5mm;
}
.b-prop p { font-size: 3.1mm; line-height: 1.4; margin: 0; font-weight: 400; }

/* Running footer on every content sheet */
.sheet__footer {
  display: flex; justify-content: space-between; align-items: center;
  gap: 6mm;
  padding: 3mm 15mm;
  border-top: 0.3mm solid var(--rule);
  font-size: 2mm; letter-spacing: 0.06em; text-transform: uppercase;
  color: #9A9A9A;
}
.sheet--dark .sheet__footer { border-top-color: var(--rule-invert); color: rgba(255,255,255,0.6); }

/* ---- Closing sheet ------------------------------------------------------ */
/* "Be the next / GAME <changers script>" — the landing page's own lockup, with
   the brush script standing in for the word. Every offset is in `em` so the
   composition holds if the heading size ever changes, exactly as it is on the
   site. */
.closing__title { font-size: 24mm; }
.closing__line {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  /* Closes the leading that line-height 0.84 still leaves between the two
     lines, so GAME sits up tight under "Be the next". */
  margin-top: -0.16em;
}
/* GAME comes back down by the amount the line above was pulled up, less half a
   word-space. `transform`, not margin: the script shares this flex line and
   must not shift, and transforms do not participate in layout. */
.closing__word { transform: translateY(0.09em); }
.closing__script {
  flex: none;
  display: block;
  width: 2.31em;          /* the same 815-against-353 ratio the hero uses */
  margin-left: -0.216em;  /* bites back over the end of GAME, clear of its E */
  margin-top: -0.10em;    /* a touch above the type's centre */
  /* --purple-light, not --purple: on the ink field #9445FF measures 2.95:1 and
     the stroke all but disappears. Same substitution the site makes on its own
     dark band. */
  color: var(--purple-light);
}
.closing__script svg { display: block; width: 100%; height: auto; fill: currentColor; }

/* ---- Overview sheets ---------------------------------------------------- */
.doc-lead { font-size: 4.2mm; line-height: 1.4; font-weight: 400; margin: 0 0 6mm; max-width: 150mm; }

/* 2x2 of cards rather than a stacked list, echoing the site's capability
   carousel — which is what lets the sheep illustrations be big enough to read
   as artwork instead of thumbnails sitting beside a paragraph. */
.b-cap-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6mm;
}
.b-cap {
  position: relative;
  border: 0.4mm solid var(--rule);
  border-radius: 1.5mm;
  padding: 6mm 6mm 0;
  min-height: 90mm;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  break-inside: avoid;
}
.b-cap h3 {
  font-family: var(--font-display);
  font-weight: 400;                      /* SCHABO is 400-only */
  font-size: 7mm; line-height: 0.9; text-transform: uppercase; margin: 0 0 2mm;
}
.b-cap p { font-size: 3.1mm; line-height: 1.45; margin: 0; }
/* Sized by HEIGHT and pinned to the card's bottom-right, as on the site: the
   four illustrations do not share an aspect ratio, so matching their widths
   would make the squat ones tower over the tall ones. */
/* Bigger than the copy needs, deliberately — the illustration is the reason
   these are cards rather than a list. Sized by HEIGHT: the four do not share an
   aspect ratio, so matching their widths would make the squat ones tower. */
.b-cap__art {
  align-self: flex-end;
  margin-top: auto;
  width: auto; height: 50mm;
  max-width: 100%;
  object-fit: contain;
  object-position: bottom right;
}

/* Tiles 2 and 3 take a slightly darker ground. In a 2x2 those are the diagonal
   pair, so the four read as a chequer rather than a block of identical boxes. */
.b-cap:nth-child(2),
.b-cap:nth-child(3) { background: var(--paper-tint); }

/* ---- What you get -------------------------------------------------------- */
/* One heading per value b-prop, in order, with the promotion-tool cards nested
   under Engagement Tools. The section used to carry "Engagement Tools" twice —
   once as a value b-prop and again as the heading over the cards. */
.b-vp { break-inside: avoid; }
.b-vp__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 9mm; line-height: 0.9; text-transform: uppercase; margin: 0 0 2mm;
}
.b-vp__body { font-size: 3.6mm; line-height: 1.45; margin: 0; max-width: 150mm; }

/* Deliberately quieter than the b-prop above them: they are the detail under
   Engagement Tools, not a third section competing with it. */
.b-tool-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4mm 5mm;
  margin-top: 4mm;
}
.b-tool {
  border-top: 0.4mm solid var(--rule);
  padding-top: 2.5mm;
  break-inside: avoid;
}
/* `non-scaling-stroke` keeps the 24x24 viewBox's stroke at the weight it was
   drawn at once the box is scaled to 6mm — without it the line lands about two
   and a half times too heavy, exactly as noted for the site's own cards. */
.b-tool__icon {
  display: block;
  width: 6mm; height: 6mm;
  margin: 0 0 1.5mm;
  color: var(--green-dark);
}
.b-tool__icon path { vector-effect: non-scaling-stroke; }
.b-tool h4 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 4.4mm; line-height: 0.9; text-transform: uppercase; margin: 0 0 1mm;
}
.b-tool p { font-size: 2.7mm; line-height: 1.35; margin: 0; }

/* Distribution reach — deliberately the smallest type on the sheet. It is a
   completeness line (10 languages, 88 currencies), not something read through. */
.b-reach {
  margin-top: 2.5mm;
  border-top: 0.4mm solid var(--rule);
  padding-top: 2mm;
}
.b-reach p {
  font-size: 1.9mm; line-height: 1.2; margin: 0 0 0.7mm; color: #7C7C7C;
}
.b-reach b {
  color: var(--ink); letter-spacing: 0.1em; text-transform: uppercase;
  margin-right: 1mm;
}

/* ---- Upcomings ---------------------------------------------------------- */
/* One sheet for the whole unreleased run: art and a date is all there is to say
   about a title that is not out, so they do not each get a game sheet. */
/* Two up, filling the page. The thumbnails are all 3:2, so `aspect-ratio` on the
   box plus `cover` crops nothing — the box IS the picture's shape, which is what
   keeps a page of them tidy at any card size. */
/* One column of wide rows — thumbnail left, title and date beside it — which is
   what fills a page with only three titles on it. The thumbnails are all 3:2, so
   `aspect-ratio` on the box plus `cover` crops nothing: the box IS the picture's
   shape, which is what keeps the page tidy at any card size. */
.b-up-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8mm;
  margin-top: 7mm;
}
.b-up {
  display: grid;
  grid-template-columns: 92mm 1fr;
  gap: 8mm;
  align-items: center;
  break-inside: avoid;
}
/* Four or more would run off the sheet as full-width rows. */
.b-up-grid--many { grid-template-columns: repeat(2, 1fr); gap: 8mm 7mm; }
.b-up-grid--many .b-up { grid-template-columns: 1fr; gap: 0; align-items: start; }
.b-up img {
  display: block;
  width: 100%;
  /* height:auto is required whenever aspect-ratio is used on an <img> — the
     height attribute is a presentational hint that would otherwise count as a
     specified height and make aspect-ratio a no-op. Hard rule 4, in print. */
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  background: var(--ink);
}
/* No colour on either line — the sheet is a dark field and the type carries it,
   the way the site's own Upcomings island does. */
.b-up h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 9mm; line-height: 0.9; text-transform: uppercase; margin: 0 0 2mm;
  color: var(--white);
}
.b-up-grid--many .b-up h3 { font-size: 7mm; margin-top: 3.5mm; }
.b-up__date { font-size: 3.6mm; font-weight: 700; margin: 0; color: rgba(255, 255, 255, 0.78); }
.sheet--dark .doc-lead { color: rgba(255, 255, 255, 0.8); }
.b-up img { background: #1E1E1E; }

/* ---- Game sheets: ONE GAME PER PAGE ------------------------------------- */
/* The sheet mirrors the game page's own order — hero, spec band, story and
   features, symbols, buy bonus — so print and web describe a title the same way
   round. Every block after the hero is content-gated in the builder, so a
   Classic title with figures and no prose renders a short clean sheet rather
   than a page of empty headings. */
.sheet--game { overflow: hidden; }

/* The hero reproduces the page's composed treatment: key art under a brand
   gradient with the logo sitting on top of it. */
.game-sheet__hero {
  position: relative;
  height: 68mm;
  flex: none;
  background: var(--hero-base);
  overflow: hidden;
}
.game-sheet__backdrop {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
/* The page's hero curve, re-tuned for a band a third of its height. The page
   runs solid to 10% and clears by 64%; over 44mm that buried most of the key
   art, so this holds solid only long enough to seat the logo and is gone by
   half way. Same five-stop shape, shallower.

   TWO PRINT RULES ARE BAKED IN HERE.
   1. It is a real <span>, not a ::after. Safari drops gradients on
      pseudo-elements often enough that a printed sheet lost its wash entirely.
   2. The stops are literal rgba(), NOT color-mix(). color-mix resolves fine on
      screen and is unreliable through the print pipeline; a gradient that fails
      to parse takes the whole background with it. The two brand colours are
      fixed values anyway (#9445FF and #FF932E), so nothing is lost by writing
      them out. */
/* The wash is now an inline <svg> emitted by svgWash() in brochure.js — see the
   note there. It is CONTENT, so it survives Safari printing with backgrounds
   off, where a CSS gradient does not. `preserveAspectRatio: none` lets a 10x10
   viewBox stretch to the band. */
.field-svg {
  position: absolute; inset: 0;
  display: block;
  width: 100%; height: 100%;
}
/* The flat cover / closing fields sit behind everything in their sheet. Both
   sheets' own children are positioned or in normal flow after it, so source
   order alone keeps the artwork underneath. */
.sheet--cover > .field-svg,
.sheet--dark > .field-svg { z-index: 0; }
.sheet--cover > *:not(.field-svg),
.sheet--dark > *:not(.field-svg) { position: relative; z-index: 1; }

/* Sized by a definite SLOT, not a width cap — the same lesson as the page's
   hero logo: capped by width alone a squat lockup and a tall one render at
   wildly different heights and every sheet opens at a different weight. */
/* Comes after .game-sheet__wash in the DOM, so it paints on top of it without a
   z-index. Don't reorder the markup.
   The width cap is what binds on the WIDE lockups (Fortunes of Sparta is 3.97:1,
   Bamboonanza 2.51:1) and the height cap on the near-square ones — which is why
   widening the cap grew everything except Blob Invasion, whose logo is 1000x1003.
   That one gets its own height below rather than inflating all 23. */
.game-sheet__logo {
  position: absolute;
  right: 12mm; top: 50%;
  transform: translateY(-50%);
  display: block;
  /* Sized by a definite HEIGHT slot with a generous width cap: capped by width
     alone a wide lockup like Blob Invasion's renders short and looks lost
     against a tall one. */
  width: auto; max-width: 92mm;
  height: 48mm;
  object-fit: contain;
  object-position: right center;
  /* Every lockup has its own aspect ratio, so a definite HEIGHT slot is what
     makes all 26 sheets open at the same weight — the same lesson as the game
     page's hero logo, where a width cap gave a 3x spread. */
}
/* Blob Invasion's lockup is square (1000x1003), so the shared height slot leaves
   it visibly smaller on the page than the wide lockups beside it. Sized on its
   own rather than raising the slot for all 23. */
.sheet--game[data-slug='blob-invasion'] .game-sheet__logo { height: 64mm; }
.status-pill--hero { position: absolute; top: 6mm; right: 6mm; margin: 0; }

/* NO TOP PADDING. The spec band is always the first block and it is a dark
   full-bleed field, so any padding here is a strip of white paper between the
   hero and it — 6mm of body padding plus the band's own 4mm margin printed a
   10mm white bar across every game sheet. The hero now hands straight off to the
   band, exactly as the site's game page does. The blocks below the band carry
   their own top margins, and the first-child rule further down covers the
   (currently impossible) case of a sheet with no spec band. */
.game-sheet__body { padding-top: 0; padding-bottom: 6mm; gap: 0; }

/* Sits in the hero band, left, opposite the logo. Comes after the wash in the
   DOM so it paints on top of it — same rule as the logo. */
.game-sheet__head {
  position: absolute;
  left: 15mm; right: 15mm; bottom: 8mm;
  max-width: 96mm;
}
/* Quiet: it labels the title rather than competing with it. */
.game-sheet__eyebrow {
  font-size: 1.9mm; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; margin: 0 0 3.5mm;
  color: rgba(255, 255, 255, 0.62);
}
.game-sheet__title {
  font-family: var(--font-display);
  font-weight: 400;                      /* SCHABO is 400-only */
  font-size: 15mm; line-height: 0.86; text-transform: uppercase; margin: 0 0 2mm;
  color: var(--white);
}
.game-sheet__tagline { font-size: 3.7mm; font-weight: 700; margin: 0 0 1.2mm; color: var(--white); }
.game-sheet__summary {
  font-size: 3mm; line-height: 1.4; font-weight: 400;
  margin: 0; color: rgba(255, 255, 255, 0.92);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
.game-sheet__note {
  font-size: 2.8mm; font-weight: 700; color: #8A6A00;
  margin: 2.5mm 0 0;
}

.doc-h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 6.5mm; line-height: 0.9; text-transform: uppercase;
  margin: 0 0 2mm;
  /* The range's own colour, like the site's SPECIFICATION heading: purple for
     Origins, orange for Classic. --purple straight, not --purple-light: this is
     on paper, where #9445FF measures 5.1:1 — it only needed lightening on the
     site's dark band. */
  color: var(--purple);
}
.sheet--game[data-brand='classic'] .doc-h3 { color: var(--orange); }
.game-sheet__block { margin-top: 3mm; }
.game-sheet__cols {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6mm;
  margin-top: 0;   /* the spec band's bottom margin owns the gap above it */
}
/* A game with only one of the two takes the full measure rather than leaving
   half the row empty. Set as a class by brochure.js rather than with :has(),
   so nothing in the printed layout depends on selector support. */
.game-sheet__cols--solo { grid-template-columns: 1fr; }
/* NOT CLAMPED, and that is deliberate (2026-09-07). This was `-webkit-line-clamp: 4`
   because an unclamped story was the block most likely to push a sheet onto a
   second page — back when a second page was forbidden. It isn't any more:
   paginateGameSheets() carries the overflow, so the story prints whole. A clamp
   here silently truncates a sentence mid-word, which is the one failure a
   printed document cannot explain away. */
.game-sheet__story p {
  font-size: 3.1mm; line-height: 1.4; margin: 0 0 1.5mm;
}
.b-feat { margin: 0 0 2mm; break-inside: avoid; }
.b-feat b { display: block; font-size: 3.3mm; }
/* Unclamped, and every paragraph of the body now prints — the builder used to
   emit `paras(f.body)[0]` and this clamped that one to three lines, so a
   two-paragraph feature lost most of itself twice over. */
.b-feat p {
  font-size: 3.05mm; line-height: 1.4; margin: 0.4mm 0 0;
}

/* The symbol strip was removed on 2026-09-07 — the paytable is page-only now.
   `.b-sym-strip`, `.b-sym` and `.b-sym__note` went with it. See the note in
   brochure.js where the block used to be built, and don't re-add them here
   without re-adding the block: an orphan rule set is how the next session
   concludes the block was lost by accident. */

/* Two rows: every portrait capture on the first, the desktop ones 2-up below.
   Interleaving the two shapes in one grid is what made this block look
   accidental — a 0.48-ratio phone screen and a 1.55-ratio desktop one share
   neither a width nor a height, so they get a row each instead.
   NO BORDER AND NO CAPTIONS. On paper the frame read as a table cell around the
   artwork, and a row of grey labels under mismatched images was most of the
   visual noise; the shots are self-evidently the game. */
.b-shots { display: block; --shot-gap: 1.5mm; }

/* Mobile: one line, TALL and tightly spaced. These are ~0.48 ratio, so five at
   52mm come to ~125mm of the 180mm column — the height is what makes them
   readable, and the thin gap is what buys the height. */
.b-shots__mobile {
  display: flex;
  gap: var(--shot-gap);
  align-items: flex-start;
  margin-bottom: 3mm;
}
/* SIX is the unit: the width is whatever makes six fill the column edge to edge,
   so a game with five gets the SAME size and simply leaves the last slot empty.
   Sizing five to fill the width instead would make each game's shots a different
   size from the next game's. 180mm of column at a 1.5mm gap is 28.75mm wide,
   and at ~0.48 ratio about 60mm tall. */
.b-shots__mobile .b-shot-fig { flex: 0 0 calc((100% - 5 * var(--shot-gap)) / 6); }
.b-shots__mobile .b-shot { width: 100%; height: auto; }

/* Desktop: 2-up, so a third and fourth capture land on a second line. */
/* FLUSH LEFT and each filling its half of the column. Sizing these by height
   left every image centred inside a much wider grid cell, which read as a large
   arbitrary gap between the pair. Width-first, height following the ratio, means
   they butt up against the gap and nothing is letterboxed. A third and fourth
   capture wrap to a second line. */
.b-shots__desktop {
  display: flex;
  flex-wrap: wrap;
  gap: var(--shot-gap);
  align-items: flex-start;
  justify-content: flex-start;
}
.b-shots__desktop .b-shot-fig { flex: 0 0 calc((100% - var(--shot-gap)) / 2); }
.b-shots__desktop .b-shot { width: 100%; height: auto; }

/* NEVER CROPPED — `contain`, not `cover`. The captures are gameplay, so a crop
   throws away the part that is worth showing. */
/* The rounded corner is PRINT-ONLY: `.b-shot` is a brochure class, and the game
   page's own shots (`.shot img` in site.css) are deliberately left square. */
.b-shot {
  object-fit: contain;
  display: block;
  border-radius: 1.5mm;
}
.b-shot-fig { margin: 0; }
/* The img carries width/height ATTRIBUTES so the box is reserved before load;
   without a height reset those count as a specified height and the CSS one is
   ignored, which is hard rule 4 in a second file. The mobile row sets its own
   definite height, so this only guards the desktop row. */
/* Both rows are WIDTH-driven now, so it is the `height` ATTRIBUTE that has to be
   overridden — an <img>'s height attribute counts as a specified height and would
   pin the box, which is hard rule 4 in a second file. This rule is more specific
   than the `.b-shots__* .b-shot` sizing above, so it has to agree with it. */
.b-shots__mobile .b-shot-fig img,
.b-shots__desktop .b-shot-fig img { height: auto; }

/* Three columns, not four. The strip used to be capped at 4 tiers so it was
   exactly one row; it now prints every tier WITH its description and its symbol
   art, and three columns is what gives that description a readable measure —
   at four the body set to about 22 characters a line. Blob Invasion's six run
   as two rows of three. */
.b-buy-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 3mm 3mm; }
.b-buy {
  border-top: 0.4mm solid var(--rule);
  padding-top: 1.6mm;
  break-inside: avoid;
}
/* Sized by a definite HEIGHT slot with object-fit, exactly as the page's
   .buy-card__symbol is: the per-tier art is a mix of near-square tiles and tall
   portraits, and matching WIDTHS would make the squat ones tower over the rest.
   Only Blob Invasion and The Void's High-Roller Boost ship this art, so the
   rule has to leave a tier without one looking deliberate rather than broken —
   which is why the symbol sits above the title instead of beside it. */
.b-buy__symbol {
  display: block;
  width: auto; height: 9mm; max-width: 100%;
  object-fit: contain; object-position: left center;
  margin: 0 0 1.2mm;
}
.b-buy b { display: block; font-size: 3.1mm; line-height: 1.2; }
/* The page's buy card carries this and the print dropped it, which left six
   near-identical tiles that named a price and never said what it bought. */
.b-buy__body {
  font-size: 2.75mm; line-height: 1.35; margin: 0.8mm 0 0; color: #4A4A4A;
}
.b-buy__cost {
  display: block; margin-top: 1mm;
  font-size: 2.8mm; font-weight: 700; color: var(--green-dark);
}

/* ---- Spec options: Crazy Speed / Flexible Max Win / Adjustable RTP -------
   The source brochure prints these three on every Origins page and this
   document carried none of them. An option the game LACKS renders as a grey
   cross rather than being dropped — the three are a fixed set, so a missing row
   would read as an oversight rather than as an absence. */
.b-options {
  list-style: none; margin: 3mm 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 2mm 6mm;
}
.b-options li {
  display: flex; align-items: center; gap: 1.5mm;
  font-size: 2.9mm; font-weight: 700;
  color: var(--green-dark);
}
.b-options svg { width: 3.6mm; height: 3.6mm; display: block; flex: none; }
.b-options .is-off, .b-options li.is-off { color: #A2A2A2; font-weight: 400; }

/* Section lead, matching the page's .section-lead. Used by the Buy Bonus tier
   count and by Spin My Drink's Customisable Booze note. */
.b-lead {
  font-size: 2.9mm; line-height: 1.35; color: #6E6E6E;
  margin: 0 0 2mm; max-width: 130mm;
}

/* ---- Continuation sheets -------------------------------------------------
   A title whose content will not fit one page continues on the next. NEVER two
   games on one sheet — that invariant is untouched; what changed is that one
   game may take two. The header replaces the 68mm hero, so a continuation page
   has substantially more room than a first page. */
/* The base rule zeroes the body's top padding so the dark spec band butts
   straight onto the hero. A CONTINUATION sheet has no hero, so that zero put
   this header hard against the paper's edge. 14mm matches .sheet__pad's own
   inset, so it reads as an ordinary page margin. Only the continuation variant —
   the first sheet must keep its flush hand-off. */
.sheet--game-cont .game-sheet__body { padding-top: 14mm; }

.game-sheet__cont {
  font-size: 2.6mm; font-weight: 700; letter-spacing: 0.14em;
  text-transform: uppercase; color: #9A9A9A;
  margin: 0 0 3mm; padding-bottom: 2mm;
  border-bottom: 0.3mm solid var(--rule);
  flex: none;
}
.sheet--game-cont[data-brand='origins'] .game-sheet__cont { color: var(--purple); }
.sheet--game-cont[data-brand='classic'] .game-sheet__cont { color: var(--orange); }

/* LOAD-BEARING FOR paginateGameSheets(). The body is a column flex container,
   so its children shrink to fit by default — every height the pass measured
   would be the SHRUNKEN one, and it would conclude that everything fits while
   the sheet quietly clipped it. `flex: none` makes the overflow real, and
   therefore measurable. */
.game-sheet__body > * { flex: none; }

/* `b-` prefixed because this sheet loads ALONGSIDE site.css, and the site's own
   game page has a `.spec-grid`, `.spec`, `.shot` and `.shot--portrait`. Sharing
   those names meant site.css won the specificity ties: the brochure's spec grid
   inherited a 72px top margin and a WHITE (--rule-invert) border on every cell,
   and the site's `@media (max-width: 1024px)` block silently forced it to two
   columns IN PRINT, because an A4 page is only ~794 CSS px wide. Keep
   brochure-only classes prefixed. */
/* ---- The specification band ---------------------------------------------
   A dark field carrying the headline figures, the spec grid, the options row and
   the distribution reach — the same treatment the site's #spec band has, and the
   same shape the source brochure's panels use.

   FULL-BLEED, so it reads as a band rather than a boxed panel: it cancels
   .sheet__pad's 15mm inset with a negative margin and puts it back as its own
   padding, so the ink runs to both paper edges while the type stays on the
   sheet's own column.

   The ground is an inline <svg> (svgField), NOT `background`. Safari prints with
   "Background graphics" off by default and drops every background-color — with
   white type on this band, a dropped ground means white on white. */
.b-spec-band {
  position: relative;
  /* Flush to the hero above (see .game-sheet__body), full-bleed either side, and
     carrying the air BELOW it as its own margin so the prose is not tight
     against the ink. */
  margin: 0 -15mm 6mm;
  padding: 7mm 15mm;
  color: var(--white);
  break-inside: avoid;
}
/* Defensive: a sheet whose first block is NOT the band would otherwise hug the
   hero. Every released title carries specs today, so this never fires — it is
   here so that adding a title without them cannot silently produce a broken
   sheet. Written as :first-child rather than with :has(), which this stylesheet
   avoids for the sake of print engines. */
.game-sheet__body > .game-sheet__cols:first-child,
.game-sheet__body > .game-sheet__block:first-child { margin-top: 6mm; }
/* svgField paints an absolutely positioned rect; everything else in the band has
   to sit above it, and source order alone does not do that against a positioned
   sibling. */
.b-spec-band > .field-svg { z-index: 0; }
.b-spec-band__inner { position: relative; z-index: 1; }

/* Inverted for the dark ground. The greys the light layout uses (#7C7C7C for a
   label, #6E6E6E for a value) are below 3:1 on ink. */
.b-spec-band .b-spec dt,
.b-spec-band .b-stat__label,
.b-spec-band .b-stat__note { color: rgba(255, 255, 255, 0.62); }
.b-spec-band .b-spec dd { color: var(--white); }
.b-spec-band .b-reach { border-top-color: var(--rule-invert); }
.b-spec-band .b-reach p { color: rgba(255, 255, 255, 0.75); }
.b-spec-band .b-reach b { color: var(--white); }
/* On ink, --purple measures 2.95:1 — the same reason the site's spec band uses
   the lightened value for purple type. Classic's orange clears it as-is. */
.sheet--game[data-brand='origins'] .b-spec-band .b-stat__value { color: var(--purple-light); }
.sheet--game[data-brand='classic'] .b-spec-band .b-stat__value { color: var(--orange); }
/* The provisional note is a warning on paper; its ochre disappears on ink. */
.b-spec-band .game-sheet__note { color: #FFC65C; }

/* ---- Headline specs: RTP and MAX WIN ------------------------------------
   Ranked above the grid, the same split the game page makes. As two cells among
   twelve they set at 2.9mm — the same size as Orientation Support — which is the
   wrong weight for the two figures an operator actually scans for. */
.b-headline {
  display: flex;
  flex-wrap: wrap;
  gap: 4mm 12mm;
  margin-top: 0;   /* the band's own padding supplies the air now */
}
.b-stat__label {
  font-size: 2.5mm; letter-spacing: 0.12em; text-transform: uppercase;
  color: #7C7C7C; margin: 0 0 1mm;
}
.b-stat__value {
  font-family: var(--font-display);
  font-weight: 400;                      /* SCHABO is 400-only — hard rule 1 */
  font-size: 10mm; line-height: 0.9;
  margin: 0;
  color: var(--ink);
}
/* The certified bands run in ONE row at ONE size. The document used to print a
   single figure here; with three of them, ranking the shipping band larger would
   imply the alternates are lesser, and the source states all three as equally
   shippable. Same call the game page makes. */
.b-stat__value--row { display: flex; flex-wrap: wrap; gap: 0 5mm; }
.b-stat__note {
  font-size: 2.4mm; color: #7C7C7C; margin: 1.2mm 0 0;
}
.sheet--game[data-brand='origins'] .b-stat__value { color: var(--purple); }
.sheet--game[data-brand='classic'] .b-stat__value { color: var(--orange); }

.b-specs {
  display: grid;
  margin: 0;
  grid-template-columns: repeat(4, 1fr);
  gap: 2mm 3mm;
  /* No rule above the figures — the band's own edge already separates them from
     the hero, and a second line there read as a table border. The margin is what
     does the separating now. */
  margin-top: 4mm;
}
.b-spec { break-inside: avoid; }
.b-spec dt {
  font-size: 2.5mm; letter-spacing: 0.12em; text-transform: uppercase;
  color: #7C7C7C; margin: 0 0 0.5mm;
}
.b-spec dd { font-size: 2.9mm; font-weight: 700; margin: 0; line-height: 1.15; }

.status-pill {
  display: inline-block;
  padding: 0.8mm 2mm;
  background: var(--green); color: var(--ink);
  /* Sits inside the display-face heading, so reset back to the body face. */
  font-family: var(--font-body);
  font-size: 2.5mm; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  margin-left: 2mm; vertical-align: middle;
}

/* Index table on the contents sheet */
.toc { width: 100%; border-collapse: collapse; font-size: 3.2mm; }
.toc th {
  text-align: left; font-size: 2.6mm; letter-spacing: 0.14em; text-transform: uppercase;
  color: #7C7C7C; padding: 0 0 2mm; border-bottom: 0.4mm solid var(--rule);
}
.toc td { padding: 1.15mm 0; border-bottom: 0.3mm solid rgba(46,46,46,0.09); }
.toc td:first-child { font-weight: 700; }
.toc td:not(:first-child) { font-weight: 400; }
.toc .num { text-align: right; color: #7C7C7C; }

/* ---- Screen-only toolbar ------------------------------------------------ */
.brochure-bar {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
  padding: 1rem clamp(1rem, 4vw, 2.5rem);
  background: var(--ink); color: var(--white);
}
.brochure-bar__meta { margin: 0; font-size: var(--t-small); opacity: 0.75; }
/* A footnote, not an instruction: Chrome's print engine is the more faithful of
   the two, and Safari in particular needed several workarounds in this file. */
.brochure-note {
  margin: 0.4rem 0 0;
  font-size: 0.75rem; line-height: 1.4;
  opacity: 0.55; max-width: 46ch;
}
.brochure-note b { font-weight: 700; opacity: 0.85; }
/* The three editions. Plain .btn language, with the active one filled — the
   same aria-pressed treatment the library's filter chips use. */
.brochure-bar__actions { display: flex; flex-direction: column; gap: 0.75rem; align-items: flex-end; }
.brochure-scopes { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.brochure-scope { font-size: var(--t-small); padding: 0.5rem 0.9rem; }
.brochure-scope[aria-pressed='true'] {
  background: var(--green); color: var(--ink);
}
.brochure-bar__title { font-family: var(--font-display);
  font-weight: 400; font-size: 1.75rem; text-transform: uppercase; margin: 0; }
/* Above the title, with the arrow leading out of the page — a way back rather
   than an action, so it is a plain link and not part of the button row. */
.brochure-back {
  display: inline-flex; align-items: center; gap: 0.5em;
  margin: 0 0 0.5rem;
  font-size: var(--t-small); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--white); opacity: 0.7;
  transition: opacity var(--dur) var(--ease), color var(--dur) var(--ease);
}
.brochure-back:hover,
.brochure-back:focus-visible { opacity: 1; color: var(--green); }
.brochure-back svg { flex: none; }

.loading { padding: 4rem; text-align: center; color: var(--white); }

/* ---- Print -------------------------------------------------------------- */
@media print {
  html, body { background: #fff; }
  .brochure-bar, .no-print { display: none !important; }
  .brochure { background: none; padding: 0; }
  /* EXACTLY the page, via a FIXED height with overflow clipped — and the
     distinction from `min-height` is the whole fix.
     With `min-height: 297mm` the box could still GROW: every sheet's content
     bottom (the running footer) landed exactly on 297.0mm, and 297mm is 1122.52px
     at 96dpi, so the engine's rounding tipped that last fraction over and
     paginated a near-empty extra page after every sheet — nearly doubling the
     page count. A fixed `height` cannot grow, and `overflow: hidden` guarantees
     nothing inside it can push the box past the boundary.
     294mm was tried in between. It fixed the pagination but left a 3mm white bar
     along the foot of every page, which is worse than the bug. 297mm is the right
     number; the fixed height is what makes it safe. The tallest sheet's INTRINSIC
     content is 284.9mm, so there is ~12mm of real headroom — check that before
     adding anything tall to the front matter. */
  .sheet {
    width: 210mm;
    height: 297mm;
    min-height: 0;
    box-sizing: border-box;
    margin: 0; box-shadow: none;
    overflow: hidden;
    break-inside: avoid; page-break-inside: avoid;
    break-after: page; page-break-after: always;
  }
  html, body { margin: 0; padding: 0; }
  .sheet:last-child { break-after: auto; page-break-after: auto; }
  /* Brand colour blocks must survive the print pipeline. */
  .sheet, .sheet * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .sheet--cover, .sheet--dark { padding: 0; }
}

/* ---- Narrow-screen preview ----------------------------------------------
   DRIVEN BY A CLASS, NOT BY A MEDIA QUERY, and that is load-bearing twice.

   1. An A4 page is only about 794 CSS px wide, so a bare `max-width: 800px`
      block fires during PRINT and reflows the sheets that were measured to fit —
      the spec grid to two columns, the symbol strip to four, every game sheet
      past its page. That was already known and was why the old rule carried
      `@media screen`.
   2. `@media screen` was not enough. paginateGameSheets() measures the built
      sheets ON SCREEN, and this workspace's preview pane is exactly 800px — so
      the pass ran against the squeezed layout and split the catalogue into 56
      pages, giving Classic titles that hold nothing but a spec grid two
      continuation sheets each. A media query cannot be turned off for the
      duration of a measurement; a class can, and paginateGameSheets() drops it
      while it measures and puts it back afterwards.

   syncNarrow() in brochure.js toggles it from matchMedia. Do not convert this
   back to a media query. */
.brochure.is-narrow { padding: 1rem 0; }
.brochure.is-narrow .sheet { width: 100%; max-width: 100%; min-height: 0; }
.brochure.is-narrow .b-specs { grid-template-columns: repeat(2, 1fr); }
.brochure.is-narrow .game-sheet__cols { grid-template-columns: 1fr; }
.brochure.is-narrow .b-buy-strip { grid-template-columns: repeat(2, 1fr); }
.brochure.is-narrow .b-options { gap: 2mm 4mm; }
@media screen and (max-width: 800px) {
  .brochure-bar__actions { align-items: flex-start; }
}
