/* ============================================================================
   THE BOOK GRID — the bento generator, first real build.
   ============================================================================

   Every number this file uses is a knob in tokens.css, under "The book grid".
   The gaps and the row unit were re-read from the live site's own CSS on
   2026-09-18 so the grid lands on live's covers within half a pixel and on
   live's rows within two.
   Read that block first: it carries the column counts, the gap, the size
   vocabulary, and the one dial that takes this page from uniform frames to the
   image-driven look. This file is only the mechanism that spends them.

   THE MECHANISM, AND WHY IT IS THIS ONE. A fixed column count, dense auto-flow,
   and every tile declaring its own span. No tile is ever placed by hand — not
   in the CSS, not in the markup, nowhere. That is the whole design. Hand-fitting
   tiles is what made the earlier attempts collapse whenever one tile changed,
   and it is the thing this grid exists not to do.

   Because the columns are fixed, the grid lines up left and right no matter
   what sizes are handed to it. Because the flow is dense, a tile that leaves a
   hole gets that hole filled by a later tile small enough to sit in it, rather
   than by somebody moving things around. Those two together are what let varied
   proportions stay tidy.

   WHAT DENSE PACKING IS AND IS NOT DOING ON THIS PAGE TODAY, stated plainly so
   nobody credits it with work it is not doing. With the twelve covers tagged as
   they are, every tile is one column wide, and a hole under a short tile is
   never big enough for the next tile to drop into — the smallest span is 22 row
   steps and the shallowest hole is 5. So dense currently changes nothing you
   can see. It is not decoration: it is what makes the `feature` tag work the
   day a book is given one, and it is what will carry Deziel's mixed-content
   vocabulary, where two-column tiles leave holes constantly. The alternative —
   turning it on later, when it is needed — means discovering then that the
   layout was quietly depending on source order.
   ========================================================================= */


.book-grid {
  display: grid;
  grid-template-columns: repeat(var(--bento-columns), 1fr);
  grid-auto-rows: var(--bento-row);
  grid-auto-flow: dense;

  /* The column gutter is real; the row gutter is zero and lives inside each
     tile instead (see .book-grid__item). tokens.css explains why: with a real
     row-gap, a tall tile collects more gaps than a short one and the whole size
     vocabulary drifts as the gap changes. */
  column-gap: var(--bento-gap);
  row-gap: 0;

  list-style: none;
  padding: 0;
  margin: 0;
  width: 100%;

  /* One gap short of the column's right edge, as live is: live gives every
     cover a right margin, the last column included, so its grid stops a gap
     early. Matching that is what puts each cover at live's width. */
  max-width: calc(100% - var(--bento-gap));
}


/* ── A tile ───────────────────────────────────────────────────────────────

   Two custom properties decide a tile's shape, and the tag sets them. The
   fallbacks are the tall box and one column, so a tile whose tag is missing or
   misspelled renders as an ordinary book rather than collapsing the row.        */

.book-grid__item {
  grid-row: span var(--tile-span, var(--bento-span-tall));
  grid-column: span var(--tile-columns, 1);

  /* The row gutter, carried inside the tile. Its own token since 2026-09-18:
     live's row gap is 24px on a phone where its column gap is 16. */
  padding-block-end: var(--bento-row-gap);
}

/* ── The vocabulary ───────────────────────────────────────────────────────

   One rule per tag, and each one only says which span token to read. The
   numbers are all in tokens.css; the dial works by changing what these tokens
   resolve to, which is why nothing here needs to know about the dial at all.    */

.book-grid__item[data-tile="square"]   { --tile-span: var(--bento-span-square); }
.book-grid__item[data-tile="standard"] { --tile-span: var(--bento-span-standard); }
.book-grid__item[data-tile="tall"]     { --tile-span: var(--bento-span-tall); }
.book-grid__item[data-tile="feature"]  {
  --tile-span: var(--bento-span-feature);
  --tile-columns: var(--bento-span-feature-columns);
}


