/* Yarn Documentary Club — shelf prototype.
   Same palette as the site so it can be dropped in later. */

:root {
  --ink:        #08061c;
  --panel:      rgba(255, 255, 255, 0.045);
  --panel-line: rgba(255, 255, 255, 0.12);
  --violet-lit: #8f81ff;
  --paper:      #f0eeff;
  --muted:      #a49ed6;
  --page:       #f3efe4;   /* booklet stock */
  --page-ink:   #1d1a2e;
  --bm:         #4b3bd6;   /* the bookmark ribbon, the site's violet */
  --font-display: 'Courier Prime', ui-monospace, monospace;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-serif: 'Playfair Display', Didot, Georgia, serif;
  /* the width a cover would like to be; app.js stretches it so a shelf comes
     out full, and --cover-h follows it at 2:3 */
  --cover-base: 168px;
  --cover-w: var(--cover-base);
  --cover-h: calc(var(--cover-w) * 1.5);
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background:
    radial-gradient(120% 70% at 50% -10%, rgba(96, 76, 230, 0.35) 0%, transparent 60%),
    linear-gradient(180deg, #171046 0%, #0c0930 40%, var(--ink) 100%);
  background-color: var(--ink);        /* under the gradients, for any gap */
  background-attachment: fixed;
  color: var(--paper);
  font-family: var(--font-body);
  min-height: 100vh;
}

img { display: block; max-width: 100%; }

/* ---- top bar ---------------------------------------------------------- */

.bar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 14px clamp(16px, 4vw, 40px);
  background: rgba(8, 6, 28, 0.72);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid rgba(255,255,255,0.07);
  font-family: var(--font-display);
  font-size: 13px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.bar-right { display: flex; align-items: center; gap: clamp(10px, 2vw, 20px); }

.bar-note { color: var(--muted); font-size: 11.5px; }

.bar-btn {
  font: inherit;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper);
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--panel-line);
  background: var(--panel);
  cursor: pointer;
  white-space: nowrap;
}

.bar-btn:hover, .bar-btn:focus-visible {
  border-color: rgba(143,129,255,0.6);
  background: rgba(143,129,255,0.16);
  outline: none;
}

/* ---- shelves ---------------------------------------------------------- */

.shelves { padding: clamp(24px, 5vw, 56px) 0 clamp(30px, 5vw, 58px); }

/* the way back to the podcast, under the last shelf */
.page-foot {
  display: grid;
  place-items: center;
  padding: 44px clamp(28px, 7vw, 120px) 96px;
}

.page-foot a {
  display: grid;
  justify-items: center;
  gap: 12px;
  color: var(--muted);
  text-decoration: none;
  opacity: 0.55;
  transition: opacity .25s ease;
}

.page-foot a:hover, .page-foot a:focus-visible { opacity: 1; outline: none; }

.page-foot img { width: 108px; height: auto; }

.page-foot span {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.shelf { margin-bottom: clamp(30px, 5vw, 58px); }

.shelf-row {
  display: flex;
  align-items: flex-end;
  gap: clamp(18px, 2.4vw, 34px);
  /* A wide margin either side, so there is somewhere to rest the pointer
     without a cover lighting up and dimming the rest of the shelf.
     overflow-x: auto clips vertically too, so the lift on hover needs room
     inside the scrollport rather than outside it */
  /* the 6px at the foot is the room the covers drop into, so the scrollport
     does not clip them - the board is pulled back up by the same amount */
  padding: 34px clamp(28px, 7vw, 120px) 6px;
  margin-top: -34px;
  overflow-x: auto;
  scrollbar-width: none;
}

.shelf-row::-webkit-scrollbar { display: none; }

/* the board itself: a plank with a lip and a shadow under the covers */
.shelf-board {
  height: 16px;
  margin-top: -8px;
  background: linear-gradient(180deg, #3b2f6d 0%, #241b4c 45%, #120d2e 100%);
  border-top: 1px solid rgba(255,255,255,0.22);
  box-shadow: 0 16px 26px -14px rgba(0,0,0,0.95), inset 0 -6px 12px -6px rgba(0,0,0,0.8);
}

.cover {
  flex: 0 0 auto;
  width: var(--cover-w);
  height: var(--cover-h);
  transform: translateY(6px);          /* sitting down into the board */
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  position: relative;
  transform-style: preserve-3d;
  transition: transform .35s cubic-bezier(.2,.7,.3,1), filter .35s ease;
  will-change: transform;
}

.cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 3px 5px 5px 3px;
  box-shadow:
    0 18px 26px -16px rgba(0,0,0,0.95),
    inset 3px 0 6px -3px rgba(255,255,255,0.35),
    inset -1px 0 0 rgba(0,0,0,0.5);
}

/* a sliver of spine, so it reads as an object rather than a picture */
.cover::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 7px;
  border-radius: 3px 0 0 3px;
  background: linear-gradient(90deg, rgba(255,255,255,0.28), rgba(0,0,0,0.35));
  z-index: 2;
}

