/* ==========================================================================
   Spyders Den Comics — one stylesheet.
   Tokens first, then chrome, then components, then pages, then admin.
   Aesthetic: the storefront on the brand art. Pure black, chrome silver,
   marquee gold and hourglass red, over a rain-slick city street.
   ========================================================================== */

/* --------------------------------------------------------------- 1. Tokens */
:root {
  /* ink — the art is pure black, so the page is too */
  --ink:        #000000;
  --ink-2:      #080705;
  --panel:      #100d09;
  --panel-2:    #17130c;
  --panel-3:    #241d12;
  --hair:       rgba(232, 179, 58, 0.16);
  --hair-2:     rgba(232, 179, 58, 0.32);

  /* chrome — the wordmark is cracked silver, not newsprint */
  --paper:      #edecef;
  --paper-2:    #cfced4;
  --paper-ink:  #0a0906;

  /* type */
  --text:       #e6e3dc;
  --text-dim:   #a8a096;
  --text-faint: #7d766a;

  /* accents */
  --gold:       #e8b33a;
  --gold-deep:  #b0821a;
  --pulp:       #d81e2c;
  --pulp-deep:  #9c1420;
  --silk:       #cdccd4;
  --mint:       #6ec6a0;

  /* type stacks — Anton is the closest free face to the logo lettering */
  --display: 'Anton', 'Oswald', 'Haettenschweiler', 'Arial Narrow', 'Impact', sans-serif;
  --body:    'Libre Franklin', 'Franklin Gothic Medium', 'Helvetica Neue', Arial, sans-serif;
  --mono:    'DM Mono', ui-monospace, 'SFMono-Regular', 'Roboto Mono', monospace;

  /* scale */
  --gut: clamp(1rem, 3.2vw, 2rem);
  --shell: 1240px;
  --r-s: 3px;
  --r-m: 6px;
  --r-l: 12px;

  /* the brand's two surface treatments, reused instead of re-typed */
  --chrome: linear-gradient(178deg, #ffffff 0%, #e3e2e6 34%, #9d9ca4 58%, #f4f3f6 74%, #b7b6be 100%);
  --gold-face: linear-gradient(178deg, #f8d67f 0%, #e8b33a 40%, #a97c15 70%, #f1c65e 100%);

  --shadow-lift: 0 1px 0 rgba(232, 179, 58, 0.10), 0 18px 44px -22px rgba(0, 0, 0, 0.95);
  --shadow-hard: 6px 6px 0 var(--ink);
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* ------------------------------------------------------------ 2. Baseline */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
  background-color: var(--ink);
}

body {
  margin: 0;
  min-height: 100vh;
  overflow-x: hidden;          /* belt and braces: nothing scrolls sideways */
  background-color: transparent;
  color: var(--text);
  font-family: var(--body);
  font-size: 1rem;
  line-height: 1.62;
  font-synthesis-weight: none;
}

/* The storefront street from the brand art, sunk far enough back that body
   copy still reads. A fixed pseudo-element, not background-attachment: fixed,
   which iOS Safari has never rendered correctly. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-color: var(--ink);
  background-image:
    linear-gradient(180deg, rgba(0, 0, 0, 0.62) 0%, rgba(0, 0, 0, 0.86) 46%, #000 82%),
    url('../img/street.jpg');
  background-size: auto, cover;
  background-position: center, center top;
  background-repeat: no-repeat, no-repeat;
}

/* Fixed grain layer — never inside a scrolling container. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  opacity: 0.5;
  background-image: radial-gradient(circle at 1px 1px, rgba(237, 236, 239, 0.05) 1px, transparent 0);
  background-size: 4px 4px;
  mix-blend-mode: soft-light;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 0.96;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  margin: 0 0 0.5em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.5rem, 7.4vw, 5rem); }
h2 { font-size: clamp(1.7rem, 4.2vw, 2.7rem); }
h3 { font-size: clamp(1.15rem, 2.4vw, 1.5rem); }
h4 { font-size: 1.02rem; font-family: var(--body); font-weight: 800; letter-spacing: 0.02em; }

/* The wordmark is brushed silver with a gold underlayer. Headings borrow it.
   The plain colour is declared first, so a browser without background-clip
   keeps a readable heading instead of an invisible one. */
h1, .chrome {
  color: var(--paper);
  background-image: var(--chrome);
  -webkit-background-clip: text;
  background-clip: text;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.6);
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  h1, .chrome { color: transparent; text-shadow: none; }
}
.gold-face {
  color: var(--gold);
  background-image: var(--gold-face);
  -webkit-background-clip: text;
  background-clip: text;
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .gold-face { color: transparent; }
}

p { margin: 0 0 1em; max-width: 66ch; }
a { color: var(--gold); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--paper); }

hr { border: 0; border-top: 1px solid var(--hair); margin: 2.5rem 0; }

::selection { background: var(--gold); color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute; left: 0.5rem; top: -4rem; z-index: 100;
  background: var(--gold); color: var(--ink); font-weight: 800;
  padding: 0.6rem 1rem; border-radius: var(--r-m);
  transition: top 0.16s var(--ease);
}
.skip:focus { top: 0.5rem; }

.sr {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ------------------------------------------------------------- 3. Layout */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
}
.shell-narrow { max-width: 860px; }

section { padding-block: clamp(3rem, 7vw, 5.5rem); }
section.tight { padding-block: clamp(2rem, 4vw, 3rem); }

.eyebrow {
  font-family: var(--mono);
  font-size: 0.735rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 1rem;
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
.eyebrow::before {
  content: '';
  width: 2.1rem; height: 2px;
  background: var(--gold);
  flex: none;
}

.lede { font-size: clamp(1.04rem, 1.9vw, 1.22rem); color: var(--text-dim); max-width: 58ch; }
.muted { color: var(--text-dim); }
.faint { color: var(--text-faint); }
.mono { font-family: var(--mono); }
.nowrap { white-space: nowrap; }
.center { text-align: center; }

/* ------------------------------------------------------------ 4. Buttons */
.btn {
  --btn-bg: var(--gold);
  --btn-fg: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  font-family: var(--body);
  font-weight: 800;
  font-size: 0.93rem;
  letter-spacing: 0.035em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.82rem 1.5rem;
  border: 2px solid var(--btn-bg);
  border-radius: var(--r-m);
  background: var(--btn-bg);
  color: var(--btn-fg);
  cursor: pointer;
  transition: transform 0.14s var(--ease), box-shadow 0.14s var(--ease),
              background-color 0.14s var(--ease), color 0.14s var(--ease);
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.55);
}
.btn:hover { transform: translateY(-2px); box-shadow: 0 6px 0 rgba(0, 0, 0, 0.55); color: var(--btn-fg); }
.btn:active { transform: translateY(1px); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.55); }
.btn[disabled], .btn[aria-disabled='true'] { opacity: 0.42; pointer-events: none; }

.btn-ghost { --btn-bg: transparent; --btn-fg: var(--text); border-color: var(--hair-2); box-shadow: none; }
.btn-ghost:hover { --btn-fg: var(--ink); background: var(--paper); border-color: var(--paper); box-shadow: none; }

