/* ===========================================================================
   binder.css — the binder itself: its boards, spine and rings, the pocket
   sheets, the cards in them, the page arrows, the page turn and the card peek.

   OWNED BY THE STAGE ENGINEER (DESIGN.md §7).

   Loaded after app.css, shell.css, search.css and arrange.css, so a rule here
   wins over the shell at equal specificity.

   ---------------------------------------------------------------------------
   HOW THE BINDER IS BUILT (binder.js renders it, pageturn.js copies pieces)

     .binder                     the object on the desk (position: relative)
       .bpage.left.has-cap       a COVER BOARD: cover colour + grain + bevel
         .bg-layer               the binder's background picture, z -1
         .punches > .punch       the holes the rings pass through — one each
         .sheet                  the translucent POCKET SHEET over the board
           .grid > .pocket       the welded pockets…
             .slot-card          …and the card in each: art, then .holder
         .page-head.is-top       page number and name — ABOVE the pockets
         .page-foot              owned, missing and total — in the BOTTOM margin
       .spine > .ring            real depth between the boards + the D-rings
       .bpage.right              …
       .edges.is-left/.is-right  the pages still to come, seen edge-on
       .sheen                    the pointer's light over the whole object

   A single page is the same, with a narrower `.spine.is-solo` before it.
   Everything but the two boards and the spine is `pointer-events: none`, so
   drag-and-drop still hit-tests straight through to `.pocket`.

   ONE LIGHT, from the top left. Every bevel, glare, shadow and gradient here
   points the same way: highlights on top / left edges, shade on bottom / right,
   `135deg` for a raking light, `160deg` for a soft wash. `--hinge` / `--outer`
   name the two horizontal directions a page cares about (the rings and the
   open edge), so one rule serves the left page, the right page and a single
   page without knowing which it is.

   MATERIALS
   · Grain — a 96px two-octave noise tile drawn once on a canvas (backdrop.js
     grainUrl(), ~8KB) and handed to CSS as `--grain`; blended `overlay` into
     the cover colour, so a board is never flat. Mid grey is neutral under
     `overlay`, so it only lightens and darkens — it never tints. One data URL
     for the whole app, made on the first render and cached in JS.
   · Plastic — never a blur: layered low-opacity white gradients plus hairline
     inset box-shadows. Static, so a page turn and a drag stay on the GPU.
   · Metal — SVG rings with a multi-stop vertical gradient (highlight, core,
     shade) and their own contact shadows (binder.js ringSvg()).

   THE BINDING. How many rings the binder has is its own setting (Binder
   settings → Look: 3 by default, 2, 4, or fitted to the page height) and
   binder.js hands it to CSS as `--rings`. One rule places both the rings and
   the punch holes — `--ring-top`/`--ring-bot` in from each end, then `--i` of
   `--rings` evenly between — so a hole is always exactly where its ring is,
   at every pocket size, in the page-turn copies (they inherit --rings), in the
   arrange thumbnails (their own rule, same arithmetic) and in the PNG.

   SIZE. Pockets are 46px wide at the least and grow to fill the screen (`--pocket-w`, set by binder.js).
   Anything on a card is in `cqi` — 1% of the pocket's width, since .slot-card
   is an inline-size container — so a top loader's rim is as thick, relatively,
   on a phone as on a 1440px desk. Page-level trim is in px: the board's margin
   does not want to grow with the cards.

   Two things to know before changing anything:
   · The shell keeps the desk: .binder-frame, .binder-scroll, the desk
     background layer and the lock chip are still in app.css. Only the binder's
     own cast shadow (--desk-shadow) is re-pitched here.
   · app.css keeps the page-level print setup (@page, what is hidden, the shell
     layout); the pocket-and-card print rules are at the bottom of this file.
   =========================================================================== */

/* ============================================================ page arrows */
.page-arrow {
  position: relative; z-index: 2; flex: none;
  display: grid; place-items: center;
  width: 44px; height: 44px; padding: 0;
  border-radius: 50%; cursor: pointer;
  color: var(--ink-2);
  background: var(--glass);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.2);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.2);
  border: 1px solid var(--line);
  box-shadow: var(--glass-edge), var(--shadow-1);
  opacity: .78;
  transition: opacity var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out),
    background var(--t-1) var(--ease-out), border-color var(--t-1) var(--ease-out),
    box-shadow var(--t-1) var(--ease-out), transform var(--t-1) var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .page-arrow { background: var(--bg-2); }
}
.page-arrow.is-prev { margin: 0 -14px 0 6px; }
.page-arrow.is-next { margin: 0 6px 0 -14px; }
.page-arrow-ico { width: 20px; height: 20px; }
.page-arrow:hover {
  opacity: 1; color: var(--ink);
  background: color-mix(in srgb, var(--ink) 8%, var(--bg-3));
  border-color: var(--ink-3);
  box-shadow: var(--glass-edge), var(--shadow-2); transform: scale(1.06);
}
.page-arrow:active { transform: scale(.96); }
.page-arrow:focus-visible { opacity: 1; color: var(--ink); outline: 2px solid var(--accent); outline-offset: 3px; }
/* aria-disabled rather than disabled: a keyboard user paging to the end keeps focus here */
.page-arrow[aria-disabled="true"] {
  opacity: .28; cursor: default; box-shadow: none; transform: none;
  color: var(--ink-3); background: transparent; border-color: var(--line);
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.page-arrow[aria-disabled="true"]:focus-visible { opacity: .7; }

/* Spring-loading (dnd.js): a card held over an arrow; the ring fills, then the page turns. */
/* drawn over the button's own border, never outside it (at a phone's edge that would overflow) */
.page-arrow-ring {
  position: absolute; inset: -1px; width: calc(100% + 2px); height: calc(100% + 2px);
  transform: rotate(-90deg); pointer-events: none;
  fill: none; stroke: var(--accent); stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 1; stroke-dashoffset: 1; opacity: 0;
}
.page-arrow.is-springing {
  opacity: 1; color: var(--accent-text); transform: scale(1.1);
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  background: color-mix(in srgb, var(--accent) 16%, var(--bg-2));
  box-shadow: var(--glass-edge), var(--shadow-2);
}
.page-arrow.is-springing .page-arrow-ring { opacity: 1; animation: spring-fill var(--spring-ms, 600ms) linear forwards; }
@keyframes spring-fill { to { stroke-dashoffset: 0; } }

/* the toolbar's prev / next spring too: a bar fills along the bottom */
.btn[data-spring] { position: relative; overflow: hidden; }
.btn[data-spring]::after {
  content: ""; position: absolute; left: 4px; right: 4px; bottom: 3px; height: 2px; border-radius: 2px;
  background: var(--accent); transform: scaleX(0); transform-origin: left; pointer-events: none;
}
.btn[data-spring].is-springing {
  color: var(--accent-text); border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, var(--bg-3));
}
.btn[data-spring].is-springing::after { animation: spring-bar var(--spring-ms, 600ms) linear forwards; }
@keyframes spring-bar { to { transform: scaleX(1); } }

/* ================================================================== binder
   The object itself, and the shadow it throws on the desk.

   app.css casts that shadow with `filter: drop-shadow()` on the scroller. A
   filter makes the whole filtered subtree re-rasterise on *any* repaint inside
   it — a card lifting on hover, a pocket lighting up under a dragged card —
   and that alone cost about 7 frames over 24ms in every pocket-to-pocket drag
   (p95 35ms → 18ms once it was gone). So the filter is switched off here and
   the binder casts its own shadow instead: two static box-shadows on a layer
   behind it, which never re-rasterise anything.  */
.binder-scroll { filter: none; }
:root { --desk-shadow: 0 26px 54px rgba(0,0,0,.5); }
:root[data-theme="light"] { --desk-shadow: 0 20px 40px rgba(20,24,32,.24); }

/* The caption strip (page number, name, total) and the air between it and the
   pockets. On :root, not on .binder, because the page-turn copies are drawn
   outside the binder and have to come out exactly the same size. */
:root { --head-h: 22px; --head-gap: 12px; --head-band: calc(var(--head-h) + var(--head-gap)); }

.binder {
  --board-pad: 34px;        /* cover showing around the pocket sheet */
  --gap: 11px;              /* between pockets — the weld lines run down it */
  --stitch: rgba(255,255,255,.3);
  --sheen: 0;               /* raised by the pointer at Full motion (binder.js) */
  /* Where the rings (and the punch holes, and the page edges) start and stop
     down the page: the same clearance at both ends, so however many rings the
     binder is bound with they sit evenly over the pockets — three of them put
     the middle one on the middle of the page, as a real 3-ring binder does. */
  --ring-top: calc(var(--board-pad, 26px) + 8px);
  --ring-bot: calc(var(--board-pad, 26px) + 8px);
  position: relative;
  margin: auto;
  display: flex; align-items: stretch; gap: 0;
}

/* The soft shadow the whole object throws, down and to the right of the light. */
.binder::before {
  content: ""; position: absolute; z-index: -2; pointer-events: none;
  inset: 8px 6px -2px 6px;
  border-radius: var(--radius-lg);
  box-shadow: var(--desk-shadow), 0 6px 14px rgba(0,0,0,.4);
}
:root[data-theme="light"] .binder::before { box-shadow: var(--desk-shadow), 0 4px 10px rgba(20,24,32,.14); }

/* The contact shadow where the binder meets the desk: tight, just under the
   bottom edge, so the boards look like they have thickness and weight. */
.binder::after {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  left: 3%; right: 3%; bottom: -7px; height: 16px;
  border-radius: 50%;
  background: radial-gradient(60% 100% at 50% 0, rgba(0,0,0,.5), rgba(0,0,0,0) 72%);
}
:root[data-theme="light"] .binder::after { background: radial-gradient(60% 100% at 50% 0, rgba(20,24,32,.3), rgba(0,0,0,0) 72%); }

/* --------------------------------------------------------- the cover board
   One board, whatever is on it: a page of pockets (.bpage[data-page]), the
   inside of a cover (.bpage.is-inside — no pockets, no holes, no number) or the
   front cover with the binder's name on it (.bcover, shown when it is shut).
   All three are exactly the same size, so the spread never shifts and a leaf
   swinging from one onto another lands square. */
