/* ==========================================================================
   shop-table.css : the shop (and product category/tag archives) as the author's
   table, built as a shelf: «כל עמודה היא ספר» (.site/shop/concept-table-v2.md; its sizes are
   those of the lean shelf, .site/shop/concept-c7-shop.md).
   Every column is one book standing on a shared board in a bay coloured from its
   own cover (`.b-<id>` rules printed by the template from inc/book-colour.php:
   --book-ground, --book-back, --book-deep); the board's front carries each book's age
   on a paper tag. The cover is the control: the reader turns it to its back.
   Loaded on shop listings only (inc/enqueue.php). Tokens live in base.css :root.
   RTL: logical properties throughout. Physical left/right appear only in the 3D
   book (the binding of a Hebrew book is on the right of its cover), in shadows
   (the light comes from the upper right) and in transforms.

   Hooks for the creative developer (motion, not built here):
   - regroup after a filter: window.pilpeletShelf.transition(update) (assets/js/shop-table.js);
     every head cell has data-i, every column's cells share it;
   - shelf entrance: .shelf-table[data-table="1".."n"] (tables 2..n), their .book;
   - turn keyframes: .stage.has-turned (armed after the first interaction), .stage.is-turned,
     .stage.is-front (a click on a hovered, turned book), .stage:hover, .contact (the contact shadow),
     .face::after (the edge-on shade, opacity 0 at rest).
   ========================================================================== */

/* ---------- page measures ---------- */
.tt {
  --label-w: 120px;          /* the row-label column */
  --colmin: 0px;             /* a book column never narrower than this (the tables scroll below 1088px) */
  --gut: 10px;               /* paper between bays */
  --head-room: 6px;          /* the turn may grow into the margin above the cover; nothing clips at this width */
  --ledge-h: 30px;           /* the board: a 4px top and a front the age tags are printed on */
  --k: .90;                  /* the book's scale (the fit box 256 × 340 at 1: 230 × 306 here; the smallest scale at which her back texts fit at 15px) */
  --thick: 14px;             /* the book's thickness */
  --pad-x: 20px;             /* the cell's inline padding: the title and the age tag start on the same line */
  --pad-cell: 10px var(--pad-x);
  --tag-h: 24px;             /* the age tag, standing on the board's front */
  --tag-lift: 3px;
  --board: linear-gradient(var(--ledge-top) 0 4px, var(--ledge) 4px calc(100% - 2px), var(--rule) calc(100% - 2px));   /* the shelf's board: top face, front, a darker foot */
  --board-shadow: 0 2px 0 var(--rule), 0 3px 4px rgb(0 0 0 / .08);   /* its contact shadow: a hard 2px under the foot, a short soft one */
  overflow-x: clip;          /* nothing on this page may widen it (the tables scroll inside their own box) */
}
.tt-wrap { padding-block: 24px 0; }
.tt-head { text-align: center; }   /* «ספרי פלפלת», centred (the author's note, Change 9); a category's lead under it too */
/* no script: the finder is not there, so the title keeps its own 24px above the first cover (the spec named .tt-wrap; the gap sits under the title) */
html:not(.js) .tt-head { margin-block-end: 24px; }
.tt-lead { margin-block-start: var(--s-3); margin-inline: auto; max-width: 60ch; color: var(--muted); }
.tt-none { padding-block: var(--s-6) var(--s-8); font: 400 22px/1.4 var(--font-display); color: var(--ink); }

/* ==========================================================================
   The finder: a question and four ages; the chosen age is circled in plum, as a child circles the answer in a workbook
   (concept-c8 note 5). No board, no rule, no grey: the only mark is the loop (an SVG printed inside each option, hand-drawn,
   drawn in 380ms when the age is chosen, none under reduced motion). The loop is the single hand-drawn mark of the site.
   ========================================================================== */
/* 7 or more products at 900px and up: the sticky finder bar (60px) must not cover the control a Tab brings into view */
@media (min-width: 900px) {
  @supports selector(:has(a)) {
    html:has(.finder[data-sticky]) { scroll-padding-top: 96px; }
  }
}
.finder-mark { display: block; height: 1px; margin-block-end: -1px; }
.finder { margin-block: 12px 24px; }
/* The script reveals the finder after first paint. For script users it is laid out from the start and only unseen
   (visibility:hidden keeps it out of the tab order and the accessibility tree), so revealing it moves nothing below it.
   Without script it stays display:none. !important: base.css hides every [hidden] with !important. */
.js .finder[hidden] { display: block !important; visibility: hidden; }
.finder-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 28px; }
.finder-q { font: 700 22px/1.3 var(--font-heading); color: var(--ink); }
.finder-count { margin-block-start: 6px; font: 600 16px/1.4 var(--font-body); color: var(--text); }
.count-n { font: 700 18px/1 var(--font-display); color: var(--ink); font-variant-numeric: tabular-nums; }   /* the number of her count text */
/* 1088px and up: one row (question, ages, the count 20px after them). The control fixes the height (44) and the server prints the
   count, so the reserved box equals the real one. */
@media (min-width: 1088px) {
  .finder { display: flex; align-items: center; }
  .finder-row { flex-wrap: nowrap; }
  .js .finder[hidden] { display: flex !important; }   /* the reserved box keeps the one-row layout */
  .finder-count { margin-block: 0; margin-inline-start: 20px; white-space: nowrap; }
}
/* The title is centred, so from 600px the finder joins its axis: question, ages and count read as one centred group under it (a phone
   keeps the question above the ages, start-aligned like the table's label column; the sticky bar of 7+ products keeps its own layout). */
@media (min-width: 600px) {
  .finder:not([data-sticky]) .finder-row { justify-content: center; }
  .finder:not([data-sticky]) .finder-count { text-align: center; }
}
@media (min-width: 1088px) {
  .finder:not([data-sticky]) { justify-content: center; }
}