.btn-pulp { --btn-bg: var(--pulp); --btn-fg: #fff6f2; }
.btn-paper { --btn-bg: var(--paper); --btn-fg: var(--paper-ink); }
.btn-sm { padding: 0.5rem 0.9rem; font-size: 0.78rem; }
.btn-lg { padding: 1rem 2rem; font-size: 1rem; }
.btn-block { width: 100%; }

.btn-link {
  background: none; border: 0; padding: 0;
  font: inherit; color: var(--gold); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.btn-link:hover { color: var(--paper); }
.btn-link.danger { color: var(--pulp); }

/* --------------------------------------------------------- 5. Site chrome */
.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgba(0, 0, 0, 0.9);
  backdrop-filter: blur(10px) saturate(120%);
  border-bottom: 1px solid var(--hair);
}
/* The gold trim off the shop sign. */
.masthead::after {
  content: '';
  display: block;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--gold-deep) 12%, var(--gold) 50%, var(--gold-deep) 88%, transparent);
}

.masthead-in {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 4.4rem;
  padding-block: 0.6rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  text-decoration: none;
  color: var(--paper);
  flex: none;
  min-width: 0;
}
.brand:hover { color: var(--paper); }
/* Also the owner's gesture target — see initOwnerShortcut in site.js. Opting
   out of double-tap zoom is what lets the desktop double-click register on a
   touch screen at all, and the callout and selection rules stop a held press
   from raising iOS's image menu or highlighting the wordmark beside it. */
.brand-mark {
  width: 3.5rem;
  height: 2.5rem;
  flex: none;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.brand-word { display: flex; flex-direction: column; line-height: 1; min-width: 0; }
.brand-word b {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.16rem;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}
.brand-word span {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.28em;
  color: var(--gold);
  margin-top: 0.22rem;
}

.nav-toggle {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  background: none;
  border: 1px solid var(--hair-2);
  border-radius: var(--r-m);
  color: var(--text);
  font: 800 0.78rem/1 var(--body);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.6rem 0.8rem;
  cursor: pointer;
}
.nav-toggle:hover { border-color: var(--gold); color: var(--gold); }
.nav-toggle i {
  display: block; width: 1rem; height: 2px; background: currentColor;
  box-shadow: 0 5px 0 currentColor, 0 -5px 0 currentColor;
}

.nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.15rem;
  flex-wrap: wrap;
}
.nav a {
  font-weight: 700;
  font-size: 0.845rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
  text-decoration: none;
  padding: 0.5rem 0.66rem;
  border-radius: var(--r-s);
  position: relative;
}
.nav a:hover { color: var(--paper); background: rgba(237, 236, 239, 0.07); }
.nav a[aria-current='page'] { color: var(--gold); }
.nav a[aria-current='page']::after {
  content: '';
  position: absolute; left: 0.66rem; right: 0.66rem; bottom: 0.18rem;
  height: 2px; background: var(--gold);
}

/* The owner's plain way in, beside the pages rather than hidden behind the
   press-and-hold on the spider. Boxed so it reads as the one item in the bar
   that is not a page of the site; it never takes the aria-current underline
   because /admin.html is not one of them. */
.nav a.nav-admin {
  margin-left: 0.4rem;
  border: 1px solid var(--hair-2);
  color: var(--text);
}
.nav a.nav-admin:hover {
  color: var(--gold);
  border-color: var(--gold);
  background: none;
}


/* The shop, reachable without opening the menu.

   Below 900px the whole nav collapses behind the Menu button, so the one thing
   a visitor is most likely to be looking for — the way in to the books that
   are actually for sale — was two taps away and invisible until the first of
   them. This strip sits in the bar itself and carries the shop glyph as an
   icon-only link, which is why it has an aria-label: there is no text beside
   it to read.

   It carries [data-shop-only] on the wrapper rather than on the link, so it is
   one node for site.js to unhide and a closed shop leaves nothing in the bar
   at all. Above 900px the full nav is already showing Shop and Basket with
   their labels, so the strip stands down.

   The Shop and not the Basket, because the bar has room for one: a 160px
   wordmark and a 94px Menu button leave 89px of the 343px content box at
   375px wide, and two 44px targets with anything between them do not fit
   without something scrolling sideways. The basket keeps its full-width
   labelled row in the panel. */
.nav-quick { display: none; }

@media (max-width: 899px) {
  /* The bar is 4.4rem of masthead plus the 2px gold trim and its hairline, so
     the panel hangs at 4.6rem — and to leave the screen it has to travel its
     own height *plus* that offset. translateY(-101%) moved it by its own height
     and one percent over, which is about three pixels where seventy were
     needed: the panel came to rest with its bottom still inside the bar, and
     the last thing in it — the full-width gold Cart button — sat across the top
     of the page on top of the logo. Since .nav is a child of .masthead it wins
     the paint order, so the logo was covered rather than merely crowded, and
     the owner lost the press-and-hold way into the back office.

     visibility is belt and braces. Whatever the arithmetic does on a viewport
     nobody tested, a closed menu cannot be seen or tapped. */
  .nav {
    position: fixed;
    inset: 4.6rem 0 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 0;
    padding: 0.5rem var(--gut) 1.2rem;
    background: var(--ink-2);
    border-bottom: 1px solid var(--hair);
    box-shadow: var(--shadow-lift);
    max-height: calc(100vh - 4.6rem);
    overflow-y: auto;
    visibility: hidden;
    transform: translateY(calc(-100% - 4.6rem));
    transition: transform 0.28s var(--ease), visibility 0s linear 0.28s;
  }
  .nav a { padding: 0.85rem 0.4rem; border-bottom: 1px solid var(--hair); font-size: 1rem; }
  /* In the panel every link is a full-width row, so the box becomes one too
     rather than a button floating in the middle of the list. */
  .nav a.nav-admin {
    margin: 0.7rem 0 0;
    padding: 0.85rem 0.4rem;
    text-align: center;
    border: 1px solid var(--hair-2);
    border-radius: var(--r-s);
  }
  .nav a[aria-current='page']::after { display: none; }
  body.nav-open .nav {
    visibility: visible;
    transform: translateY(0);
    /* no delay on the way in, or the slide happens invisibly */
    transition: transform 0.28s var(--ease), visibility 0s;
  }
  body.nav-open { overflow: hidden; }
  /* The logo is the owner's way into the back office, so it outranks the menu:
     the mark and the Menu button stay on top of the panel at every point in
     the slide and cannot be covered by it again. */
  .brand,
  .nav-toggle { position: relative; z-index: 1; }

  /* The shop shortcut, in the bar beside the Menu button.

     It takes the automatic left margin that used to push the Menu button to
     the right, and hands the button a plain gap instead — but only while the
     strip is actually showing. `:not([hidden])` is doing real work there: a
     hidden element still matches a sibling selector, so without it a closed
     shop would strip the auto margin off the Menu button and leave it sitting
     against the wordmark instead of out at the edge. */
  .nav-quick {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    margin-left: auto;
    position: relative;
    z-index: 1;
  }
  .nav-quick:not([hidden]) ~ .nav-toggle { margin-left: 0; }
  .nav-quick a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 44px each way: this strip is thumb-only, and the glyph on its own is a
       far smaller target than the full-width labelled rows in the panel. */
    min-width: 2.75rem;
    min-height: 2.75rem;
    color: var(--text);
    padding: 0.5rem;
    border-radius: var(--r-s);
    text-decoration: none;
  }
  .nav-quick a:hover { color: var(--gold); background: rgba(237, 236, 239, 0.07); }
  /* `flex: none` against the baseline `max-width: 100%` in section 2: as a
     flex item the glyph was shrinkable, and the reset let the flex algorithm
     squeeze a 22px-wide drawing down to 9px while leaving its height alone —
     a shop door stretched into a letterbox. */
  .nav-quick .nav-ico { flex: none; width: 1.4rem; height: 1.4rem; margin: 0; }
}
@media (min-width: 900px) {
  .nav-toggle { display: none; }
  .nav { transform: none !important; }
}

