/* Library: the pile. A dark stage holding the books, after Stripe Press.

   Each book is a CSS 3D hardcover lying flat with its spine to you: spine in
   front, cover on top, back cover underneath, and the page block showing
   between the boards at both ends and the fore-edge. Every book carries its
   own perspective, and library.js moves each one's perspective-origin to the
   middle of the screen, so the pile reads as one camera. Scrolling fast tips
   the pile toward its covers; press and drag turns one book in the hand.

   Per book, on the <li>: --paint (cover), --on (ink on the cover), --t
   (thickness, 1 is about 320 pages; library.js sets it from data-pages) and
   data-art (the cover pattern). The book pages live in reader.css and the
   tick index in rail.css. */

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

/* Shared with reader.css. */
.lib-page {
    /* Cloth grain laid over every cover. Parentheses are escaped so no
       tool mistakes the inner url() for the end of this one. */
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .16 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url%28%23n%29'/%3E%3C/svg%3E");
    --page-paper: #f4f0e6;
    --page-ink: #1b1a17;
    /* Page edges: fine lines on cream, lighter in the middle of the block. */
    --page-lines: repeating-linear-gradient(to bottom, rgba(70, 58, 36, 0.12) 0 1px, transparent 1px 3px);
    --page-block: linear-gradient(to bottom, #e6dec9, #f5f0e3 50%, #e1d9c4);
}

/* Cover patterns, drawn in the book's own ink. */
[data-art] { --mark: color-mix(in srgb, var(--on) 30%, transparent); }
[data-art="lines"] { --art: repeating-linear-gradient(90deg, var(--mark) 0 2px, transparent 2px 10px); }
[data-art="rings"] { --art: repeating-radial-gradient(circle at 32% 58%, var(--mark) 0 2px, transparent 2px 18px); }
[data-art="grid"] { --art: repeating-linear-gradient(90deg, var(--mark) 0 1px, transparent 1px 26px), repeating-linear-gradient(0deg, var(--mark) 0 1px, transparent 1px 26px); }
[data-art="diag"] { --art: repeating-linear-gradient(45deg, var(--mark) 0 7px, transparent 7px 24px); }
[data-art="bands"] { --art: repeating-linear-gradient(0deg, var(--mark) 0 16px, transparent 16px 44px); }
[data-art="rays"] { --art: repeating-conic-gradient(from 0deg at 68% 36%, var(--mark) 0 3deg, transparent 3deg 12deg); }

/* Hero: short, so the dark stage starts in the first screen. When the stage
   holds the middle of the screen, app.js sets body.theme-dark and the whole
   page goes to ink, hero included. */
.lib-hero.content-page-hero {
    min-height: 0;
    padding-top: calc(var(--header-height) + clamp(3rem, 6vw, 5rem));
    padding-bottom: clamp(3rem, 6vw, 5rem);
    border-bottom: 0;
}

.lib-hero h1,
.lib-hero .content-page-intro p:first-child,
.lib-hero .crumb [aria-current] { transition: color 700ms ease; }
.theme-dark .lib-hero h1,
.theme-dark .lib-hero .content-page-intro p:first-child,
.theme-dark .lib-hero .crumb [aria-current] { color: var(--paper); }
.theme-dark .lib-hero .content-page-intro p:last-child,
.theme-dark .lib-hero .crumb a { color: rgba(242, 239, 229, 0.6); }
.theme-dark .subpage-site-header { border-bottom-color: rgba(242, 239, 229, 0.18); background: rgba(17, 20, 24, 0.9); }

/* ---------------------------------------------------------------------
   The stage and the pile
   --------------------------------------------------------------------- */
.lib-stage {
    --L: clamp(250px, 50vw, 720px);         /* book length, left to right */
    --D: calc(var(--L) * 0.64);             /* cover width, into the screen */
    --T0: clamp(40px, 7vw, 104px);          /* thickness of an average book */
    position: relative;
    padding: clamp(3.5rem, 8vw, 6rem) var(--page-pad) clamp(7rem, 16vw, 14rem);
    background: var(--ink);
    color: var(--paper);
    --rail: var(--paper);
}

.lib-stage-note {
    margin: 0 0 clamp(3rem, 7vw, 6rem);
    color: rgba(242, 239, 229, 0.55);
    font: 700 var(--fs-micro)/1 var(--mono);
    letter-spacing: 0.14em;
    text-align: center;
    text-transform: uppercase;
}

.lib-stack {
    display: grid;
    justify-items: center;
    gap: clamp(1.4rem, 3.6vw, 3.2rem);
    margin: 0 auto;
    padding: 0;
    list-style: none;
}

/* library.js sets z-index so the book nearest the middle paints on top;
   the book in your hand beats all of them. */
.lib-item { position: relative; width: min(100%, var(--L)); }
.lib-item.is-held { z-index: 5000 !important; }

/* Without JS the books are a plain list on the dark stage. */
.lib-book { padding: 1rem 0; border-top: 1px solid rgba(242, 239, 229, 0.18); }
.lib-title { margin: 0; font: 400 var(--fs-block)/1.05 var(--fancy); }
.lib-author { margin: 0.4rem 0 0; color: rgba(242, 239, 229, 0.62); font: 400 var(--fs-small)/1.4 var(--mono); }
.lib-why { margin: 0.8rem 0 0; }
.lib-notes,
.lib-quotes { margin: 0.6rem 0 0; padding-left: 1.2rem; color: rgba(242, 239, 229, 0.78); }
.lib-quotes cite { display: block; color: rgba(242, 239, 229, 0.55); font: 400 var(--fs-small)/1.4 var(--mono); }

.lib-stage.is-3d .lib-book {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* The button that holds one book. Vertical swipes still scroll on a phone;
   sideways ones turn the book. */
.lib-pick {
    --T: calc(var(--T0) * var(--t, 1));
    display: block;
    width: 100%;
    height: var(--T);
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    cursor: grab;
    perspective: 2600px;
    perspective-origin: 50% var(--po, 50%);
    touch-action: pan-y;
    -webkit-tap-highlight-color: transparent;
}

.lib-item.is-held .lib-pick { cursor: grabbing; }
.lib-pick:focus-visible { outline: 2px solid var(--signal); outline-offset: 10px; }

.bk-lift,
.bk-spin,
.bk {
    position: relative;
    display: block;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
}

.bk-lift { transition: transform 600ms var(--ease-out); }

@media (hover: hover) and (pointer: fine) {
    .lib-pick:hover .bk-lift { transform: translateZ(46px) translateY(-4px); }
}

/* Turned by the hand (library.js writes the transform while you drag), then
   eased back when you let go. Both turn about the middle of the book. */
.bk-spin {
    transform-origin: 50% 50% calc(var(--D) * -0.5);
    transition: transform 900ms var(--ease-out);
}

.lib-item.is-held .bk-spin { transition-duration: 90ms; transition-timing-function: linear; }

/* Tilted by library.js from scroll speed. */
.bk {
    transform: rotateX(var(--tilt, 0deg));
    transform-origin: 50% 50% calc(var(--D) * -0.5);
}

.bk-face {
    position: absolute;
    display: block;
    backface-visibility: hidden;
}

/* Spine: a rounded back, light across the middle and falling into shade at
   the boards, with a raised band near each end. */
.bk-spine {
    inset: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: 1rem;
    align-items: center;
    padding: 0 clamp(1.1rem, 3.2vw, 2.6rem);
    background-color: var(--paint);
    background-image:
        var(--grain),
        linear-gradient(to bottom, rgba(0, 0, 0, 0.38), rgba(255, 255, 255, 0.1) 14%, rgba(255, 255, 255, 0.2) 34%, rgba(255, 255, 255, 0) 58%, rgba(0, 0, 0, 0.36));
    background-size: 180px 180px, auto;
    color: var(--on);
}

.bk-spine::before,
.bk-spine::after {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 3px;
    content: "";
    border-right: 1px solid currentColor;
    border-left: 1px solid currentColor;
    opacity: 0.22;
}

.bk-spine::before { left: clamp(0.35rem, 1.2vw, 0.8rem); }
.bk-spine::after { right: clamp(0.35rem, 1.2vw, 0.8rem); }

.bk-author {
    justify-self: start;
    overflow: hidden;
    max-width: 100%;
    font: 400 clamp(0.5rem, 1vw, 0.72rem)/1 var(--mono);
    letter-spacing: 0.08em;
    text-overflow: ellipsis;
    text-transform: uppercase;
    white-space: nowrap;
}

.bk-title {
    max-width: min(34ch, calc(var(--L) * 0.56));
    overflow: hidden;
    font: 400 clamp(0.95rem, 2.1vw, 1.75rem)/1 var(--fancy);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bk-no {
    justify-self: end;
    padding: 0.28em 0.4em;
    border: 1px solid currentColor;
    font: 700 clamp(0.5rem, 0.9vw, 0.66rem)/1 var(--mono);
    letter-spacing: 0.06em;
    opacity: 0.85;
}

/* Cover: the top face, hinged on the spine's top edge, lying back. */
.bk-cover {
    top: calc(var(--D) * -1);
    left: 0;
    width: 100%;
    height: var(--D);
    overflow: hidden;
    transform: rotateX(90deg);
    transform-origin: 50% 100%;
    background-color: var(--paint);
}

/* The cover's art, drawn upright (spine on its left, head at its top) and
   turned a quarter so its head lies at the left end of the book. */
.bk-cover-art {
    position: absolute;
    top: 50%;
    left: 50%;
    display: flex;
    flex-direction: column;
    width: var(--D);
    height: var(--L);
    padding: calc(var(--D) * 0.1) calc(var(--D) * 0.09) calc(var(--D) * 0.08) calc(var(--D) * 0.13);
    background-image:
        var(--grain),
        linear-gradient(to right, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0) 4%, rgba(255, 255, 255, 0.08) 5.5%, rgba(0, 0, 0, 0) 8%),
        linear-gradient(to left, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0) 55%),
        var(--art, none);
    background-size: 180px 180px, auto, auto, auto;
    color: var(--on);
    transform: translate(-50%, -50%) rotate(-90deg);
}

.bk-cover-no { font: 700 calc(var(--D) * 0.03)/1 var(--mono); letter-spacing: 0.12em; opacity: 0.85; }
.bk-cover-title { margin-top: auto; font: 400 calc(var(--D) * 0.1)/1 var(--fancy); text-wrap: balance; }
.bk-cover-author { margin-top: calc(var(--D) * 0.04); font: 400 calc(var(--D) * 0.032)/1.2 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; }

/* Back cover: the bottom face, lying back from the spine's bottom edge. */
.bk-back {
    top: 100%;
    left: 0;
    width: 100%;
    height: var(--D);
    transform: rotateX(-90deg);
    transform-origin: 50% 0;
    background-color: var(--paint);
    background-image: var(--grain), linear-gradient(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4));
    background-size: 180px 180px, auto;
}