.seg { display: inline-flex; gap: 4px; }
.seg-ind { display: none; }   /* kept in the markup for the script, which still measures it; the loop replaces it */
.seg-btn {
  position: relative; isolation: isolate;
  min-width: 44px; min-height: 44px; padding: 0 14px; border: 0; border-radius: 50%; margin: 0;   /* the round corners make the focus ring an ellipse, like the loop */
  background: transparent; color: var(--ink-soft); cursor: pointer;
  font: 700 18px/1 var(--font-display); white-space: nowrap;
  transition: color var(--dur-state) var(--ease-standard);
}
.seg-btn[aria-pressed="true"] { color: var(--ink); }
.seg-btn:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
/* the loop: behind the word, loosely round it, tilted a little as a hand tilts it. The viewBox keeps its proportions (meet), so the
   pen's line is the same at every width of label; the paths are drawn from the inline start and overlap at the end like a pen. */
.seg-loop {
  position: absolute; z-index: -1; inset: -3px -6px; width: calc(100% + 12px); height: calc(100% + 6px);
  overflow: visible; pointer-events: none; transform: rotate(-2.5deg);
}
.seg-loop path {
  fill: none; stroke: var(--plum); stroke-width: 2.75; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke;
  stroke-dasharray: 1 1; stroke-dashoffset: 1; opacity: 0;
  transition: opacity var(--dur-feedback) linear;
}
.seg-btn[aria-pressed="true"] .seg-loop path { stroke-dashoffset: 0; opacity: 1; }
@media (hover: hover) and (pointer: fine) {   /* hover: the same loop, faint */
  .seg-btn:hover { color: var(--ink); }
  .seg-btn:not([aria-pressed="true"]):hover .seg-loop path { stroke-dashoffset: 0; opacity: .38; }
}
/* drawn when an age is chosen (not on load: the page opens at rest); choosing again from the hover state still draws it, as the
   animation starts from an undrawn path */
@media (prefers-reduced-motion: no-preference) {
  .seg.is-live .seg-btn[aria-pressed="true"] .seg-loop path { animation: pil-circle 380ms var(--ease-arrive) both; }
}
@keyframes pil-circle { from { stroke-dashoffset: 1; opacity: 1; } }
/* Forced colours (Windows contrast themes): the browser keeps an SVG stroke's own colour, and plum on a black theme is under 3:1. The
   loop is the only sign of the chosen age, so it takes the theme's text colour, which always contrasts with its canvas (a11y C8). */
@media (forced-colors: active) {
  .seg-loop path { stroke: CanvasText; }
}

/* 7 or more products: the finder stays at the top while the shelf scrolls (wide screens) */
@media (min-width: 900px) {
  .finder[data-sticky] { position: sticky; inset-block-start: 0; z-index: 15; padding-block: 8px; }
  .finder[data-sticky]::before {   /* the bar's paper, shown only once stuck (no change of size); a soft shadow, no line */
    content: ""; position: absolute; inset-block: 0; inset-inline: calc(50% - 50vw); z-index: -1;
    background: var(--paper); box-shadow: 0 8px 14px -12px rgba(40, 32, 20, .45);
    opacity: 0; transition: opacity var(--dur-state) var(--ease-standard);
  }
  .finder[data-sticky] .finder-row { flex-wrap: nowrap; }
  .finder[data-sticky] .finder-count { margin-block: 0; margin-inline-start: 20px; }   /* 20px after the control, never pushed to the far end */
  .finder[data-sticky] { display: flex; align-items: center; justify-content: flex-start; gap: 0; }
  .js .finder[hidden][data-sticky] { display: flex !important; }   /* the reserved box keeps the sticky bar's own layout */
  .finder.is-stuck::before { opacity: 1; }
  .finder.is-stuck .finder-q { font-size: 18px; }
}

/* ==========================================================================
   The shelf: one table per three columns
   ========================================================================== */
.hint { display: none; align-items: center; gap: 8px; margin-block: 0 12px; font: 400 15px/1.4 var(--font-body); color: var(--muted); }
.hint-arrow { flex: none; color: var(--ink); }
.hint.is-nudging .hint-arrow { animation: pil-nudge 600ms var(--ease-standard) 2; }
@keyframes pil-nudge { 50% { transform: translateX(-6px); } }

.shelf-section ~ .shelf-section { margin-block-start: 72px; }   /* ~ : the empty state sits between the books and the next kind */
.shelf-h { margin-block-end: 32px; font: 700 30px/1.3 var(--font-heading); color: var(--ink); }
.shelf-table { position: relative; }
.shelf-table:focus-visible { outline-offset: 6px; }
@media (max-width: 1099px) { .shelf-table:focus-visible { outline-offset: -3px; } }   /* the page clips at its edge: the ring would lose its start side */

/* The stage is as tall as THIS table's tallest cover (--tall: the largest unscaled cover height of its columns, a «בקרוב» blank
   included, printed by the template and recomputed by shop-table.js after every regroup). 340 is the fallback of a stage
   outside a table (the empty state). */
.tbl, .shelf-empty {
  --stage-h: calc(var(--head-room) + var(--tall, 340) * var(--k) * 1px + var(--ledge-h));   /* table 1 at 1440: 6 + 306 + 30 = 342 */
}
.tbl {
  width: calc(var(--label-w) + var(--n, 3) * max(var(--colmin), (100% - var(--label-w)) / 3));
  table-layout: fixed; border-collapse: separate; border-spacing: 0;
}
.tbl th, .tbl td { padding: 0; vertical-align: top; text-align: start; font-weight: 400; }
.tbl thead th.rl, .tbl .c-rl { width: var(--label-w); }
.tbl thead th.rl { position: relative; }

/* a bay: the book's ground on every cell of its column, 10px of paper between bays,
   a rule over each body cell that stops at the gutters */