/* Footer */
.footer {
  border-top: 1px solid var(--hair);
  background: rgba(0, 0, 0, 0.78);
  margin-top: 3rem;
  padding-block: 3rem 2rem;
  position: relative;
  z-index: 1;
}
/* Every track is even now. The wide first column existed for the brand mark
   and its tagline, which the footer no longer carries; a leftover 1.4fr would
   just make Browse twice the width of Get in touch. The 9rem minimum is what
   keeps the two link lists side by side at 375px rather than stacking, so the
   footer stays two short rows on a phone. */
.footer-grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
}
.footer h4 {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.9rem;
}
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.45rem; }
.footer a { color: var(--text-dim); text-decoration: none; font-size: 0.92rem; }
.footer a:hover { color: var(--paper); text-decoration: underline; }
.footer-fine {
  margin-top: 2.5rem;
  padding-top: 1.3rem;
  border-top: 1px solid var(--hair);
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  font-size: 0.8rem;
  color: var(--text-faint);
  font-family: var(--mono);
}

/* The glyphs on the Shop and Basket links. Inline SVG rather than an icon
   font or a sprite: there is no build step to assemble one, and a font that
   fails to load leaves a stray letter in the masthead where a picture should
   be. They inherit `currentColor`, so hover and the gold aria-current state
   carry the drawing with them for free.

   vertical-align rather than flex on `.nav a` on purpose — the links are
   inline, and at mobile width `.nav a.nav-admin` is centred with text-align,
   which a flex container would quietly stop honouring.

   `display` is restated here because the baseline reset in section 2 sets
   every img/svg/video to `display: block`, which outranks nothing but applies
   to this element too — and a block-level glyph is not something
   `vertical-align` can move. Left as a block it left the shop bar with the
   icon sitting on its own line *above* the label, which stretched the Shop and
   Basket rows to 52px against the 38px of every other link beside them and
   read as a smudge over the word rather than a mark next to it. */
.nav-ico {
  display: inline-block;
  width: 1.05em;
  height: 1.05em;
  margin-right: 0.4rem;
  vertical-align: -0.19em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The basket lives in the masthead, and only when the shop is open — the link
   itself carries [data-shop-only] and starts hidden, so a closed shop shows no
   basket at all rather than an empty one. */
.nav-cart { position: relative; }
.nav-cart .cart-badge {
  display: inline-block;
  min-width: 1.15rem;
  margin-left: 0.4rem;
  padding: 0.05rem 0.3rem;
  border-radius: 999px;
  background: var(--pulp);
  color: #fff;
  font-family: var(--mono);
  font-size: 0.66rem;
  line-height: 1.5;
  text-align: center;
  vertical-align: middle;
}

/* ---------------------------------------------------------- 6. The splash */
.splash {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: var(--gut);
  background:
    radial-gradient(ellipse at 50% 40%, rgba(232, 179, 58, 0.14), transparent 60%),
    var(--ink);
  text-align: center;
}
.splash[hidden] { display: none; }
/* An inline script in the <head> sets data-entered before first paint, so a
   visitor who has already entered never sees the overlay flash on later pages
   in the same session. data-splash locks the page behind the overlay. */
html[data-entered='1'] .splash { display: none; }
html[data-splash='on'], html[data-splash='on'] body { overflow: hidden; }
/* The wash over the street art has to stay light. The art is a night scene that
   measures about a tenth of white on its own, so a heavy vignette does not dim
   the city, it deletes it — and because the element is inset -10% and drifts to
   scale 1.1, the part on screen is drawn from the densest ring of the gradient.
   Nothing here needs protecting but the logo and one button, and both carry
   their own shadow, so this stops well short of opaque at the edge. */
.splash-web {
  position: absolute;
  inset: -10%;
  pointer-events: none;
  background-color: var(--ink);
  background-image:
    radial-gradient(ellipse at 50% 44%, rgba(0, 0, 0, 0.28) 0%, rgba(0, 0, 0, 0.52) 52%, rgba(0, 0, 0, 0.82) 100%),
    url('../img/street.jpg');
  background-size: auto, cover;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
  animation: splash-drift 24s var(--ease) infinite alternate;
}
/* cover on a 3:2 image in a portrait viewport crops to the horizontal middle,
   which throws the storefront off the side of the phone. Pull the frame right. */
@media (max-width: 619px) {
  .splash-web { background-position: center, 68% center; }
}
@keyframes splash-drift {
  from { transform: scale(1.02) rotate(-0.6deg); }
  to   { transform: scale(1.1) rotate(0.6deg); }
}
.splash-in { position: relative; max-width: 42rem; }
/* The other gesture target: on a phone this is the biggest thing on screen and
   it is not a link, so a held press here has nothing to collide with. */
.splash-logo {
  width: min(34rem, 88vw);
  margin: 0 auto 1.4rem;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  filter: drop-shadow(0 0.4rem 1.4rem rgba(0, 0, 0, 0.95))
          drop-shadow(0 0 3rem rgba(232, 179, 58, 0.28));
  animation: drop-in 0.85s var(--ease) both;
}
.splash-in p {
  margin: 0 auto 2rem;
  color: var(--text-dim);
  max-width: 34ch;
  font-size: clamp(0.98rem, 2.2vw, 1.1rem);
  /* the backdrop is no longer flat black behind this line */
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.95), 0 0 1.4rem rgba(0, 0, 0, 0.85);
  animation: drop-in 0.85s 0.18s var(--ease) both;
}
.splash-btn { animation: drop-in 0.85s 0.32s var(--ease) both; }
/* In normal flow under the button, not absolutely positioned off the bottom of
   .splash-in: the gap is then guaranteed, and on a short screen the line cannot
   end up below the fold of the fixed overlay. It overrides the .splash-in p
   margin and max-width, and wraps rather than forcing sideways scroll. */
.splash-note {
  margin: 2.8rem auto 0;
  max-width: 30rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--text-faint);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.95);
  animation: drop-in 0.85s 0.5s var(--ease) both;
}
@keyframes drop-in {
  from { opacity: 0; transform: translateY(1.4rem); }
  to   { opacity: 1; transform: none; }
}
.splash.leaving { animation: splash-out 0.44s var(--ease) forwards; }
@keyframes splash-out {
  to { opacity: 0; transform: scale(1.06); visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .splash-web { animation: none; }
  .splash-logo, .splash-in p, .splash-btn, .splash-note { animation-duration: 0.01s; }
  html { scroll-behavior: auto; }
}

/* ---------------------------------------------------------- 7. Hero/banner */
.banner {
  position: relative;
  border-bottom: 1px solid var(--hair-2);
  background: var(--ink);
  overflow: hidden;
}
.banner img {
  width: 100%;
  /* The art is cropped tight to the lockup already, so it is never cropped
     again here — clipping it would cut "UNLIMITED" off the sign. On a very
     wide screen it letterboxes on black rather than growing without limit. */
  max-width: 1500px;
  margin-left: auto;
  margin-right: auto;
}

.hero { position: relative; padding-block: clamp(3rem, 8vw, 6rem); }
/* The hero runs one column wide. Capped, because a display heading set across
   the full 1240px shell reads as a thin band rather than a headline. */
.hero-solo { max-width: 54rem; }
.hero h1 span {
  display: block;
  color: var(--gold);
  background-image: var(--gold-face);
  -webkit-background-clip: text;
  background-clip: text;
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero h1 span { color: transparent; }
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 0.8rem; margin-top: 1.8rem; }


/* -------------------------------------------------- 8. Cards & catalogue */
.grid-cards {
  display: grid;
  gap: clamp(1rem, 2.2vw, 1.5rem);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 14.5rem), 1fr));
}

