/* Babe's Bookstore — Serious Library System */
:root{
  --paper:#fcfaf7; --paper2:#f6f1e7; --panel:#ffffff;
  --ink:#0b0b0c; --ink2:#1f1f1f; --muted:#6b655f; --line:#e7e2d9; --line2:#d6d0c2;
  --maxw:1180px; --r:16px; --r2:20px;
  --font-serif:"EB Garamond", Georgia, serif; --font-sans:"Inter", system-ui, sans-serif;
}

/* WCAG AA contrast: the CDN Tailwind muted greys are too faint on paper.
   Default to a dark-enough neutral; keep the warm grey for text that really
   sits on near-black navs/footers. */
.text-stone-400{ color:#6e675f }
nav .text-stone-400, footer .text-stone-400,
.bg-stone-900 .text-stone-400, .bg-stone-950 .text-stone-400,
.bg-\[\#0b0b0c\] .text-stone-400{ color:#a8a29e }
.text-\[\#8a8683\]{ color:#6b655f }
nav .text-\[\#8a8683\], footer .text-\[\#8a8683\],
.bg-stone-900 .text-\[\#8a8683\], .bg-stone-950 .text-\[\#8a8683\],
.bg-\[\#0b0b0c\] .text-\[\#8a8683\]{ color:#a8a29e }
*{ -webkit-tap-highlight-color:transparent }
html{ scroll-behavior:smooth }
html,body{ overflow-x:clip; }
body{ background:var(--paper); color:var(--ink); font-family:var(--font-sans); font-size:15px; line-height:1.6; -webkit-font-smoothing:antialiased; max-width:100%; }
img{ max-width:100%; height:auto }
:focus-visible{ outline:2px solid #0b0b0c; outline-offset:2px }
.container,.max-w-7xl{ max-width:var(--maxw)!important }
section{ padding-block: clamp(2rem, 4vw, 4rem) }
.line-clamp-2{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
a{ text-underline-offset:2px }

#african-toggle.active{ background:#0b0b0c; color:#fff; border-color:#0b0b0c }

/* nav is handled per-page (dark on homepage, light elsewhere) */
nav{ backdrop-filter:saturate(1.1) blur(8px); -webkit-backdrop-filter:saturate(1.1) blur(8px) }
nav input[type="search"]{ font-size:14px }

/* cards */
.bundle-card,.book-card{ background:var(--panel); border:1px solid var(--line); border-radius:18px; transition:border-color .18s, transform .18s; }
.bundle-card:hover,.book-card:hover{ border-color:var(--ink); transform:translateY(-2px) }
.bundle-card .cover{ background:var(--paper2); border-bottom:1px solid var(--line) }

/* buttons */
.btn{ border-radius:999px; font-weight:600; transition:all .16s }
.btn-dark{ background:var(--ink); color:#fff; border:1px solid var(--ink) }
.btn-dark:hover{ background:#1f1f1f }
.btn-light{ background:var(--panel); color:var(--ink); border:1px solid var(--line) }
.btn-light:hover{ background:var(--paper2) }

/* footer handled per-page */
footer{ background:var(--ink); color:#a8a29e }
footer a{ color:#a8a29e } footer a:hover{ color:#fff }

/* reveal */
.reveal{ opacity:0; transform:translateY(8px); transition:opacity .5s, transform .5s }
.reveal.revealed{ opacity:1; transform:none }

/* scrollbar */
::-webkit-scrollbar{ width:10px; height:10px }
::-webkit-scrollbar-thumb{ background:#d6d0c2; border-radius:999px; border:2px solid var(--paper) }

/* coming soon */
.coming-soon{ display:flex; align-items:flex-start; gap:.75rem; background:linear-gradient(180deg,#fff, #fbf9f5); border:1px dashed var(--line2); border-radius:14px; padding:.9rem 1rem; }
.coming-soon-badge{ flex:0 0 auto; font-size:10px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:#7c2d12; background:#ffedd5; border:1px solid #fed7aa; padding:.3rem .6rem; border-radius:999px; }
.coming-soon-body{ display:flex; flex-direction:column; gap:.15rem; min-width:0 }
.coming-soon-title{ font-family:var(--font-serif); font-size:.95rem; font-weight:600; line-height:1.2 }
.coming-soon-copy{ font-size:.82rem; line-height:1.45; color:var(--muted) }
.coming-soon-link{ flex:0 0 auto; align-self:center; font-size:.8rem; font-weight:600; color:var(--ink); text-decoration:underline; text-underline-offset:2px; white-space:nowrap }
.coming-soon-link:hover{ color:#57534e }

/* ── prose (typography for book descriptions / long-form) ─────────────── */
.prose{ color:#292524; font-size:1.0625rem; line-height:1.75; word-wrap:break-word }
.prose-stone{ color:#44403c }
.prose > *{ margin-top:1.1em; margin-bottom:1.1em }
.prose h1,.prose h2,.prose h3,.prose h4{ font-family:var(--font-serif); font-weight:600; line-height:1.25; color:#1c1917; margin-top:1.6em; margin-bottom:.7em }
.prose h1{ font-size:1.9em } .prose h2{ font-size:1.5em } .prose h3{ font-size:1.25em } .prose h4{ font-size:1.1em }
.prose p{ margin-top:0; margin-bottom:1.1em }
.prose a{ color:#b45309; text-decoration:underline; text-underline-offset:2px }
.prose a:hover{ color:#92400e }
.prose blockquote{ border-left:3px solid #d6d3d1; padding-left:1.1em; color:#57534e; font-style:italic }
.prose strong{ font-weight:700 } .prose em{ font-style:italic }
.prose ul,.prose ol{ padding-left:1.5em; display:flex; flex-direction:column; gap:.4em }
.prose ul{ list-style:disc } .prose ol{ list-style:decimal }
.prose li > ul,.prose li > ol{ margin-top:.4em }
.prose img{ border-radius:8px; max-width:100%; height:auto }
.prose table{ width:100%; border-collapse:collapse; font-size:.95em }
.prose th,.prose td{ border:1px solid #d6d3d1; padding:.5em .75em; text-align:left }
.prose th{ background:#f5f5f4; font-weight:600 }
.prose hr{ border:none; border-top:1px solid #e7e5e4; margin:2em 0 }
.prose pre{ background:#1c1917; color:#f5f5f4; padding:1em; border-radius:10px; overflow-x:auto; font-size:.9em }
.prose code{ font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.9em }
.prose:not(.not-prose) pre code{ background:transparent; padding:0 }
.prose .not-prose{ font-size:1rem }
@media (max-width:640px){ .prose{ font-size:1rem; line-height:1.7 } }

/* ── shelf carousel ────────────────────────────────────────────────────────
   Rows of book cards scroll horizontally. The scrollbar is hidden (it was
   styled by a .scrollbar-thin class that never existed, so rows showed the
   browser default) and replaced by snap points, edge fades, hover arrows and
   a progress bar. */
.shelf{ position:relative }

.shelf-track{
  display:flex;
  gap:1rem;
  overflow-x:auto;
  scroll-snap-type:x mandatory;
  scroll-behavior:smooth;
  /* room for the focus ring and the card shadow without clipping */
  padding:.25rem .25rem 1rem;
  margin:-.25rem -.25rem 0;
  scrollbar-width:none;          /* Firefox */
  -ms-overflow-style:none;       /* old Edge */
  overscroll-behavior-x:contain; /* don't chain-scroll the page sideways */
  /* fade the cards out at both ends instead of guillotining them */
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 1.75rem,#000 calc(100% - 1.75rem),transparent 100%);
          mask-image:linear-gradient(to right,transparent 0,#000 1.75rem,#000 calc(100% - 1.75rem),transparent 100%);
}
.shelf-track::-webkit-scrollbar{ display:none }
.shelf-track > *{ scroll-snap-align:start; scroll-snap-stop:always }

/* Card geometry lives here, not in a Tailwind utility.
   w-[158px], sm:w-[184px], flex-shrink-0 and h-44 are not in the committed
   tailwind.css -- the JIT build purged them, because nothing in the HTML or
   templates contained them: this markup is assembled in JS. So the cards
   arrived with no width and no flex-shrink in a display:flex row and each one
   stretched to fill the track, which is what turned a shelf into a full-width
   column. Sizing the carousel here instead of hand-reimplementing four
   utilities means the next Tailwind purge cannot take the layout with it. */
.shelf-card{
  flex:0 0 158px;
  width:158px;
  display:block;
}
@media (min-width:640px){
  .shelf-card{ flex-basis:184px; width:184px }
}
/* shared by the cover image and the placeholder card used when a book has no
   cover, so a missing cover cannot change the row's height */
.shelf-cover{ height:11rem; width:100% }

/* Hide the fades when there is nothing to scroll to, so a short row does not
   look like it is fading out for no reason. */
.shelf.is-end-start .shelf-track{
  -webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 1.75rem),transparent 100%);
          mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 1.75rem),transparent 100%);
}
.shelf.is-end-end .shelf-track{
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 1.75rem,#000 100%);
          mask-image:linear-gradient(to right,transparent 0,#000 1.75rem,#000 100%);
}
.shelf.is-end-start.is-end-end .shelf-track{
  -webkit-mask-image:none; mask-image:none;
}

/* Arrows: pointer devices only. On touch the row is swiped directly and two
   2rem targets in the content area are just clutter. */
.shelf-arrow{
  position:absolute;
  top:calc(50% - 5.5rem);
  transform:translateY(-50%);
  z-index:5;
  display:none;
  align-items:center;
  justify-content:center;
  width:2.25rem;
  height:2.25rem;
  border-radius:9999px;
  background:rgba(12,12,12,.82);
  border:1px solid #44403c;
  color:#fcfaf7;
  font-size:1.05rem;
  line-height:1;
  cursor:pointer;
  backdrop-filter:blur(4px);
  transition:opacity .18s ease,background .18s ease,border-color .18s ease;
}
.shelf-arrow-prev{ left:-.7rem }
.shelf-arrow-next{ right:-.7rem }
.shelf-arrow:hover{ background:#1c1b1a; border-color:#a8a29e }
.shelf-arrow:disabled{ opacity:0; pointer-events:none }
.shelf-arrow:focus-visible{ outline:2px solid #fafaf9; outline-offset:2px; opacity:1 }

@media (hover:hover) and (pointer:fine){
  .shelf-arrows .shelf-arrow{ display:flex }
  /* only reveal while the row is hovered or something inside it has focus */
  .shelf-arrows .shelf-arrow:not(:disabled){ opacity:0 }
  .shelf:hover .shelf-arrow:not(:disabled),
  .shelf:focus-within .shelf-arrow:not(:disabled){ opacity:1 }
  .shelf:hover .shelf-arrow-prev:disabled,
  .shelf:focus-within .shelf-arrow-prev:disabled,
  .shelf:hover .shelf-arrow-next:disabled,
  .shelf:focus-within .shelf-arrow-next:disabled){ opacity:0 }
}

/* Progress: a hairline that shows how much of the row is off-screen. */
.shelf-progress{
  height:2px;
  border-radius:9999px;
  background:#292524;
  overflow:hidden;
}
.shelf-progress span{
  display:block;
  height:100%;
  width:25%;
  border-radius:9999px;
  background:#a8a29e;
  transform-origin:left center;
  transition:transform .18s ease,width .18s ease;
}

.shelf-track:focus-visible{ outline:2px solid #57534e; outline-offset:2px; border-radius:.5rem }

@media (prefers-reduced-motion:reduce){
  .shelf-track{ scroll-behavior:auto }
  .shelf-progress span{ transition:none }
  .shelf-arrow{ transition:none }
}

/* ── same-element contrast pairs ──────────────────────────────────────────
   These are combinations where the label and its own surface both come from
   Tailwind defaults, so no per-theme remap can rescue them: a remap has to
   change one side, and these are wrong in *every* theme. Kept here rather
   than in theme.css because they are not theme-specific. */

/* White on emerald-600 is 3.77:1. Darkening the surface to emerald-700 gives
   5.48:1 and is visually near-identical at button size. */
.bg-emerald-600{ background-color:#047857 }
.bg-emerald-600:hover{ background-color:#065f46 }

/* The rules above scope to nav/footer *descendants*, so they cannot reach a
   text-stone-400 sitting on the <footer> itself. A class selector also beats
   the bare `footer{ color:#a8a29e }` type rule, so that combination rendered
   at 3.53:1 on paper. Pin the element too. */
footer.text-stone-400, nav.text-stone-400{ color:#a8a29e }

/* ══ Tailwind utility shim ═══════════════════════════════════════════════
   static/tailwind.css is a *purged* JIT build (v3.4.17): it contains only the
   classes that existed when it was generated. There is no package.json, no
   tailwind.config.js and no node in this image, so it cannot be rebuilt, and
   any utility not baked in at build time silently does nothing -- no error,
   no warning, the element just renders unstyled. That is how the carousel
   shipped with no card width and the catalogue filters shipped with no height.

   Everything below is a utility the storefront references but the purged
   build does not contain, written out with stock Tailwind v3 values. Keep this
   list in sync with backend/tests/test_frontend_classes.py, which fails if a
   page or script references a class defined nowhere. */

.bg-\[\#0b0b0c\]\/70{ background-color:rgba(11,11,12,.7) }
.bg-\[\#121212\]{ background-color:#121212 }
.bg-\[\#161514\]{ background-color:#161514 }
.bg-\[\#1c1b1a\]{ background-color:#1c1b1a }
.bg-\[\#f6f4f0\]{ background-color:#f6f4f0 }
.bg-black\/80{ background-color:rgba(0,0,0,.8) }
.bg-white\/90{ background-color:rgba(255,255,255,.9) }
.bg-red-500{ background-color:#ef4444 }
.bg-red-600{ background-color:#dc2626 }
.bg-red-900\/60{ background-color:rgba(127,29,29,.6) }
.bg-red-950\/30{ background-color:rgba(69,10,10,.3) }
.bg-rose-50{ background-color:#fff1f2 }
.bg-stone-700{ background-color:#44403c }
.bg-stone-800{ background-color:#292524 }

.border-\[\#292524\]{ border-color:#292524 }
.border-\[\#ece9e3\]{ border-color:#ece9e3 }
.border-b-2{ border-bottom-width:2px }
.border-l-4{ border-left-width:4px }
.border-red-700{ border-color:#b91c1c }
.border-red-700\/50{ border-color:rgba(185,28,28,.5) }
.border-red-800\/40{ border-color:rgba(153,27,27,.4) }
.border-red-900\/50{ border-color:rgba(127,29,29,.5) }
.border-rose-200{ border-color:#fecdd3 }
.border-stone-100{ border-color:#f5f5f4 }
.border-stone-600{ border-color:#57534e }
.border-stone-700{ border-color:#44403c }

.text-\[\#f5f5f4\]{ color:#f5f5f4 }
.text-\[1\.3rem\]{ font-size:1.3rem; line-height:1.9rem }
.text-base{ font-size:1rem; line-height:1.5rem }
/* Bundle pick order is a 1..n column; proportional digits make 10 sit left of
   9 and the whole list shimmer as it reorders. */
.tabular-nums{ font-variant-numeric:tabular-nums }
.text-red-200{ color:#fecaca }
.text-red-300{ color:#fca5a5 }
.text-red-400{ color:#f87171 }
.text-rose-800{ color:#9f1239 }
.accent-stone-200{ accent-color:#e7e5e4 }

.h-1{ height:.25rem }
.h-9{ height:2.25rem }
.h-40{ height:10rem }
.h-px{ height:1px }
.w-9{ width:2.25rem }
.w-20{ width:5rem }
/* flex-shrink-0 / h-44 / w-[158px] / sm:w-[184px] were here. They existed
   only for the home carousel, which now sizes its own cards via .shelf-card,
   so hand-writing them was a stub that could hide a real Tailwind build. */
@media (min-width:640px){ .sm\:text-xl{ font-size:1.25rem; line-height:1.75rem }
.sm\:text-2xl{ font-size:1.5rem; line-height:2rem } }
@media (min-width:768px){ .md\:text-4xl{ font-size:2.25rem; line-height:2.5rem } }

.max-h-\[90vh\]{ max-height:90vh }
.max-h-\[224px\]{ max-height:224px }
.max-w-\[260px\]{ max-width:260px }
.max-w-lg{ max-width:32rem }
.min-h-\[44px\]{ min-height:44px }
.min-h-\[72px\]{ min-height:72px }
.min-w-\[44px\]{ min-width:44px }
.min-w-\[200px\]{ min-width:200px }

.mb-1\.5{ margin-bottom:.375rem }
.mb-9{ margin-bottom:2.25rem }
.mr-3{ margin-right:.75rem }
.mt-1\.5{ margin-top:.375rem }
.mt-auto{ margin-top:auto }
.pb-0\.5{ padding-bottom:.125rem }
.pt-3{ padding-top:.75rem }
.py-6{ padding-top:1.5rem; padding-bottom:1.5rem }
.py-14{ padding-top:3.5rem; padding-bottom:3.5rem }

.leading-\[\.98\]{ line-height:.98 }
.leading-snug{ line-height:1.375 }
.tracking-widest{ letter-spacing:.1em }
.tracking-\[-0\.01em\]{ letter-spacing:-.01em }
.tracking-\[0\.16em\]{ letter-spacing:.16em }
.tracking-\[0\.2em\]{ letter-spacing:.2em }

.line-clamp-1{ display:-webkit-box; overflow:hidden; -webkit-box-orient:vertical; -webkit-line-clamp:1 }
.line-clamp-3{ display:-webkit-box; overflow:hidden; -webkit-box-orient:vertical; -webkit-line-clamp:3 }
.whitespace-nowrap{ white-space:nowrap }
.z-\[60\]{ z-index:60 }
.backdrop-blur{ -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px) }
.backdrop-blur-sm{ -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px) }
.shadow-2xl{ box-shadow:0 25px 50px -12px rgba(0,0,0,.25) }

/* Visually hidden but available to screen readers. reader.html relies on
   this too, and it was missing from the purged build. */
.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border-width:0 }

.hover\:bg-red-100:hover{ background-color:#fee2e2 }
.hover\:bg-red-50:hover{ background-color:#fef2f2 }
.hover\:bg-red-700:hover{ background-color:#b91c1c }
.hover\:bg-rose-100:hover{ background-color:#ffe4e6 }
.hover\:bg-stone-700:hover{ background-color:#44403c }
.hover\:bg-stone-800:hover{ background-color:#292524 }
.hover\:bg-stone-900:hover{ background-color:#1c1917 }
.hover\:bg-white:hover{ background-color:#fff }
.hover\:border-red-800:hover{ border-color:#991b1b }
.hover\:border-stone-400:hover{ border-color:#a8a29e }
.hover\:border-stone-500:hover{ border-color:#78716c }
.hover\:border-stone-600:hover{ border-color:#57534e }
.hover\:opacity-90:hover{ opacity:.9 }
.focus\:border-stone-500:focus{ border-color:#78716c }
.focus\:ring-stone-900:focus{ --tw-ring-color:#1c1917 }
.placeholder\:text-stone-500::placeholder{ color:#78716c }

/* store.js toggles .scrolled on the nav past 8px of scroll so the sticky bar
   can separate from the content passing under it. No rule consumed the class,
   so the effect was a silent no-op. */
.scrolled{ box-shadow:0 1px 0 var(--line), 0 6px 20px rgba(11,11,12,.05) }
.scrolled nav, nav.scrolled{ background:var(--panel) }

/* ══ component layer ═══════════════════════════════════════════════════
   Classes the storefront puts on elements that no stylesheet defined. Each
   one shipped as a silent no-op: the element rendered, unstyled, and nothing
   logged an error. backend/tests/test_frontend_classes.py now fails on any
   of them coming back.

   Everything here is expressed with the :root design tokens rather than
   literal colours, and theme.css redefines those tokens per theme -- so this
   layer themes itself instead of needing a hand-written dark override for
   every component (which is how .bundle-card ended up paper-white on a dark
   page in the first place). */

/* Small uppercase label that sits above a page or card heading. Ten pages
   use it, including every category and author page. */
.eyebrow{
  font-family:var(--font-sans);
  font-size:.6875rem; font-weight:600;
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--muted);
}

/* Filter chips (the 21-way category filter on /bundles). Sized to the 44px
   touch target the rest of the storefront uses. */
.genre-pill{
  display:inline-flex; align-items:center;
  min-height:44px; padding:0 1rem;
  border:1px solid var(--line); border-radius:999px;
  background:var(--panel); color:var(--ink);
  font-family:var(--font-sans); font-size:.8125rem; font-weight:500;
  cursor:pointer; white-space:nowrap;
  transition:background-color .16s, border-color .16s, color .16s;
}
.genre-pill:hover{ background:var(--paper2); border-color:var(--line2) }
.genre-pill.active{ background:var(--ink); border-color:var(--ink); color:var(--paper) }
.genre-pill:focus-visible{ outline:2px solid var(--ink); outline-offset:2px }

/* Bundle card cover. This block previously had only a background and a
   bottom border, so the card's height was decided entirely by its contents --
   an unstyled .bundle-orb holding a bare emoji. The row of bundle cards
   rendered as flat, ragged slivers. A fixed aspect ratio gives every card
   the same height regardless of which orb it draws. */
.bundle-card .cover{
  aspect-ratio:16 / 10;
  display:flex; align-items:center; justify-content:center;
  overflow:hidden;
}
.bundle-orb{
  font-size:3.25rem; line-height:1;
  filter:saturate(.9);
  transition:transform .22s ease;
}
.bundle-card:hover .bundle-orb{ transform:scale(1.08) }

/* Anchor used where a link must not pick up an underline. */
.no-underline{ text-decoration:none }

/* Rejected-books banner. The copy wraps to a readable column instead of
   being squeezed flat by the buttons beside it, and only when there is room
   for the two-column layout to hold. */
.banner-text-col{ flex:1 1 100% }
@media (min-width:768px){ .banner-text-col{ min-width:260px } }
