/* Books page: the reading list, the shelf view and the switch between them.
   Loaded by books.html only; base.css and styles.css come first. */

/* Sits above the shelf and the list alike: what is being read right now,
   which is why it is not one of the entries below. */
.now-reading {
  max-width: 680px;
  margin: 0 0 var(--space-10);
}

.now-reading__label {
  margin: 0 0 var(--space-2);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--mono-2xs);
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
}

/* Laid out like an entry of the list below: title, then the author set out at
   the far edge, both at the size the list uses. */
.now-reading__book {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-6);
  margin: 0;
}

.now-reading__title,
.now-reading__author {
  font-family: var(--font-mono);
  font-size: var(--book-size, var(--mono-lg));
  line-height: var(--leading-snug);
}

.now-reading__author { color: var(--muted); }

/* The shelf is a picture of the books read: what is being read right now has
   no cover standing there, so it belongs to the list view alone. */
.view-shelf .now-reading { display: none; }


.books {
  list-style: none;
  max-width: 680px;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--border-soft);
}

.book {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-4) 2px;
  border-bottom: 1px solid var(--border-soft);
}

/* Title and author are set at the same size, from one place */
.book__title,
.book__author {
  font-family: var(--font-mono);
  font-size: var(--book-size, var(--mono-lg));
  line-height: var(--leading-snug);
}

.book__author {
  flex-shrink: 0;
  color: var(--muted);
}

/* ---- View switch (list / shelf) ---- */
.view-switch {
  --active: 0;
  position: relative;
  display: flex;
  width: fit-content;
  gap: 1px;
  /* sits immediately after the page title */
  margin-left: var(--space-4);
  align-self: end;
  padding: 2px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .5); /* opaque fallback without backdrop-filter */
}

/* One pill for both buttons, travelling between them, rather than a background
   that goes out on one and comes on at the other. The state change is then
   something the eye can follow instead of something it has to notice.
   29px is the button plus the 1px gap; books.js only moves the index. */
.view-switch::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .85);
  transform: translateX(calc(var(--active) * 29px));
  transition: transform .22s var(--ease-out);
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .view-switch::before { transition: none; }
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .view-switch {
    background: rgba(255, 255, 255, .28);
    -webkit-backdrop-filter: blur(12px) saturate(160%);
    backdrop-filter: blur(12px) saturate(160%);
  }
}

.view-switch__btn {
  /* above the travelling pill */
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--muted);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              transform var(--dur-press) var(--ease-out);
}

.view-switch__btn:hover { color: var(--ink); }

/* The pill carries the background now; the button only takes the ink. */
.view-switch__btn.is-active {
  color: var(--ink);
}

/* ---- Shelf view: covers standing on thin japandi-toned ledges ---- */
.shelf {
  --cover-h: 156px;      /* tallest a cover may stand */
  --cover-w: 112px;      /* widest a cover may be, so formats stay comparable */
  /* one source of truth for the lean, reused by the hover state and the reveal */
  --book-tilt: perspective(520px) rotateX(12deg);
  --book-tilt-hover: perspective(520px) rotateX(4deg);
  display: flex;
  flex-direction: column;
  gap: var(--space-20);
  padding: 0 var(--space-12); /* ledges stop short of the page edges */
}

/* One ledge per row: books are spread across it so no shelf looks half empty */
.shelf__row {
  --ledge-h: 28px;     /* total: top surface + front face */
  --ledge-top: 13px;   /* the visible depth of the shelf, seen from slightly above */
  --cols: 4;
  --row-gap: var(--space-6);
  /* the widest a book may be before it would push past the end of the ledge */
  --slot: calc((100% - (var(--cols) - 1) * var(--row-gap)) / var(--cols));
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: space-evenly;
  gap: var(--row-gap);
  min-height: var(--cover-h);
  /* heels land near the front of the top surface, so the books stand forward
     on the shelf rather than flat against the wall */
  padding-bottom: calc(var(--ledge-h) - var(--ledge-top) + 5px);
}

/* The ledge is its own strip: its shadow falls from the shelf itself rather
   than from the full height of the row, and the gradient gives it a top
   surface + a front face instead of reading as a flat rule. */
.shelf__row::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--ledge-h);
  background: linear-gradient(
    to bottom,
    var(--shelf-wood-top) 0 var(--ledge-top),
    var(--shelf-wood) var(--ledge-top) calc(var(--ledge-top) + 2px),
    var(--shelf-wood-face) calc(var(--ledge-top) + 2px) calc(var(--ledge-h) - 3px),
    var(--shelf-wood-lip) calc(var(--ledge-h) - 3px) var(--ledge-h)
  );
  box-shadow: 0 16px 20px -9px rgba(60, 45, 25, .32);
}

/* Books lean back against the wall: their top edge rests on it, their
   bottom edge stands forward on the ledge. */
.shelf__book {
  display: block;
  /* never wider than its slot, so books stay on the ledge at any width */
  max-width: min(var(--cover-w), var(--slot));
  /* the book stands in front of the shelf, so it must occlude the wood
     surface behind its heel: that visible strip is what reads as depth */
  position: relative;
  z-index: 1;
  /* short focal length: a pronounced lean, offset by a shorter cover so the
     book does not read as stretched */
  /* The lean is the book's own; the press composes on top of it (see the
     pressable block in base.css) rather than replacing it. */
  --press: 1;
  transform: var(--book-tilt) scale(var(--press));
  transform-origin: bottom center;
  transition: transform var(--dur) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .shelf__book:hover {
    transform: var(--book-tilt-hover) translateY(-6px) scale(var(--press));
  }
}