/* The collection is a gallery, not a stock catalogue. Its cards stay larger
   and breathe even on wide screens instead of packing into a dense wall. */
.collection-page {
  position: relative;
  overflow: hidden;
}
.collection-page::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 28rem;
  pointer-events: none;
  background:
    radial-gradient(circle at 82% 12%, rgba(222,169,58,.13), transparent 28rem),
    linear-gradient(180deg, rgba(255,255,255,.025), transparent);
}
.collection-page > * { position: relative; }
.collection-heading {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem;
  align-items: end;
  padding-bottom: clamp(1.5rem, 4vw, 2.75rem);
  border-bottom: 1px solid var(--hair-2);
}
.collection-heading h1 { max-width: 11ch; margin-bottom: .8rem; }
.collection-heading .lede { max-width: 48rem; margin-bottom: 0; }
.collection-note {
  max-width: 28rem;
  padding: 1rem 1.1rem;
  border-left: 3px solid var(--gold);
  background: rgba(222,169,58,.06);
  color: var(--text-dim);
}
.collection-note b {
  display: block;
  margin-bottom: .3rem;
  color: var(--paper);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.collection-toolbar {
  display: grid;
  gap: .8rem;
  margin: clamp(1.5rem, 4vw, 2.5rem) 0 clamp(1.25rem, 3vw, 2rem);
  padding: 1rem;
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: rgba(27,21,36,.72);
}
.collection-toolbar input[type="search"] { min-width: 0; }
.collection-toolbar select { width: 100%; }
.collection-toolbar .check { margin: 0; align-self: center; }
.collection-count-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}
.collection-count-row::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--hair);
}
.collection-page .grid-cards {
  gap: clamp(1.4rem, 3vw, 2.4rem);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
}
.collection-page .card-body { padding: 1rem 1.05rem 1.2rem; gap: .45rem; }
.collection-page .card-title { font-size: 1.18rem; }
@media (min-width: 760px) {
  .collection-heading { grid-template-columns: minmax(0, 1.35fr) minmax(16rem, .65fr); }
  .collection-toolbar { grid-template-columns: minmax(15rem, 1fr) auto auto auto; align-items: center; }
  .collection-toolbar select { width: auto; min-width: 9.5rem; }
}
@media (min-width: 1180px) {
  .collection-page .grid-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.card {
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: transform 0.18s var(--ease), border-color 0.18s var(--ease), box-shadow 0.18s var(--ease);
  position: relative;
}
.card:hover {
  transform: translateY(-4px);
  border-color: var(--gold);
  box-shadow: var(--shadow-lift);
  color: inherit;
}
.card-cover {
  position: relative;
  aspect-ratio: 2 / 3;
  background:
    repeating-linear-gradient(135deg, rgba(243,236,225,0.035) 0 10px, transparent 10px 20px),
    var(--panel-2);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.card-cover img { width: 100%; height: 100%; object-fit: cover; }
/* Also the item page's "no photo yet" placeholder, hence no .card-cover scope. */
.no-cover {
  color: var(--silk);
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-align: center;
  padding: 1rem;
}
.card-body { padding: 0.85rem 0.9rem 1rem; display: flex; flex-direction: column; gap: 0.35rem; flex: 1; }
.card-title {
  font-family: var(--display);
  font-size: 1.02rem;
  line-height: 1.12;
  margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card-meta { font-family: var(--mono); font-size: 0.72rem; color: var(--text-faint); letter-spacing: 0.04em; }
.card-foot { margin-top: auto; display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; padding-top: 0.5rem; }
/* The slot a price used to sit in. A collection card shows the condition. */
.card-grade { font-family: var(--display); font-size: 1.12rem; color: var(--gold); }

.flag {
  position: absolute;
  top: 0.55rem; left: 0.55rem;
  z-index: 2;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.28rem 0.5rem;
  border-radius: var(--r-s);
  background: var(--ink);
  color: var(--paper);
  border: 1px solid var(--hair-2);
}
.flag-key { background: var(--gold); color: var(--ink); border-color: var(--gold); }
/* A key flag sits top-left; a sale flag sits top-right so the two never
   collide on a book that is both. */
.flag-sale, .flag-sold, .flag-held { left: auto; right: 0.55rem; }
.flag-sale { background: var(--mint); color: var(--ink); border-color: var(--mint); }
.flag-sold { background: var(--pulp); color: #fff; border-color: var(--pulp); }
.flag-held { background: var(--panel-3); color: var(--text-dim); }

/* On a card for a book that is for sale, the price takes the slot the grade
   would otherwise have. */
.card-price {
  font-family: var(--display);
  font-size: 1.05rem;
  letter-spacing: 0.02em;
  color: var(--gold);
}
.card-price.sold { color: var(--text-faint); text-decoration: line-through; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.24rem 0.55rem;
  border: 1px solid var(--hair-2);
  border-radius: 999px;
  color: var(--text-dim);
}
.chip-gold { border-color: var(--gold); color: var(--gold); }
.chip-mint { border-color: var(--mint); color: var(--mint); }
.chip-pulp { border-color: var(--pulp); color: var(--pulp); }

/* Filter rail */
.shop-layout {
  display: grid;
  gap: clamp(1.4rem, 3vw, 2.4rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 940px) {
  .shop-layout { grid-template-columns: 15.5rem minmax(0, 1fr); }
  .rail { position: sticky; top: 6.2rem; }
}
.rail {
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: rgba(27, 21, 36, 0.72);
  padding: 1.1rem;
}
.rail-group + .rail-group { margin-top: 1.4rem; padding-top: 1.4rem; border-top: 1px solid var(--hair); }
.rail-group > h4 {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.7rem;
}
.facets { display: grid; gap: 0.42rem; max-height: 14rem; overflow-y: auto; }
.facet {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 0.88rem;
  cursor: pointer;
  color: var(--text-dim);
}
.facet:hover { color: var(--paper); }
.facet input { accent-color: var(--gold); width: 1rem; height: 1rem; flex: none; }
.facet .n { margin-left: auto; font-family: var(--mono); font-size: 0.72rem; color: var(--text-faint); }

.shop-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 1.4rem;
}
.shop-bar .count { font-family: var(--mono); font-size: 0.8rem; color: var(--text-faint); margin-right: auto; }

/* Era tiles on the home page — five doors into filtered shop results. */
.era-tiles {
  display: grid;
  gap: 0.8rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9.5rem), 1fr));
  margin-top: 1.6rem;
}
.era-tile {
  display: grid;
  gap: 0.2rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: rgba(27, 21, 36, 0.7);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.18s var(--ease), transform 0.18s var(--ease);
}
.era-tile:hover { border-color: var(--gold); transform: translateY(-3px); color: inherit; }
.era-tile b { font-family: var(--display); font-weight: 400; font-size: 1.32rem; line-height: 1; color: var(--gold); }
.era-tile span { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-faint); }