/* One cover at a time is the one you are on, and app.js decides which - the
   mouse and the arrow keys were two separate CSS states, so moving from one
   to the other left two covers lit and the rest stuck behind the blur. */
.cover.is-active {
  transform: translateY(-10px);      /* just off the shelf, no tilt */
  outline: none;
}

.cover.is-active img {
  box-shadow: 0 42px 50px -22px rgba(0,0,0,0.95), 0 0 0 1px rgba(143,129,255,0.45);
}

/* arrowed to rather than pointed at, so it says so */
.cover:focus-visible img { box-shadow: 0 42px 50px -22px rgba(0,0,0,0.95), 0 0 0 2px rgba(143,129,255,0.9); }
.cover:focus-visible { outline: none; }

/* the hovered cover is the only thing in focus */
.shelves .cover, .shelves .shelf-board {
  transition: transform .35s cubic-bezier(.2,.7,.3,1), filter .35s ease, opacity .35s ease;
}

.shelves.is-dimmed .cover:not(.is-active) {
  filter: blur(4px) brightness(0.55);
}

.shelves.is-dimmed .shelf-board {
  filter: blur(3px);
  opacity: 0.5;
}

.cover.is-opening { opacity: 0; }

/* ---- the stage the booklet opens on ----------------------------------- */

.stage {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: clamp(10px, 1.6vw, 20px);
  background: rgba(4, 3, 16, 0.86);
  backdrop-filter: blur(10px);
  animation: fade .3s ease both;
}

@keyframes fade { from { opacity: 0 } to { opacity: 1 } }

.stage-close {
  position: absolute;
  top: clamp(12px, 3vw, 28px);
  right: clamp(12px, 3vw, 28px);
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--panel-line);
  background: var(--panel);
  color: var(--paper);
  cursor: pointer;
}

.stage-close svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

.stage-close:hover { border-color: rgba(143,129,255,0.6); background: rgba(143,129,255,0.14); }

/* ---- the booklet ------------------------------------------------------ */

.booklet { display: grid; justify-items: center; gap: 12px; }

/* Two pages side by side. The book is sized off the viewport so it never
   overflows; leaves are absolutely positioned on the right half. */
/* Each half is a 2:3 DVD case, so the shut book shows its whole cover and
   nothing is cropped; the open spread is therefore 4:3. */
.book {
  position: relative;
  /* as big as the window allows: the stage padding, the gap under the book
     and the pager are all the height this does not get */
  width: min(94vw, calc((100vh - 104px) * 4 / 3), 1160px);
  aspect-ratio: 4 / 3;
  perspective: 2200px;
  transform-style: preserve-3d;
  transition: transform .9s cubic-bezier(.3,.05,.25,1);
}

/* shut, the book is only its right half, so shift it to sit centred */
.book.is-shut { transform: translateX(-25%); }

/* The two fixed pages are the floor of the book: the inside front cover and
   the inside back cover. Every leaf is translated in front of them, because
   in a preserve-3d context depth decides what paints on top, not z-index. */
.page, .leaf-face {
  position: absolute;
  top: 0;
  width: 50%;
  height: 100%;
  background: var(--page);
  color: var(--page-ink);
  padding: clamp(18px, 2.6vw, 38px);
  overflow: hidden;
}

.page--right {
  left: 50%;
  border-radius: 0 6px 6px 0;
  box-shadow: inset 22px 0 26px -22px rgba(0,0,0,0.55);
}

