/* Reader: the books one at a time, as on Stripe Press (reader.js).

   The dialog is one long scroll with a section per book in the book's own
   colours: the book standing in a sticky column on the left, the notes on
   the right and the favourite quotes full width below. book3d.js draws a
   WebGL book over each .lib-sec-stage; without it reader.js builds a CSS
   book (a "tome") inside the stage. "Open the book" shows the reading
   layer, where a CSS tome lies open and the notes are its pages.

   Per book, set by Library.applyLook: --paint, --on, --t and data-art. */

/* ---------------------------------------------------------------------
   The dialog
   --------------------------------------------------------------------- */
dialog.lib-detail {
    --rail-z: 10;
    --rail-dim: rgba(12, 12, 14, 0.55);
    position: fixed;
    inset: 0;
    width: 100%;
    max-width: none;
    height: 100%;
    max-height: none;
    margin: 0;
    padding: 0;
    overflow: hidden auto;
    border: 0;
    background: var(--ink);
    color: var(--paper);
    overscroll-behavior: contain;
    scroll-behavior: auto;
}

dialog.lib-detail::backdrop { background: rgba(17, 20, 24, 0.6); }

@keyframes lib-fade { from { opacity: 0; } }
dialog.lib-detail[open] { animation: lib-fade 450ms ease backwards; }
dialog.lib-detail.is-reading { overflow: hidden; }

.lib-detail .lib-d-btn {
    padding: 0.75rem 1rem;
    border: 1px solid currentColor;
    background: transparent;
    color: inherit;
    font: 700 var(--fs-label)/1 var(--mono);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background-color 200ms ease, color 200ms ease;
}

.lib-detail .lib-d-btn:hover,
.lib-detail .lib-d-btn:focus-visible { background: var(--on); color: var(--paint); }
.lib-detail .lib-d-btn:focus-visible { outline: 2px solid var(--on); outline-offset: 3px; }
.lib-detail .lib-d-btn--solid { border-color: var(--on); background: var(--on); color: var(--paint); }
.lib-detail .lib-d-btn--solid:hover,
.lib-detail .lib-d-btn--solid:focus-visible { background: transparent; color: var(--on); }
.lib-detail .lib-d-btn:disabled { opacity: 0.35; cursor: default; pointer-events: none; }

/* ---------------------------------------------------------------------
   One section per book
   --------------------------------------------------------------------- */
.lib-sec {
    --W: min(30vw, 380px);
    position: relative;
    padding: 0 var(--page-pad) 0 6rem;
    background-color: var(--paint);
    background-image: var(--grain, none);
    background-size: 180px 180px;
    color: var(--on);
}

.lib-sec-top {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
    column-gap: clamp(2rem, 5vw, 6rem);
    min-height: 100vh;
}

/* The book stays put while its text scrolls past, then leaves with it. */
.lib-sec-hold {
    position: sticky;
    top: 0;
    display: grid;
    place-items: center;
    align-self: start;
    height: 100vh;
}

.lib-sec-stage {
    width: var(--W);
    aspect-ratio: 1 / 1.46;
    touch-action: none;
}

/* The camera sits on the book. */
.lib-sec-stage.is-css {
    perspective: 1800px;
    cursor: grab;
    -webkit-user-select: none;
    user-select: none;
}

.lib-sec-stage.is-css:active { cursor: grabbing; }

.lib-sec-text {
    align-self: center;
    max-width: 34rem;
    padding: clamp(6rem, 18vh, 10rem) 0 clamp(4rem, 12vh, 8rem);
}

.lib-sec-no {
    margin: 0 0 1.4rem;
    font: 700 var(--fs-micro)/1 var(--mono);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    opacity: 0.75;
}

.lib-sec-title {
    margin: 0;
    font: 400 var(--fs-section)/1 var(--fancy);
    letter-spacing: -0.01em;
    text-wrap: balance;
}