/* --------------------------------------------------------- 9. Form system */
.field { display: grid; gap: 0.4rem; margin-bottom: 1.1rem; min-width: 0; }
.field > label, .lbl {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.field .hint { font-size: 0.82rem; color: var(--text-faint); }
.req { color: var(--pulp); }

input[type='text'], input[type='email'], input[type='tel'], input[type='number'],
input[type='search'], input[type='password'], input[type='url'], select, textarea {
  width: 100%;
  min-width: 0;
  font: inherit;
  font-size: 0.95rem;
  color: var(--text);
  background: var(--ink-2);
  border: 1px solid var(--hair-2);
  border-radius: var(--r-m);
  padding: 0.68rem 0.8rem;
  transition: border-color 0.14s var(--ease), background-color 0.14s var(--ease);
}
textarea { resize: vertical; min-height: 6.5rem; line-height: 1.55; }
select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-dim) 50%),
                    linear-gradient(135deg, var(--text-dim) 50%, transparent 50%);
  background-position: right 1.05rem center, right 0.8rem center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 2.1rem;
}
input:hover, select:hover, textarea:hover { border-color: var(--silk); }
input:focus, select:focus, textarea:focus { border-color: var(--gold); background: var(--ink); outline: none; }
input::placeholder, textarea::placeholder { color: var(--text-faint); }
input[type='number'] { font-family: var(--mono); }

.row { display: grid; gap: 0 1rem; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 620px) {
  .row-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .row-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .row-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

fieldset { border: 1px solid var(--hair); border-radius: var(--r-m); padding: 1.1rem; margin: 0 0 1.3rem; min-width: 0; }
legend {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--gold); padding-inline: 0.5rem;
}

.check {
  display: grid;
  grid-template-columns: 1.15rem minmax(0, 1fr);
  gap: 0.65rem;
  align-items: start;
  font-size: 0.9rem;
  color: var(--text-dim);
  cursor: pointer;
  margin-bottom: 0.6rem;
}
.check input { accent-color: var(--gold); width: 1.15rem; height: 1.15rem; margin: 0.2rem 0 0; }


.panel {
  border: 1px solid var(--hair);
  border-radius: var(--r-l);
  background: linear-gradient(180deg, rgba(36, 29, 48, 0.9), rgba(27, 21, 36, 0.9));
  padding: clamp(1.2rem, 3vw, 2rem);
  box-shadow: var(--shadow-lift);
}
.panel + .panel { margin-top: 1.4rem; }
.panel-flat { background: rgba(27, 21, 36, 0.6); box-shadow: none; border-radius: var(--r-m); }

.note {
  border-left: 3px solid var(--gold);
  background: rgba(240, 180, 41, 0.07);
  padding: 0.85rem 1rem;
  border-radius: 0 var(--r-m) var(--r-m) 0;
  font-size: 0.9rem;
  color: var(--text-dim);
  margin-bottom: 1.2rem;
}
.note strong { color: var(--paper); }
.note-pulp { border-left-color: var(--pulp); background: rgba(217, 68, 54, 0.09); }
.note-mint { border-left-color: var(--mint); background: rgba(110, 198, 160, 0.08); }


.thumbs { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem; }
.thumb {
  position: relative;
  width: 4.4rem; height: 5.8rem;
  border-radius: var(--r-s);
  overflow: hidden;
  border: 1px solid var(--hair-2);
  background: var(--panel-2);
}
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb button {
  position: absolute; top: 2px; right: 2px;
  width: 1.3rem; height: 1.3rem;
  border-radius: 999px;
  border: 0;
  background: var(--ink);
  color: var(--paper);
  font: 700 0.8rem/1 var(--body);
  cursor: pointer;
}
.thumb button:hover { background: var(--pulp); }

/* -------------------------------------------------- 10. States & feedback */
.empty {
  border: 1px dashed var(--hair-2);
  border-radius: var(--r-l);
  padding: clamp(2rem, 5vw, 3.4rem) clamp(1.2rem, 4vw, 2.6rem);
  text-align: center;
  background: rgba(20, 16, 25, 0.55);
}
.empty-mark { width: 5.5rem; margin: 0 auto 1.2rem; color: var(--silk); opacity: 0.85; }
.empty h3 { margin-bottom: 0.5rem; }
.empty p { margin-inline: auto; color: var(--text-dim); }
.empty .btn { margin-top: 1.3rem; }

.skeleton { display: grid; gap: 0.5rem; }
.sk {
  background: linear-gradient(90deg, var(--panel) 0%, var(--panel-3) 50%, var(--panel) 100%);
  background-size: 220% 100%;
  border-radius: var(--r-s);
  animation: sk 1.3s linear infinite;
}
.sk-cover { aspect-ratio: 2 / 3; border-radius: var(--r-m); }
.sk-line { height: 0.7rem; }
.sk-line.short { width: 55%; }
@keyframes sk { from { background-position: 120% 0; } to { background-position: -120% 0; } }
@media (prefers-reduced-motion: reduce) { .sk { animation: none; } }