.page--left {
  left: 0;
  border-radius: 6px 0 0 6px;
  box-shadow: inset -22px 0 26px -22px rgba(0,0,0,0.55);
  opacity: 0;
  transition: opacity .25s ease;
}

/* Only once the cover has finished its swing and become the inside front
   cover - a timer was a guess, this waits for the thing itself. */
.book:has(.cover-hinge.is-settled) .page--left { opacity: 1; }


.leaves { position: absolute; inset: 0; transform-style: preserve-3d; }

/* The leaf stack and the cover's hinge are empty boxes that span the whole
   book, and in a 3D context they take the click before the page underneath
   them does. They pass it through; the faces themselves still catch it. */
.leaves, .leaf, .cover-hinge, .cover-leaf { pointer-events: none; }
.leaf-face, .cover-leaf-face { pointer-events: auto; }

.leaf {
  position: absolute;
  top: 0;
  left: 50%;
  width: 50%;
  height: 100%;
  transform-origin: left center;
  transform-style: preserve-3d;
  transition: transform .85s cubic-bezier(.3,.05,.25,1);
}

.leaf-face {
  left: 0;
  width: 100%;          /* a leaf is already half the book */
  backface-visibility: hidden;
  border-radius: 0 6px 6px 0;
  box-shadow: inset 22px 0 26px -22px rgba(0,0,0,0.55);
}

.leaf-face--back {
  transform: rotateY(180deg);
  border-radius: 6px 0 0 6px;
  box-shadow: inset -22px 0 26px -22px rgba(0,0,0,0.55);
}

/* the turn itself is set inline, in Z as well as rotation - see app.js */

/* The cover sits well in front of every leaf while it is shut and while it
   swings, or the pages show through it. Depth lives on the hinge, which has
   no transition, so changing it cannot fire a transitionend of its own. */
.cover-hinge {
  position: absolute;
  top: 0;
  left: 50%;
  width: 50%;
  height: 100%;
  transform-style: preserve-3d;
  transform: translateZ(8px);
}

/* once open it is the inside front cover, and pages turn on top of it */
.cover-hinge.is-settled { transform: translateZ(0.5px); }

.cover-leaf {
  position: absolute;
  inset: 0;
  transform-origin: left center;
  transform-style: preserve-3d;
  transition: transform .9s cubic-bezier(.3,.05,.25,1);
}

.cover-leaf.is-open { transform: rotateY(-180deg); }

.cover-leaf-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  border-radius: 0 6px 6px 0;
  overflow: hidden;
  box-shadow: 0 30px 60px -30px rgba(0,0,0,0.9);
}

.cover-leaf-front img { width: 100%; height: 100%; object-fit: cover; }

.cover-leaf-back {
  transform: rotateY(180deg);
  background: var(--page);
  color: var(--page-ink);
  padding: clamp(18px, 2.6vw, 38px);
  border-radius: 6px 0 0 6px;
  box-shadow: inset -22px 0 26px -22px rgba(0,0,0,0.55);
}

/* ---- page contents ---------------------------------------------------- */

/* A page holds what it holds. When a theme's description or a long entry runs
   past the foot of the paper it scrolls inside the page rather than being cut
   off, with the running foot and the ribbon staying where they are. */
.p-scroll {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-bottom: 34px;                  /* clear of the running foot */
  scrollbar-width: thin;
  scrollbar-color: rgba(40,34,70,0.26) transparent;
}