/* Books rise onto the shelves, one after the other, when the view opens.
   `backwards` fill keeps them hidden during their delay and hands the
   element back to its normal styles afterwards, so :hover still works. */
@media (prefers-reduced-motion: no-preference) {
  .shelf--reveal .shelf__book {
    animation: bookIn .8s cubic-bezier(.22, .7, .25, 1) backwards;
    animation-delay: calc(var(--row-delay, 0s) + var(--col-delay, 0s));
  }

  .shelf--reveal .shelf__row:nth-child(1) .shelf__book { --row-delay: 0s; }
  .shelf--reveal .shelf__row:nth-child(2) .shelf__book { --row-delay: .16s; }
  .shelf--reveal .shelf__row:nth-child(3) .shelf__book { --row-delay: .32s; }
  .shelf--reveal .shelf__row:nth-child(4) .shelf__book { --row-delay: .48s; }
  .shelf--reveal .shelf__row:nth-child(n+5) .shelf__book { --row-delay: .64s; }

  .shelf--reveal .shelf__book:nth-child(1) { --col-delay: 0s; }
  .shelf--reveal .shelf__book:nth-child(2) { --col-delay: .07s; }
  .shelf--reveal .shelf__book:nth-child(3) { --col-delay: .14s; }
  .shelf--reveal .shelf__book:nth-child(n+4) { --col-delay: .21s; }
}

/* Every book starts from the same point (the left end of its shelf) and
   slides right into place, coming into focus as it settles. --slide-from is
   each book's own distance to that point, measured in books.js. */
@keyframes bookIn {
  from {
    opacity: 0;
    filter: blur(9px);
    transform: var(--book-tilt) translateX(var(--slide-from, -60px));
  }
  to {
    opacity: 1;
    filter: blur(0);
    transform: var(--book-tilt) translateX(0);
  }
}

/* Printed-cover finish: a soft sheen from the upper left and a darker
   gutter along the spine, so the cover reads as paper rather than a flat image */
.shelf__book::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: 1px 2px 2px 1px;
  background:
    linear-gradient(104deg,
      rgba(255, 255, 255, .3) 0%,
      rgba(255, 255, 255, .08) 16%,
      rgba(255, 255, 255, 0) 40%,
      rgba(0, 0, 0, .05) 100%),
    linear-gradient(to right,
      rgba(0, 0, 0, .12) 0,
      rgba(0, 0, 0, .04) 4px,
      rgba(0, 0, 0, 0) 11px);
}

.shelf__cover {
  display: block;
  width: auto;
  height: auto;
  /* capping the width too keeps square-format books (Steal Like an Artist)
     from dwarfing the portrait ones: they simply stand shorter.
     The slot cap itself lives on .shelf__book. */
  max-width: 100%;
  max-height: var(--cover-h);
  border-radius: 1px 2px 2px 1px;
  filter: saturate(.96) contrast(1.03) brightness(.99); /* print, not screen */
  /* stacked edges on the right read as the page block, then a contact shadow */
  /* Page block on the right, then a shadow cast sideways onto the wall.
     Nothing is offset downwards: the base sits on the shelf, so no shadow
     should show under the book. */
  box-shadow:
    2px 0 0 #efe9dd,
    4px 0 0 #e4ddcd,
    5px 0 0 rgba(90, 70, 45, .15),
    7px 0 9px -1px rgba(40, 30, 15, .14),
    12px 0 20px -4px rgba(40, 30, 15, .09);
}

/* Books without an available cover get a clean typographic one */
.shelf__fallback {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: 100%;
  max-width: 152px;
  height: calc(var(--cover-h) - var(--space-8));
  padding: var(--space-3);
  border-radius: 1px 2px 2px 1px;
  background: var(--ink);
  /* Page block on the right, then a shadow cast sideways onto the wall.
     Nothing is offset downwards: the base sits on the shelf, so no shadow
     should show under the book. */
  box-shadow:
    2px 0 0 #efe9dd,
    4px 0 0 #e4ddcd,
    5px 0 0 rgba(90, 70, 45, .15),
    7px 0 9px -1px rgba(40, 30, 15, .14),
    12px 0 20px -4px rgba(40, 30, 15, .09);
  color: #fff;
  text-align: left;
}

.shelf__fallback-title {
  font-family: var(--font-mono);
  font-size: var(--mono-2xs);
  line-height: var(--leading-snug);
}

.shelf__fallback-author {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .4px;
  text-transform: uppercase;
  opacity: .6;
}

@media (max-width: 560px) {
  .shelf {
    --cover-h: 124px;
    --cover-w: 86px;
    gap: var(--space-12);
    padding: 0 var(--space-4);
  }
  .shelf__row {
    --ledge-h: 18px;
    --ledge-top: 8px;
    --cols: 3;
    --row-gap: var(--space-3);
  }
}

.books-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  max-width: 680px;
  padding: var(--space-10) 0 0;
}

/* Shelf view: the invitation sits centred under the shelves, button below it */
.view-shelf .books-cta {
  flex-direction: column;
  justify-content: center;
  margin-inline: auto;
  text-align: center;
}

.books-cta__line {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-xl);
  line-height: var(--leading-snug);
}

/* Mobile overrides: kept after the base rules above so they win the cascade */
@media (max-width: 560px) {
  /* one knob: titles and authors shrink together, in the list and above it */
  .book,
  .now-reading__book { --book-size: var(--mono-sm); }
}