.alert {
  border: 1px solid var(--pulp);
  background: rgba(217, 68, 54, 0.12);
  color: #ffd9d2;
  border-radius: var(--r-m);
  padding: 0.8rem 1rem;
  font-size: 0.9rem;
  margin-bottom: 1rem;
}
.alert-ok { border-color: var(--mint); background: rgba(110, 198, 160, 0.12); color: #d6f5e6; }
.alert[hidden] { display: none; }

.err { color: #ff9d90; font-size: 0.82rem; }

.toasts {
  position: fixed;
  right: 1rem; bottom: 1rem;
  z-index: 80;
  display: grid;
  gap: 0.5rem;
  max-width: min(24rem, calc(100vw - 2rem));
}
.toast {
  background: var(--panel-2);
  border: 1px solid var(--hair-2);
  border-left: 3px solid var(--gold);
  border-radius: var(--r-m);
  padding: 0.75rem 0.95rem;
  font-size: 0.88rem;
  box-shadow: var(--shadow-lift);
  animation: toast-in 0.24s var(--ease) both;
}
.toast.bad { border-left-color: var(--pulp); }
.toast.good { border-left-color: var(--mint); }
.toast.warn { border-left-color: var(--gold); }
@keyframes toast-in { from { opacity: 0; transform: translateY(0.7rem); } to { opacity: 1; transform: none; } }

.spin {
  display: inline-block;
  width: 0.95em; height: 0.95em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 999px;
  animation: spin 0.7s linear infinite;
  vertical-align: -0.1em;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------- 11. Item page */
.listing-grid {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 900px) {
  .listing-grid { grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr); }
}
.gallery { display: grid; gap: 0.7rem; }
.gallery-main {
  aspect-ratio: 2 / 3;
  border: 1px solid var(--hair-2);
  border-radius: var(--r-m);
  background: var(--panel-2);
  overflow: hidden;
  display: grid;
  place-items: center;
}
.gallery-main img { width: 100%; height: 100%; object-fit: contain; background: var(--ink); }
.gallery-strip { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.gallery-strip button {
  width: 3.6rem; height: 4.8rem;
  padding: 0;
  border: 1px solid var(--hair-2);
  border-radius: var(--r-s);
  overflow: hidden;
  background: var(--panel-2);
  cursor: pointer;
}
.gallery-strip button[aria-current='true'] { border-color: var(--gold); }
.gallery-strip img { width: 100%; height: 100%; object-fit: cover; }

.spec { border-top: 1px solid var(--hair); margin: 1.4rem 0 0; }
.spec div {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr);
  gap: 0.5rem 1rem;
  padding: 0.62rem 0;
  border-bottom: 1px solid var(--hair);
  font-size: 0.9rem;
}
.spec dt { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; color: var(--text-faint); }
.spec dd { margin: 0; }

/* ------------------------------------------------- 12. Shop & item page buy */

/* Sections 12 and 13 were the cart and the policy pages. They went when the
   shop went, and they are back now that it is: 12 is the shop and the basket,
   13 is the receipt. The numbering either side never moved, so the "section
   16b" everything refers to is still section 16b. */

/* The three-fact strip under the shop heading: one of each, postage, cards. */
.trust-row {
  list-style: none;
  margin: 1.8rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.9rem;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 720px) { .trust-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.trust-row li {
  padding: 0.9rem 1rem;
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: var(--panel);
}
.trust-row b {
  display: block;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.3rem;
}
.trust-row span { font-size: 0.88rem; color: var(--text-dim); }

/* The search and sort controls in the shop toolbar. */
.shop-bar-tools { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.shop-bar-tools input[type="search"] { width: min(100%, 15rem); }
.shop-bar-tools select { max-width: 10.5rem; }

.how-list { margin: 0 0 1.4rem; padding-left: 1.2rem; display: grid; gap: 0.6rem; }
.how-list li { font-size: 0.92rem; color: var(--text-dim); }
.how-list b { color: var(--text); }

/* --- the buy box on the item page --- */

.buy-box {
  margin: 1.2rem 0 1.6rem;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--hair-2);
  border-radius: var(--r-m);
  background: var(--panel-2);
}
.buy-box.sold, .buy-box.held { background: var(--panel); border-color: var(--hair); }
.buy-price {
  margin: 0 0 0.8rem;
  font-family: var(--display);
  font-size: clamp(1.7rem, 5vw, 2.3rem);
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--gold);
}
.buy-box.sold .buy-price { color: var(--text-faint); }
.buy-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.buy-fine {
  margin: 0.9rem 0 0;
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--text-faint);
}

/* --- the basket page --- */

.cart-layout { display: grid; gap: clamp(1.4rem, 4vw, 2.4rem); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 900px) { .cart-layout { grid-template-columns: minmax(0, 1.5fr) minmax(0, 0.85fr); } }
.cart-side { display: grid; gap: 1.2rem; align-content: start; }

.cart-line {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr);
  gap: 0.9rem 1rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--hair);
}
@media (min-width: 560px) { .cart-line { grid-template-columns: 5.5rem minmax(0, 1fr) auto; } }
.cart-line:first-child { padding-top: 0; }

.cart-thumb { display: block; border-radius: var(--r-s); overflow: hidden; background: var(--panel); }
.cart-thumb img { display: block; width: 100%; height: auto; }
.cart-thumb .no-cover { font-size: 0.6rem; min-height: 6rem; }

.cart-detail h3 { margin: 0 0 0.3rem; font-size: 1rem; }
.cart-detail h3 a { color: var(--text); text-decoration: none; }
.cart-detail h3 a:hover { color: var(--gold); }
.cart-detail .card-meta { margin: 0 0 0.15rem; }
.warn-line { margin: 0.4rem 0 0; font-size: 0.8rem; color: var(--gold); }

.cart-money {
  grid-column: 2;
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
}
@media (min-width: 560px) {
  .cart-money { grid-column: auto; flex-direction: column; align-items: flex-end; gap: 0.4rem; }
}
.cart-price { font-family: var(--display); font-size: 1.15rem; color: var(--gold); }

/* ---------------------------------------------------------- 13. Receipt */

.receipt-lines { margin: 1.6rem 0; border-top: 1px solid var(--hair); padding-top: 0.4rem; }
.receipt-line { padding: 0.9rem 0; }
.receipt-line .cart-detail h3 { margin: 0; }
.receipt-sums { margin-bottom: 1.6rem; }
.receipt-sums dd strong { color: var(--gold); font-size: 1.05rem; }


/* --------------------------------------------------- 14. Collectables page */
/* The shelf is a product page, so it reads like one: one column of headings,
   one grid, three cards built to exactly the same shape. No rotated stamps,
   no one card singled out with a gold outline, no display type inside a card
   competing with the page title — the pieces are the loudest thing here. */

.collectables-head {
  border-bottom: 1px solid var(--hair);
}
.collectables-head h1 { max-width: 18ch; margin-bottom: .9rem; }
.collectables-head .lede { max-width: 56ch; margin-bottom: 0; }

.collectables-bar {
  display: grid;
  gap: .4rem;
  margin-bottom: clamp(1.5rem, 3.5vw, 2.25rem);
}
.collectables-bar h2 { font-size: clamp(1.5rem, 3vw, 2rem); }
.collectables-bar p { color: var(--text-dim); font-size: .95rem; }

.collectables-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.1rem, 2.4vw, 1.75rem);
  align-items: start;
}
@media (min-width: 680px)  { .collectables-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1040px) { .collectables-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* Every card is the same card: same border, same art ratio, same copy block,
   and the row stretches them to a common height so the grid lines up. */
.collectable-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: var(--panel);
  box-shadow: var(--shadow-lift);
  transition: border-color .25s var(--ease), transform .25s var(--ease);
}
.collectable-card:hover {
  transform: translateY(-3px);
  border-color: var(--hair-2);
}

.collectable-art {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--ink-2);
  border-bottom: 1px solid var(--hair);
}
.collectable-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s var(--ease);
}
.collectable-card:hover .collectable-art img { transform: scale(1.03); }

/* A piece without photographs yet holds the same frame quietly rather than
   filling it with oversized lettering. */