/* the theme's name stays put while its description moves under it */
.p-head {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.p-head .p-theme { flex: 0 0 auto; }

.p-scroll--flush { flex: 1 1 auto; min-height: 0; padding-bottom: 0; }

/* a film the description names, and the way to its page */
.p-link {
  font: inherit;
  color: inherit;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: rgba(75, 59, 214, 0.45);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

.p-link:hover, .p-link:focus-visible {
  color: var(--bm);
  text-decoration-color: currentColor;
  outline: none;
}

/* more below than the page shows: the last lines fade out rather than being
   cut off at the edge of the paper */
.p-scroll.has-more {
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 52px), transparent);
  mask-image: linear-gradient(180deg, #000 calc(100% - 52px), transparent);
}

.p-scroll::-webkit-scrollbar { width: 6px; }
.p-scroll::-webkit-scrollbar-track { background: transparent; }
.p-scroll::-webkit-scrollbar-thumb { background: rgba(40,34,70,0.22); border-radius: 3px; }

.p-kicker {
  font-family: var(--font-display);
  font-size: 11.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #6f6796;
  margin: 0 0 14px;
}

.p-theme {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(24px, 2.9vw, 36px);
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: 0 0 18px;
}

.p-blurb {
  font-size: clamp(14px, 1.25vw, 16px);
  line-height: 1.62;
  color: #3a3552;
  margin: 0;
}

.p-still {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 3px;
  margin-bottom: 16px;
  filter: saturate(0.92);
}

/* where TMDB has no still at all, the poster stands in - shown as a poster
   rather than cropped into the shape of a still */
.p-still--poster {
  width: min(52%, 190px);
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 2px;
  box-shadow: 0 10px 20px -12px rgba(20,16,40,0.7);
}

.p-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(17px, 1.8vw, 23px);
  line-height: 1.2;
  letter-spacing: -0.015em;
  margin: 0 0 6px;
}

.p-year { font-family: var(--font-display); font-size: 13px; color: #6f6796; }

.p-stars { color: #b4442f; letter-spacing: 3px; margin: 10px 0 12px; font-size: 15px; }

.p-line { font-size: clamp(14px, 1.3vw, 16.5px); line-height: 1.6; color: #3a3552; margin: 0; }

/* the introduction's pages: the same measure as a film's blurb, with room
   kept at the foot for the running head so the text never runs under it */
.p-prose-page { padding-bottom: 34px; }

.p-standfirst {
  font-family: var(--font-display);
  font-size: clamp(13px, 1.25vw, 15px);
  line-height: 1.5;
  color: #6f6796;
  margin: -8px 0 20px;
}

.p-prose {
  font-size: clamp(14px, 1.25vw, 16px);
  line-height: 1.62;
  color: #3a3552;
  margin: 0 0 15px;
}

.p-prose:last-child { margin-bottom: 0; }

.p-sign {
  font-family: var(--font-display);
  font-size: clamp(13px, 1.2vw, 15px);
  line-height: 1.5;
  color: #3a3552;
  margin: 0 0 4px;
}

/* The blank page facing the disc, and the foot of the introduction: the club
   belongs to the podcast, and this is where it says so. */
.p-colophon {
  height: 100%;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 14px;
  padding: clamp(18px, 2.6vw, 38px);
  text-align: center;
}

.p-mark {
  width: min(52%, 150px);
  height: auto;
  opacity: 0.85;
}

.p-out {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #55507a;
  text-decoration: underline;
  text-decoration-color: rgba(75, 59, 214, 0.4);
  text-underline-offset: 4px;
}

.p-out:hover, .p-out:focus-visible { color: var(--bm); outline: none; }

/* at the foot of a page that already has text on it, rather than alone on one */
.p-colophon--foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 14px;
  height: auto;
  padding: 0 clamp(18px, 2.6vw, 38px);
  gap: 8px;
}

.p-colophon--foot .p-mark { width: 86px; opacity: 0.7; }
.p-colophon--foot .p-out { font-size: 10px; }

/* that page keeps room for it */
.p-prose-page--signed { padding-bottom: 76px; }

.p-foot {
  position: absolute;
  left: clamp(18px, 2.6vw, 38px);
  right: calc(clamp(18px, 2.6vw, 38px) + 46px);   /* clear of the ribbon */
  bottom: 16px;
  display: flex;
  gap: 12px;
  white-space: nowrap;
  justify-content: space-between;
  font-family: var(--font-display);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #8c85ad;
}

/* ---- pager ------------------------------------------------------------ */

.pager { display: flex; align-items: center; gap: 16px; }

.pager button {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--panel-line);
  background: var(--panel);
  color: var(--paper);
  font-size: 17px;
  cursor: pointer;
}

.pager button:hover:not(:disabled) { border-color: rgba(143,129,255,0.6); background: rgba(143,129,255,0.14); }
.pager button:disabled { opacity: 0.3; cursor: default; }

/* ---- surprise me ------------------------------------------------------ */

/* The room goes dark, counts you in, and the spread is simply there when the
   lights come back. */
.countdown {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  background: #000;
  opacity: 0;
  transition: opacity .22s ease;
  pointer-events: none;
}

.countdown.is-on { opacity: 1; pointer-events: auto; }

.countdown span {
  font-family: var(--font-display);
  font-size: clamp(96px, 24vw, 240px);
  line-height: 1;
  color: var(--paper);
  opacity: 0;
}

.countdown span.is-tick { animation: tick .66s ease both; }

@keyframes tick {
  0%   { opacity: 0; transform: scale(1.4); }
  20%  { opacity: 1; transform: scale(1); }
  70%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.94); }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (max-width: 720px) {
  :root { --cover-base: 128px; }
  /* one page at a time on a phone: a single 2:3 page */
  .book { width: min(92vw, calc((100vh - 96px) * 2 / 3)); aspect-ratio: 2 / 3; }
  .page--left { display: none; }
  .page, .leaf-face { width: 100%; }
  /* the back cover is the floor under the single run of pages, not a right
     hand half - left at 50% it hung off the side of every page */
  .page--right { left: 0; border-radius: 6px; }
  .leaf, .cover-hinge { left: 0; width: 100%; }
  .book.is-shut { transform: none; }

  /* A turned page stays lying to the left of the phone book, where you can
     see it. It reads as a book rather than as one page replacing another. */
}