/* The two ends and the fore-edge: a board at the top and bottom, the page
   block between them. */
.bk-edge {
    background-image:
        linear-gradient(to bottom, var(--paint) 0 4px, rgba(0, 0, 0, 0.25) 4px 5px, transparent 5px calc(100% - 5px), rgba(0, 0, 0, 0.25) calc(100% - 5px) calc(100% - 4px), var(--paint) calc(100% - 4px)),
        var(--page-lines),
        var(--page-block);
    box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.06);
}

.bk-head {
    top: 0;
    left: calc(var(--D) * -1);
    width: var(--D);
    height: 100%;
    transform: rotateY(-90deg);
    transform-origin: 100% 50%;
}

.bk-tail {
    top: 0;
    left: 100%;
    width: var(--D);
    height: 100%;
    transform: rotateY(90deg);
    transform-origin: 0 50%;
}

.bk-fore {
    inset: 0;
    transform: translateZ(calc(var(--D) * -1)) rotateY(180deg);
}

/* Where the spine wraps round the ends. */
.bk-head::after,
.bk-tail::after {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 6px;
    content: "";
    background: var(--paint);
}

.bk-head::after { right: 0; }
.bk-tail::after { left: 0; }

/* WebGL books (book3d.js) paint on a canvas fixed over the screen; the
   buttons stay underneath as the things you press, and the CSS books step
   aside once the canvas has drawn. */
.lib-gl {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

.lib-stage.is-webgl .bk-lift { visibility: hidden; }

/* Books come in from below as the pile scrolls into view. */
@keyframes lib-arrive {
    from { opacity: 0; transform: translateY(60px); }
}

.js .lib-stage.is-3d .lib-item { opacity: 0; }
.js .lib-stage.is-3d .lib-item.is-in { opacity: 1; animation: lib-arrive 900ms var(--ease-out) both; }

/* A phone gets the full width, and the spine keeps only title and number:
   the author is on the book's page one press away. */
@media (max-width: 760px) {
    .lib-stage { --L: calc(100vw - 2 * var(--page-pad) - 0.5rem); --T0: 44px; }
    .bk-author { visibility: hidden; }
    .bk-spine { gap: 0.5rem; padding: 0 1.1rem; }
}

@media (prefers-reduced-motion: reduce) {
    .js .lib-stage.is-3d .lib-item { opacity: 1; animation: none; }
}