/* ── THE DIAL ─────────────────────────────────────────────────────────────

   How many size categories are allowed. One attribute on the grid element,
   `data-size-categories`, from 1 to 4.

   Each setting works by REFUSING to distinguish one more tag — it points the
   finer tags at the coarser one's token, and every tile rule above follows
   without knowing anything happened. So setting 4 is the vocabulary as written,
   and turning the dial down folds it inwards one bucket at a time until, at 1,
   every book is in the same box.

   Read from the bottom up it is the same story the other way: turn it up and
   each setting hands the grid one more shape to work with.

   WHY THE SETTING IS AN ATTRIBUTE AND NOT PURELY A TOKEN. CSS has no way to
   branch on a custom property's value — there is no `@if var(--x) = 1` — so
   something has to be a selector. One attribute, on one element, is the
   smallest that can be. Every number still lives in tokens.css.                */

/* 1 — every book in an identical box. The uniform-frame treatment.
       The shared box is the TALL one, deliberately: it is the only choice that
       never crops a cover. Shorter covers letterbox instead, and Perfect Square
       — the one true square — letterboxes most. That is the tell, and it is
       what the Figma file's uniform page shows. */
.book-grid[data-size-categories="1"] {
  --bento-span-square: var(--bento-span-tall);
  --bento-span-standard: var(--bento-span-tall);
  --bento-span-feature: var(--bento-span-tall);
  --bento-span-feature-columns: 1;
}

/* 2 — square told apart from portrait. Perfect Square gets its own box; the
       other eleven still share the tall one, so Punch! and Monkey Time still
       letterbox a little. */
.book-grid[data-size-categories="2"] {
  --bento-span-standard: var(--bento-span-tall);
  --bento-span-feature: var(--bento-span-tall);
  --bento-span-feature-columns: 1;
}

/* 3 — all three height buckets live. This IS the image-driven look, and it is
       what the page ships at. Three buckets is not twelve bespoke boxes: the
       tall box is one tall cover exactly (Little i, 1.385), the square box is
       6–10% taller than Perfect Square and the standard box 3–4% taller than
       Punch! and Monkey Time; each shorter cover sits at the top of its box
       with that much blue below, as on the live site. Measured 2026-09-18. */
.book-grid[data-size-categories="3"] {
  --bento-span-feature: var(--bento-span-tall);
  --bento-span-feature-columns: 1;
}

/* 4 — the feature tile unlocks: two columns wide, for a book given emphasis.
       No book is tagged `feature` today. The tag works; assigning it is an
       editorial choice, and it costs image quality, because a feature tile is
       about 353px across at laptop width and the cover files are 200px — about
       1.8x. That is a matter of degree: an ordinary tile is about 169px, so on
       a Retina screen these 1x covers are already drawn at roughly double.
       Nothing needs overriding here — this is the vocabulary as written. */


/* ── The cover ────────────────────────────────────────────────────────────

   One anchor per cover, wrapping one image. That is the entire link mechanism.

   On the live site each of these twelve covers carries a Premium Addons
   JavaScript wrapper-link, the destination URL stuffed into Elementor's
   custom-HTML-attributes field with the real link field left empty, and on ten
   of them an Elementor dynamic tag as well — three mechanisms for one click,
   plus `is_external` on eleven internal links (which is what emits
   target="_blank"), a path that has not existed for two slugs, and two entries
   ending in a literal tab character. That is crust item 1, the worst thing on
   the site. It is replaced by `<a href>`.

   object-fit: contain is what keeps the art honest. A cover whose proportions
   fall a little short of its bucket shows a hairline of the page's blue rather
   than losing a sliver of the drawing. For a picture-book illustrator's covers
   that is the only acceptable direction to round.                              */

.book-grid__link {
  display: block;
  height: 100%;
  text-decoration: none;
}

.book-grid__link img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* A cover shorter than its box sits at the top with blue below — live's
     rows are top-aligned (align-items: start), so a short cover shows the
     same blue under it there. */
  object-position: 50% 0;
}

.book-grid__link:focus-visible {
  outline: 2px solid var(--body-text);
  outline-offset: 2px;
}