@media (prefers-reduced-motion: reduce) {
  .leaf, .cover-leaf, .cover { transition-duration: .01ms !important; }
  .stage { animation: none; }
}

/* the book is not shown until the cover flying off the shelf has landed */
.book.is-arriving { opacity: 0; }

/* ---- the inside back cover's colophon --------------------------------- */

/* The inside back cover, done as the inside of a real case: the wash colour
   behind, the cover under a clear sheet, and the disc in a moulded well with
   the spindle in the middle and a thumb cut-out beside it. The page gives up
   its padding so the colour reaches the edges. */
.page:has(.p-end), .leaf-face:has(.p-end) { padding: 0; }

.p-end {
  position: relative;
  height: 100%;
  overflow: hidden;
  background: var(--tint, #2b2350);
}

/* the cover again, well out of focus and blended into the wash so it reads as
   the colour of the theme rather than as a second copy of the cover */
.p-end-art {
  position: absolute;
  inset: -14%;
  width: 128%;
  height: 128%;
  object-fit: cover;
  filter: blur(5px);
  opacity: 0.62;
  mix-blend-mode: luminosity;
}

/* the sheet itself: one raking highlight, and enough shade under it that the
   type reads over any cover, including the white one */
.p-end-sheet {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(118deg, rgba(255,255,255,0.20) 0%, rgba(255,255,255,0.05) 24%, rgba(255,255,255,0) 44%),
    linear-gradient(180deg, rgba(8,5,20,0.16), rgba(8,5,20,0.46));
}

.p-end-body {
  position: relative;
  height: 100%;
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  padding: clamp(18px, 2.6vw, 38px);
}

.p-end-title {
  font-family: var(--font-display);
  font-size: clamp(17px, 1.9vw, 24px);
  line-height: 1.15;
  color: #fff;
  text-shadow: 0 1px 12px rgba(0,0,0,0.55);
  margin: 0 0 8px;
  text-wrap: balance;
}

/* an empty book's one line sits where the title would, with nothing under it */
.p-end-title:last-of-type { margin-bottom: clamp(18px, 3vh, 34px); }

.p-end-sub {
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.74);
  text-shadow: 0 1px 8px rgba(0,0,0,0.5);
  margin: 0 0 clamp(18px, 3vh, 34px);
}

/* the way on to the next book, set small at the foot of the tray */
.p-next {
  position: absolute;
  left: 50%;
  bottom: clamp(14px, 2.4vh, 26px);
  transform: translateX(-50%);
  max-width: 82%;
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.72);
  text-shadow: 0 1px 8px rgba(0,0,0,0.5);
  padding: 4px 2px;
  border: 0;
  background: none;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-decoration: underline;
  text-decoration-color: rgba(255,255,255,0.34);
  text-underline-offset: 4px;
}