.collectable-art-placeholder {
  display: grid;
  place-items: center;
  height: 100%;
  padding: 1.25rem;
  text-align: center;
  background:
    repeating-linear-gradient(135deg, transparent 0 18px, rgba(232,179,58,.035) 18px 19px),
    var(--ink-2);
}
.collectable-art-placeholder span {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.collectable-status {
  position: absolute;
  z-index: 1;
  top: .7rem;
  right: .7rem;
  padding: .3rem .5rem;
  border-radius: var(--r-s);
  background: var(--gold);
  color: var(--paper-ink);
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.collectable-copy {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: .5rem;
  padding: clamp(1rem, 2.4vw, 1.35rem);
}
.collectable-kind {
  margin: 0;
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.collectable-copy h3 {
  margin: 0;
  font-size: clamp(1.2rem, 2.2vw, 1.4rem);
  line-height: 1.15;
}
.collectable-description {
  margin: 0;
  color: var(--text-dim);
  font-size: .95rem;
}
.collectable-price {
  margin: .2rem 0 0;
  font-family: var(--display);
  font-size: 1.35rem;
  line-height: 1;
  color: var(--gold);
}
.collectable-state {
  margin: 0;
  color: var(--text-dim);
  font-size: .85rem;
}
.collectable-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem;
  margin-top: auto;
  padding-top: 1rem;
}
.collectable-actions .btn { flex: 1 1 100%; }

.collectables-foot {
  max-width: 62ch;
  margin: clamp(1.75rem, 4vw, 2.75rem) 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--hair);
  color: var(--text-dim);
  font-size: .95rem;
}

/* ------------------------------------------ 14b. Intake & policy pages */
/* Section 14b rather than a renumbering, for the same reason 16b is 16b: the
   numbers in this file are referred to elsewhere and moving them costs more
   than it buys. The two Sell/Consign pages and the policies page share this
   block because they are the same shape — a column of prose beside something
   narrower that sticks. */

.intake-layout {
  display: grid;
  gap: clamp(1.6rem, 4vw, 3rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 940px) {
  .intake-layout { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); }
  /* The form is the point of the page, so it is the half that stays put. */
  .intake-form-wrap { position: sticky; top: 6.2rem; }
}
.intake-intro > p { max-width: 60ch; color: var(--text-dim); }
.intake-intro h3 { margin-top: 1.8rem; }
.intake-form-wrap .panel { margin: 0; }
.intake-form-wrap textarea { resize: vertical; }

.policy-layout {
  display: grid;
  gap: clamp(1.4rem, 3vw, 2.6rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 940px) {
  .policy-layout { grid-template-columns: 16rem minmax(0, 1fr); }
  .policy-nav { position: sticky; top: 6.2rem; }
}
.policy-nav {
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: rgba(27, 21, 36, 0.72);
  padding: 1.1rem;
}
.policy-nav > h4 {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.7rem;
}
.policy-nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.policy-nav a { color: var(--text-dim); font-size: 0.92rem; text-decoration: none; }
.policy-nav a:hover { color: var(--gold); }

.policy-body { max-width: 70ch; }
.policy-body h2 {
  /* Anchored headings land under the sticky masthead without this. */
  scroll-margin-top: 6.4rem;
  margin-top: 2.6rem;
  font-size: clamp(1.3rem, 3.4vw, 1.7rem);
}
.policy-body h2:first-child { margin-top: 0; }
.policy-body p { color: var(--text-dim); }
.policy-body code { font-family: var(--mono); font-size: 0.86em; color: var(--paper-2); }
.policy-quote {
  margin: 1rem 0 1.4rem;
  padding: 0.9rem 1.1rem;
  border-left: 3px solid var(--gold);
  background: var(--panel);
  color: var(--text);
  font-size: 1rem;
}
.policy-list { list-style: none; margin: 0.6rem 0 1.4rem; padding: 0; display: grid; gap: 0.8rem; }
.policy-list li {
  color: var(--text-dim);
  padding-left: 1.1rem;
  position: relative;
}
.policy-list li::before { content: ''; position: absolute; left: 0; top: 0.62em; width: 5px; height: 5px; background: var(--gold); }


/* -------------------------------------------------------- 15. Admin panel */
body.admin { background-color: var(--ink); }
/* The street backdrop is atmosphere for the shop, not for reading tables against. */
body.admin::before { background-image: none; }
body.admin::after { opacity: 0.28; }

.gate { min-height: 100vh; display: grid; place-items: center; padding: var(--gut); }
.gate-card { width: 100%; max-width: 25rem; text-align: center; }
/* display: block matters — outside .brand the mark is a bare inline span, so
   width, height and the auto margins are otherwise ignored and the image
   stretches to the full width of the card. */
.gate-card .brand-mark { display: block; width: 7rem; height: 5rem; margin: 0 auto 1.2rem; }

.admin-bar {
  position: sticky; top: 0; z-index: 30;
  background: rgba(0, 0, 0, 0.95);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hair);
}
.admin-bar-in { display: flex; align-items: center; gap: 0.8rem; min-height: 3.6rem; flex-wrap: wrap; padding-block: 0.5rem; }
.admin-bar .brand-word b { font-size: 1rem; }
.admin-bar .who { margin-left: auto; font-family: var(--mono); font-size: 0.74rem; color: var(--text-faint); }

.tabs {
  display: flex;
  gap: 0.2rem;
  overflow-x: auto;
  border-bottom: 1px solid var(--hair);
  scrollbar-width: none;
  padding-bottom: 0;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs button {
  flex: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-dim);
  font: 800 0.82rem/1 var(--body);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 0.9rem 0.85rem;
  cursor: pointer;
  white-space: nowrap;
}
.tabs button:hover { color: var(--paper); }
.tabs button[aria-selected='true'] { color: var(--gold); border-bottom-color: var(--gold); }
/* The unread count on the Intake tab. Ships hidden and stays that way at
   zero, so a quiet queue looks quiet rather than looking like a zero. */
.tab-badge {
  display: inline-block;
  margin-left: 0.4rem;
  min-width: 1.15rem;
  padding: 0.1rem 0.3rem;
  border-radius: 999px;
  background: var(--pulp);
  color: var(--paper);
  font-family: var(--mono);
  font-size: 0.66rem;
  line-height: 1.35;
  text-align: center;
}

.tab-panel { padding-block: 1.8rem 4rem; }
.tab-panel[hidden] { display: none; }

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1.3rem;
}
.toolbar .grow { flex: 1 1 12rem; min-width: 0; }
.toolbar .spacer { flex: 1 1 auto; }

.stat-row {
  display: grid;
  gap: 0.8rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9.5rem), 1fr));
  margin-bottom: 1.6rem;
}
.stat {
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: rgba(27, 21, 36, 0.7);
  padding: 0.9rem 1rem;
}
.stat .k { font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-faint); }
.stat .v { font-family: var(--display); font-size: 1.6rem; line-height: 1.1; margin-top: 0.25rem; }
.stat .v.gold { color: var(--gold); }
.stat .v.pulp { color: var(--pulp); }

.table-wrap {
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  overflow-x: auto;
  background: rgba(27, 21, 36, 0.6);
  -webkit-overflow-scrolling: touch;
}
table.data { width: 100%; border-collapse: collapse; font-size: 0.88rem; min-width: 46rem; }
table.data th, table.data td { padding: 0.62rem 0.7rem; text-align: left; border-bottom: 1px solid var(--hair); vertical-align: middle; }
table.data th {
  font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--gold); background: rgba(0, 0, 0, 0.82); position: sticky; top: 0; z-index: 1; white-space: nowrap;
}
table.data tbody tr:hover { background: rgba(232, 179, 58, 0.05); }
table.data td.num { font-family: var(--mono); text-align: right; white-space: nowrap; }
table.data td.act { white-space: nowrap; text-align: right; }
table.data td.act .btn-link + .btn-link { margin-left: 0.7rem; }
table.data .cell-title { font-weight: 700; }
table.data .cell-sub { font-family: var(--mono); font-size: 0.72rem; color: var(--text-faint); }
table.data img.mini { width: 2rem; height: 2.8rem; object-fit: cover; border-radius: 2px; border: 1px solid var(--hair); }

.pill {
  display: inline-block;
  font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 0.2rem 0.45rem; border-radius: 999px; border: 1px solid currentColor;
}
/* An item is either on the site or it is not. The scan queue has its own set. */
.pill.public { color: var(--mint); }
.pill.private { color: var(--text-faint); }
.pill.queued, .pill.working { color: var(--gold); }
.pill.done { color: var(--mint); }
.pill.failed, .pill.off { color: var(--pulp); }
.pill.sold { color: var(--pulp); }
.pill.held { color: var(--gold); }

/* The two shop fields in the book editor, fenced off from the rest of the form
   so nobody puts a price on a book by accident. */
.sale-block {
  margin: 1.4rem 0;
  padding: 1rem 1.1rem;
  border: 1px solid var(--hair-2);
  border-radius: var(--r-m);
  background: var(--panel-2);
}
.sale-block h4 {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.8rem;
}