.bpage, .bcover {
  /* which way the rings are (--hinge) and which way the open edge is (--outer);
     the page turn sets the same two on its own pieces */
  --hinge: to right; --outer: to left;
  position: relative;
  padding: var(--board-pad, 18px);
  display: flex; flex-direction: column; justify-content: center;
  isolation: isolate;
  background-color: var(--cover, #2f6f4f);
  background-image:
    var(--grain, none),
    /* the one light, from over the binder's top left corner: each board shows
       its own share of it, so the right-hand one sits deeper in shade */
    radial-gradient(130% 95% at var(--wash-x, 2%) -10%,
      rgba(255,255,255,var(--wash-a, .2)), rgba(255,255,255,0) 58%),
    linear-gradient(135deg,
      color-mix(in srgb, var(--cover, #2f6f4f) 90%, #ffffff) 0%,
      var(--cover, #2f6f4f) 40%,
      color-mix(in srgb, var(--cover, #2f6f4f) 76%, #000) 100%);
  background-size: 96px 96px, auto, auto;
  background-blend-mode: overlay, normal, normal;
  /* bevel: light along the top and hinge-side edges, shade along the bottom and
     outer edge, then an ambient-occlusion wash into all four sides */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.3),
    inset 1px 0 0 rgba(255,255,255,.1),
    inset -1px -1px 0 rgba(0,0,0,.45),
    inset 0 0 22px rgba(0,0,0,.2);
}
/* The page number sits above the pockets (binder.js pageHead) and the prices
   sit in the bottom margin (pageFoot), which is where the extra room below
   the pockets already is: half the caption band comes off the top margin and
   is added to the bottom one. The page stays the height it was, and the
   pockets stay in the middle of it. */
.bpage.has-cap, .bcover.has-cap {
  padding-top: max(6px, calc(var(--board-pad, 18px) - var(--head-band, 28px) / 2));
  padding-bottom: calc(var(--board-pad, 18px) + var(--head-band, 28px) / 2);
}

.bpage.left  { --hinge: to left; --outer: to right; --wash-x: 2%; --wash-a: .22; border-radius: var(--radius-lg) 3px 3px var(--radius-lg); }
.bpage.right { --wash-x: -55%; --wash-a: .15; border-radius: 3px var(--radius-lg) var(--radius-lg) 3px; }
.bpage.solo  { --wash-x: -6%; --wash-a: .2; border-radius: var(--radius-lg); }
/* a single page still hangs on rings: its left corners are the spine's */
.bpage.solo.has-spine { border-radius: 3px var(--radius-lg) var(--radius-lg) 3px; }
/* The front cover sits where the right-hand board does, hinged at the spine, so
   it takes the same light and the same corners. */
.bcover { --wash-x: -4%; --wash-a: .24; border-radius: 3px var(--radius-lg) var(--radius-lg) 3px; }

/* The boards have a clean edge: no stitched thread runs round the pages or the
   cover (it read as clutter around the pockets). */

/* The gutter: the page bends into the rings, so everything near the hinge —
   board, sheet and cards alike — falls into shadow. Above the cards (z 4), and
   the pointer goes straight through it. */
.bpage::after, .bcover::after {
  content: ""; position: absolute; z-index: 4; inset: 0;
  border-radius: inherit; pointer-events: none;
  background: linear-gradient(var(--hinge),
    rgba(0,0,0,.38) 0, rgba(0,0,0,.2) 2.5%, rgba(0,0,0,.07) 7%, rgba(0,0,0,0) 14%);
}

/* The pointer sheen: one wide, soft highlight travelling across the whole
   object — one light, one layer over both boards and the spine. Full motion
   only: binder.js raises --sheen and writes --sx / --sy through motion's own
   frame loop, so there is no loop of ours and an idle binder costs nothing. */
.binder > .sheen {
  position: absolute; z-index: 6; inset: 0;
  border-radius: var(--radius-lg); pointer-events: none;
  opacity: var(--sheen, 0);
  background: radial-gradient(26% 40% at var(--sx, 50%) var(--sy, 50%),
    rgba(255,255,255,.15), rgba(255,255,255,.045) 46%, rgba(255,255,255,0) 74%);
  transition: opacity var(--t-3) var(--ease-out);
}
:root[data-motion="reduced"] .sheen,
:root[data-motion="off"] .sheen { display: none; }

/* ------------------------------------------------------- the inside covers
   A real binder has no page against the inside of its front cover: page 1 sits
   alone on the right. An even page count leaves the same gap at the other end.
   What fills it is board — the same material as the outside, deeper in the
   shade the closed boards keep, with nothing on it: no pocket sheet, no punch
   holes, no number, no name. There is no `.pocket` here at all, so a drop and a
   click have nothing to land on.

   The blank grid is a spacer and nothing else: it gives the board exactly a
   page's size, so the spread holds still and a leaf lands square on it. */
.bpage.is-inside {
  --wash-a: .09;
  background-image:
    var(--grain, none),
    radial-gradient(130% 95% at var(--wash-x, 2%) -10%,
      rgba(255,255,255,var(--wash-a, .09)), rgba(255,255,255,0) 52%),
    linear-gradient(160deg,
      color-mix(in srgb, var(--cover, #2f6f4f) 68%, #000) 0%,
      color-mix(in srgb, var(--cover, #2f6f4f) 54%, #000) 58%,
      color-mix(in srgb, var(--cover, #2f6f4f) 46%, #000) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.16),
    inset -1px -1px 0 rgba(0,0,0,.5),
    inset 0 0 44px rgba(0,0,0,.34);
}
/* …and it falls away into the binding, deeper than an open page does. */
.bpage.is-inside::after {
  background: linear-gradient(var(--hinge),
    rgba(0,0,0,.52) 0, rgba(0,0,0,.34) 3%, rgba(0,0,0,.14) 10%, rgba(0,0,0,0) 24%);
}
.blank-cell { aspect-ratio: var(--card-ratio); }

/* ========================================================== the front cover
   The binder shut: the front of a padded collector's binder, at the size its
   boards are open. Cover colour and grain, the crease where
   the padded board bends at the spine and metal caps on its two free corners;
   a display window near the top with one card behind clear plastic (the most
   valuable one — binder.js coverContents); the binder's name foil-stamped under
   it in the cover's own accent metal, with what is inside said quietly below.
   There are no rings on the outside of a binder: beside the cover is only its
   rounded back (.spine.is-shut).

   The whole board is the control. At Full motion the pointer lifts it a few
   degrees off the binder about the spine, and a click carries the swing on from
   there (pageturn.js reads the angle), so hover and open are one movement.
   binder.js frontCover(); the swing itself is in pageturn.js. */
.bcover {
  cursor: pointer;
  /* padded: the board pillows up from a darker rim */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.3),
    inset 1px 0 0 rgba(255,255,255,.1),
    inset -1px -1px 0 rgba(0,0,0,.45),
    inset 0 0 26px rgba(0,0,0,.26),
    inset 0 0 90px rgba(0,0,0,.16);
}
/* A closed cover curves into its spine rather than falling into a gutter. */
.bcover::after {
  background: linear-gradient(to right, rgba(0,0,0,.26) 0, rgba(0,0,0,.08) 3%, rgba(0,0,0,0) 8%);
}
.bcover:focus-visible { outline: 2px solid #fff; outline-offset: -7px; }

/* the crease: where the padded board bends at the spine */
.cover-hinge {
  position: absolute; z-index: 2; top: 0; bottom: 0; pointer-events: none;
  left: clamp(9px, calc(var(--cover-w, 420px) * .034), 18px); width: 5px;
  background: linear-gradient(90deg,
    rgba(0,0,0,.36), rgba(0,0,0,.14) 40%, rgba(255,255,255,.1) 62%, rgba(255,255,255,0));
}

/* metal caps on the two free corners */
.cover-corner {
  position: absolute; z-index: 2; right: 0; pointer-events: none;
  width: clamp(14px, calc(var(--cover-w, 420px) * .07), 32px); aspect-ratio: 1;
  background:
    radial-gradient(circle at 70% 30%, rgba(255,255,255,.75) 0, rgba(255,255,255,0) 1.8px),
    linear-gradient(135deg,
      color-mix(in srgb, var(--cover-accent, #d8b160) 50%, #fff) 0%,
      var(--cover-accent, #d8b160) 38%,
      color-mix(in srgb, var(--cover-accent, #d8b160) 52%, #000) 100%);
  opacity: .92;
}
.cover-corner.is-top {
  top: 0; border-top-right-radius: var(--radius-lg);
  clip-path: polygon(0 0, 100% 0, 100% 100%);
}
.cover-corner.is-bot {
  bottom: 0; border-bottom-right-radius: var(--radius-lg);
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
  background:
    radial-gradient(circle at 70% 70%, rgba(255,255,255,.55) 0, rgba(255,255,255,0) 1.8px),
    linear-gradient(45deg,
      color-mix(in srgb, var(--cover-accent, #d8b160) 42%, #000) 0%,
      var(--cover-accent, #d8b160) 60%,
      color-mix(in srgb, var(--cover-accent, #d8b160) 62%, #fff) 100%);
}

.cover-face {
  position: absolute; z-index: 3; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(var(--cover-h, 620px) * .045);
  padding: 8% 12% 12%;
  pointer-events: none;
}

/* The display window: a recess pressed into the padded board, framed by its
   own row of stitching, with the card behind clear plastic. */
.cover-window {
  position: relative; flex: none;
  width: min(64%, calc(var(--cover-h, 620px) * .42 * .714));
  padding: clamp(4px, calc(var(--cover-w, 420px) * .016), 8px);
  border-radius: clamp(6px, calc(var(--cover-w, 420px) * .022), 11px);
  background: color-mix(in srgb, var(--cover, #2f6f4f) 42%, #000);
  box-shadow:
    inset 0 3px 8px rgba(0,0,0,.7),
    inset 0 0 0 1px rgba(0,0,0,.45),
    0 1px 0 rgba(255,255,255,.16),
    0 -1px 0 rgba(0,0,0,.35);
}
.cover-window::before {
  content: ""; position: absolute; inset: calc(clamp(5px, calc(var(--cover-w, 420px) * .018), 9px) * -1);
  border: 1px dashed var(--stitch, rgba(255,255,255,.3));
  border-radius: calc(clamp(6px, calc(var(--cover-w, 420px) * .022), 11px) + 5px);
  pointer-events: none;
}
/* the card, and the pointer's foil over it (motion.foil) — the art takes the
   pointer so the sheen can follow it; a click on it still opens the binder */
.cover-art {
  position: relative; display: block; pointer-events: auto;
  border-radius: 4.6% / 3.3%;
  overflow: hidden;
  box-shadow: 0 2px 7px rgba(0,0,0,.55);
}
.cover-card {
  display: block; width: 100%; aspect-ratio: var(--card-ratio, .714);
  object-fit: cover; background: rgba(255,255,255,.04);
}
.cover-card.is-missing { filter: grayscale(1) brightness(.72); }
/* the clear front of the window: a lit rim and one glare band across it */
.cover-glass {
  position: absolute; z-index: 4; pointer-events: none;
  inset: clamp(4px, calc(var(--cover-w, 420px) * .016), 8px);
  border-radius: 4.6% / 3.3%;
  background:
    linear-gradient(118deg, rgba(255,255,255,0) 28%, rgba(255,255,255,.17) 40%, rgba(255,255,255,.04) 47%, rgba(255,255,255,0) 54%),
    linear-gradient(180deg, rgba(255,255,255,.1), rgba(255,255,255,0) 26%);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.2), inset 0 1px 0 rgba(255,255,255,.34);
}
/* an empty binder's window: the recess, and the outline of the card it is waiting for */
.cover-emblem {
  display: block; width: 100%; aspect-ratio: var(--card-ratio, .714);
  border-radius: 4.6% / 3.3%;
  border: 1px dashed rgba(255,255,255,.22);
  background:
    radial-gradient(60% 40% at 50% 45%, rgba(255,255,255,.08), rgba(255,255,255,0) 70%),
    repeating-linear-gradient(135deg, rgba(255,255,255,.035) 0 6px, rgba(255,255,255,0) 6px 12px);
}

/* The name, foil-stamped in the cover's accent metal: pressed into the board
   (a dark lip above, a lit one below), with a glint that follows the pointer's
   light across the binder (--sx, binder.js wireSheen). */
.cover-title {
  display: flex; flex-direction: column; align-items: center; gap: .7em;
  max-width: 100%; text-align: center;
  font-size: clamp(9px, calc(var(--cover-w, 420px) * .026), 14px);
}
.cover-name {
  --glint: var(--sx, 32%);
  font-size: clamp(15px, calc(var(--cover-w, 420px) * .076), 42px);
  font-weight: 750; letter-spacing: -.012em; line-height: 1.12;
  color: var(--cover-accent, #d8b160);
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--cover-accent, #d8b160) 70%, #000) 0%,
    color-mix(in srgb, var(--cover-accent, #d8b160) 78%, #fff) calc(var(--glint) - 22%),
    color-mix(in srgb, var(--cover-accent, #d8b160) 22%, #fff) var(--glint),
    color-mix(in srgb, var(--cover-accent, #d8b160) 78%, #fff) calc(var(--glint) + 22%),
    color-mix(in srgb, var(--cover-accent, #d8b160) 74%, #000) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 -1px 0 rgba(0,0,0,.55)) drop-shadow(0 1px 0 rgba(255,255,255,.12));
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
  padding: 0 .06em .08em;
}
.cover-name.is-long { font-size: clamp(14px, calc(var(--cover-w, 420px) * .062), 34px); }
.cover-name.is-longer { font-size: clamp(12px, calc(var(--cover-w, 420px) * .05), 28px); }
/* a hairline of the same metal, with a small lozenge at its middle */
.cover-rule {
  position: relative; flex: none; width: 5.2em; height: 1px;
  background: linear-gradient(90deg, rgba(0,0,0,0), var(--cover-accent, #d8b160) 30%, var(--cover-accent, #d8b160) 70%, rgba(0,0,0,0));
  opacity: .85;
}
.cover-rule::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px; transform: rotate(45deg);
  background: var(--cover-accent, #d8b160);
  box-shadow: 0 0 0 2.5px color-mix(in srgb, var(--cover, #2f6f4f) 88%, #000);
}
.cover-meta {
  font-weight: 650; letter-spacing: .15em; text-transform: uppercase;
  color: rgba(255,255,255,.74); font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 1px rgba(0,0,0,.5);
}
/* A cover asked to show only its name (Home's shelf, binder-cover.js meta: false). */
.cover-meta:empty { display: none; }
/* A picture on the cover: the lettering gets a dark panel so it always reads. */
.bcover.has-art .cover-title {
  padding: 1em 1.6em; border-radius: 12px;
  background: rgba(8,9,14,.5);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
}

/* What the board does, written on it quietly; brighter under the pointer. */
.cover-hint {
  position: absolute; z-index: 3; left: 50%; bottom: 5.5%; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  font-size: clamp(9px, calc(var(--cover-w, 420px) * .024), 11px);
  font-weight: 650; letter-spacing: .2em; text-transform: uppercase;
  color: rgba(255,255,255,.5); pointer-events: none;
  transition: color var(--t-2) var(--ease-out);
}
.cover-hint::after {
  content: ""; flex: none; width: 5px; height: 5px; margin-left: -2px;
  border-top: 1.5px solid currentColor; border-right: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--t-2) var(--ease-out);
}
.bcover:hover .cover-hint,
.bcover:focus-visible .cover-hint { color: rgba(255,255,255,.9); }
.bcover:hover .cover-hint::after,
.bcover:focus-visible .cover-hint::after { transform: translateX(3px) rotate(45deg); }

/* Shut, the binder holds its cover in the same perspective the swing is drawn
   in (pageturn.js: 3.6 page-heights, the eye a little below the middle), and
   turns it about the same hinge — the middle of the spine — so lifting it under
   the pointer and swinging it open are one continuous movement. */
.binder.is-closed {
  perspective: clamp(1800px, calc(var(--cover-h, 620px) * 3.6), 4800px);
  perspective-origin: var(--cover-eye, 50%) 55%;
}
.binder.is-closed > .bcover {
  transform-origin: var(--cover-hinge, 0px) 50%;
  transition: transform 520ms var(--ease-out);
}
:root[data-motion="full"] .binder.is-closed > .bcover:hover,
:root[data-motion="full"] .binder.is-closed > .bcover:focus-visible { transform: rotateY(-8deg); }
:root:not([data-motion="full"]) .cover-hint,
:root:not([data-motion="full"]) .cover-hint::after { transition: none; }

/* The binder standing aside while its cover swings: the swing is drawn over
   the desk, at sizes and places the shut and open binders do not share, so the
   object itself (and the shadow it casts) waits until the leaf has landed. */
.binder.is-swinging > * { visibility: hidden; }
.binder.is-swinging::before,
.binder.is-swinging::after { opacity: 0; }

/* ------------------------------------------------------- spine and D-rings */
/* Real depth between the boards: the inside of the spine is in shadow, with a
   lit roll where it meets each cover. The rings stand above both pages. */
.spine {
  position: relative; z-index: 3; flex: none;
  width: var(--spine-w, 34px);
  /* the inside of the spine: each board rolls into it, so it is darkest just
     off the two folds and picks up a little light down the middle */
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--cover, #2f6f4f) 62%, #000) 0%,
      color-mix(in srgb, var(--cover, #2f6f4f) 26%, #000) 22%,
      color-mix(in srgb, var(--cover, #2f6f4f) 42%, #000) 50%,
      color-mix(in srgb, var(--cover, #2f6f4f) 26%, #000) 78%,
      color-mix(in srgb, var(--cover, #2f6f4f) 62%, #000) 100%);
  box-shadow:
    inset 7px 0 12px -7px rgba(0,0,0,.9),
    inset -7px 0 12px -7px rgba(0,0,0,.9),
    inset 0 1px 0 rgba(255,255,255,.12);
}
/* A single page shows the spine from outside, so it takes the binder's own
   rounded corner and its rings only reach in over the page. */
.spine.is-solo {
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--cover, #2f6f4f) 76%, #000) 0%,
      color-mix(in srgb, var(--cover, #2f6f4f) 92%, #fff) 26%,
      color-mix(in srgb, var(--cover, #2f6f4f) 40%, #000) 74%,
      color-mix(in srgb, var(--cover, #2f6f4f) 24%, #000) 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.2), inset -7px 0 12px -7px rgba(0,0,0,.9);
}
.spine.is-solo::before { left: 62%; right: auto; width: 8px; margin-left: 0; }
.spine.is-solo .ring { left: 6px; margin-left: 0; }
/* Shut, the rings are inside the binder: what shows beside the front cover is
   the binder's rounded back — padded board rolling round from the cover, lit
   along its crown, in shade where it turns under — with no metal on it at all. */
.spine.is-shut {
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
  background-color: var(--cover, #2f6f4f);
  background-image:
    var(--grain, none),
    linear-gradient(90deg,
      color-mix(in srgb, var(--cover, #2f6f4f) 46%, #000) 0%,
      color-mix(in srgb, var(--cover, #2f6f4f) 80%, #000) 14%,
      color-mix(in srgb, var(--cover, #2f6f4f) 86%, #fff) 42%,
      var(--cover, #2f6f4f) 64%,
      color-mix(in srgb, var(--cover, #2f6f4f) 62%, #000) 100%);
  background-size: 96px 96px, auto;
  background-blend-mode: overlay, normal;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.2),
    inset 0 -1px 0 rgba(0,0,0,.45),
    inset -4px 0 6px -3px rgba(0,0,0,.6);
}
.spine.is-shut::before { content: none; }

/* the steel plate the rings are riveted to, running the length of the spine */
.spine::before {
  content: ""; position: absolute;
  top: calc(var(--ring-top, 56px) - 16px); bottom: calc(var(--ring-bot, 32px) - 10px);
  left: 50%; width: 11px; margin-left: -5.5px;
  border-radius: 2px;
  /* …with a rivet at each end */
  background:
    radial-gradient(circle 2.2px at 50% 8px, #dfe4ec, #7d8490 58%, rgba(74,79,88,0) 72%),
    radial-gradient(circle 2.2px at 50% calc(100% - 8px), #dfe4ec, #7d8490 58%, rgba(74,79,88,0) 72%),
    linear-gradient(90deg, #6d7480 0%, #939aa6 20%, #5e6570 48%, #33383f 72%, #4a505a 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22), inset 0 -1px 0 rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.7);
  opacity: .85;
}
/* Each ring sits at the same fraction of the page's height as its punch hole:
   --ring-pad in from both ends, then evenly spaced. */
.ring, .punch {
  position: absolute;
  top: calc(var(--ring-top, 52px)
    + (100% - var(--ring-top, 52px) - var(--ring-bot, 26px)) * (var(--i, 0) + .5) / var(--rings, 3));
}
.ring {
  left: 50%; width: var(--ring-w, 64px); height: var(--ring-h, 18px);
  margin: calc(var(--ring-h, 18px) / -2) 0 0 calc(var(--ring-w, 64px) / -2);
  pointer-events: none;
}
.ring svg { display: block; width: 100%; height: 100%; overflow: visible; }

/* The holes the rings pass through, punched in the sheet on the hinge side. */
.punches {
  position: absolute; z-index: 5; top: 0; bottom: 0;
  width: var(--board-pad, 18px); pointer-events: none;
}
.bpage.left > .punches { right: 0; }
.bpage.right > .punches, .bpage.solo > .punches { left: 0; }
/* The hole is cut through the sheet, so it is darker than anything around it,
   with the cut edge in shadow at the top and the lit lip of the far side
   showing at the bottom. The ring's wire is thinner than the hole, so a little
   of the hole shows above and below the metal — which is what says the ring
   goes *through* the page. */
.punch {
  left: 50%; width: 12px; height: 18px;
  margin: -9px 0 0 -6px;
  border-radius: 6px;
  background: linear-gradient(180deg, rgba(0,0,0,.88), rgba(0,0,0,.6) 66%, rgba(255,255,255,.12));
  box-shadow:
    inset 0 2px 3px rgba(0,0,0,.95),
    inset 0 -2px 0 rgba(255,255,255,.38),
    0 1px 0 rgba(255,255,255,.2),
    0 0 0 1px rgba(0,0,0,.35);
}

/* --------------------------------------------------------------- page head
   The page's caption: its number, its name (click to type one) and what the
   cards on it are worth. --head-h + --head-gap is the 28px band it has always
   taken, so pockets keep their size wherever it is drawn. */
.page-head {
  position: relative; z-index: 2;
  display: flex; align-items: center; gap: 10px;
  height: var(--head-h, 22px); margin-bottom: var(--head-gap, 6px);
  color: rgba(255,255,255,.84); flex: none;
}
/* …above the pockets, in the page's top margin (the binder's own layout).
   No fill: it sits on the cover board, which every theme keeps dark, and the
   letters carry their own shadow — a bar there would read as a second object. */
.page-head.is-top { margin: 0 0 var(--head-gap, 6px); }
/* A page's head is as wide as its pockets and never wider: a long name (or the
   input) ellipsizes instead of stretching the page. */
.bpage[data-page] > .page-head { width: 0; min-width: 100%; }
.page-title { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; }
/* The camera before the number when the page has record photos (binder.js pagePhotoMark): a click shows them. */
.page-no { display: inline-flex; align-items: center; }
.page-photos {
  display: inline-grid; place-items: center; flex: none;
  width: 20px; height: 20px; margin: -3px 5px -3px -3px; padding: 0;
  border: 0; border-radius: 6px; cursor: pointer;
  color: rgba(255, 255, 255, .92);
  background: rgba(0, 0, 0, .28);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16);
  transition: background var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out);
}
.page-photos:hover { background: color-mix(in srgb, var(--accent) 45%, rgba(0, 0, 0, .3)); color: #fff; }
.page-photos:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Cards only: on the desk, in its ink */
[data-frame="none"] .page-photos { color: var(--ink-2); background: color-mix(in srgb, var(--ink) 8%, transparent); box-shadow: inset 0 0 0 1px var(--line); }
@media print { .page-photos { display: none; } }
.page-no {
  flex: none; font-size: var(--fs-micro, 11px); font-weight: 650;
  letter-spacing: .1em; text-transform: uppercase;
  text-shadow: 0 1px 2px rgba(0,0,0,.45);
}
.page-sum {
  flex: none; margin-left: auto; font-size: 11.5px; font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--gold) 72%, #fff); font-weight: 650;
  text-shadow: 0 1px 2px rgba(0,0,0,.5);
}

/* The prices, in the page's bottom margin (the band .has-cap already adds
   under the pockets). Owned at the left, missing in the middle, the two
   together at the right. A binder that does not track owned cards has the
   one total, at the right, where the old figure sat. */
.page-foot {
  container-type: inline-size; container-name: pagefoot;
  position: absolute; z-index: 2; left: var(--board-pad, 18px); right: var(--board-pad, 18px); bottom: 0;
  box-sizing: border-box;
  height: calc(var(--board-pad, 18px) + var(--head-band, 28px) / 2);
  /* The pocket sheet overlaps this band by its own margin; the figures sit below that. */
  padding-top: 8px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  pointer-events: none;
  color: rgba(255,255,255,.84);
}
.page-foot.is-single { justify-content: flex-end; }
.page-money {
  display: inline-flex; align-items: baseline; gap: 4px; min-width: 0;
  pointer-events: auto;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0,0,0,.5);
}
.page-money-k {
  flex: none; font-size: 9px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: rgba(255,255,255,.7);
}
.page-money-v {
  font-size: 11.5px; font-weight: 650; color: rgba(255,255,255,.92);
}
.page-money.is-missing .page-money-v { color: rgba(255,255,255,.78); }
.page-money.is-total .page-money-v { color: color-mix(in srgb, var(--gold) 78%, #fff); }
.page-money .pm-short { display: none; }
@container pagefoot (max-width: 360px) {
  .page-money { gap: 3px; }
  .page-money-k { font-size: 8px; letter-spacing: .04em; }
  .page-money-v { font-size: 10px; }
  .page-money .pm-long { display: none; }
  .page-money .pm-short { display: inline; }
}

/* The page's name. It sits on the cover in both themes, so it is white on the
   board (every cover is dark) with a shadow for the lighter gradient stops. */
.page-name {
  display: inline-flex; align-items: center; gap: 5px;
  min-width: 0; max-width: 100%; height: var(--head-h, 22px);
  padding: 0 6px; margin: 0;
  font-size: 13px; font-weight: 600; letter-spacing: -0.005em; line-height: 1.35;
  color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.45);
  background: transparent; border: 1px solid transparent; border-radius: 6px;
}
.page-name.is-static { display: block; height: auto; padding: 0 2px; }
.page-name-t, .page-name.is-static { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.page-name-ico { display: inline-grid; flex: none; opacity: 0; transition: opacity var(--t-1) var(--ease-out); }

button.page-name {
  cursor: pointer;
  transition: background var(--t-1) var(--ease-out), border-color var(--t-1) var(--ease-out), opacity var(--t-1) var(--ease-out);
}
button.page-name:hover { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.24); }
button.page-name:focus-visible { outline: 2px solid rgba(255,255,255,.9); outline-offset: 1px; }
button.page-name:hover .page-name-ico,
button.page-name:focus-visible .page-name-ico { opacity: .85; }

/* No name yet: a quiet prompt that shows while you are on the page. */
.page-name.is-unnamed {
  font-size: 11.5px; font-weight: 550; letter-spacing: 0;
  color: rgba(255,255,255,.78); opacity: 0;
}
.page-name.is-unnamed .page-name-ico { order: -1; opacity: .85; }
.bpage:hover .page-name.is-unnamed { opacity: .8; }
.page-name.is-unnamed:hover,
.page-name.is-unnamed:focus-visible { opacity: 1; color: #fff; }
@media (hover: none) {
  .page-name.is-unnamed { opacity: .7; }
}
body.is-dragging-card .page-name.is-unnamed { opacity: 0; }

.page-name-input {
  flex: 1 1 auto; width: 100%; min-width: 0; height: var(--head-h, 22px);
  padding: 0 7px; margin: 0;
  font: inherit; font-size: 13px; font-weight: 600; color: #fff;
  background: rgba(0,0,0,.34); border: 1px solid rgba(255,255,255,.5); border-radius: 6px;
  caret-color: #fff;
}
.page-name-input::placeholder { color: rgba(255,255,255,.55); font-weight: 500; }
.page-name-input:focus { outline: none; border-color: rgba(255,255,255,.9); box-shadow: 0 0 0 3px rgba(255,255,255,.16); }

/* ========================================================== the pocket sheet
   One welded sheet of clear plastic lying on the board, reaching past the
   pockets to the board's margin and all the way to the rings. Its welds run
   down the gaps between pockets; a raking glare crosses it; the light off the
   gutter reflects along its hinge edge. Nothing in it takes the pointer. */
.sheet {
  position: relative;
  margin: -7px;
  padding: 7px;
  border-radius: 7px;
  background:
    linear-gradient(160deg, rgba(255,255,255,.07), rgba(255,255,255,.015) 38%, rgba(255,255,255,.055));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.3),
    inset 0 0 0 1px rgba(255,255,255,.07),
    inset 0 -1px 0 rgba(0,0,0,.34),
    0 1px 4px rgba(0,0,0,.35);
}
/* it runs on under the rings on the hinge side */
.bpage.left > .sheet  { margin-right: calc(-1 * var(--board-pad, 18px)); padding-right: var(--board-pad, 18px); border-radius: 7px 0 0 7px; }
.bpage.right > .sheet,
.bpage.solo > .sheet  { margin-left: calc(-1 * var(--board-pad, 18px)); padding-left: var(--board-pad, 18px); border-radius: 0 7px 7px 0; }

/* the welds: a hairline down the middle of every gap, both ways. Measured
   from the pockets' corner, not the sheet's: the layer takes the sheet's
   padding (more on the hinge side), so its content box — where the
   gradients start — is the grid. */
.sheet::before {
  content: ""; position: absolute; z-index: 0; inset: 0;
  padding: inherit;
  border-radius: inherit; pointer-events: none;
  background:
    repeating-linear-gradient(90deg,
      transparent 0 calc(var(--pocket-w, 100px) + var(--gap, 11px) / 2 - 1px),
      rgba(255,255,255,.085) calc(var(--pocket-w, 100px) + var(--gap, 11px) / 2 - 1px) calc(var(--pocket-w, 100px) + var(--gap, 11px) / 2),
      rgba(0,0,0,.2) calc(var(--pocket-w, 100px) + var(--gap, 11px) / 2) calc(var(--pocket-w, 100px) + var(--gap, 11px) / 2 + 1px),
      transparent calc(var(--pocket-w, 100px) + var(--gap, 11px) / 2 + 1px) calc(var(--pocket-w, 100px) + var(--gap, 11px))),
    repeating-linear-gradient(180deg,
      transparent 0 calc(var(--pocket-h, 140px) + var(--gap, 11px) / 2 - 1px),
      rgba(255,255,255,.085) calc(var(--pocket-h, 140px) + var(--gap, 11px) / 2 - 1px) calc(var(--pocket-h, 140px) + var(--gap, 11px) / 2),
      rgba(0,0,0,.2) calc(var(--pocket-h, 140px) + var(--gap, 11px) / 2) calc(var(--pocket-h, 140px) + var(--gap, 11px) / 2 + 1px),
      transparent calc(var(--pocket-h, 140px) + var(--gap, 11px) / 2 + 1px) calc(var(--pocket-h, 140px) + var(--gap, 11px)));
  background-origin: content-box;
  background-clip: padding-box;
}
/* The plastic itself: a raking glare band across the whole sheet and the
   reflection of the gutter along the hinge edge — both above the cards,
   because they are on the near side of the plastic. */
.sheet::after {
  content: ""; position: absolute; z-index: 4; inset: 0;
  border-radius: inherit; pointer-events: none;
  background:
    linear-gradient(var(--hinge), rgba(255,255,255,.1), rgba(255,255,255,.02) 6%, rgba(255,255,255,0) 15%),
    linear-gradient(112deg,
      rgba(255,255,255,0) 20%, rgba(255,255,255,.045) 31%, rgba(255,255,255,.085) 36%,
      rgba(255,255,255,.02) 41%, rgba(255,255,255,0) 54%);
}

.grid { position: relative; z-index: 1; display: grid; gap: var(--gap, 11px); }

/* ================================================================= pockets */
.pocket {
  position: relative;
  aspect-ratio: var(--card-ratio);
  border-radius: 6px;
  background: linear-gradient(180deg, rgba(0,0,0,.4), rgba(0,0,0,.26) 14%, rgba(0,0,0,.34));
  /* the weld ring round the pocket, the well's own shading, and the seam ridge */
  box-shadow:
    inset 0 2px 5px rgba(0,0,0,.5),
    inset 0 0 0 1px rgba(255,255,255,.07),
    0 0 0 1px rgba(0,0,0,.22),
    0 1px 0 rgba(255,255,255,.07);
  transition: box-shadow var(--t-1) var(--ease-out), transform var(--t-1) var(--ease-out);
}
/* the pocket's lip: the open top edge of the welded pouch, lit from above — a
   thin edge of light, never more than a few pixels, however big the pocket. It
   is on the near side of the plastic, so over the card: no shadow under it,
   which would cross the card's art as a dark line. */
.pocket::before {
  content: ""; position: absolute; z-index: 2; left: 0; right: 0; top: 0;
  height: clamp(3px, 2.5%, 6px); border-radius: 6px 6px 0 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(255,255,255,.24), rgba(255,255,255,.07) 60%, rgba(255,255,255,0));
}
.pocket.is-empty::after {
  content: "";
  position: absolute; inset: 9px;
  border: 1.5px dashed rgba(255,255,255,.2);
  border-radius: 5px;
}
.pocket.is-over {
  box-shadow:
    inset 0 0 0 2px var(--gold),
    0 0 0 3px color-mix(in srgb, var(--gold) 30%, transparent),
    0 0 18px color-mix(in srgb, var(--gold) 35%, transparent);
  transform: scale(1.02);
}
/* A pocket the library sent you to (app.js flashPocket) flashes gold: the rule
   and its keyframes belong to shell.css, so they are not repeated here — its
   last keyframe still ends on the pocket's old inner shadow, which is close
   enough not to show, and is the shell's to retune. */
.is-drag-source { opacity: .3; }

/* The card that follows the pointer during a drag. */
.drag-ghost {
  position: fixed; top: 0; left: 0; z-index: 90;
  width: 68px; pointer-events: none;
  filter: drop-shadow(0 10px 20px rgba(0,0,0,.5));
  transform: translate(-999px, -999px);
  rotate: -4deg;
}
.drag-ghost img { width: 100%; aspect-ratio: var(--card-ratio); object-fit: cover; border-radius: 5px; display: block; }
/* Held at a screen edge (dnd.js, touch): a ring runs once around the card, then the page turns. */
.drag-ghost-ring {
  position: absolute; inset: -4px; width: calc(100% + 8px); height: calc(100% + 8px); overflow: visible; pointer-events: none;
  fill: none; stroke: var(--accent); stroke-width: 3.5; stroke-linecap: round;
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: spring-fill var(--spring-ms, 750ms) linear forwards;
}
.drag-ghost.is-edge-springing { filter: drop-shadow(0 10px 20px rgba(0,0,0,.5)) drop-shadow(0 0 10px color-mix(in srgb, var(--accent) 45%, transparent)); }
/* and the edge itself lights up, so it reads as the way to the next page */
body[data-drag-edge]::after {
  content: ""; position: fixed; top: 0; bottom: 0; width: 44px; z-index: 89; pointer-events: none;
  background: linear-gradient(to right, color-mix(in srgb, var(--accent) 38%, transparent), transparent);
}
body[data-drag-edge="prev"]::after { left: 0; }
body[data-drag-edge="next"]::after { right: 0; transform: scaleX(-1); }
body.is-dragging-card { cursor: grabbing; user-select: none; }
body.is-dragging-card .slot-card:hover { transform: none; box-shadow: var(--shadow-card); }

/* ==================================================== a card in its pocket
   --in-t / --in-x / --in-b are how far the card sits inside its holder (Binder
   settings → How cards are held); 0 for a card straight in the pocket. The
   card is an inline-size container, so everything drawn on it is in `cqi` and
   scales with the pocket, however big. The pocket is one too: the card's own
   radius and margins in `cqi` measure against the nearest container above it
   — in the binder, in a page turn's copies of its pages (pageturn.js puts
   them beside the binder, not in it: without this a missing card's glow
   there would be measured against the whole window), in a thumbnail, and in
   Binder settings' preview and its style tiles (else measured against the dialog). */
#binder .pocket, .turn-layer .pocket, .ar-thumb .pocket,
.set-preview .pocket, .opt-page .pocket { container-type: inline-size; }
.slot-card {
  --in-t: 0%; --in-x: 0%; --in-b: 0%; --in-r: 0px;
  container-type: inline-size;
  position: absolute; inset: 0;
  border-radius: 6px; overflow: hidden;
  cursor: grab; background: var(--pocket);
  box-shadow: var(--shadow-card);
  transition: transform var(--t-1) var(--ease-out), box-shadow var(--t-1) var(--ease-out);
  touch-action: none;
}
.slot-card:active { cursor: grabbing; }
.slot-card:hover { transform: translateY(-3px) scale(1.015); box-shadow: 0 10px 22px rgba(0,0,0,.55); z-index: 3; }
.slot-card img {
  position: absolute; top: var(--in-t); left: var(--in-x); right: var(--in-x); bottom: var(--in-b);
  width: calc(100% - 2 * var(--in-x)); height: calc(100% - var(--in-t) - var(--in-b));
  object-fit: cover; display: block; border-radius: var(--in-r);
  /* the art's own edge, so a card reads as printed stock sitting in plastic */
  outline: 1px solid rgba(0,0,0,.3); outline-offset: -1px;
}
/* The foil sheen (design.css paints it from --mx/--my) belongs on the art, not
   on the holder around it; this only trims it to the card. */
.slot-card[data-foil]::after {
  inset: var(--in-t) var(--in-x) var(--in-b);
  border-radius: var(--in-r);
}
.slot-card[data-foil].is-foil::after { opacity: .2; }
.slot-card[data-foil].is-foil::before { inset: var(--in-t) var(--in-x) var(--in-b); border-radius: var(--in-r); }

/* ------------------------------------------------ missing cards (Binder settings) */
/* stamped (the default): greyscale, darkened, with a MISSING stamp */
.slot-card.is-missing img { filter: grayscale(1) brightness(.42); }
.slot-miss {
  position: absolute; z-index: 3; left: 50%;
  top: calc(var(--in-t) + (100% - var(--in-t) - var(--in-b)) / 2);
  transform: translate(-50%,-50%) rotate(-12deg);
  font-size: clamp(7px, 8.5cqi, 15px); font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(255,255,255,.82);
  border: clamp(1px, 1.4cqi, 2px) solid rgba(255,255,255,.6); border-radius: 3px;
  padding: clamp(1px, 2cqi, 3px) clamp(3px, 5.5cqi, 7px); white-space: nowrap; pointer-events: none;
}
.slot-ghost { display: none; }
/* greyscale only */
[data-missing="grey"] .slot-card.is-missing img { filter: grayscale(1); }
/* faded colour */
[data-missing="dim"] .slot-card.is-missing img { filter: none; opacity: .32; }
/* full colour, a small corner badge */
[data-missing="badge"] .slot-card.is-missing img { filter: none; }
[data-missing="badge"] .slot-miss {
  top: calc(var(--in-t) + 4px); left: calc(var(--in-x) + 4px); transform: none;
  padding: 1.5px 5px; border: none; border-radius: 4px;
  font-size: clamp(7px, 7.5cqi, 12px); letter-spacing: .08em; color: #fff;
  background: color-mix(in srgb, var(--danger) 88%, #000); box-shadow: 0 1px 3px rgba(0,0,0,.4);
}
/* Under it, not beside it, the card's number and rarity: on a small pocket the
   badge reached across and covered them ("MISSING /30"). */
[data-missing="badge"] .slot-card.is-missing .slot-tags {
  top: calc(var(--in-t) + 4px + 1.3 * clamp(7px, 7.5cqi, 12px) + 3px + 3px);
}
/* …and a red ring and glow round the card, so a missing one in full colour still
   stands out at a glance. An outline and a drop-shadow rather than a box-shadow:
   they go over whatever shadow the card's holder casts, and follow its shape. A
   card tapped on a phone keeps its accent ring (is-menu) instead. */
[data-missing="badge"] .slot-card.is-missing {
  --miss-red: color-mix(in srgb, var(--danger) 55%, #ff2a2a);
  filter:
    drop-shadow(0 0 max(2px, 2cqi) color-mix(in srgb, var(--miss-red) 90%, transparent))
    drop-shadow(0 0 max(6px, 7cqi) color-mix(in srgb, var(--miss-red) 60%, transparent));
}
[data-missing="badge"] .slot-card.is-missing:not(.is-menu) {
  outline: max(1px, .8cqi) solid var(--miss-red);
  outline-offset: max(1px, .8cqi);
}
[data-missing="grey"] .slot-miss,
[data-missing="dim"] .slot-miss,
[data-missing="hidden"] .slot-miss { display: none; }
/* hidden: an empty-looking pocket that keeps its place — a faint outline and the card's number */
[data-missing="hidden"] .slot-card.is-missing { background: transparent; box-shadow: none; }
[data-missing="hidden"] .slot-card.is-missing::before,
[data-missing="hidden"] .slot-card.is-missing::after { content: none; }
[data-missing="hidden"] .slot-card.is-missing > .holder { display: none; }
[data-missing="hidden"] .slot-card.is-missing img,
[data-missing="hidden"] .slot-card.is-missing .slot-label,
[data-missing="hidden"] .slot-card.is-missing .slot-tags,
[data-missing="hidden"] .slot-card.is-missing .slot-price { visibility: hidden; }
[data-missing="hidden"] .slot-card.is-missing .slot-ghost {
  display: grid; place-items: center;
  position: absolute; inset: 7px; padding: 4px;
  border: 1.5px dashed rgba(255,255,255,.26); border-radius: 5px;
  font-size: clamp(9px, 10cqi, 18px); font-weight: 650; text-align: center; line-height: 1.2;
  color: rgba(255,255,255,.55); overflow: hidden; overflow-wrap: anywhere; pointer-events: none;
}
[data-missing="hidden"] .slot-card.is-missing:hover { transform: none; box-shadow: none; }
[data-missing="hidden"] .slot-card.is-missing:hover .slot-ghost { border-color: rgba(255,255,255,.45); color: rgba(255,255,255,.8); }

/* The quick view (All · Owned · Missing) dims what it is not picking out, in place. */
.pocket.is-muted .slot-card { opacity: .2; filter: saturate(.4); }
.pocket.is-muted .slot-card:hover { opacity: .75; filter: none; }

.slot-price {
  position: absolute; z-index: 2; left: calc(var(--in-x) + 4px); bottom: calc(var(--in-b) + 4px);
  font-size: clamp(8px, 9cqi, 15px); font-weight: 700; font-variant-numeric: tabular-nums;
  background: rgba(8,10,14,.82); color: color-mix(in srgb, var(--gold) 82%, #fff);
  padding: 1.5px 5px; border-radius: 4px;
  box-shadow: 0 1px 2px rgba(0,0,0,.4);
}
/* An estimate (no market price yet): quieter, with a dashed edge, the same size. It sits
   on the card art in both themes, so it keeps the badge's own dark ground. */
.slot-price.is-est {
  padding: .5px 4px;
  font-weight: 650;
  color: color-mix(in srgb, var(--gold) 70%, #fff);
  background: rgba(8,10,14,.7);
  border: 1px dashed color-mix(in srgb, var(--gold) 85%, #fff);
  cursor: help;
}
.page-sum.is-est, .page-money.is-est { cursor: help; }
/* The owner's own price (card dialog → Your price): ringed in the accent. */
.slot-price.is-own { box-shadow: inset 0 0 0 1.5px var(--accent); }
/* Card badges (Binder settings → Display): collector number and rarity, top right. */
.slot-tags {
  position: absolute; z-index: 2; right: calc(var(--in-x) + 4px); top: calc(var(--in-t) + 4px);
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px; pointer-events: none;
}
.slot-num, .slot-rar {
  font-size: clamp(7.5px, 8cqi, 14px); font-weight: 600; line-height: 1.35; white-space: nowrap;
  background: rgba(8,10,14,.72); color: rgba(255,255,255,.8);
  padding: 1px 4px; border-radius: 3px;
}
.slot-rar { font-weight: 700; color: rgba(255,255,255,.92); }
.slot-stars { color: color-mix(in srgb, var(--gold) 78%, #fff); letter-spacing: -.04em; }

/* The card's actions (binder.js cardActions): a glass bar standing upright
   inside the card along its right edge, centred, shown under the pointer or
   when a button in it has the keyboard. The buttons grow with the card (up to
   34px). They stand in one column when it fits in the card, and otherwise in
   two even ones (--n is how many there are): the rows repeat as far as the
   bar's height allows, empty ones folding away, so however small the pocket,
   every button is there and none is cut off. */
.slot-actions {
  /* Fewer buttons than there were (binder.js cardActions), so each is larger. */
  --b: clamp(16px, 25cqi, 32px); --g: clamp(2px, 3cqi, 5px); --p: 0px; --m: max(3px, 3cqi);
  --room: calc(100% - var(--in-t) - var(--in-b) - 2 * var(--m));
  position: absolute; z-index: 4;
  right: calc(var(--in-x) + var(--m));
  top: calc(50% + (var(--in-t) - var(--in-b)) / 2);
  max-height: var(--room);
  display: grid; grid-auto-flow: column;
  grid-template-rows: repeat(auto-fit, var(--b)); grid-auto-columns: var(--b);
  gap: var(--g); padding: var(--p);
  opacity: 0; transform: translate(5px, -50%) scale(.96); transform-origin: right center;
  transition: opacity var(--t-2) var(--ease-out), transform var(--t-2) var(--ease-out);
  pointer-events: none;
}
/* The height of one column of them all, and of half of them: one column where
   the first fits, two of the second's height where it does not (round() is 0
   short of a whole column, which max() then passes over). Half a pixel over,
   so the rows that should fit are never a rounding error short. */
@supports (max-height: round(down, 10px, 3px)) {
  .slot-actions {
    --one: calc(var(--n, 5) * (var(--b) + var(--g)) - var(--g) + 2 * var(--p) + .5px);
    --half: calc(round(up, var(--n, 5) / 2, 1) * (var(--b) + var(--g)) - var(--g) + 2 * var(--p) + .5px);
    max-height: max(min(var(--half), var(--room)), min(round(down, var(--room), var(--one)), var(--one)));
  }
}
/* Up under a real pointer only: a touch screen gets the card's panel instead (binder.js drawCardPanel). */
@media (hover: hover) {
  .slot-card:hover .slot-actions { opacity: 1; transform: translate(0, -50%) scale(1); pointer-events: auto; }
}
.slot-card:focus-within .slot-actions { opacity: 1; transform: translate(0, -50%) scale(1); pointer-events: auto; }
body.is-dragging-card .slot-actions { display: none; }
/* Each action a small glass button of its own. */
.slot-btn {
  position: relative;
  width: var(--b); height: var(--b); display: grid; place-items: center; flex: none;
  color: rgba(255,255,255,.92);
  background: color-mix(in srgb, #0a0c12 70%, transparent);
  -webkit-backdrop-filter: blur(8px) saturate(1.4); backdrop-filter: blur(8px) saturate(1.4);
  border: none; border-radius: calc(var(--b) * .32); cursor: pointer; padding: 0;
  box-shadow: 0 2px 6px rgba(0,0,0,.4), inset 0 0 0 1px rgba(255,255,255,.14), inset 0 1px 0 rgba(255,255,255,.12);
  transition: background var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out), transform var(--t-1) var(--ease-out);
}
.slot-btn > span { display: grid; place-items: center; width: 62%; height: 62%; }
.slot-btn svg { display: block; width: 100%; height: 100%; }
/* Each action in its own colour (binder.js cardActions sets data-key): the icon in it on the dark
   glass, a wash of it behind an action that is on, and the whole button in it under the pointer. */
.slot-btn[data-key] { color: var(--tint, rgba(255,255,255,.92)); }
.slot-btn[data-key="owned"] { --tint: #4ade80; }
.slot-btn[data-key="missing"] { --tint: #fbbf24; }
.slot-btn[data-key="trade"] { --tint: #fb923c; }
.slot-btn[data-key="lock"], .slot-btn[data-key="unlock"] { --tint: #818cf8; }
.slot-btn[data-key="cover"] { --tint: #facc15; }
.slot-btn[data-key="info"] { --tint: #60a5fa; }
.slot-btn[data-key="replace"] { --tint: #22d3ee; }
.slot-btn[data-key="copy"] { --tint: #2dd4bf; }
.slot-btn[data-key="sold"] { --tint: #f472b6; }
.slot-btn[data-key="grading"] { --tint: #c084fc; }
.slot-btn[data-key="remove"] { --tint: #f87171; }
.slot-btn[data-key="tcgplayer"] { --tint: #34d399; }
.slot-btn:hover { background: color-mix(in srgb, #1b2130 82%, transparent); color: #fff; transform: scale(1.08); }
.slot-btn[data-key]:hover { background: color-mix(in srgb, var(--tint, #1b2130) 78%, #0a0c12); }
.slot-btn.is-on { color: var(--accent); }
.slot-btn[data-key].is-on { color: var(--tint); background: color-mix(in srgb, var(--tint) 26%, color-mix(in srgb, #0a0c12 70%, transparent)); }
.slot-btn[data-key].is-on:hover { color: #fff; background: color-mix(in srgb, var(--tint) 78%, #0a0c12); }
.slot-btn.danger:hover { background: var(--danger); color: #fff; }
.slot-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* What a button does (binder.js showSlotTip): a label fixed to the window,
   level with the button, just beside it — over the card, as the big preview
   (.card-peek) takes the room outside it — and never cut off by the card. */
.slot-tip {
  position: fixed; z-index: 75; top: 0; left: 0;
  padding: 5px 9px; border-radius: 7px; white-space: nowrap;
  font-size: 12px; font-weight: 600; letter-spacing: .01em; line-height: 1.2;
  background: rgba(8,10,14,.92); color: #fff;
  box-shadow: 0 4px 12px rgba(0,0,0,.4), inset 0 0 0 1px rgba(255,255,255,.08);
  opacity: 0; transform: translate(var(--tip-from, -4px), -50%); pointer-events: none;
  transition: opacity var(--t-1) var(--ease-out), transform var(--t-1) var(--ease-out);
}
.slot-tip[data-side="left"] { --tip-from: 4px; }
.slot-tip.is-on { opacity: 1; transform: translate(0, -50%); }
body.is-dragging-card .slot-tip { display: none; }

/* A finger gets the card's panel beside it instead (binder.js drawCardPanel):
   there is no bar on the card itself, and the card the panel belongs to lifts
   a little, ringed in the accent, so it is clear which one it is about. */
@media (hover: none), (pointer: coarse) {
  .slot-actions { display: none; }
  .slot-card.is-menu {
    z-index: 5;
    outline: 2px solid var(--accent); outline-offset: 2px;
    box-shadow: 0 10px 24px rgba(0,0,0,.5), 0 0 0 5px color-mix(in srgb, var(--accent) 22%, transparent);
  }
  /* The card you tapped is the one you are looking at: show it in colour, even when
     the pocket marks missing cards grey or faded. */
  .slot-card.is-missing.is-menu img { filter: none; opacity: 1; }
  :root:not([data-motion="off"]) .slot-card.is-menu { transform: translateY(-2px) scale(1.03); }
}

/* ---- the card's panel (touch): fixed beside the card, over the rest of the
   page; its caret points at the card, its own list scrolls when it is taller
   than the room between the toolbar and the bottom bar. It wears the card
   dialog's look: the card's colours washed behind its top, the art lit from
   behind, chips for what the card is, the price large in gold, and each action
   on a tile in the colour its button wears on the card (--tone). */
.pocket-panel {
  position: fixed; z-index: 46;
  --cp-bg: color-mix(in srgb, var(--bg-2) 94%, var(--ink));
  background: var(--cp-bg);
  border-radius: 20px;
  box-shadow: 0 26px 56px rgba(0,0,0,.6), 0 0 0 1px color-mix(in srgb, var(--ink) 10%, var(--line)), inset 0 1px 0 rgba(255,255,255,.07);
}
:root[data-theme="light"] .pocket-panel { box-shadow: 0 18px 40px rgba(20,24,32,.22), 0 0 0 1px var(--line); }
.cp-caret {
  position: absolute; top: calc(var(--caret-y, 50%) - 7px);
  width: 14px; height: 14px; rotate: 45deg; border-radius: 3px;
  background: var(--cp-bg);
  box-shadow: -1px 1px 0 var(--line);
}
.pocket-panel[data-side="right"] .cp-caret { left: -6px; }
.pocket-panel[data-side="left"] .cp-caret { right: -6px; box-shadow: 1px -1px 0 var(--line); }
.cp-body {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column; gap: 11px;
  max-height: var(--cp-max-h, 70vh); padding: 12px;
  overflow-y: auto; overscroll-behavior: contain; border-radius: inherit;
}
.cp-ambient {
  position: absolute; inset: 0 0 auto; height: 260px; z-index: -1; overflow: hidden; pointer-events: none;
  border-radius: inherit;
  -webkit-mask-image: linear-gradient(180deg, #000, transparent);
          mask-image: linear-gradient(180deg, #000, transparent);
}
.cp-ambient img { display: block; width: 100%; height: 100%; object-fit: cover; filter: blur(34px) saturate(1.8); opacity: .5; transform: scale(1.4); }
:root[data-theme="light"] .cp-ambient img { opacity: .32; }
.cp-art {
  align-self: center; flex: none;
  /* By the room the panel has (--cp-max-h, binder.js), not the window's: on a
     short screen the art took it all and pushed the actions out of sight. */
  width: min(100%, calc(min(40vh, 340px, var(--cp-max-h, 70vh) * .42) * .714));
  border-radius: 4.6% / 3.3%; overflow: hidden;
  box-shadow: 0 18px 32px -12px rgba(0,0,0,.7), 0 0 0 1px rgba(255,255,255,.1);
}
.cp-art img { display: block; width: 100%; aspect-ratio: var(--card-ratio, .714); object-fit: cover; background: var(--bg-3); }
.cp-info { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.cp-name { font-size: 16px; font-weight: 760; letter-spacing: -0.015em; line-height: 1.22; color: var(--ink); overflow-wrap: anywhere; }
.cp-meta { display: flex; flex-wrap: wrap; gap: 4px; }
.cp-chip {
  display: inline-flex; align-items: center; height: 21px; padding: 0 8px; border-radius: var(--radius-pill);
  font-size: 11px; font-weight: 650; color: var(--ink-2); white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
  background: color-mix(in srgb, var(--bg-3) 75%, transparent); border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
}
.cp-chip.is-rarity { color: var(--gold-text); border-color: color-mix(in srgb, var(--gold) 38%, transparent); background: color-mix(in srgb, var(--gold) 12%, transparent); }
.cp-grade {
  align-self: flex-start; font-size: 12px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ink);
  padding: 2px 8px 2px 9px; border-radius: 6px; background: var(--bg-3);
  box-shadow: inset 3px 0 0 var(--tone, var(--ink-3)), inset 0 0 0 1px var(--line);
}
/* the price, large and gold, with what it is in small capitals beside it */
.cp-price { display: flex; align-items: baseline; gap: 7px; margin-top: 2px; }
.cp-price b { font-size: 22px; font-weight: 760; letter-spacing: -0.025em; color: var(--gold-text); font-variant-numeric: tabular-nums; }
.cp-price span { font-size: 10px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); }
.cp-price.is-est b { color: var(--ink-2); }
.cp-price.is-own b { padding: 0 6px; border-radius: 6px; box-shadow: inset 0 0 0 1.5px var(--accent); }
/* Its details: under the price, across the panel, in the accent: the way to all the rest of it. */
.cp-details {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; margin-top: 4px; padding: 0 12px 0 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--line)); border-radius: 13px; cursor: pointer;
  font: inherit; font-size: 14.5px; font-weight: 700; letter-spacing: -0.01em;
  color: var(--accent-text); background: color-mix(in srgb, var(--accent) 14%, var(--bg-3));
  transition: scale var(--t-1) var(--ease-out), background var(--t-1) var(--ease-out);
}
.cp-details .cp-ico { color: var(--accent-text); background: color-mix(in srgb, var(--accent) 20%, transparent); }
.cp-details-label { flex: 1; text-align: left; }
.cp-details-go { display: grid; place-items: center; opacity: .75; }
.cp-details:active { scale: .98; background: color-mix(in srgb, var(--accent) 22%, var(--bg-3)); }
.cp-details:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cp-flag { align-self: flex-start; font-size: 11px; font-weight: 700; color: #fbbf24; padding: 2px 8px; border-radius: var(--radius-pill); background: color-mix(in srgb, #fbbf24 14%, transparent); }
.cp-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.pocket-panel.is-narrow .cp-actions { grid-template-columns: minmax(0, 1fr); }
.pocket-panel.is-narrow .cp-name { font-size: 14px; }
.cp-btn {
  --tone: var(--accent);
  --tone-text: var(--tone);
  /* a tile, as the card dialog's actions are: the icon over its name, which has the tile's whole width */
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; min-width: 0;
  min-height: 64px; padding: 8px 4px 7px;
  border: 1px solid var(--line); border-radius: 12px; cursor: pointer;
  background: color-mix(in srgb, var(--bg-3) 70%, transparent);
  color: var(--ink); font: inherit; font-size: 12px; font-weight: 600; line-height: 1.2; text-align: center;
  transition: background var(--t-1) var(--ease-out), border-color var(--t-1) var(--ease-out), scale var(--t-1) var(--ease-out);
}
.cp-btn:active { background: color-mix(in srgb, var(--tone) 12%, var(--bg-3)); scale: .97; }
.cp-btn.is-on { border-color: color-mix(in srgb, var(--tone) 50%, var(--line)); background: color-mix(in srgb, var(--tone) 12%, var(--bg-3)); }
.cp-btn:focus-visible { outline: 2px solid var(--tone); outline-offset: 1px; }
/* each action's icon on a tile of its own colour; lit solid when it is on */
.cp-ico {
  display: grid; place-items: center; flex: none; width: 28px; height: 28px; border-radius: 9px;
  color: var(--tone-text); background: color-mix(in srgb, var(--tone) 16%, transparent);
}
.cp-ico svg { width: 16px; height: 16px; }
.cp-btn.is-on .cp-ico { color: #0b0d12; background: var(--tone); }
.cp-act-select { --tone: var(--accent); }
.cp-act-owned { --tone: #4ade80; }
.cp-act-missing { --tone: #fbbf24; }
.cp-act-trade { --tone: #fb923c; }
.cp-act-lock, .cp-act-unlock { --tone: #818cf8; }
.cp-act-cover { --tone: #facc15; }
.cp-act-info { --tone: #60a5fa; }
.cp-act-replace { --tone: #22d3ee; }
.cp-act-copy { --tone: #2dd4bf; }
.cp-act-insert { --tone: #a78bfa; }
.cp-act-sold { --tone: #f472b6; }
.cp-act-grading { --tone: #c084fc; }
.cp-act-tcgplayer { --tone: #34d399; }
.cp-btn.is-danger { --tone: #f87171; color: var(--danger); }
:root[data-theme="light"] .cp-btn { --tone-text: color-mix(in srgb, var(--tone) 60%, #000); }
.cp-label { min-width: 0; max-width: 100%; overflow-wrap: break-word; }
/* one column (a narrow panel): back to a row, the icon beside its name */
.pocket-panel.is-narrow .cp-btn { flex-direction: row; justify-content: flex-start; min-height: 46px; padding: 0 8px 0 6px; gap: 8px; text-align: left; }
/* One long word ("TCGplayer"): a touch smaller rather than broken in two. */
.cp-btn.cp-act-tcgplayer .cp-label { overflow-wrap: normal; font-size: .86em; letter-spacing: -0.01em; }
/* In from the card's side, springing a little at Full; a fade at Reduced; nothing at Off. */
:root[data-motion="full"] .pocket-panel.is-entering { animation: cp-in 320ms var(--ease-spring); }
:root[data-motion="reduced"] .pocket-panel.is-entering { animation: cp-fade 160ms var(--ease-out); }
.pocket-panel.is-leaving { animation: cp-fade 150ms var(--ease-out) reverse forwards; pointer-events: none; }
:root[data-motion="off"] .pocket-panel.is-leaving { animation: none; display: none; }
@keyframes cp-in {
  from { opacity: 0; translate: var(--cp-from, -12px) 0; scale: .96; }
}
.pocket-panel[data-side="left"] { --cp-from: 12px; }
@keyframes cp-fade { from { opacity: 0; } }
/* ---- on a phone: a sheet from the bottom, as the menu and the binder's actions
   are (binder.js sheetWide), over a dimmed page — a grab bar and a × at its top,
   the card large beside what it is, and its actions as a grid of tiles under them. */
.cp-scrim {
  position: fixed; inset: 0; z-index: 89; touch-action: none;
  background: rgba(4, 6, 10, .46);
  animation: cp-fade var(--t-2) var(--ease-out);
}
.cp-scrim.is-leaving { animation: cp-fade 200ms var(--ease-out) reverse forwards; pointer-events: none; }
.pocket-panel.is-sheet {
  left: 0; right: 0; bottom: 0; top: auto; width: auto; z-index: 90;
  max-height: 88dvh; display: flex; flex-direction: column; overflow: hidden;
  border-radius: 22px 22px 0 0;
  padding: 0 max(4px, env(safe-area-inset-right, 0px)) env(safe-area-inset-bottom, 0px) max(4px, env(safe-area-inset-left, 0px));
  background:
    radial-gradient(120% 50% at 50% -10%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 60%),
    var(--cp-bg);
}
/* Over the top of its list, so the card's colours wash right up to the sheet's edge. */
.cp-sheet-top { position: absolute; z-index: 2; top: 0; left: 0; right: 0; display: flex; align-items: center; justify-content: center; height: 34px; pointer-events: none; }
.cp-sheet-top > * { pointer-events: auto; }
.cp-grab { width: 40px; height: 5px; border-radius: 3px; background: color-mix(in srgb, var(--ink) 28%, transparent); }
.cp-x {
  position: absolute; right: 10px; top: 8px;
  display: grid; place-items: center; width: 36px; height: 36px; padding: 0;
  border: 0; border-radius: 50%; cursor: pointer; background: var(--bg-3); color: var(--ink-2);
}
.pocket-panel.is-sheet .cp-body {
  display: grid; grid-template-columns: minmax(0, 42%) minmax(0, 1fr); align-items: start; gap: 14px 14px;
  padding: 40px 14px 16px; border-radius: inherit;
}
.pocket-panel.is-sheet .cp-art { grid-column: 1; grid-row: 1; width: 100%; max-width: 200px; justify-self: center; }
.pocket-panel.is-sheet .cp-info { grid-column: 2; grid-row: 1; gap: 8px; padding-top: 4px; }
/* The column as tall as the card beside it, View Details at its foot: level with the card's bottom edge. */
.pocket-panel.is-sheet .cp-info { align-self: stretch; }
.pocket-panel.is-sheet .cp-details { margin-top: auto; }
.pocket-panel.is-sheet .cp-name { font-size: 19px; }
.pocket-panel.is-sheet .cp-price b { font-size: 26px; }
.pocket-panel.is-sheet .cp-actions { grid-column: 1 / -1; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.pocket-panel.is-sheet .cp-btn { min-height: 76px; font-size: 12.5px; border-radius: 14px; }
.pocket-panel.is-sheet .cp-ico { width: 32px; height: 32px; border-radius: 10px; }
.pocket-panel.is-sheet .cp-ico svg { width: 18px; height: 18px; }
:root[data-motion="full"] .pocket-panel.is-sheet.is-entering,
:root[data-motion="reduced"] .pocket-panel.is-sheet.is-entering { animation: cp-sheet-in 300ms var(--ease-out); }
.pocket-panel.is-sheet.is-leaving { animation: cp-sheet-in 220ms var(--ease-out) reverse forwards; }
@keyframes cp-sheet-in { from { transform: translateY(100%); } }
:root[data-motion="off"] .cp-scrim { animation: none; }

/* A phone on its side: the art beside the words and buttons, not above them. */
@media (max-height: 500px) {
  .cp-body { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; column-gap: 12px; }
  .cp-body > .cp-art { grid-row: 1 / span 3; width: calc(min(var(--cp-max-h, 70vh) - 20px, 220px) * .714); }
  .cp-body > :not(.cp-art):not(.cp-ambient) { grid-column: 2; }
}

/* A card locked in its pocket (the bar's padlock): a small padlock in its
   corner, and it cannot be picked up, replaced or removed. */
.slot-lock {
  position: absolute; z-index: 3; left: calc(var(--in-x) + max(3px, 2.4cqi)); top: calc(var(--in-t) + max(3px, 2.4cqi));
  width: clamp(14px, 11cqi, 22px); height: clamp(14px, 11cqi, 22px);
  display: grid; place-items: center; border-radius: 999px;
  background: color-mix(in srgb, #0a0c12 70%, transparent); color: var(--accent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 60%, transparent);
  pointer-events: none;
}
.slot-lock svg { width: 60%; height: 60%; }
.slot-card.is-locked { cursor: pointer; }

/* The owner's cover card (the bar's star): a small star in the other corner. */
.slot-cover {
  position: absolute; z-index: 3; right: calc(var(--in-x) + max(3px, 2.4cqi)); top: calc(var(--in-t) + max(3px, 2.4cqi) + clamp(14px, 11cqi, 22px) + 3px);
  width: clamp(14px, 11cqi, 22px); height: clamp(14px, 11cqi, 22px);
  display: grid; place-items: center; border-radius: 999px;
  background: color-mix(in srgb, #0a0c12 70%, transparent); color: var(--gold);
  pointer-events: none;
}
.slot-cover svg { width: 62%; height: 62%; }

/* ---- an empty pocket you can fill: a soft glass tile with a plus, lit in the
   accent under the pointer (overrides the older look in search.css). */
#binder .pocket-add {
  position: absolute; inset: 9px; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: max(4px, 5cqi);
  border-radius: 8px; opacity: 0; pointer-events: none;
  background:
    radial-gradient(120% 90% at 50% 40%, color-mix(in srgb, var(--accent) 22%, transparent), transparent 70%),
    color-mix(in srgb, #0a0c12 38%, transparent);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 55%, transparent), 0 8px 24px color-mix(in srgb, var(--accent) 16%, transparent);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  transform: scale(.97);
  transition: opacity var(--t-2) var(--ease-out), transform var(--t-2) var(--ease-out);
}
#binder .pocket.is-addable:hover .pocket-add,
#binder .pocket.is-addable:focus-visible .pocket-add { opacity: 1; transform: none; }
#binder .pocket-add-plus {
  width: clamp(26px, 30cqi, 52px); height: clamp(26px, 30cqi, 52px);
  display: grid; place-items: center; border-radius: 999px;
  font-size: 0; line-height: 0;
  background: linear-gradient(145deg, color-mix(in srgb, var(--accent) 92%, #fff), var(--accent));
  color: var(--accent-ink);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 45%, transparent), inset 0 1px 0 rgba(255,255,255,.45);
  transition: transform var(--t-2) var(--ease-spring, var(--ease-out));
}
#binder .pocket-add-plus svg { width: 46%; height: 46%; }
#binder .pocket.is-addable:hover .pocket-add-plus { transform: rotate(90deg); }
#binder .pocket-add-label {
  font-size: clamp(9px, 9cqi, 13px); font-weight: 650; letter-spacing: .04em; text-transform: uppercase;
  color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,.6);
}
@container (max-width: 72px) { #binder .pocket-add-label { display: none; } }
@media (hover: none) {
  /* No hover on a touch screen: a quiet plus is always there to tap. */
  #binder .pocket.is-addable .pocket-add { opacity: .55; transform: none; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent); background: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
  #binder .pocket-add-label { display: none; }
}

/* ---- the sleeve / holder colour (Binder settings → Display): tints the edge of
   a coloured sleeve, a penny sleeve, a top loader or a slab. */
[data-holder="sleeve"] .slot-card {
  --in-t: 3.2%; --in-x: 3.6%; --in-b: 3.2%; --in-r: max(1px, 1.6cqi);
  border-radius: max(3px, 4.4cqi);
  background: var(--holder-tint, #1f2937);
  box-shadow: var(--shadow-card), inset 0 0 0 1px rgba(255,255,255,.12);
}
[data-holder="sleeve"] .holder {
  background:
    linear-gradient(115deg, rgba(255,255,255,0) 30%, rgba(255,255,255,.14) 40%, rgba(255,255,255,0) 52%),
    linear-gradient(180deg, rgba(255,255,255,.14), rgba(255,255,255,0) 20%, rgba(0,0,0,.12));
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.25);
}
[data-holder="sleeve"] .slot-card img { border-radius: max(2px, 2cqi); }
[data-tint="on"][data-holder="toploader"] .slot-card,
[data-tint="on"][data-holder="slab"] .slot-card,
[data-tint="on"][data-holder="penny"] .slot-card {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--holder-tint) 70%, rgba(255,255,255,.3)),
    color-mix(in srgb, var(--holder-tint) 40%, transparent) 50%,
    color-mix(in srgb, var(--holder-tint) 65%, rgba(255,255,255,.25)));
}
[data-tint="on"][data-holder="toploader"] .holder,
[data-tint="on"][data-holder="slab"] .holder {
  outline: max(1px, 1cqi) solid color-mix(in srgb, var(--holder-tint) 80%, transparent);
  outline-offset: calc(-1 * max(1px, 1cqi));
}

/* ============================================ how cards are held (Binder settings)
   `.holder` is the clear plastic over the card — one span, never taking the
   pointer — and the card is set inside it by the holder's --in-* margins.
   Every measurement is in cqi (1% of the pocket's width) or a %, so a holder is
   the same object at a 46px pocket as at a 400px one. The pocket itself, and
   the drop target, never change.

   Straight in the pocket (the default): no holder of its own, just the sheet's
   own plastic passing over the art — the sheen sits above the card. */
.holder {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none; border-radius: inherit;
  background: linear-gradient(112deg,
    rgba(255,255,255,0) 32%, rgba(255,255,255,.075) 43%, rgba(255,255,255,.02) 50%, rgba(255,255,255,0) 62%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14);
}
[data-holder="toploader"] .slot-card,
[data-holder="penny"] .slot-card,
[data-holder="slab"] .slot-card { overflow: visible; }

/* ---- a rigid top loader: thick bevelled clear edges, larger than the card,
   with the rounded thumb cut at its open top and a hard glare down one side */
[data-holder="toploader"] .slot-card {
  --in-t: 9%; --in-x: 6.5%; --in-b: 4.5%; --in-r: max(1px, 1cqi);
  border-radius: max(3px, 3.4cqi);
  background:
    linear-gradient(150deg, rgba(232,242,255,.34) 0%, rgba(196,212,234,.12) 45%, rgba(224,236,252,.28) 100%);
  box-shadow:
    0 max(2px, 2.6cqi) max(6px, 7cqi) rgba(0,0,0,.45),
    0 1px 2px rgba(0,0,0,.4);
}
[data-holder="toploader"] .holder {
  background:
    /* the thumb cut-out at the open top */
    radial-gradient(ellipse 18% 5% at 50% 0, rgba(0,0,0,.5) 0 66%, rgba(0,0,0,0) 72%),
    /* the lit rim of that opening */
    linear-gradient(180deg, rgba(255,255,255,.4), rgba(255,255,255,0) 4.5%),
    /* the raking glare, one light */
    linear-gradient(115deg,
      rgba(255,255,255,0) 26%, rgba(255,255,255,.27) 33%, rgba(255,255,255,.06) 39%, rgba(255,255,255,0) 47%),
    /* corner highlights where the bevel turns */
    radial-gradient(circle at 0 0, rgba(255,255,255,.3) 0 6%, rgba(255,255,255,0) 14%),
    radial-gradient(circle at 100% 100%, rgba(255,255,255,.14) 0 6%, rgba(255,255,255,0) 14%);
  box-shadow:
    inset 0 0 0 max(1px, 1.2cqi) rgba(255,255,255,.5),
    inset 0 0 0 max(2px, 2.6cqi) rgba(168,188,214,.16),
    inset max(1px, 1.6cqi) max(1px, 1.6cqi) 0 max(1px, 1.2cqi) rgba(255,255,255,.14),
    inset calc(-1 * max(1px, 1.6cqi)) calc(-1 * max(1px, 1.6cqi)) 0 max(1px, 1.2cqi) rgba(0,0,0,.18);
}

/* ---- a penny sleeve: thin and soft, the card almost filling it, the mouth a
   touch loose at the top, one gentle sheen down the fold */
[data-holder="penny"] .slot-card {
  --in-t: 4%; --in-x: 2.6%; --in-b: 1.4%; --in-r: max(1px, 1.4cqi);
  border-radius: max(3px, 4cqi) max(3px, 4cqi) max(2px, 2.6cqi) max(2px, 2.6cqi);
  background: linear-gradient(170deg, rgba(255,255,255,.2), rgba(255,255,255,.08) 30%, rgba(255,255,255,.12));
  box-shadow: var(--shadow-card);
}
[data-holder="penny"] .holder {
  background:
    /* the loose mouth: the film lifts off the card at the top */
    linear-gradient(180deg, rgba(255,255,255,.34) 0 1.6%, rgba(255,255,255,.1) 3.4%, rgba(255,255,255,0) 6%),
    linear-gradient(100deg, rgba(255,255,255,0) 20%, rgba(255,255,255,.17) 31%, rgba(255,255,255,.03) 38%, rgba(255,255,255,0) 46%),
    linear-gradient(180deg, rgba(255,255,255,.1), rgba(255,255,255,.02) 40%, rgba(255,255,255,.07));
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.34),
    inset 0 1px 0 rgba(255,255,255,.46);
}

/* ---- a graded-style slab: a thick clear case, the label strip at the top
   (name, set, number and rarity — text only, never a grade), the card sunk in
   its well below */
[data-holder="slab"] .slot-card {
  --in-t: 24%; --in-x: 12%; --in-b: 5%; --in-r: max(1px, 1cqi);
  border-radius: max(3px, 4cqi);
  background: linear-gradient(170deg, rgba(236,244,255,.34), rgba(190,204,224,.14) 55%, rgba(214,228,246,.24));
  box-shadow:
    0 max(3px, 3cqi) max(7px, 8cqi) rgba(0,0,0,.5),
    0 1px 2px rgba(0,0,0,.4);
}
[data-holder="slab"] .holder {
  background:
    linear-gradient(118deg,
      rgba(255,255,255,0) 28%, rgba(255,255,255,.3) 36%, rgba(255,255,255,.06) 44%, rgba(255,255,255,0) 52%),
    /* the seam where the two halves of the case are welded */
    linear-gradient(180deg, rgba(255,255,255,0) 21.6%, rgba(0,0,0,.2) 22%, rgba(255,255,255,.14) 22.6%, rgba(255,255,255,0) 23.4%),
    radial-gradient(circle at 0 0, rgba(255,255,255,.26) 0 5%, rgba(255,255,255,0) 13%);
  box-shadow:
    inset 0 0 0 max(1px, 1.2cqi) rgba(255,255,255,.5),
    inset 0 0 0 max(3px, 3.4cqi) rgba(255,255,255,.08),
    inset max(1px, 1.4cqi) max(1px, 1.4cqi) 0 max(1px, 1cqi) rgba(255,255,255,.12);
}
.slot-label {
  position: absolute; z-index: 2; top: 3.5%; left: 6%; right: 6%; height: 17%;
  display: flex; flex-direction: column; justify-content: center; gap: 1px;
  padding: 0 6%; border-radius: max(1px, 1.4cqi); overflow: hidden; pointer-events: none;
  background: linear-gradient(180deg, #f7f8fa, #dce1e9); color: #1c2230;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.16), inset 0 1px 0 rgba(255,255,255,.9), 0 1px 2px rgba(0,0,0,.35);
}
.slot-label > * { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.15; }
.slot-label b { font-size: clamp(6px, 8cqi, 16px); font-weight: 750; }
.slot-label span { font-size: clamp(5px, 6.4cqi, 13px); font-weight: 600; color: #4a5263; }
/* smaller pockets: the name alone; too small to read at all: the strip alone */
@container (max-width: 100px) { .slot-label span { display: none; } }
@container (max-width: 58px) { .slot-label b { display: none; } }
/* A graded copy's label carries its grade on the right, as a real slab's does,
   marked in its grader's colour; it is the last thing a small label keeps. */
.slot-label.is-graded {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-content: center; column-gap: 5%;
}
.slot-label.is-graded > b, .slot-label.is-graded > span { grid-column: 1; }
.slot-label-grade {
  grid-column: 2; grid-row: 1 / span 2; align-self: center;
  font-style: normal; font-weight: 800; font-size: clamp(6px, 9cqi, 17px); font-variant-numeric: tabular-nums;
  padding-left: 5%; border-left: max(1px, 1.2cqi) solid var(--tone, #1c2230);
}

/* A graded copy's grade ("PSA 10") on its card, in the corner the price leaves
   free, edged in its grader's colour (web/js/grading.js). A small pocket has
   no room for both side by side, so there it stands just above the price's line. */
.slot-grade {
  position: absolute; z-index: 2; right: calc(var(--in-x) + 4px); bottom: calc(var(--in-b) + 4px);
  font-size: clamp(7px, 8.5cqi, 14px); font-weight: 800; letter-spacing: .02em; font-variant-numeric: tabular-nums;
  background: rgba(8,10,14,.84); color: #fff;
  padding: 1.5px 5px 1.5px 6px; border-radius: 4px;
  box-shadow: inset max(2px, 1.4cqi) 0 0 var(--tone, var(--accent)), 0 1px 2px rgba(0,0,0,.4);
  white-space: nowrap; pointer-events: none;
}
@container (max-width: 96px) {
  .slot-grade { padding: 1px 3px 1px 4px; }
}
/* With a price pill in the corner beside it, the grade stands on top of the
   pill rather than sharing its row (a wide one, "CGC Authentic", ran under
   the price), and is never wider than the card. */
.slot-card:has(.slot-price) .slot-grade {
  bottom: calc(var(--in-b) + 4px + 1.25 * clamp(8px, 9cqi, 15px) + 3px + 3px);
}
.slot-grade { max-width: calc(100% - 2 * var(--in-x) - 8px); overflow: hidden; text-overflow: ellipsis; }

/* ------------------------------------------------- empty pockets (Binder settings) */
[data-empty="plain"] .pocket.is-empty::after { content: none; }
[data-empty="plain"] .pocket.is-addable:hover::after { content: ""; }
/* a generic card back (no one game's): a framed lattice with an oval at its heart */
[data-empty="back"] .pocket.is-empty::after {
  inset: 5px; border: none; border-radius: 5px;
  background:
    radial-gradient(ellipse 30% 22% at 50% 50%, rgba(255,255,255,.14) 0 58%, transparent 62%),
    radial-gradient(ellipse 36% 27% at 50% 50%, transparent 0 80%, color-mix(in srgb, var(--gold) 60%, transparent) 83% 90%, transparent 93%),
    repeating-linear-gradient(45deg, rgba(255,255,255,.06) 0 2px, transparent 2px 9px),
    repeating-linear-gradient(-45deg, rgba(255,255,255,.06) 0 2px, transparent 2px 9px),
    linear-gradient(160deg, color-mix(in srgb, var(--cover, #2f6f4f) 45%, #10131c), color-mix(in srgb, var(--cover, #2f6f4f) 25%, #06070b));
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.12), inset 0 0 0 5px rgba(0,0,0,.25), 0 2px 5px rgba(0,0,0,.35);
  opacity: .9;
}
[data-empty="back"] .pocket.is-addable:hover::after { opacity: .6; }

/* ======================================================== stacked page edges
   The pages still to come on this side, seen edge-on in the board's margin:
   two to four slivers, the outermost lowest and palest, so a thick binder
   looks thick. binder.js sets --n and each sliver's --i. They belong to the
   binder, not to a page, so a leaf lifting off them leaves them behind. */
.edges {
  /* The pages still on this side, seen edge-on: tall, thin and quiet, so they
     read as the fore-edges of a stack tucked under the open page rather than a
     bar lying on the cover. They sit just outside the pocket sheet, which the
     sheet's own -7px bleed puts at (--board-pad - 7) in from the page edge. */
  position: absolute; z-index: 1;
  top: calc(var(--ring-top, 52px) - 26px); bottom: calc(var(--ring-bot, 26px) - 26px);
  width: 9px; pointer-events: none;
}
.edges.is-left { left: calc(var(--board-pad, 26px) - 22px); }
.edges.is-right { right: calc(var(--board-pad, 26px) - 22px); }
.edge {
  position: absolute;
  top: calc(var(--i) * 5px); bottom: calc(var(--i) * 5px);
  width: 3px; border-radius: 1px;
  background: linear-gradient(90deg,
    rgba(238,243,252,.34), rgba(214,222,236,.14) 45%, rgba(0,0,0,.34) 82%, rgba(0,0,0,.46));
  box-shadow: 0 1px 1px rgba(0,0,0,.4);
  opacity: calc(.34 + .07 * var(--i));
}
.edges.is-left .edge  { left: calc((var(--n) - 1 - var(--i)) * 3px); }
.edges.is-right .edge {
  right: calc((var(--n) - 1 - var(--i)) * 3px);
  background: linear-gradient(270deg,
    rgba(238,243,252,.34), rgba(214,222,236,.14) 45%, rgba(0,0,0,.34) 82%, rgba(0,0,0,.46));
}

/* ------------------------------------------------ backgrounds (Binder settings → Look)
   backdrop.js puts a .bg-layer first inside a page (or a thumbnail, a library cover, the
   desk). It sits behind the page's own content and above its cover colour, clipped to
   the page; its ::after is the dimming. In a spread each page's art spans both pages
   and the spine, offset so the two halves meet. */
.bg-layer {
  --spine: var(--spine-w, 34px);
  position: absolute; inset: 0; z-index: -1;
  overflow: hidden; border-radius: inherit; pointer-events: none;
}
.bg-layer::after { content: ""; position: absolute; inset: 0; background: rgba(0,0,0,var(--bg-dim, .25)); }
.bg-art {
  position: absolute; inset: calc(-2 * var(--bg-blur, 0px));
  background-color: var(--cover, #2f6f4f);
  background-position: center; background-size: cover; background-repeat: no-repeat;
  filter: blur(var(--bg-blur, 0px));
}
.bg-layer.is-left > .bg-art { right: calc(-100% - var(--spine) - 2 * var(--bg-blur, 0px)); }
.bg-layer.is-right > .bg-art { left: calc(-100% - var(--spine) - 2 * var(--bg-blur, 0px)); }
.bg-art.is-tile { background-size: auto; background-repeat: repeat; background-position: 0 0; }

/* the built-in patterns, drawn in CSS (leather and linen take the cover's colour) */
.bg-art.is-leather {
  background:
    radial-gradient(120% 90% at 18% 8%, rgba(255,255,255,.14), transparent 55%),
    radial-gradient(circle at 30% 40%, rgba(0,0,0,.2) 0 .8px, transparent 1.3px) 0 0 / 7px 7px,
    radial-gradient(circle at 70% 60%, rgba(255,255,255,.07) 0 .8px, transparent 1.3px) 0 0 / 5px 5px,
    radial-gradient(circle at 50% 50%, rgba(0,0,0,.12) 0 1px, transparent 1.6px) 2px 3px / 11px 11px,
    linear-gradient(135deg, color-mix(in srgb, var(--cover, #2f6f4f) 82%, #000), var(--cover, #2f6f4f) 50%, color-mix(in srgb, var(--cover, #2f6f4f) 70%, #000));
}
.bg-art.is-linen {
  background:
    repeating-linear-gradient(0deg, rgba(255,255,255,.07) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(0,0,0,.12) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg, rgba(0,0,0,.06) 0 2px, transparent 2px 7px),
    linear-gradient(160deg, color-mix(in srgb, var(--cover, #2f6f4f) 70%, #d9d2c3), color-mix(in srgb, var(--cover, #2f6f4f) 62%, #8c8475));
}
.bg-art.is-carbon {
  background:
    linear-gradient(27deg, #151515 5px, transparent 5px) 0 5px / 20px 20px,
    linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0 / 20px 20px,
    linear-gradient(27deg, #222 5px, transparent 5px) 0 10px / 20px 20px,
    linear-gradient(207deg, #222 5px, transparent 5px) 10px 5px / 20px 20px,
    linear-gradient(90deg, #1b1b1b 10px, transparent 10px) 0 0 / 20px 20px,
    linear-gradient(#1d1d1d 25%, #1a1a1a 25%, #1a1a1a 50%, transparent 50%, transparent 75%, #242424 75%, #242424) 0 0 / 20px 20px,
    #131313;
}
.bg-art.is-starfield {
  background:
    radial-gradient(1.2px 1.2px at 20px 30px, #fff, transparent) 0 0 / 190px 190px,
    radial-gradient(1px 1px at 60px 90px, rgba(255,255,255,.8), transparent) 0 0 / 190px 190px,
    radial-gradient(1.6px 1.6px at 120px 40px, #fff, transparent) 0 0 / 190px 190px,
    radial-gradient(1px 1px at 150px 140px, rgba(255,255,255,.7), transparent) 0 0 / 190px 190px,
    radial-gradient(1.3px 1.3px at 90px 170px, #dfe8ff, transparent) 0 0 / 190px 190px,
    radial-gradient(1px 1px at 35px 120px, rgba(255,255,255,.6), transparent) 0 0 / 130px 130px,
    radial-gradient(1px 1px at 100px 20px, rgba(255,255,255,.55), transparent) 0 0 / 130px 130px,
    radial-gradient(ellipse at 30% 20%, rgba(120,90,200,.35), transparent 60%),
    radial-gradient(ellipse at 80% 80%, rgba(40,120,200,.3), transparent 55%),
    linear-gradient(160deg, #0b1026, #05060f);
}
.bg-art.is-holo {
  background:
    linear-gradient(115deg, rgba(255,255,255,0) 30%, rgba(255,255,255,.22) 45%, rgba(255,255,255,0) 60%),
    repeating-linear-gradient(60deg, rgba(255,255,255,.05) 0 2px, transparent 2px 6px),
    linear-gradient(125deg, #a2437f, #a38a3c 20%, #3c9a6c 40%, #3c7ea8 60%, #7148a6 80%, #a2437f);
}
/* Over a picture or a pattern the page's own words keep a shadow, whatever is behind them. */
.bpage:has(> .bg-layer) .page-no,
.bpage:has(> .bg-layer) .page-sum,
.bpage:has(> .bg-layer) .page-money,
.bpage:has(> .bg-layer) .page-name { text-shadow: 0 1px 3px rgba(0,0,0,.85), 0 0 1px rgba(0,0,0,.6); }
.bpage:has(> .bg-layer) .page-name.is-unnamed { color: rgba(255,255,255,.9); }

/* ==================================================== the settings preview
   Binder settings draws the binder in miniature (settings.js paintPreview) out
   of these very parts — cover board, spine and D-rings, the punch holes they
   pass through, one welded pocket sheet, and the caption strip under the
   pockets — so the preview *is* the binder, only smaller. Everything `.binder`
   sets on itself is therefore set again here at preview size; settings.js
   sizes the spine's SVG metal to match (its PREVIEW_* constants), and
   dialogs.css keeps the frame the whole thing sits in.

   The size: a 46px pocket — the smallest the binder itself ever draws at, on a
   phone — so the preview is not a special small rendering of the cards but a
   rendering the app really does. That makes a 3 x 3 page 170 x 248, and the
   binder beside its 21px spine 191 x 248: a page standing up, the way a real
   one does, rather than the squat strip this used to be.

   One more thing to know: shell.css still carries the pre-redesign copy of
   these preview rules, on `.bpage.set-preview-page` — two classes. Everything
   here that has to beat it therefore names the binder as well (three), which
   also reads as what it is: this page, inside the preview binder. */
.set-preview-binder {
  --ring-top: 16px; --ring-bot: 16px;     /* clearance at each end of the spine */
  --stitch: rgba(255,255,255,.3);
  --sheen: 0;                             /* no pointer light on a preview */
  position: relative; z-index: 1;
  display: flex; align-items: stretch;
}
/* the shadow the little binder throws on the desk, under the same top-left light */
.set-preview-binder::before {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: 5px 3px -3px 3px; border-radius: 11px;
  box-shadow: 0 10px 20px rgba(0,0,0,.45), 0 3px 7px rgba(0,0,0,.3);
}
:root[data-theme="light"] .set-preview-binder::before {
  box-shadow: 0 10px 20px rgba(20,24,32,.2), 0 3px 7px rgba(20,24,32,.12);
}

/* The page: the binder's own trim, scaled. It hangs on the rings, so its
   hinge-side corners are the spine's, and it keeps the board's bevel — the
   same four inset shadows `.bpage` gives every board, said again here only
   because the shell's older rule would otherwise replace them. */
.set-preview-binder > .bpage.set-preview-page {
  --board-pad: 10px;        /* cover showing around the pocket sheet */
  --gap: 6px;               /* between pockets — the welds run down it */
  --pocket-w: 46px;
  --pocket-h: 64px;         /* --pocket-w / --card-ratio: the welds need the pitch */
  /* a slimmer caption band than the desk's, to a page a fifth of the size */
  --head-h: 14px; --head-gap: 4px; --head-band: 18px;
  padding-left: var(--board-pad); padding-right: var(--board-pad);
  border-radius: 2px 12px 12px 2px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.3),
    inset 1px 0 0 rgba(255,255,255,.1),
    inset -1px -1px 0 rgba(0,0,0,.45),
    inset 0 0 18px rgba(0,0,0,.2);
}
/* the pocket sheet's own margin narrower */
.set-preview-binder > .bpage.set-preview-page > .sheet {
  margin: -4px; padding: 4px;
  margin-left: calc(-1 * var(--board-pad, 10px)); padding-left: var(--board-pad, 10px);
  border-radius: 0 5px 5px 0;
}
.set-preview-binder .grid.set-preview-grid {
  grid-template-columns: repeat(3, var(--pocket-w)); gap: var(--gap);
}
/* the page number, in the page's top margin, above the pockets */
.set-preview-binder .bpage > .page-head.is-top {
  height: var(--head-h); margin: 0 0 var(--head-gap);
}
/* the prices, shortened: a preview page is a fifth of the desk's */
.set-preview-binder .page-foot { padding-top: 3px; gap: 3px; }
.set-preview-binder .page-money { gap: 2px; }
.set-preview-binder .page-money-k { font-size: 7px; letter-spacing: .03em; }
.set-preview-binder .page-money-v { font-size: 8px; }
.set-preview-binder .page-money .pm-long { display: none; }
.set-preview-binder .page-money .pm-short { display: inline; }
/* A 46px card is narrower than a long collector number, and the holders that
   let their bevel hang out (toploader, penny, slab) would then spill a badge
   or a MISSING stamp across the next pocket. Here the card keeps what is on
   it: the badges end at its edge, with an ellipsis rather than a cut glyph. */
.set-preview-binder .pocket > .slot-card { overflow: hidden; }
.set-preview-binder .slot-tags { left: calc(var(--in-x) + 4px); align-items: flex-end; }
.set-preview-binder .slot-num,
.set-preview-binder .slot-rar { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }

/* the holes, and the rings that go through them */
.set-preview-binder .punch {
  width: 6px; height: 10px; margin: -5px 0 0 -3px; border-radius: 3px;
}
.set-preview-binder .spine.is-solo { border-radius: 10px 0 0 10px; }
.set-preview-binder .spine.is-solo::before { width: 6px; margin-left: -3px; }
.set-preview-binder .spine.is-solo .ring { left: 3px; }

/* =============================================================== page turn
   pageturn.js: copies of the old page(s) laid over the binder while a leaf
   turns about the rings. The leaf carries its pocket sheet with it (the sheet
   is part of the page), a sweeping glare runs across the plastic as it lifts,
   and the back face is the next page's pockets. Fixed over the binder's scroll
   box and clipped to it; nothing in it takes the pointer or focus. */
.turn-layer { position: fixed; z-index: 30; overflow: hidden; pointer-events: none; }
.turn-scene { position: absolute; inset: 0; }
.turn-under, .turn-reveal, .turn-leaf, .turn-still { position: absolute; }
.turn-leaf { transform-style: preserve-3d; will-change: transform; }
/* The whole cover swing slides as it turns (a shut binder is one board wide
   where an open one is two, and both sit in the middle of the desk). */
.turn-shift { position: absolute; inset: 0; will-change: transform; }
/* The binder's shadow on the desk while it stands aside for the swing: the same
   two shadows .binder::before / ::after cast, so the hand-back is seamless. */
.turn-desk { position: absolute; pointer-events: none; will-change: opacity; }
.turn-desk::before {
  content: ""; position: absolute; inset: 8px 6px -2px 6px;
  border-radius: var(--radius-lg);
  box-shadow: var(--desk-shadow), 0 6px 14px rgba(0,0,0,.4);
}
:root[data-theme="light"] .turn-desk::before { box-shadow: var(--desk-shadow), 0 4px 10px rgba(20,24,32,.14); }
.turn-desk::after {
  content: ""; position: absolute; left: 3%; right: 3%; bottom: -7px; height: 16px;
  border-radius: 50%;
  background: radial-gradient(60% 100% at 50% 0, rgba(0,0,0,.5), rgba(0,0,0,0) 72%);
}
:root[data-theme="light"] .turn-desk::after { background: radial-gradient(60% 100% at 50% 0, rgba(20,24,32,.3), rgba(0,0,0,0) 72%); }
/* The cover's thickness: a strip standing back from its free edge, square to
   the board, so it only shows as the cover passes edge-on. */
.turn-thick {
  position: absolute; top: 3px; bottom: 3px; right: 0; width: 6px;
  transform-origin: 100% 50%; transform: rotateY(-90deg);
  border-radius: 2px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--cover, #2f6f4f) 55%, #000),
    color-mix(in srgb, var(--cover, #2f6f4f) 85%, #fff) 45%,
    color-mix(in srgb, var(--cover, #2f6f4f) 50%, #000));
}
.turn-face {
  position: absolute; inset: 0; overflow: hidden;
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
  /* its edge, as it lifts off a page of the same colour */
  box-shadow: 0 0 0 1px rgba(0,0,0,.12), 0 2px 14px rgba(0,0,0,.22);
}
.turn-face.is-back { transform: rotateY(180deg); }
.turn-under { overflow: hidden; }
.turn-face > .bpage, .turn-under > .bpage, .turn-still > .bpage,
.turn-face > .bcover, .turn-under > .bcover, .turn-still > .bcover {
  position: absolute; inset: 0; margin: 0; border-radius: inherit;
}
/* A copied spine keeps its own corners, and its rings still reach past it. */
.turn-still > .spine { position: absolute; inset: 0; margin: 0; }
/* A leaf in the air is rasterised as a whole new layer at the start of every
   turn, so anything on it that cannot be seen at that speed is dropped: the
   foil sheen, the pointer light, the hairline welds between pockets and the
   pockets' layered inner shadows. The boards keep their grain and bevel — the
   leaf is the thing you are looking at. */
.turn-layer [data-foil]::after, .turn-layer [data-foil]::before,
.turn-layer .sheen { content: none; display: none; }
.turn-layer .sheet::before { content: none; }
.turn-layer .pocket { box-shadow: inset 0 2px 5px rgba(0,0,0,.5), inset 0 0 0 1px rgba(255,255,255,.07); }
.turn-layer .slot-price { backdrop-filter: none; }

/* each piece is shaped like the page it shows, and knows which edge is the hinge */
.turn-left  { border-radius: var(--radius-lg) 3px 3px var(--radius-lg); --hinge: to left; --outer: to right; }
.turn-right { border-radius: 3px var(--radius-lg) var(--radius-lg) 3px; --hinge: to right; --outer: to left; }
.turn-solo  { border-radius: 3px var(--radius-lg) var(--radius-lg) 3px; --hinge: to right; --outer: to left; }

/* Shadow, darkest at the rings: on the leaf as it turns from the light, on the page it
   uncovers, and on the page it comes down on. pageturn.js animates only their opacity. */
.turn-shade, .turn-gloss, .turn-sheen { position: absolute; inset: 0; border-radius: inherit; opacity: 0; pointer-events: none; }
.turn-shade {
  background: linear-gradient(var(--hinge), rgba(0,0,0,.86), rgba(0,0,0,.58) 40%, rgba(0,0,0,.42));
}
.turn-reveal .turn-shade { background: linear-gradient(var(--hinge), rgba(0,0,0,.72), rgba(0,0,0,.32) 42%, rgba(0,0,0,.08)); }
.turn-under .turn-shade { background: linear-gradient(var(--hinge), rgba(0,0,0,.66), rgba(0,0,0,.3) 50%, rgba(0,0,0,.1)); }
/* the paper curving where it meets the rings */
.turn-face::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(var(--hinge), rgba(0,0,0,.26), rgba(0,0,0,0) 9%);
}
/* light catching the leaf as it lifts */
.turn-gloss {
  background: linear-gradient(var(--outer), rgba(255,255,255,.2), rgba(255,255,255,.06) 55%, rgba(255,255,255,0) 85%);
}
/* The glare that sweeps across the plastic as the leaf swings through the
   light: one band, moved by transform alone (pageturn.js). */
.turn-sheen {
  width: 45%; inset: 0 auto 0 0; opacity: 1;
  background: linear-gradient(105deg,
    rgba(255,255,255,0) 0%, rgba(255,255,255,.1) 38%, rgba(255,255,255,.28) 50%,
    rgba(255,255,255,.08) 62%, rgba(255,255,255,0) 100%);
  transform: translate3d(-160%, 0, 0);
  will-change: transform;
}
.turn-rings { position: absolute; background: none !important; box-shadow: none !important; }
.turn-rings::before { content: none !important; }

/* =============================================================== card peek */
.card-peek {
  position: fixed; z-index: 70; pointer-events: none;
  width: 250px; border-radius: var(--radius); overflow: hidden;
  box-shadow: var(--glass-edge), 0 24px 60px rgba(0,0,0,.6); background: var(--bg-2);
  border: 1px solid var(--line);
}
.card-peek img { width: 100%; display: block; aspect-ratio: var(--card-ratio); object-fit: cover; }
.peek-body { padding: 9px 11px; }
.peek-name { font-size: 13px; font-weight: 600; }
.peek-set { font-size: 11.5px; color: var(--ink-3); margin-top: 1px; }
.peek-prices { display: flex; gap: 10px; margin-top: 7px; font-size: 11.5px; }
.peek-prices b { display: block; font-size: 13px; color: var(--gold-text); font-variant-numeric: tabular-nums; }
.peek-prices span { color: var(--ink-3); }
.peek-prices .is-est b { font-weight: 650; text-decoration: underline dashed color-mix(in srgb, var(--gold) 55%, transparent); text-underline-offset: 3px; }
.peek-est { margin-top: 6px; font-size: 11px; line-height: 1.35; color: var(--ink-3); }

/* ================================================================ responsive */
@media (max-width: 980px) {
  .page-arrow { width: 38px; height: 38px; }
  .page-arrow.is-prev { margin: 0 -6px 0 4px; }
  .page-arrow.is-next { margin: 0 4px 0 -6px; }
  .binder { --board-pad: 20px; }
}

/* Phones: small, at the very edges, and not tucked into the scroller's padding, since a
   spread wider than the screen scrolls sideways through it. */
@media (max-width: 640px) {
  .page-arrow { width: 32px; height: 32px; }
  .page-arrow-ico { width: 17px; height: 17px; }
  .page-arrow.is-prev { margin: 0 0 0 4px; }
  .page-arrow.is-next { margin: 0 4px 0 0; }
  .binder { --board-pad: 20px; }
  .page-foot { gap: 4px; }
  /* a slimmer caption band, so the narrow board still has a margin under it */
  :root { --head-h: 18px; --head-gap: 8px; }
  .page-name { font-size: 12.5px; }
  .edges { width: 9px; }
  .edge { width: 3px; }
  .punch { width: 7px; height: 11px; margin: -5.5px 0 0 -3.5px; }
}

@media (hover: none) {
  .page-arrow:hover { transform: none; box-shadow: var(--shadow-1); }
}

@media (prefers-reduced-motion: reduce) {
  .page-arrow { transition: none; }
  .page-arrow:hover, .page-arrow:active, .page-arrow.is-springing { transform: none; }
  /* still says "about to turn", without the sweep */
  .page-arrow.is-springing .page-arrow-ring { animation: none; stroke-dashoffset: 0; }
  .btn[data-spring].is-springing::after { animation: none; transform: scaleX(1); }
  .drag-ghost-ring { animation: none; stroke-dashoffset: 0; }
}
/* The same, from Preferences → Motion rather than the system (motion.js). */
:root[data-motion="reduced"] .page-arrow,
:root[data-motion="off"] .page-arrow { transition: none; }
:root[data-motion="reduced"] .page-arrow:hover,
:root[data-motion="off"] .page-arrow:hover,
:root[data-motion="reduced"] .page-arrow.is-springing,
:root[data-motion="off"] .page-arrow.is-springing { transform: none; }
:root[data-motion="reduced"] .page-arrow.is-springing .page-arrow-ring,
:root[data-motion="off"] .page-arrow.is-springing .page-arrow-ring { animation: none; stroke-dashoffset: 0; }
:root[data-motion="reduced"] .btn[data-spring].is-springing::after,
:root[data-motion="off"] .btn[data-spring].is-springing::after { animation: none; transform: scaleX(1); }
:root[data-motion="reduced"] .drag-ghost-ring,
:root[data-motion="off"] .drag-ghost-ring { animation: none; stroke-dashoffset: 0; }
:root[data-motion="reduced"] .turn-sheen,
:root[data-motion="off"] .turn-sheen { display: none; }

/* ==================================================================== print
   Pockets print at true card size (2.5in x 3.5in) so a printed sheet can be
   used as a placeholder layout for a real binder. app.css holds the page setup
   and hides the rest of the app. No plastic, no metal, no grain: paper. */
@media print {
  .page-arrow, .turn-layer, .drag-ghost, .bg-layer, .card-peek,
  .edges, .punches, .sheen { display: none !important; }
  /* Covers are the object, not the contents: paper gets the pages only. */
  .bcover, .bpage.is-inside { display: none !important; }
  .binder { display: block; }
  .binder::before, .binder::after { display: none; }
  .spine { display: none; }
  .bpage {
    background: #fff !important; padding: 0; border-radius: 0;
    box-shadow: none !important;
    break-after: page; page-break-after: always;
  }
  .bpage::before, .bpage::after { content: none !important; }
  .bpage:last-child { break-after: auto; page-break-after: auto; }
  .page-head { color: #333; margin: 0 0 8px; }
  /* Printed pages are built by export.js; the binder's own pages print with the
     same heading on top, the prices under the pockets, and no page margins. */
  .bpage.has-cap { padding: 0; }
  .page-foot {
    position: static; height: auto; margin: 8px 0 0; padding: 0;
    left: auto; right: auto; bottom: auto; color: #333;
  }
  .page-no, .page-sum, .page-name, .page-money { text-shadow: none !important; }
  .page-sum, .page-money-k, .page-money-v { color: #333; }
  .page-money.is-total .page-money-v { color: #333; }
  .page-name { color: #333; }
  .page-name.is-unnamed, .page-name-ico { display: none !important; }
  .sheet {
    margin: 0 !important; padding: 0 !important;
    background: none !important; box-shadow: none !important;
  }
  .sheet::before, .sheet::after { content: none !important; }
  .grid { gap: 0.08in; }
  /* --print-scale is 1 for true 2.5 x 3.5in cards, or shrunk to fit one sheet. */
  .pocket {
    width: calc(2.5in * var(--print-scale, 1));
    height: calc(3.5in * var(--print-scale, 1));
    aspect-ratio: auto;
    box-shadow: none; border: 1px solid #bbb; background: #fff;
  }
  .pocket::before { content: none; }
  .pocket.is-empty::after { border-color: #ddd; }
  .slot-card { box-shadow: none; }
  .slot-card img { outline: none; }
  .slot-actions { display: none; }
  .slot-price { background: #fff; color: #222; border: 1px solid #ddd; box-shadow: none; }
  .slot-price.is-est { background: #fff; color: #444; border: 1px dashed #999; }
  /* holders on paper: an outline instead of plastic and glare */
  .holder { display: none !important; }
  [data-holder="toploader"] .slot-card, [data-holder="penny"] .slot-card, [data-holder="slab"] .slot-card {
    background: #fff; box-shadow: inset 0 0 0 1px #bbb;
  }
  .slot-label { background: #fff; box-shadow: inset 0 0 0 1px #bbb; }
  [data-empty="back"] .pocket.is-empty::after { opacity: .35; }
  [data-missing="hidden"] .slot-card.is-missing .slot-ghost { border-color: #bbb; color: #777; }
  /* The red ring prints; its glow would only be a smudge on paper. */
  [data-missing="badge"] .slot-card.is-missing { filter: none; }
}

/* ---- a copy on the trade list (binder.js cardFace): two arrows in the top
   corner, the lock's size; beside the lock when the card has both */
.slot-trade {
  position: absolute; z-index: 3; left: calc(var(--in-x) + max(3px, 2.4cqi)); top: calc(var(--in-t) + max(3px, 2.4cqi));
  width: clamp(14px, 11cqi, 22px); height: clamp(14px, 11cqi, 22px); padding: 2px;
  display: grid; place-items: center; border-radius: 999px;
  background: color-mix(in srgb, #0a0c12 72%, transparent); color: var(--gold);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gold) 60%, transparent);
  pointer-events: none;
}
.slot-trade svg { width: 100%; height: 100%; }
.slot-card.is-locked .slot-trade { left: calc(var(--in-x) + max(3px, 2.4cqi) + clamp(14px, 11cqi, 22px) + 3px); }
body.is-shared .slot-trade { display: none; }


/* ------------------------------------------------------------ dense pages
   Cards under 64px across (a 5 × 5 or 6 × 6 page, or a crowded screen): the
   pocket keeps what is worth reading at that size — the price, smaller, and
   a grade as a dot in its grader's colour — and the number and rarity step
   aside. Under the pointer the card comes forward at nearly twice its size
   with everything back (binder.js sets data-dense on #binder); a finger's tap
   brings up its panel with the art large, as on any page. */
@container (max-width: 63px) {
  .slot-tags { display: none; }
  .slot-price { left: calc(var(--in-x) + 2px); bottom: calc(var(--in-b) + 2px); padding: 1px 3px; border-radius: 3px; font-size: 7.5px; }
  .slot-price.is-est { padding: 0 2px; }
  .slot-grade {
    width: 7px; height: 7px; padding: 0; border-radius: 50%; font-size: 0;
    right: calc(var(--in-x) + 2px); bottom: calc(var(--in-b) + 2px);
    background: var(--tone, var(--accent)); box-shadow: 0 0 0 1px rgba(0,0,0,.55);
  }
  .slot-card:has(.slot-price) .slot-grade { bottom: calc(var(--in-b) + 3px); }
  .slot-miss { letter-spacing: .06em; padding: 1px 2px; }
  .slot-card:hover .slot-tags, .slot-card:focus-within .slot-tags { display: flex; }
  .slot-card:hover .slot-grade, .slot-card:focus-within .slot-grade {
    width: auto; height: auto; padding: 1px 3px 1px 4px; border-radius: 4px; font-size: 7.5px;
    background: rgba(8,10,14,.84); box-shadow: inset 2px 0 0 var(--tone, var(--accent)), 0 1px 2px rgba(0,0,0,.4);
  }
  .slot-card:hover:has(.slot-price) .slot-grade, .slot-card:focus-within:has(.slot-price) .slot-grade { bottom: calc(var(--in-b) + 15px); }
}
@media (hover: hover) and (pointer: fine) {
  #binder[data-dense] .pocket:hover, #binder[data-dense] .pocket:focus-within { z-index: 6; }
  #binder[data-dense] .slot-card { transition: transform 160ms var(--ease-out), box-shadow 160ms var(--ease-out); }
  body:not(.is-dragging-card) #binder[data-dense] .pocket:hover > .slot-card:not(.is-drag-source),
  body:not(.is-dragging-card) #binder[data-dense] .pocket:focus-within > .slot-card:not(.is-drag-source) {
    transform: scale(1.9);
    box-shadow: 0 16px 34px rgba(0,0,0,.6), 0 0 0 1px rgba(255,255,255,.12);
  }
  :root[data-motion="off"] #binder[data-dense] .slot-card { transition: none; }
}


/* ---- choosing several (binder.js): a checkbox in the card's top-left
   corner, up under the pointer and on every card while any are chosen; a
   chosen card ringed in the accent; and the bar at the binder's top. */
.slot-check {
  --c: clamp(15px, 15cqi, 24px);
  position: absolute; z-index: 5;
  left: calc(var(--in-x) + max(3px, 2.4cqi)); top: calc(var(--in-t) + max(3px, 2.4cqi));
  width: var(--c); height: var(--c); padding: 0; border: 0; border-radius: calc(var(--c) * .28); cursor: pointer;
  display: grid; place-items: center; color: transparent;
  background: color-mix(in srgb, #0a0c12 58%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: inset 0 0 0 1.6px rgba(255,255,255,.82), 0 2px 6px rgba(0,0,0,.4);
  opacity: 0; transform: scale(.9); pointer-events: none;
  transition: opacity var(--t-2) var(--ease-out), transform var(--t-2) var(--ease-out), background var(--t-1) var(--ease-out);
}
.slot-check svg { width: 72%; height: 72%; }
.slot-check:hover { background: color-mix(in srgb, #1b2130 80%, transparent); }
.slot-check:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (hover: hover) {
  .slot-card:hover .slot-check { opacity: 1; transform: none; pointer-events: auto; }
}
.slot-card:focus-within .slot-check,
#binder.is-selecting .slot-check { opacity: 1; transform: none; pointer-events: auto; }
.slot-check[aria-checked="true"] {
  color: #fff; background: var(--accent);
  box-shadow: 0 0 0 2px rgba(0,0,0,.28), 0 3px 10px color-mix(in srgb, var(--accent) 50%, transparent);
}
/* the lock badge steps down out of the checkbox's way while it shows */
@media (hover: hover) { .slot-card:hover .slot-lock { translate: 0 calc(clamp(15px, 15cqi, 24px) + 3px); } }
#binder.is-selecting .slot-lock { translate: 0 calc(clamp(15px, 15cqi, 24px) + 3px); }
.slot-card.is-selected { outline: 2.5px solid var(--accent); outline-offset: -1px; }
#binder.is-selecting .slot-card:not(.is-selected) { filter: saturate(.85) brightness(.92); }
body.is-dragging-card .slot-check { display: none; }

.bulk-bar {
  position: absolute; z-index: 30; top: 10px; left: 50%; translate: -50% 0;
  max-width: calc(100% - 20px);
  display: flex; align-items: center; gap: 4px; padding: 5px 6px 5px 12px;
  border-radius: 14px; overflow-x: auto; scrollbar-width: none;
  background: color-mix(in srgb, var(--bg-2) 88%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(1.3); backdrop-filter: blur(16px) saturate(1.3);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--hairline);
  animation: bulk-in var(--t-2) var(--ease-out);
}
.bulk-bar::-webkit-scrollbar { display: none; }
@keyframes bulk-in { from { opacity: 0; translate: -50% -8px; } }
:root[data-motion="off"] .bulk-bar { animation: none; }
.bulk-count { flex: none; padding-right: 4px; font-size: 12.5px; color: var(--ink-2); white-space: nowrap; }
.bulk-count b { color: var(--ink); font-size: 14px; font-variant-numeric: tabular-nums; }
.bulk-sep { flex: none; width: 1px; height: 20px; margin: 0 3px; background: var(--line); }
.bulk-btn {
  flex: none; display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 10px;
  border: 0; border-radius: 9px; background: none; color: var(--ink-2); cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 650; white-space: nowrap;
  transition: background var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out);
}
.bulk-btn:hover { background: var(--bg-3); color: var(--ink); }
.bulk-btn:focus-visible, .bulk-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.bulk-btn.is-danger:hover { background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger); }
.bulk-btn.is-plain { color: var(--accent-text); }
.bulk-ico { display: grid; place-items: center; }
.bulk-ico svg { width: 15px; height: 15px; }
.bulk-x {
  flex: none; display: grid; place-items: center; width: 30px; height: 30px; margin-left: 2px; padding: 0;
  border: 0; border-radius: 9px; background: none; color: var(--ink-3); cursor: pointer;
}
.bulk-x:hover { background: var(--bg-3); color: var(--ink); }
/* A phone: across the top, icons and words, scrolling sideways when they will not all fit. */
@media (max-width: 640px) {
  .bulk-bar { top: 6px; left: 8px; right: 8px; translate: none; max-width: none; }
  @keyframes bulk-in { from { opacity: 0; transform: translateY(-8px); } }
  .bulk-btn { height: 34px; padding: 0 9px; }
}
@media print { .bulk-bar, .slot-check { display: none !important; } }

/* ============================================================ cards only
   Binder settings → Look → Binder style → Cards Only (binder.js puts
   data-frame on the binder's frame, so the page turn's copies beside it
   follow; settings.js on its preview). No binder round the cards: no board,
   shadow, gutter, spine, rings, punch holes, page edges or plastic sheet —
   the pockets stand on the desk. Every part keeps its size, so the pockets
   are exactly where they would be in the binder, and a page still turns. */
[data-frame="none"] .binder::before,
[data-frame="none"] .binder::after,
[data-frame="none"] .bpage::after,
[data-frame="none"] .sheet::before,
[data-frame="none"] .sheet::after { content: none; }
[data-frame="none"] .bpage { background: none; box-shadow: none; }
/* …and the room the board took is the cards': only a sliver of margin round them
   (binder.js sizes the pockets from this, and leaves out the spine). */
[data-frame="none"] .binder { --board-pad: 6px; }
[data-frame="none"] .sheet { background: none; box-shadow: none; border-color: transparent; }
[data-frame="none"] .spine:not(.is-shut),
[data-frame="none"] .turn-layer .ring,
[data-frame="none"] .bpage.is-inside { visibility: hidden; }
[data-frame="none"] .punches,
[data-frame="none"] .edges,
[data-frame="none"] .binder > .sheen { display: none; }
/* the page's number and total sit on the desk now, so they take its ink */
[data-frame="none"] .bpage .page-head,
[data-frame="none"] .bpage .page-foot { color: var(--ink-2); text-shadow: none; }
/* …and the settings preview's little binder (its own, higher-specificity trim) */
.set-preview-binder[data-frame="none"]::before { content: none; }
.set-preview-binder[data-frame="none"] > .bpage.set-preview-page { box-shadow: none; }

/* ---- Between two cards (binder.js pocketInsert): a seam in the gap before a card. Under the
   pointer it lights, with a + in the middle, to put a card in between or make an empty pocket. */
.pocket-insert {
  position: absolute; z-index: 6; top: 8%; bottom: 8%;
  left: -14.5px; width: 18px;              /* centred in the 11px gap, a little over each card's edge */
  display: grid; place-items: center;
  padding: 0; border: 0; background: transparent; cursor: copy;
  opacity: 0; transition: opacity var(--t-1, .15s) var(--ease-out, ease);
}
.pocket-insert::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: 50%; width: 2px; margin-left: -1px; border-radius: 2px;
  background: var(--accent); box-shadow: 0 0 10px var(--accent);
  transform: scaleY(.35); transition: transform var(--t-2, .2s) var(--ease-out, ease);
}
.pocket-insert-plus {
  position: relative; display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  color: #fff; background: var(--accent);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .92), 0 3px 10px rgba(0, 0, 0, .5);
  transform: scale(.6); transition: transform var(--t-2, .2s) var(--ease-out, ease);
}
.pocket-insert-plus svg { width: 12px; height: 12px; }
.pocket-insert:hover, .pocket-insert:focus-visible { opacity: 1; }
.pocket-insert:hover::before, .pocket-insert:focus-visible::before { transform: scaleY(1); }
.pocket-insert:hover .pocket-insert-plus, .pocket-insert:focus-visible .pocket-insert-plus { transform: scale(1); }
.pocket-insert:focus-visible { outline: none; }
/* A finger has the card's panel (Insert Before…); a card being carried or several being chosen want the gap left alone. */
@media (hover: none) { .pocket-insert { display: none; } }
#binder.is-selecting .pocket-insert, body.is-dragging-card .pocket-insert { display: none; }

/* ---- A page's own buttons — Insert, Copy, Delete — at the right end of its caption
   (binder.js pageActions): shown with the page under the pointer. */
.page-acts { order: 2; margin-left: auto; display: inline-flex; align-items: center; gap: 4px; flex: none; }
.page-act {
  display: inline-grid; place-items: center; flex: none;
  width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: 6px; cursor: pointer;
  color: rgba(255, 255, 255, .9);
  background: rgba(0, 0, 0, .26);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .15);
  opacity: 0; transition: opacity var(--t-1, .15s) var(--ease-out, ease), background var(--t-1, .15s) var(--ease-out, ease);
}
.page-act svg { width: 14px; height: 14px; }
.bpage:hover .page-act, .page-act:focus-visible, .page-act[aria-expanded="true"] { opacity: 1; }
.page-act:hover { background: color-mix(in srgb, var(--accent) 45%, rgba(0, 0, 0, .3)); color: #fff; }
.page-act.page-delete { color: #fca5a5; }
.page-act.page-delete:hover { background: var(--danger); color: #fff; }
.page-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (hover: none) { .page-act { opacity: .8; } }
/* A phone's caption is shorter than its buttons: a touch smaller, and a little higher, they sit
   between the cover's rim and the page's edge with room above and below; the page's number,
   name and photos with them. */
@media (max-width: 640px) {
  .page-head > .page-title, .page-head > .page-acts { translate: 0 -2.5px; }
  .page-head .page-name { translate: 0 1px; }
  .page-act { width: 20px; height: 20px; }
  .page-act svg { width: 13px; height: 13px; }
}

/* ---- Remove an empty pocket (binder.js pocketClose): in the corner of an empty pocket with cards
   after it, shown with the pocket under the pointer; the cards after it move back one. */
#binder .pocket-close {
  position: absolute; z-index: 4; top: 12px; right: 12px;
  display: grid; place-items: center;
  width: clamp(20px, 20cqi, 26px); height: clamp(20px, 20cqi, 26px); padding: 0;
  border: 0; border-radius: 7px; cursor: pointer;
  color: rgba(255, 255, 255, .92);
  background: color-mix(in srgb, #0a0c12 70%, transparent);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .15);
  opacity: 0; transition: opacity var(--t-1, .15s) var(--ease-out, ease), background var(--t-1, .15s) var(--ease-out, ease);
}
#binder .pocket-close svg { width: 62%; height: 62%; }
#binder .pocket.is-addable:hover .pocket-close, #binder .pocket-close:focus-visible { opacity: 1; }
#binder .pocket-close { color: #f87171; }
#binder .pocket-close:hover { background: var(--danger); color: #fff; }
#binder .pocket-close:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
@media (hover: none) { #binder .pocket-close { opacity: .75; } }
#binder.is-selecting .pocket-close, body.is-dragging-card .pocket-close { display: none; }

/* ---- Four pages at once (binder.js render, quad): two spreads, one above the other, each a row
   of its own boards and spine. TIER_GAP in binder.js is the gap here. */
.binder.is-quad { flex-direction: column; gap: 22px; }
.binder.is-quad > .spread-tier { position: relative; display: flex; align-items: stretch; }

/* ---- A 1st Edition copy (binder.js cardFace, slot.printing): "1st" in the bottom-right corner,
   above a grade when there is one. Unlimited, the usual printing, has no badge. */
.slot-ed {
  position: absolute; z-index: 2; right: calc(var(--in-x) + 4px); bottom: calc(var(--in-b) + 4px);
  padding: 1px 5px; border-radius: 4px;
  font-size: clamp(8px, 8cqi, 11px); font-weight: 800; line-height: 1.35; letter-spacing: .02em;
  color: #1a1206; background: linear-gradient(180deg, #ffe08a, #e9b949);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .45), inset 0 0 0 1px rgba(255, 255, 255, .35);
}
.slot-card:has(.slot-grade) .slot-ed { bottom: calc(var(--in-b) + 4px + clamp(14px, 13cqi, 20px) + 3px); }