.lib-sec-author {
    margin: 1rem 0 0;
    font: 400 var(--fs-small)/1.4 var(--mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.8;
}

.lib-sec-open { margin-top: 2rem; }

.lib-sec-why {
    margin: 2.2rem 0 0;
    font: 400 clamp(1.15rem, 1.6vw, 1.4rem)/1.4 var(--fancy);
    text-wrap: pretty;
}

/* Labels as on Stripe Press: a short rule, then the name in the serif. */
.lib-label {
    display: flex;
    gap: 1rem;
    align-items: center;
    margin: 3.2rem 0 1.4rem;
    font: 400 1.35rem/1.2 var(--fancy);
}

.lib-label::before {
    flex: 0 0 3.75rem;
    height: 1px;
    content: "";
    background: currentColor;
}

.lib-sec-notes {
    display: grid;
    gap: 1.1rem;
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: note;
}

.lib-sec-notes li {
    display: grid;
    grid-template-columns: 2.6rem minmax(0, 1fr);
    font: 400 1.08rem/1.5 var(--fancy);
    counter-increment: note;
    text-wrap: pretty;
}

.lib-sec-notes li::before {
    content: counter(note, decimal-leading-zero);
    font: 700 var(--fs-micro)/2.6 var(--mono);
    letter-spacing: 0.1em;
    opacity: 0.7;
}

.lib-sec-empty { margin: 0; font: 400 1.08rem/1.5 var(--fancy); opacity: 0.7; }

.lib-sec-quotes { padding: clamp(3rem, 8vh, 6rem) 0 clamp(6rem, 18vh, 11rem); }
.lib-sec-quotes > .lib-label { margin: 0 0 2.4rem; }

/* auto-fill, not auto-fit: one quote keeps a column's width instead of
   running the full width of the screen. */
.lib-quote-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
    gap: 3rem clamp(2rem, 4vw, 4.5rem);
    margin: 0;
    padding: 0;
    list-style: none;
}

.lib-quote { display: flex; flex-direction: column; align-items: flex-start; }

.lib-quote-mark {
    height: 0.5em;
    margin-bottom: 0.7rem;
    font: 400 4.2rem/1 var(--fancy);
}

.lib-quote-text {
    margin: 0;
    font: 400 1.2rem/1.45 var(--fancy);
    text-wrap: pretty;
}

.lib-quote-rule {
    width: 2.5rem;
    height: 1px;
    margin: 1.4rem 0 1rem;
    background: currentColor;
    opacity: 0.6;
}

.lib-quote-cite {
    font: 400 var(--fs-small)/1.45 var(--mono);
    font-style: normal;
    opacity: 0.75;
}

/* ---------------------------------------------------------------------
   The reading layer
   --------------------------------------------------------------------- */
.lib-reading {
    position: fixed;
    inset: 0;
    z-index: 50;
    background-color: var(--paint);
    background-image: var(--grain, none);
    background-size: 180px 180px;
    color: var(--on);
    opacity: 0;
    pointer-events: none;
    transition: opacity 450ms ease;
}

.lib-reading[hidden] { display: none; }
.lib-reading.is-shown { opacity: 1; pointer-events: auto; }

/* The camera sits on the middle of the open spread. */
.lib-reading-stage {
    --W: clamp(180px, 26vw, 360px);
    position: absolute;
    inset: 0 0 4.5rem;
    display: grid;
    place-items: center;
    perspective: 1800px;
}

.lib-d-reader {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    justify-content: center;
    padding: 1rem var(--page-pad) calc(1rem + env(safe-area-inset-bottom, 0px));
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 300ms ease, transform 400ms var(--ease-out);
}

.lib-reading.is-open .lib-d-reader {
    opacity: 1;
    transform: none;
    transition: opacity 400ms ease 400ms, transform 500ms var(--ease-out) 400ms;
}

.lib-d-count { min-width: 6rem; font: 700 var(--fs-label)/1 var(--mono); letter-spacing: 0.1em; text-align: center; text-transform: uppercase; }

/* ---------------------------------------------------------------------
   The tome: a CSS hardcover
   --------------------------------------------------------------------- */
.tome-in,
.tome {
    position: relative;
    transform-style: preserve-3d;
}

/* Transform only: opacity inside the 3D chain would flatten it. */
.tome-in.is-arriving { animation: tome-in 1200ms var(--ease-out) backwards; }

@keyframes tome-in {
    from { transform: translateY(40px) rotateY(-200deg) scale(0.7); }
}

.tome {
    --H: calc(var(--W) * 1.46);
    --TT: calc(var(--W) * 0.12 * var(--t, 1));
    --b: max(2px, calc(var(--W) * 0.012));   /* board thickness */
    --gap: calc(var(--TT) / (var(--n, 1) + 1));
    --ax: -9deg;
    --ay: 27deg;
    --ox: 0px;
    width: var(--W);
    height: var(--H);
    /* Turns about the middle of the book, not the face of its cover. */
    transform-origin: 50% 50% calc(var(--TT) * -0.5);
    transform:
        scale(var(--fit, 1))
        rotateX(calc(var(--ax) + var(--gx, 0deg) + var(--py, 0) * 9deg))
        rotateY(calc(var(--ay) + var(--gy, 0deg) + var(--px, 0) * 16deg))
        translateX(var(--ox));
    transition: transform 1000ms var(--ease-out), transform-origin 1000ms var(--ease-out);
}