.tbl .col, .tbl td { border-inline-start: var(--gut) solid transparent; }
.tbl td {
  padding: var(--pad-cell);
  background: linear-gradient(var(--rule), var(--rule)) no-repeat 0 0 / 100% 1px padding-box, var(--book-ground, var(--paper-light)) padding-box;
}
.tbl .col {
  position: relative;
  /* where the bay colour starts: the table's SHORTEST cover (--bay-bh, the smallest unscaled cover height) rises 40% out of it
     into the paper, whatever the tallest cover of the table is */
  --tint-top: calc(var(--head-room) + (var(--tall, 340) - .6 * var(--bay-bh, 340)) * var(--k) * 1px);
  background: linear-gradient(to bottom, transparent var(--tint-top), var(--book-ground, var(--paper-light)) var(--tint-top)) padding-box;
}
.tbl .col-soon { --book-ground: var(--paper-light); }
.tbl tr:not([data-row="about"]) td.col-soon { --book-ground: transparent; }   /* the soon bay ends after «על מה הסיפור» (its only text): paper and the rule */
.tbl tr[data-row="buy"] td.col-soon { background: none; }   /* its foot is the values row's rule: no hairlines across the empty cells under it */
.tbl tbody th.rl {
  padding-block: 10px; padding-inline-end: 12px;
  font: 700 16px/1.35 var(--font-heading); color: var(--plum);
  background-image: linear-gradient(var(--rule), var(--rule)); background-repeat: no-repeat; background-size: 100% 1px;   /* longhands: the sticky label column's paper (.tbl .rl, below 1088px) must not be reset by a shorthand */
}
/* the buy row (28px price, 48px button): the label shares the baseline of the row's first line.
   The text rows (about, values) stay top-aligned. */
.tbl tr[data-row="buy"] > * { vertical-align: baseline; }

/* ---------- the cover stage and the board ---------- */
.stage {
  position: relative; height: var(--stage-h);
  display: flex; align-items: flex-end; justify-content: center;
  padding-block-end: var(--ledge-h);
  perspective: 1400px; perspective-origin: 50% calc(100% - var(--ledge-h));   /* at the ledge line: mid-turn the book grows upward, never into the shelf */
}
.stage::after, .tbl thead th.rl::after {      /* the board: one band across the whole table, gutters included */
  content: ""; position: absolute; z-index: 0; inset-block-end: 0; height: var(--ledge-h);
  inset-inline-start: calc(-1 * var(--gut)); inset-inline-end: 0;
  background: var(--board);
  box-shadow: var(--board-shadow);
  pointer-events: none;
}
.tbl thead th.rl::after { inset-block-end: auto; inset-block-start: calc(var(--stage-h) - var(--ledge-h)); }
.tbl thead th:last-child .stage::after { inset-inline-end: calc(-1 * var(--gut)); }

/* the age tag: a paper label on the board's front under its book, on the cover's axis (every column of a row shows its tag on
   one line; physical left is the one allowed here, centring has no direction). A longer line wraps inside the tag, which then
   grows upward over the cover's foot; it never clips (z-index 3: above the book at z-index 2, so the grown tag is not cut by the cover, WCAG 1.4.12). */
.age-tag {
  position: absolute; z-index: 3; inset-block-end: var(--tag-lift); left: 50%; transform: translateX(-50%); width: max-content;
  box-sizing: border-box; display: flex; align-items: center; min-height: var(--tag-h); max-width: calc(100% - 2 * var(--pad-x));
  margin: 0; padding: 2px 8px; border-radius: 2px; background: var(--paper-light);
}
.age-vis { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; }
.age-tag .age-n { font: 700 20px/1 var(--font-display); }
.age-tag .age-words { font: 400 15px/1 var(--font-body); color: var(--text); }
.age-tag .age-whole { color: var(--muted); }
.age-tag[data-empty-age] { font: 700 20px/1 var(--font-display); color: var(--ink); }   /* the chosen age, copied from the finder by shop-table.js */

.contact, .stage-blank::before {          /* the contact shadow, sunk 5px into the board's top */
  content: ""; position: absolute; z-index: 1; inset-block-end: calc(var(--ledge-h) - 5px); left: 50%;
  width: calc((var(--bw, 236) * var(--k) + 28) * 1px); max-width: 100%; height: 16px;   /* max-width: on a 320px phone the column is narrower than the shadow, which made a one-book table scroll by 5px */
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(40, 32, 20, .45), rgba(40, 32, 20, 0));
  pointer-events: none;
}

/* ---------- the book: a cover, a back, a spine and a page block ---------- */
.book {
  position: relative; z-index: 2;
  width: calc(var(--bw) * var(--k) * 1px); height: calc(var(--bh) * var(--k) * 1px);
  transform-style: preserve-3d;
  transition: transform var(--dur-return) var(--ease-turn);
}
.face {
  position: absolute; inset: 0;
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
  box-shadow: -14px 10px 22px -14px rgba(40, 32, 20, .40);   /* cast on the bay, light from the upper right */
}
.face::after {                                   /* the shade of a face going edge-on (keyframes: creative developer) */
  content: ""; position: absolute; inset: 0; background: rgba(40, 32, 20, .28); opacity: 0; pointer-events: none;
}
.front { transform: translateZ(calc(var(--thick) * var(--k) / 2)); }
.tt .front img { display: block; width: 100%; height: 100%; max-width: none; object-fit: cover; }
.front::before {                                 /* the binding on the cover's right edge, with its hinge line */
  content: ""; position: absolute; z-index: 1; inset-block: 0; right: 0; width: 12px; pointer-events: none;
  background: linear-gradient(to left, rgba(0, 0, 0, .22), rgba(0, 0, 0, 0) 60%, rgba(255, 255, 255, .18) 75%, rgba(255, 255, 255, 0));
}
.back {
  transform: rotateY(180deg) translateZ(calc(var(--thick) * var(--k) / 2));
  display: flex; flex-direction: column;
  padding: 16px 14px 0;                          /* the foot below carries the bottom */
  background: var(--book-back);
}
.back::before {                                  /* the binding, now on the left */
  content: ""; position: absolute; inset-block: 0; left: 0; width: 12px; pointer-events: none;
  background: linear-gradient(to right, rgba(0, 0, 0, .18), rgba(0, 0, 0, 0));
}
/* Her text on the back of the book: Assistant 15px in #333 on the book's own tint (7.6 to 8.8:1), centred between the top and the foot.
   Verse (a text with line breaks) is printed one span per line, so every verse starts its own line and one that is too long is
   balanced over two; prose is one paragraph, start-aligned. The line clamp is only the safety for a longer text (the owner's
   answer to a long text is a back-cover image, which wins); the four real texts fit with no clamp. */