/* --- the order ledger --- */

.order-card {
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: var(--panel);
  padding: 1rem 1.1rem;
  margin-bottom: 0.9rem;
}
.order-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  justify-content: space-between;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--hair);
}
.order-body {
  display: grid;
  gap: 0.9rem 1.4rem;
  padding: 0.8rem 0;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 700px) { .order-body { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.order-buyer { border-left: 2px solid var(--hair-2); padding-left: 0.9rem; }
.ship-to {
  margin: 0.4rem 0 0;
  font-family: var(--mono);
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-dim);
  white-space: pre-wrap;
}
/* What somebody typed into the Sell to us box, kept as they typed it —
   line breaks and all — because how they describe a box of books is half of
   what tells you whether it is worth answering. */
.intake-text {
  margin: 0;
  font-family: var(--body);
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--text);
  white-space: pre-wrap;
}
.order-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--hair);
}
.order-foot input[type="text"] { width: min(100%, 14rem); }

/* Drawer / modal */
.drawer {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  background: rgba(6, 5, 9, 0.72);
  backdrop-filter: blur(3px);
}
.drawer[hidden] { display: none; }
.drawer-panel {
  margin-left: auto;
  width: min(46rem, 100%);
  height: 100%;
  overflow-y: auto;
  background: var(--ink-2);
  border-left: 1px solid var(--hair-2);
  box-shadow: -30px 0 60px -30px rgba(0, 0, 0, 0.9);
  animation: slide-in 0.24s var(--ease) both;
}
@keyframes slide-in { from { transform: translateX(3rem); opacity: 0.6; } to { transform: none; opacity: 1; } }
.drawer-head {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; gap: 0.8rem;
  padding: 1rem clamp(1rem, 3vw, 1.7rem);
  background: rgba(20, 16, 25, 0.97);
  border-bottom: 1px solid var(--hair);
}
.drawer-head h3 { margin: 0; flex: 1; min-width: 0; }
.drawer-body { padding: clamp(1rem, 3vw, 1.7rem); }
.drawer-foot {
  position: sticky; bottom: 0;
  display: flex; gap: 0.7rem; flex-wrap: wrap;
  padding: 1rem clamp(1rem, 3vw, 1.7rem);
  background: rgba(20, 16, 25, 0.97);
  border-top: 1px solid var(--hair);
}
.x-btn {
  flex: none;
  width: 2.2rem; height: 2.2rem;
  border-radius: var(--r-m);
  border: 1px solid var(--hair-2);
  background: none; color: var(--text-dim);
  font: 700 1.1rem/1 var(--body);
  cursor: pointer;
}
.x-btn:hover { border-color: var(--pulp); color: var(--pulp); }

/* Scanner */
.scan-stage {
  border: 1px solid var(--hair-2);
  border-radius: var(--r-l);
  background: var(--panel);
  overflow: hidden;
  margin-bottom: 1.4rem;
}
.scan-video {
  position: relative;
  aspect-ratio: 3 / 4;
  max-height: 62vh;
  background: #08070b;
}
@media (min-width: 700px) { .scan-video { aspect-ratio: 16 / 10; } }
.scan-video video, .scan-video canvas { width: 100%; height: 100%; object-fit: cover; display: block; }
.scan-reticle {
  position: absolute; inset: 8% 14%;
  border: 2px solid rgba(240, 180, 41, 0.65);
  border-radius: var(--r-m);
  pointer-events: none;
  box-shadow: 0 0 0 100vmax rgba(8, 7, 11, 0.42);
}
.scan-reticle::after {
  content: attr(data-hint);
  position: absolute; left: 0; right: 0; bottom: -2.2rem;
  text-align: center;
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--gold);
}
.scan-shots { display: flex; gap: 0.5rem; flex-wrap: wrap; padding: 0 0.9rem 0.9rem; }

.queue { display: grid; gap: 0.9rem; }
.scan-card {
  border: 1px solid var(--hair);
  border-radius: var(--r-m);
  background: rgba(27, 21, 36, 0.7);
  padding: 1rem;
  display: grid;
  gap: 0.9rem;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 660px) { .scan-card { grid-template-columns: 5.5rem minmax(0, 1fr); } }
.scan-card .shot { width: 5.5rem; aspect-ratio: 2/3; border-radius: var(--r-s); overflow: hidden; border: 1px solid var(--hair-2); background: var(--panel-2); }
.scan-card .shot img { width: 100%; height: 100%; object-fit: cover; }
.scan-card h4 { margin-bottom: 0.3rem; }
.scan-card .conf { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; margin: 0.5rem 0; }
.scan-card .srcs { font-size: 0.82rem; }
.scan-card .srcs a { display: inline-block; margin-right: 0.7rem; word-break: break-all; }
.scan-card .acts { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-top: 0.8rem; }
.scan-card .flagbox { font-size: 0.85rem; color: #ffd9d2; }

.kv { display: grid; gap: 0.3rem 1rem; grid-template-columns: max-content minmax(0, 1fr); font-size: 0.86rem; margin: 0; }
.kv dt { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint); }
.kv dd { margin: 0; }

/* The cataloguer import preview. It is the inventory table again, but read
   inside the drawer rather than across the page, so it does not get the same
   46rem floor — and the flag cell is allowed to wrap onto a second line
   instead of pushing the whole table sideways. */
#imp-rows table.data { min-width: 30rem; }
#imp-rows table.data td .pill { margin: 0.1rem 0.15rem 0.1rem 0; }

/* ------------------------------------------------------------ 16. Utility */
.stack > * + * { margin-top: 1rem; }
.stack-s > * + * { margin-top: 0.5rem; }
.stack-l > * + * { margin-top: 2rem; }
.inline { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.between { display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: center; justify-content: space-between; }
.mt0 { margin-top: 0; }
.mb0 { margin-bottom: 0; }
.hide { display: none !important; }
@media (max-width: 619px) { .hide-sm { display: none !important; } }


/* print: policies are the only page anyone prints */
@media print {
  body { background: #fff; color: #000; }
  body::before, body::after, .masthead, .footer, .splash { display: none !important; }
  a { color: #000; }
  /* these are painted with background-clip: text on screen, which prints blank */
  h1, h2, h3, h4, .chrome, .gold-face, .hero h1 span {
    color: #000 !important;
    background-image: none !important;
  }
}

/* Owner-set announcement bar. Painted from settings; hidden until there is
   something to say. */
.announce {
  margin: 0;
  padding: 0.55rem var(--gut);
  background: var(--gold);
  color: var(--ink);
  font-weight: 700;
  font-size: 0.88rem;
  text-align: center;
}
.announce[hidden] { display: none; }

/* The mark is an <img> so it can be cached like any other asset. */
.brand-mark img { width: 100%; height: 100%; object-fit: contain; }

/* ------------------------------------------------------------------------- *
   16b. THE HIDDEN ATTRIBUTE, MEANT LITERALLY

   Half the interface is shown and hidden by setting element.hidden from
   JavaScript: the sign-in gate, the bulk bar, the scan stage, the home page
   stat strip. The browser's default [hidden] rule is display:none at the lowest
   possible weight, so any layout rule above — .gate{display:grid},
   .toolbar{display:flex} — quietly outranks it and the element stays on
   screen. One declaration, stated once, so hidden always means hidden.
 * ------------------------------------------------------------------------- */
[hidden] { display: none !important; }