.tome.is-held { transition-duration: 90ms; }
.tome.is-snap { transition: none; }

.lib-reading.is-open .tome {
    --ax: 20deg;
    --ay: 0deg;
    --ox: calc(var(--W) / 2);
    transform-origin: 50% 50% 0;
    cursor: pointer;
}

.tome-side {
    position: absolute;
    display: block;
    backface-visibility: hidden;
    transition: opacity 500ms ease;
}

/* Open, only the back board stays; the leaves are the pages. */
.lib-reading.is-open .tome-side:not(.tome-back) { opacity: 0; }

/* Spine: the left face, from the back board to the front. Light and shade
   across it make it read round. */
.tome-spine {
    top: 0;
    left: calc(var(--TT) * -1);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    width: var(--TT);
    height: 100%;
    padding: calc(var(--W) * 0.08) 0 calc(var(--W) * 0.06);
    overflow: hidden;
    transform: rotateY(-90deg);
    transform-origin: 100% 50%;
    background-color: var(--paint);
    background-image:
        var(--grain, none),
        linear-gradient(to right, rgba(0, 0, 0, 0.34), rgba(0, 0, 0, 0.08) 22%, rgba(255, 255, 255, 0.14) 48%, rgba(0, 0, 0, 0.06) 74%, rgba(0, 0, 0, 0.3));
    background-size: 180px 180px, auto;
    color: var(--on);
}

.tome-spine-title {
    overflow: hidden;
    max-height: 78%;
    font: 400 clamp(0.5rem, calc(var(--TT) * 0.42), calc(var(--W) * 0.055))/1 var(--fancy);
    text-overflow: ellipsis;
    white-space: nowrap;
    writing-mode: vertical-rl;
}

.tome-spine-no { font: 700 clamp(0.45rem, calc(var(--TT) * 0.26), calc(var(--W) * 0.032))/1 var(--mono); opacity: 0.8; }

/* Fore-edge, head and tail: the boards' edges frame the cream page block. */
.tome-fore,
.tome-head,
.tome-tail {
    --edge: var(--paint) var(--b), rgba(0, 0, 0, 0.3) var(--b), transparent calc(var(--b) + 8%),
        transparent calc(92% - var(--b)), rgba(0, 0, 0, 0.3) calc(100% - var(--b)), var(--paint) calc(100% - var(--b));
}

.tome-fore {
    top: 0;
    left: 100%;
    width: var(--TT);
    height: 100%;
    transform: rotateY(90deg);
    transform-origin: 0 50%;
    background:
        linear-gradient(to right, var(--edge)),
        repeating-linear-gradient(to right, rgba(70, 58, 36, 0.14) 0 1px, transparent 1px 3px),
        var(--page-paper, #f4f0e6);
}

.tome-head,
.tome-tail {
    left: 0;
    width: 100%;
    height: var(--TT);
    background:
        linear-gradient(to bottom, var(--edge)),
        repeating-linear-gradient(to bottom, rgba(70, 58, 36, 0.14) 0 1px, transparent 1px 3px),
        var(--page-paper, #f4f0e6);
}

.tome-head {
    top: calc(var(--TT) * -1);
    transform: rotateX(90deg);
    transform-origin: 50% 100%;
}

.tome-tail {
    top: 100%;
    transform: rotateX(-90deg);
    transform-origin: 50% 0;
}

/* The back cover: the author and the why-line, as a blurb. */
.tome-back {
    inset: 0;
    display: flex;
    flex-direction: column;
    gap: calc(var(--W) * 0.06);
    padding: calc(var(--W) * 0.12) calc(var(--W) * 0.1);
    transform: translateZ(calc(var(--TT) * -1)) rotateY(180deg);
    background-color: var(--paint);
    background-image:
        var(--grain, none),
        linear-gradient(to left, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0) 5%, rgba(255, 255, 255, 0.06) 6%, rgba(0, 0, 0, 0) 9%),
        linear-gradient(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.12));
    background-size: 180px 180px, auto, auto;
    color: var(--on);
}

.tome-back .pg-no { font: 700 calc(var(--W) * 0.034)/1.2 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.8; }
.tome-blurb { font: 400 calc(var(--W) * 0.056)/1.35 var(--fancy); text-wrap: pretty; }
.lib-reading .tome-blurb { visibility: hidden; }

/* A leaf turns on its left edge. Unturned leaves stack down from the cover;
   turned ones stack the other way, so the last page turned is on top. */
.tome-leaf {
    position: absolute;
    inset: 0;
    transform-style: preserve-3d;
    transform-origin: 0 50%;
    transform: translateZ(calc(var(--k) * var(--gap) * -1)) rotateY(0deg);
    transition: transform 1000ms var(--ease-in-out);
}