.p-next:hover, .p-next:focus-visible {
  color: #fff;
  text-decoration-color: currentColor;
  outline: none;
}

/* the moulded well the disc drops into */
.disc-well {
  position: relative;
  display: grid;
  place-items: center;
  width: min(82%, 330px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(6, 4, 16, 0.42);
  box-shadow:
    inset 0 5px 14px rgba(0,0,0,0.7),
    inset 0 -3px 0 rgba(255,255,255,0.12),
    0 1px 0 rgba(255,255,255,0.18);
}

.disc {
  position: relative;
  display: grid;
  place-items: center;
  width: 86%;
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 26%, rgba(255,255,255,0.75), rgba(255,255,255,0) 46%),
    conic-gradient(from 205deg,
      #c7d0e2, #e5d6c2, #cadfd4, #ded0e2, #c7d0e2, #e7d9c4, #cddfd6, #c7d0e2);
  box-shadow:
    0 8px 14px -8px rgba(0,0,0,0.8),
    inset 0 0 0 1px rgba(40,34,70,0.22),
    inset 0 0 0 9px rgba(255,255,255,0.26);
}

/* the clear plastic ring the print stops at */
.disc::before {
  content: '';
  position: absolute;
  inset: 30%;
  border-radius: 50%;
  background: rgba(247,244,236,0.5);
  box-shadow: inset 0 0 0 1px rgba(40,34,70,0.14);
}

/* the hole, and the spindle sitting in it */
.disc-hub {
  position: relative;
  display: grid;
  place-items: center;
  width: 26%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(6, 4, 16, 0.5);
  box-shadow: inset 0 2px 5px rgba(0,0,0,0.7), 0 0 0 5px rgba(255,255,255,0.32);
}

.disc-hub::after {
  content: '';
  width: 54%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 36% 30%, #fdfcf7, #d2ccc0 56%, #8d8678);
  box-shadow: 0 1px 3px rgba(0,0,0,0.6);
}

/* ---- bookmarking ------------------------------------------------------ */

/* Bottom right of the page, rising from the edge. Outline means not kept,
   solid means kept. Nothing moves, nothing resizes, nothing fades: the only
   hover tell is the paper warming behind it. */
.bm {
  position: absolute;
  bottom: 0;
  right: clamp(18px, 2.6vw, 38px);
  width: 34px;
  height: 46px;
  padding: 0;
  border: 0;
  cursor: pointer;
  background: transparent;
  color: var(--bm);
}

.bm svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
  transform: scaleY(-1);          /* the notch points up, out of the edge */
}

.bm svg path {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.3;
  transition: fill .18s ease;
}

.bm[aria-pressed="true"] svg path { fill: currentColor; }

/* The hover tell fills the ribbon itself rather than a box behind it, so
   there is no square of tint sitting under a shape that is not square. */
.bm:hover svg path { fill: rgba(75, 59, 214, 0.22); }
.bm[aria-pressed="true"]:hover svg path { fill: rgba(75, 59, 214, 0.72); }
.bm:focus-visible { outline: 2px solid var(--bm); outline-offset: 2px; }

/* what just happened, said once and then gone */
.bm-toast {
  position: absolute;
  bottom: 18px;
  right: calc(clamp(18px, 2.6vw, 38px) + 44px);
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bm);
  white-space: nowrap;
  pointer-events: none;
  animation: bm-said 1.8s ease forwards;
}

@keyframes bm-said {
  0%   { opacity: 0; transform: translateY(4px); }
  14%  { opacity: 1; transform: none; }
  74%  { opacity: 1; }
  100% { opacity: 0; }
}

/* the bookmarked book's cover carries a live count */
.cover-badge {
  position: absolute;
  inset: 10px 10px auto auto;
  min-width: 34px;
  padding: 5px 9px;
  border-radius: 999px;
  background: rgba(8, 6, 28, 0.82);
  border: 1px solid rgba(255,255,255,0.3);
  color: var(--paper);
  font-family: var(--font-display);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-align: center;
  z-index: 3;
  pointer-events: none;
}

.p-from {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #8c85ad;
  margin: 0 0 12px;
}

/* the surround fades as the book flies home */
.stage { transition: opacity .3s ease; }
.stage.is-leaving { opacity: 0; }