.back-text {
  margin-block: auto;
  font: 400 15px/1.6 var(--font-body); color: var(--text); text-align: start; text-wrap: pretty;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: var(--lines); overflow: hidden;
}
.back-text[data-verse] { text-align: center; display: block; -webkit-line-clamp: none; max-height: calc(var(--lines) * 1.6em + 2px); }   /* Firefox draws the clamp's ellipsis after the last verse (its spans use text-wrap: balance) even with room to spare, so a verse is capped by height, never by a line clamp */
.back-text .v { display: block; text-wrap: balance; }
.face.back[data-placeholder] .back-text::before { content: attr(data-text); }   /* the placeholder is drawn here, not printed in the page */
.back-foot {
  position: relative; height: 30px; display: flex; align-items: center; justify-content: center;   /* the leaf mark, centred under a hairline */
}
.back-foot::before {
  content: ""; position: absolute; inset-block-start: 0; inset-inline: 22%; height: 1px;
  background: var(--book-deep); opacity: .3;
}
.back-mark { width: 44px; }
.back-mark, .plate-mark {
  display: block; aspect-ratio: 387 / 176; background: var(--book-deep);
  -webkit-mask: url(../img/logo-mark-mask.png) center / contain no-repeat;
  mask: url(../img/logo-mark-mask.png) center / contain no-repeat;
}
.back-img { padding: 0; }
.tt .back-img img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; object-fit: cover; }
.spine {
  position: absolute; inset-block: 0; right: calc(var(--thick) * var(--k) / -2);
  width: calc(var(--thick) * var(--k)); background: var(--book-deep);
  transform: rotateY(90deg);
}
.edge {
  position: absolute; inset-block: 3px; left: calc(var(--thick) * var(--k) / -2);
  width: calc(var(--thick) * var(--k));
  background: repeating-linear-gradient(to bottom, #F6F2E6 0 2px, #E4DDCA 2px 3px);
  transform: rotateY(-90deg);
}
/* a product with no cover: a cloth binding in its colour, its title stamped, the mark at the foot */
.plate {
  position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: space-between; align-items: center;
  padding: calc(40px * var(--k)) calc(24px * var(--k)) calc(28px * var(--k));
  background: var(--book-back); text-align: center;
}
.plate-title { font: 700 calc(24px * var(--k) + 2px)/1.3 var(--font-heading); color: var(--ink); text-wrap: balance; }
.plate-mark { width: calc(110px * var(--k)); }

/* the turn: hover (fine pointers, after a short intent delay), the cover button, and keyboard focus without script.
   A click on a book that hover already turned returns the cover (.is-front) until the pointer leaves. */
.stage.is-turned .book, html:not(.js) .col:focus-within .book {
  transform: rotateY(180deg); transition-duration: var(--dur-turn);
}
@media (hover: hover) and (pointer: fine) {
  .stage:hover:not(.is-front) .book { transform: rotateY(180deg); transition-duration: var(--dur-turn); transition-delay: var(--dur-intent); }
}
/* the contact shadow narrows while the book is edge-on (two names, so each change restarts it) */
.stage.is-turned .contact { animation: pil-turn-a var(--dur-turn) var(--ease-turn); }
.stage.has-turned:not(.is-turned):is(.is-front, :not(:hover)) .contact { animation: pil-turn-b var(--dur-return) var(--ease-turn); }
@media (hover: hover) and (pointer: fine) {
  .stage.has-turned:hover:not(.is-turned):not(.is-front) .contact { animation: pil-turn-a var(--dur-turn) var(--ease-turn) var(--dur-intent); }
}
@keyframes pil-turn-a { 50% { transform: translateX(-50%) scaleX(.16); } }
@keyframes pil-turn-b { 50% { transform: translateX(-50%) scaleX(.16); } }

/* The faces swap by visibility at the edge-on point, so the turn does not depend on backface-visibility (an engine that
   ignores it drew the mirrored back over the cover at rest). ease-turn puts 90 degrees at 37% of the time: 192ms of the
   520ms turn, 140ms of the 380ms return; a hover turn adds its intent delay. Delay-only transitions (0s duration) flip
   the value at that moment, in either direction. With the script, shop-motion.js sets stage[data-face] from the book's
   real angle and takes over (sweeps, reversals). Reduced motion keeps its own path (the cross-fade below). */
@media (prefers-reduced-motion: no-preference) {
  .stage { --edge-turn: calc(var(--dur-turn) * .37); --edge-return: calc(var(--dur-return) * .37); }
  .tt .face { transition: visibility 0s linear var(--edge-return); }
  .tt .back { visibility: hidden; }
  .stage.is-turned .front, html:not(.js) .col:focus-within .front { visibility: hidden; transition-delay: var(--edge-turn); }
  .stage.is-turned .back, html:not(.js) .col:focus-within .back { visibility: visible; transition-delay: var(--edge-turn); }
}
@media (prefers-reduced-motion: no-preference) and (hover: hover) and (pointer: fine) {
  .stage:hover:not(.is-front) .front { visibility: hidden; transition-delay: calc(var(--dur-intent) + var(--edge-turn)); }
  .stage:hover:not(.is-front) .back { visibility: visible; transition-delay: calc(var(--dur-intent) + var(--edge-turn)); }
}

/* a product that is not a book (a print, an item): flat on the ledge, no turn */
.object { position: relative; z-index: 2; width: calc(var(--bw) * var(--k) * 1px); height: calc(var(--bh) * var(--k) * 1px); box-shadow: -14px 10px 22px -14px rgba(40, 32, 20, .40); }
.tt .object img { display: block; width: 100%; height: 100%; max-width: none; object-fit: cover; }

/* the turn button: the cover itself. Hidden without script (the focus-within rule above turns the book); with script an empty
   button laid exactly over the cover, no glyph and no label. The ring sits 4px outside the cover and does not turn with it. */
.turn { display: none; }
/* With script only the cover answers the pointer: the stage (the bay beside the cover, the board) lets it through, so a pointer
   crossing the empty bay turns nothing and `.stage:hover` is true only while the pointer is on the cover button. Without
   script nothing changes (the whole stage hovers). */
.js .stage { pointer-events: none; }
.js .stage .turn { pointer-events: auto; }
.js .turn {
  position: absolute; z-index: 3; display: block; left: 50%; inset-block-end: var(--ledge-h);
  width: calc(var(--bw) * var(--k) * 1px); height: calc(var(--bh) * var(--k) * 1px);
  min-height: 0; margin: 0; padding: 0; border: 0; border-radius: 2px;
  transform: translateX(-50%); background: transparent; cursor: pointer;
}
.js .turn:focus-visible { outline: 3px solid var(--focus); outline-offset: 4px; }

/* ---------- the title ---------- */
.col-title { padding: 8px var(--pad-x) 10px; font: 700 22px/1.25 var(--font-heading); color: var(--ink); text-wrap: balance; text-align: center; }   /* Change 21 (the owner: «למרכז את שמות הספרים לאמצע הכריכות»): the name stands under the middle of its cover, not at the column's right edge */
.col-title a {
  display: inline-block; padding-block: 10px; margin-block: -10px;   /* a 44px target, same layout */
  color: inherit; text-decoration: underline 1px transparent; text-underline-offset: 4px;
  transition: text-decoration-color var(--dur-state) var(--ease-standard);
}
.col-title a:hover, .col-title a:focus-visible { text-decoration-color: currentColor; }
.col-soon .col-title { color: var(--muted); }

/* ---------- a book still to come (and the empty state): an unpainted book, its title sketched in pencil ---------- */
.stage-blank { --bw: 196; --bh: 272; }
.blank {
  position: relative; z-index: 2;
  width: calc(var(--bw) * var(--k) * 1px); height: calc(var(--bh) * var(--k) * 1px);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(22px * var(--k));
  background: var(--paper-light);
  border: 1.5px solid var(--pencil); border-right-width: 3px;     /* the spine line: on the right, as the books */
}
.blank-branch {
  width: calc(64px * var(--k)); aspect-ratio: 99 / 166; background: rgba(142, 135, 120, .6);
  -webkit-mask: url(../img/logo-branch-mask.png) center / contain no-repeat;
  mask: url(../img/logo-branch-mask.png) center / contain no-repeat;
}
.blank-lines { display: flex; flex-direction: column; align-items: center; gap: calc(10px * var(--k)); }
.blank-lines i { display: block; width: calc(96px * var(--k)); height: 2px; background: var(--pencil); }
.blank-lines i + i { width: calc(64px * var(--k)); }

/* ==========================================================================
   The rows
   ========================================================================== */
/* Three text rows from the author's content table (Change 9): one type scale for all of them, set a step smaller than running
   text so the table stays short (the four books' longest «על מה הסיפור» is 4 lines at 1440); the label column's own size stays.
   Their cells and labels take 8px above and below instead of 10. */
.desc, .values { font: 400 15px/1.55 var(--font-body); color: var(--text); }
.desc + .desc { margin-block-start: 4px; }   /* a book to come: her two lines in one cell */
.tbl tbody tr:not([data-row="buy"]) > :is(td, th.rl) { padding-block: 8px; }

/* the purchase row: the price at the start, then two buttons in two colours (concept-c8 note 4): «לעמוד הספר» on paper with an ink edge,
   «הוספה לעגלה» in the shop's red. The same three lines in every column at every width: the price line, the buttons that share the next, the note
   under them. (Until 1.9.1 the price and the buttons stood on one line from 1200px when they happened to fit, so a column whose price line is wider, a
   book on sale with its regular price struck through beside it, a «from» price, a bigger price, broke away from its neighbours onto three lines:
   the owner, Change 15 fix 2, «המבנה נשבר ומשתבש עם ההנחה». A structure that depends on what fits is the defect; this one cannot differ between columns.) */
.buy { display: flex; flex-direction: column; align-items: stretch; gap: 10px; }
.price-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; }
.price { font: 700 28px/1 var(--font-display); color: var(--text); font-variant-numeric: tabular-nums; }
.price-from { font: 600 14px/1 var(--font-body); color: var(--muted); margin-inline-end: 6px; }
.price-was { font: 400 20px/1 var(--font-display); color: var(--muted); text-decoration: line-through 1px; font-variant-numeric: tabular-nums; }
.price-note { font: 600 16px/1.4 var(--font-body); color: var(--muted); }
.buy-acts { display: flex; gap: 8px; }
.buy-acts > * { flex: 1 1 0; }   /* the two buttons share the line equally; a lone button (a product with options, a book that cannot be bought) takes it whole */
.buy > .stock-note { margin-block-start: 2px; }
.tbl .buy .page-link, .tbl .buy .btn-buy {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 46px; margin: 0; padding: 0 12px; border: 0; border-radius: 3px;
  font: 700 16px/1.15 var(--font-body); text-decoration: none; white-space: nowrap;
  transition: background-color var(--dur-state) var(--ease-standard), color var(--dur-state) var(--ease-standard), box-shadow var(--dur-state) var(--ease-standard);
}
.tbl .buy .page-link { background: var(--paper-light); color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--ink); }
.tbl .buy .page-link:hover, .tbl .buy .page-link:focus-visible { background: #DCE6E3; color: var(--ink); box-shadow: inset 0 0 0 2.5px var(--ink); }   /* the paper stays and the edge deepens: a solid ink fill would stand beside the red button as two heavy blocks */
.tbl .buy .page-link:focus-visible, .tbl .buy .btn-buy:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.col-soon .desc a { color: var(--link); }

/* ---- shared with shop.css: the buy action and the age numeral (concept-table-v2 §3.4, §3.8).
   The shop listing does not load shop.css and the book page does not load this file, so the two
   copies are kept the same; the one deliberate difference is the numeral's face and size (set with the age tag
   above: 18px on the board's tag; 40px on the book page). ---- */
.btn-buy {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 0 24px; border: 0; border-radius: 3px;
  background: var(--add); color: var(--add-text); text-decoration: none; text-align: center; white-space: nowrap;
  font: 700 18px/1.15 var(--font-body); cursor: pointer;
  transition: background-color var(--dur-state) var(--ease-standard), transform var(--dur-feedback) var(--ease-standard);
}
.btn-buy:hover, .btn-buy:focus-visible { background: var(--add-hover); color: var(--add-text); }
.btn-buy:active { transform: translateY(1px); }
.btn-buy.is-added::before {
  content: ""; width: 16px; height: 16px; flex: none; background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5l3.5 3.5 7.5-8' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5l3.5 3.5 7.5-8' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
.age-n {
  display: block; color: var(--ink);
  direction: ltr; unicode-bidi: isolate; text-align: end; font-variant-numeric: tabular-nums;
}
/* ---- end of the shared block ---- */

/* ---------- between tables: a dotted line and the logo's three colours ---------- */
.sep { display: flex; align-items: center; gap: 10px; margin-block: 28px; }
.sep::before, .sep::after { content: ""; flex: 1; border-block-start: 3px dotted #9C9786; }
.sep i { flex: none; width: 12px; height: 12px; border-radius: 50%; background: var(--plum); }
.sep i:nth-child(2) { background: var(--leaf); }
.sep i:nth-child(3) { background: var(--ink); }

/* ---------- a filter with no book: an unpainted book on the board, in the first column's place ---------- */
.shelf-empty {
  position: relative; display: grid; padding-block-end: 32px;
  grid-template-columns: var(--label-w) minmax(0, max(var(--colmin), (100% - var(--label-w)) / 3));
}
.shelf-empty[hidden] { display: none; }
.shelf-empty::before {                          /* the board, across the shelf */
  content: ""; position: absolute; inset-block-start: calc(var(--stage-h) - var(--ledge-h)); inset-inline: 0; height: var(--ledge-h);
  background: var(--board);
  box-shadow: var(--board-shadow);
}
.empty-col { grid-column: 2; border-inline-start: var(--gut) solid transparent; }
.shelf-empty .col-title { padding-block-end: 4px; color: var(--ink); }
.shelf-empty .link-btn { margin-inline-start: var(--pad-x); }
.link-btn {
  min-height: 44px; margin-block-start: 4px; padding: 0; border: 0; background: none; cursor: pointer;
  font: 600 17px/1.3 var(--font-body); color: var(--link); text-decoration: underline 1px; text-underline-offset: 4px;
}
.link-btn:hover { text-decoration-thickness: 2px; }

/* ==========================================================================
   The colouring box: the author's text and three real sheets rising out of it
   ========================================================================== */
.colouring-box {
  position: relative; display: flex; align-items: center; justify-content: space-between; gap: 32px 48px;
  margin-block: 56px 48px; padding: 24px 40px; background: var(--paper-light);
}
.cb-text { display: grid; grid-template-columns: max-content max-content; justify-content: start; column-gap: 32px; align-items: center; }   /* her words in the first column, the button 32px after them */
.cb-text h2 { grid-column: 1; font: 700 26px/1.3 var(--font-heading); color: var(--ink); }
.cb-text p { grid-column: 1; margin-block: 4px 0; font: 400 17px/1.65 var(--font-body); color: var(--text); }
.cb-text .btn-ink { grid-column: 2; grid-row: 1 / 3; }
.btn-ink {
  display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding: 0 24px; border-radius: 3px;
  background: var(--ink); color: var(--paper-light); text-decoration: underline 1px transparent; text-underline-offset: 4px;
  font: 700 18px/1.15 var(--font-body);
  transition: text-decoration-color var(--dur-state) var(--ease-standard);
}
.btn-ink:hover, .btn-ink:focus-visible { color: var(--paper-light); text-decoration-color: currentColor; }
.cb-sheets {
  --sheet: 132px; --step: 88px;                   /* each sheet overlaps the next by 44px */
  position: relative; flex: none; display: block;
  width: calc(var(--sheet) + 2 * var(--step)); height: 172px;
  margin-block: -64px -24px;                      /* the stack rises 40px above the panel's top edge */
}
.tt .sheet {
  position: absolute; inset-block-start: 0; width: var(--sheet); height: auto; max-width: none;
  background: #fff; border: 1px solid #DDD8CC; box-shadow: var(--shadow-raise);
  transition: transform var(--dur-state) var(--ease-standard);
}
.sheet-1 { inset-inline-start: 0; z-index: 3; }
.sheet-2 { inset-inline-start: var(--step); z-index: 2; }
.sheet-3 { inset-inline-start: calc(2 * var(--step)); z-index: 1; }
.cb-sheets:hover .sheet-2, .colouring-box:focus-within .sheet-2 { transform: translateX(-28px); }
.cb-sheets:hover .sheet-3, .colouring-box:focus-within .sheet-3 { transform: translateX(-56px); }

/* ---------- pagination ---------- */
.tt .woocommerce-pagination { margin-block: var(--s-7) 0; }
.tt .woocommerce-pagination ul.page-numbers { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 0; padding: 0; border: 0; list-style: none; }
.tt .woocommerce-pagination ul.page-numbers li { float: none; margin: 0; padding: 0; border: 0; overflow: visible; }
.tt .woocommerce-pagination ul.page-numbers li .page-numbers {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0 14px; margin: 0; border-radius: 3px;
  box-shadow: inset 0 0 0 1.5px var(--ink); background: transparent; color: var(--ink);
  font: 600 17px/1 var(--font-body); font-variant-numeric: tabular-nums; text-decoration: none;
}
.tt .woocommerce-pagination ul.page-numbers li a.page-numbers:hover { background: rgba(16, 72, 72, .08); }
.tt .woocommerce-pagination ul.page-numbers li .page-numbers.current { background: var(--ink); color: var(--paper-light); }

/* ==========================================================================
   Reduced motion: no rotation; the back cross-fades over the cover
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .tt .book { transform: none !important; transform-style: flat; transition: none; }
  .spine, .edge { display: none; }
  .face { -webkit-backface-visibility: visible; backface-visibility: visible; }
  .tt .front { transform: none; }
  .tt .back { transform: none; opacity: 0; visibility: hidden; transition: opacity 200ms linear, visibility 0s linear 200ms; }   /* visibility: the unturned back's text stays out of the accessibility tree, as in the turn (a11y C8) */
  .stage.is-turned .back, html:not(.js) .col:focus-within .back { opacity: 1; visibility: visible; transition-delay: 0s; }
  .stage .contact { animation: none !important; }
  .hint.is-nudging .hint-arrow { animation: none; }
}
@media (prefers-reduced-motion: reduce) and (hover: hover) and (pointer: fine) {
  .stage:hover:not(.is-front) .back { opacity: 1; visibility: visible; transition-delay: 0s; }
}

/* ==========================================================================
   Below a 1040px container the tables scroll, each in its own box
   ========================================================================== */
@media (max-width: 1087px) {
  .tt { --label-w: 104px; --colmin: 280px; --head-room: 14px; }   /* the tables scroll here, so the turn's growth must fit inside the stage */
  html:not(.js) .hint, .hint.is-on { display: flex; }
  .js .hint { display: flex; visibility: hidden; }   /* its line is reserved from first paint (the script turns it on once a table overflows), so nothing moves */
  .js .hint.is-on { visibility: visible; }
  .js .hint.is-off { display: none; }
  @media (min-width: 967px) { .js .hint:not(.is-on) { display: none; } }   /* three columns fit here with four books: no reserved line to give back after the script (it was a 33 px jump, CLS 0.017) */
  .shelf-table {
    display: flex;   /* so the room after the last book (--end, below) is part of what scrolls in every engine: a flex item's margin is */
    overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory; scroll-padding-inline-start: var(--label-w);
    margin-inline-end: calc(-1 * var(--gutter));   /* bleed to the screen edge so the next book peeks */
    -webkit-overflow-scrolling: touch;
  }
  /* --end: written by shop-table.js on a phone-sized scroller, where one book and a peek of the next fill the screen. The scroll runs on by what
     the screen has left over once its whole books are counted (the peek of the next book at the start, as air after the last one), so the last
     stop is the last book whole, next to the label, and not a sliver of the book before it (the owner's note, Change 12: the scroll "stopped in
     the middle of Ariel's book"). Without script it is 0: the scroll ends with the last book at the screen's edge, as before. */
  .tbl { flex: none; margin-inline-end: var(--end, 0px); width: calc(var(--label-w) + var(--n, 3) * max(var(--colmin), (100% - var(--label-w)) / 3)); }
  .tbl .col, .tbl td { scroll-snap-align: start; }
  .tbl .rl {
    position: sticky; inset-inline-start: 0; z-index: 4;
    background-color: var(--paper);
    box-shadow: inset 1px 0 0 var(--rule), -6px 0 8px -6px rgba(40, 32, 20, .25);   /* the rule on the inline end (left) */
  }
  /* the label's column holds in the cover row too (an empty cell with the board's piece): the covers slide UNDER it, as the rows' text does. When it
     was left to scroll away, the book before the last one showed as a cut strip of cover beside the label at the last stop. */
  .tbl thead th.rl { position: sticky; }
  .tbl thead th:last-child .stage::after { inset-inline-end: 0; }
  .colouring-box { flex-direction: column; align-items: flex-start; }
  .cb-text { display: block; }
  .cb-text p { margin-block: 4px 16px; }
  .cb-sheets { margin-block: -64px 0; order: -1; }
}

@media (max-width: 599px) {
  .tt {
    --label-w: 76px; --colmin: min(268px, 100% - 92px);   /* 268 at 390 (the next book peeks 30px); narrower screens keep a 30px peek down to 360 */
    --head-room: 16px; --ledge-h: 26px; --k: .86; --thick: 10px;   /* the fit box 220 × 292 */
    --pad-x: 14px; --tag-h: 22px; --tag-lift: 2px;
  }
  .tt-wrap { padding-block-start: 20px; }
  .stage { perspective: 900px; }
  .back { padding: 14px 12px 0; }
  .back-text { line-height: 1.55; -webkit-line-clamp: var(--lines-s); }
  .back-text[data-verse] { max-height: calc(var(--lines-s) * 1.55em + 2px); }
  .back-foot { height: 26px; }
  .back-mark { width: 38px; }
  .finder { margin-block: 12px 16px; }
  .finder-row { display: block; }
  .finder-q { font-size: 20px; margin-block-end: 4px; }
  .finder-count { margin-block-start: 6px; font-size: 15px; }
  .seg { display: flex; justify-content: space-between; width: 100%; gap: 0; }   /* four labels sized by their words, spread over the row */
  .seg-btn { padding: 0 8px; font-size: 17px; }
  .seg-loop path { stroke-width: 2.5; }
  .tbl tbody th.rl { padding-inline: 4px 8px; font-size: 15px; }
  .tbl .rl { box-shadow: inset 1px 0 0 var(--rule); }   /* the phone keeps only the rule: a shadow here reads as a grey pillar */
  .col-title { padding-block: 6px 8px; font-size: 20px; }
  .age-tag { padding-inline: 6px; }
  .age-tag .age-n, .age-tag[data-empty-age] { font-size: 18px; }
  .buy-acts { gap: 6px; }
  .tbl .buy .page-link, .tbl .buy .btn-buy { min-height: 44px; padding: 0 8px; font-size: 15px; }
  .buy .price { font-size: 26px; }
  .hint { margin-block-end: 8px; }
  .sep { margin-block: 24px; }
  .colouring-box { padding: 20px; margin-block: 48px 40px; }
  .cb-sheets { --sheet: 104px; --step: 64px; height: 135px; margin-block: -56px 0; }
  .cb-text h2 { font-size: 24px; }
  .cb-text .btn-ink { width: 100%; }
}

/* the narrowest phones: the column fills the scroller (the hint line is the cue for the next book), the back gives back 2px of padding. One book fills the
   screen beside the label exactly, so every stop is already a whole book there and the scroll needs no room after the last one (shop-table.js --end is 0) */
@media (max-width: 359px) {
  .tt { --k: .84; --colmin: calc(100% - 76px); }
  .back { padding: 12px 10px 0; }
  .back-text { line-height: 1.5; }
  .back-text[data-verse] { max-height: calc(var(--lines-s) * 1.5em + 2px); }
  .buy-acts { gap: 4px; }
  .tbl .buy .page-link, .tbl .buy .btn-buy { padding: 0 6px; }   /* the two buttons fit the 190px of the column at 320 with room to spare (90 + 6 + 96 was 192) */
}

/* 340px and down: tighter labels, still one line at 320. Below 360 the labels may wrap rather than clip (text spacing, 1.4.12) */
@media (max-width: 340px) {
  .seg-btn { padding-inline: 6px; }
}
@media (max-width: 359px) {
  .seg-btn { white-space: normal; line-height: 1.2; }
}
/* the first option stands on the content's start edge where the ages wrap or spread: its loop stays inside it */
@media (max-width: 1087px) {
  .seg-btn:first-of-type .seg-loop { inset-inline-start: 0; width: calc(100% + 6px); }
}

/* ==========================================================================
   The cover glide (book-room): going from the shelf to a book's page the cover travels from its place on the shelf into
   its bay, and back. A cross-document view transition, so progressive: Chromium and Safari 18.2+ run it, any other engine
   loads the page as usual, and neither reduced motion nor a browser with script off is inside the media query (no transition at all). product.css carries the same
   block, so a navigation between the shop and the book pages is the only one that transitions.
   Every cover carries its own name (cover-<id>, from the --vt custom property the templates print) so the page that is
   revealed can name it before any script has run; the scripts (shop-motion.js, book.js) leave the name on the one cover that is
   being opened and switch the others off when the visitor leaves (pageswap), so no other cover is captured, glides to the
   other page or lingers over it. Names are applied only with script (html.js) and not while the finder's own transition
   runs (html.pil-vt); with script off the media query is false and the page loads as usual.
   ========================================================================== */
/* The glide was filmed on Chromium only. WebKit (Safari and every iOS browser) supports cross-document view transitions too, but
   its look has not been checked on a real device, so it keeps ordinary page loads for now: no names and no at-rule there.
   Chromium has no -webkit-hyphens and WebKit has it, which tells them apart. To switch the glide on in WebKit, delete this
   @supports wrapper (here and at the end of product.css / shop-table.css) once it has been seen on a real Safari. */
@supports not (-webkit-hyphens: none) {
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) {
  @view-transition { navigation: auto; }
  html.js:not(.pil-vt) .face.front, html.js:not(.pil-vt) .stage-flat .object {   /* the cover with its shadow and binding, not the book (its 3D turn must stay) */
    view-transition-name: var(--vt, none); view-transition-class: cover;
  }
  /* the page around the cover: a short cross-fade (the finder's own transition keeps the default) */
  html:not(.pil-vt)::view-transition-old(root), html:not(.pil-vt)::view-transition-new(root) { animation-duration: 180ms; }
  /* the cover: one group from its old place to the new, the same picture at both ends */
  ::view-transition-group(*.cover) { animation-duration: var(--dur-glide, 480ms); animation-timing-function: var(--ease-glide, cubic-bezier(.25, .1, .15, 1)); }
  ::view-transition-old(*.cover), ::view-transition-new(*.cover) { height: 100%; object-fit: cover; }
  /* the book's spine and page edge are planes seen edge-on: with the cover lifted out for the glide they would show as a hairline in
     the empty slot, so they step aside while a transition runs (engines without the pseudo-class keep the hairline) */
  @supports selector(:active-view-transition) {
    html:active-view-transition:not(.pil-vt) .book :is(.spine, .edge) { visibility: hidden; }
  }
  /* a cover with no partner on the other page fades with the page, like everything that is not named */
  ::view-transition-old(*.cover):only-child, ::view-transition-new(*.cover):only-child { animation-duration: 180ms; }
}
}