.tome-leaf.is-turned {
    transform: translateZ(calc((var(--n) - var(--k)) * var(--gap) * -1)) rotateY(-180deg);
}

.leaf-face {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: calc(var(--W) * 0.1) calc(var(--W) * 0.1) calc(var(--W) * 0.08);
    background-color: var(--page-paper, #f4f0e6);
    background-image: linear-gradient(to right, rgba(0, 0, 0, 0.13), rgba(0, 0, 0, 0) 14%);
    color: var(--page-ink, #1b1a17);
    font-size: calc(var(--W) * 0.052);
    line-height: 1.4;
    backface-visibility: hidden;
}

.leaf-back {
    transform: rotateY(180deg);
    background-image: linear-gradient(to left, rgba(0, 0, 0, 0.13), rgba(0, 0, 0, 0) 14%);
}

/* The front cover: pattern, grain and a hinge groove by the spine. */
.leaf-cover {
    background-color: var(--paint);
    background-image:
        var(--grain, none),
        linear-gradient(to right, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0) 5%, rgba(255, 255, 255, 0.07) 6%, rgba(0, 0, 0, 0.16) 7.5%, rgba(0, 0, 0, 0) 10%),
        var(--art, none);
    background-size: 180px 180px, auto, auto;
    color: var(--on);
}

.leaf-cover .pg-no { font: 700 calc(var(--W) * 0.036)/1 var(--mono); letter-spacing: 0.12em; opacity: 0.85; }
.leaf-cover .pg-title { margin-top: auto; font: 400 calc(var(--W) * 0.12)/1 var(--fancy); text-wrap: balance; }
.leaf-cover .pg-author { margin-top: calc(var(--W) * 0.05); font: 400 calc(var(--W) * 0.038)/1.2 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; }

.leaf-endpaper {
    background-color: var(--paint);
    background-image:
        var(--grain, none),
        linear-gradient(to left, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0) 12%),
        linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
        var(--art, none);
    background-size: 180px 180px, auto, auto, auto;
}

.pg-label { font: 700 calc(var(--W) * 0.032)/1.3 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.6; }
.pg-folio { margin-top: auto; font: 400 calc(var(--W) * 0.032)/1 var(--mono); opacity: 0.55; }
.leaf-back .pg-folio { align-self: flex-start; }
.leaf-front .pg-folio { align-self: flex-end; }

.pg-title-page { align-items: center; justify-content: center; text-align: center; }
.pg-title-page .pg-title { margin: calc(var(--W) * 0.05) 0; font: 400 calc(var(--W) * 0.1)/1.05 var(--fancy); text-wrap: balance; }
.pg-title-page .pg-rule { width: 30%; height: 1px; margin-bottom: calc(var(--W) * 0.05); background: currentColor; opacity: 0.4; }
.pg-title-page .pg-why { margin-top: calc(var(--W) * 0.08); font-size: calc(var(--W) * 0.046); opacity: 0.8; text-wrap: balance; }

.pg-num { margin: calc(var(--W) * 0.06) 0 0; color: var(--paint); font: 900 calc(var(--W) * 0.34)/0.85 var(--display); letter-spacing: -0.06em; }
.pg-note { margin-top: calc(var(--W) * 0.06); font-size: calc(var(--W) * 0.066); font-weight: 650; line-height: 1.3; text-wrap: pretty; }
.pg-empty { align-items: center; justify-content: center; text-align: center; }
.pg-empty span { opacity: 0.7; }

/* ---------------------------------------------------------------------
   Phones and tablets: one column, the book on top and not sticky
   --------------------------------------------------------------------- */
@media (max-width: 900px) {
    .lib-sec { --W: min(52vw, 250px); padding: 0 var(--page-pad); }
    .lib-sec-top { grid-template-columns: minmax(0, 1fr); min-height: 0; }
    .lib-sec-hold { position: relative; height: 60vh; height: 60svh; }
    .lib-sec-text { align-self: start; max-width: none; padding: 0 0 1rem; }
    .lib-label { margin-top: 2.6rem; }
    .lib-sec-quotes { padding: 2.6rem 0 5rem; }
    .lib-reading-stage { --W: min(52vw, 250px); }

    /* The rail's back button sits over the scrolling text here. */
    .lib-detail .lib-rail-back { background: var(--rail-bg, var(--ink)); }
}

@media (prefers-reduced-motion: reduce) {
    dialog.lib-detail[open],
    .tome-in.is-arriving { animation: none; }

    .tome,
    .tome-leaf,
    .tome-side,
    .lib-reading,
    .lib-d-reader,
    .lib-reading.is-open .lib-d-reader { transition: none; }
}
