/* Generated by site/build-site.mjs from src/book-cover-3d.partial.html — edit the source, not this file. */
/* ------------------------------------------------------------------
     All of Us Wildflowers — mouse-reactive 3D cover
     Pure CSS 3D (no WebGL, no dependencies). Transparent background.
     Palette sampled from the cover artwork itself.

     Performance rule: nothing that animates may touch a gradient. Every
     per-frame value drives either a transform or an opacity, so the browser
     re-composites rather than recomputing and repainting each face.

     Geometry rules, learned the hard way:
     1. `translate(-50%, -50%)` comes FIRST in every face's transform chain.
        transform-origin defaults to the element's centre, so a LEADING
        translate is a world-space shift that exactly cancels the centre
        offset for any rotation. Trailing, it shifts along the face's
        rotated axes and strands every rotated face half its size away.
     2. Nothing is ever exactly coplanar with, or edge-touching, another
        face's plane — the page block keeps --bk-eps of clearance from the
        board planes. Exact coincidence is where 3D plane-splitting starts
        flickering and dropping polygons, differently in every engine.
     3. The only interior surface (.inner) sits BEHIND the whole solid and
        inset from its sides, clear of every other face's plane, where the
        splitter can never be asked to cut it.

     The book is a true stepped casebound solid: two board slabs with
     exposed edges, a page block recessed --bk-square behind them, a flush
     spine.
     ------------------------------------------------------------------ */

  .bk-stage {
    /* Artwork. All four are generated by src/build-book-render.mjs. */
    --bk-cover: url('assets/cover-960.webp');
    --bk-spine-tex: url('assets/spine.webp');
    --bk-pages-fore-tex: url('assets/pages-fore.webp');
    --bk-pages-head-tex: url('assets/pages-head.webp');

    /* Book geometry. 1688x2550 trim -> 0.662 aspect. */
    --bk-aspect: 0.66196;
    --bk-w: clamp(170px, min(62vw, 48vh), 400px);
    --bk-h: calc(var(--bk-w) / var(--bk-aspect));
    --bk-d: calc(var(--bk-w) * 0.172);            /* spine depth, ~0.97in on a 5.6in trim */
    --bk-board: calc(var(--bk-w) * 0.019);        /* cover board thickness */
    --bk-square: calc(var(--bk-w) * 0.012);       /* board overhang past the page block */
    --bk-eps: 0.6px;                           /* clearance from neighbouring planes */
    --bk-pd: calc(var(--bk-d) - var(--bk-board) * 2 - var(--bk-eps) * 2);  /* page block depth */
    --bk-zf: calc(var(--bk-d) / 2 - var(--bk-board) / 2);   /* z-centre of a board-edge strip */

    /* Corner rounding on the boards — a hardcover's fore corners are gently
       radiused; the hinge side stays square. The page block stays square-cut. */
    --bk-r: max(4px, calc(var(--bk-w) * 0.02));

    /* Sampled from the artwork */
    --bk-spine-deep: #122a24;
    --bk-board-face: #16262b;
    --bk-shadow-core: 8, 16, 20;
    --bk-paper: #ded3c2;
    --bk-paper-shade: 120, 104, 82;

      }

  .bk-stage {
    position: relative;
    width: var(--bk-w);
    height: var(--bk-h);
    perspective: 2400px;
    perspective-origin: 50% 45%;
  }

  /* ---- cast shadow -------------------------------------------------- */

  .bk-cast {
    position: absolute;
    left: 50%;
    top: 50%;
    width: calc(var(--bk-w) * 1.04);
    height: calc(var(--bk-h) * 0.92);
    background:
      radial-gradient(
        42% 34% at 50% 88%,
        rgba(var(--bk-shadow-core), 0.66),
        rgba(var(--bk-shadow-core), 0) 72%
      ),
      radial-gradient(
        48% 48% at 50% 58%,
        rgba(var(--bk-shadow-core), 0.44),
        rgba(var(--bk-shadow-core), 0.18) 54%,
        rgba(var(--bk-shadow-core), 0) 76%
      );
    filter: blur(24px);
    transform:
      translate(-50%, -50%)
      translate3d(var(--bk-cast-x, 0px), calc(var(--bk-h) * 0.075), 0)
      scale(var(--bk-cast-s, 1));
    opacity: var(--bk-cast-o, 0.97);
    will-change: transform, opacity;
    pointer-events: none;
  }
  .bk-cast[hidden] { display: none; }

  /* ---- the book ------------------------------------------------------ */

  .bk-book {
    position: absolute;
    inset: 0;
    transform-style: preserve-3d;
    will-change: transform;
    /* JS writes .style.transform directly; this is the pre-script pose,
       matching REST_Y / REST_X so there is no jump when the loop starts. */
    transform: rotateY(3deg) rotateX(-1deg);
  }

  /* Every face is an absolutely-positioned box whose top-left sits at the
     book's centre. The `translate(-50%, -50%)` MUST come FIRST in each
     chain: as the outermost operation it is a plain world-space shift that
     exactly cancels the element's own centre offset (transform-origin
     defaults to the element's centre), so every face stays centred no
     matter how it is rotated. Put it last and it shifts along the face's
     ROTATED axes instead — every rotated face lands half its own size away
     (the back board a full cover-width away). */
  .bk-f {
    position: absolute;
    left: 50%;
    top: 50%;
    transform-style: flat;
    backface-visibility: hidden;
  }

  /* front cover */
  .bk-front {
    width: var(--bk-w);
    height: var(--bk-h);
    border-radius: 2px var(--bk-r) var(--bk-r) 2px;
    overflow: hidden;
    transform: translate(-50%, -50%) translateZ(calc(var(--bk-d) / 2));
    box-shadow:
      inset 0 0 0 1px rgba(255, 255, 255, 0.06),
      0 0 0 0.5px rgba(var(--bk-shadow-core), 0.5);
  }

  .bk-art {
    position: absolute;
    inset: 0;
    background-image: var(--bk-cover);
    background-size: cover;
    background-position: center;
  }

  /* Form shading. Four fixed gradients whose opacity is animated — the
     alternative, animating alpha stops inside one gradient, repaints the
     whole face every frame. */
  .bk-sh {
    position: absolute;
    inset: 0;
    opacity: 0;
  }
  .bk-sh-l {
    background: linear-gradient(to right, rgba(var(--bk-shadow-core), 1) 0%, rgba(var(--bk-shadow-core), 0) 34%);
    opacity: var(--bk-sh-l, 0);
  }
  .bk-sh-r {
    background: linear-gradient(to left, rgba(var(--bk-shadow-core), 1) 0%, rgba(var(--bk-shadow-core), 0) 34%);
    opacity: var(--bk-sh-r, 0.07);
  }
  .bk-sh-t {
    background: linear-gradient(to bottom, rgba(var(--bk-shadow-core), 1) 0%, rgba(var(--bk-shadow-core), 0) 26%);
    opacity: var(--bk-sh-t, 0);
  }
  .bk-sh-b {
    background: linear-gradient(to top, rgba(var(--bk-shadow-core), 1) 0%, rgba(var(--bk-shadow-core), 0) 26%);
    opacity: var(--bk-sh-b, 0.05);
  }

  /* the groove where the board meets the spine */
  .bk-hinge {
    position: absolute;
    inset: 0;
    background: linear-gradient(
      to right,
      rgba(var(--bk-shadow-core), 0.6) 0%,
      rgba(var(--bk-shadow-core), 0.26) 1.6%,
      rgba(var(--bk-shadow-core), 0.05) 5%,
      transparent 11%
    );
  }

  /* Broad specular. Oversized and centred, then slid with a transform so the
     highlight tracks the turn without the gradient ever being recomputed. */
  .bk-sheen {
    position: absolute;
    left: -50%;
    top: -50%;
    width: 200%;
    height: 200%;
    background: radial-gradient(
      closest-side circle at 50% 50%,
      rgba(226, 238, 252, 0.15),
      rgba(210, 228, 245, 0.05) 42%,
      transparent 72%
    );
    transform: translate3d(var(--bk-sheen-x, 0%), var(--bk-sheen-y, -8%), 0);
  }

  /* narrow gloss band across the laminate */
  .bk-gloss {
    position: absolute;
    inset: -30%;
    opacity: var(--bk-gloss-o, 0.5);
    background: linear-gradient(
      104deg,
      transparent 40%,
      rgba(255, 255, 255, 0.05) 47%,
      rgba(255, 255, 255, 0.085) 50%,
      rgba(255, 255, 255, 0.05) 53%,
      transparent 60%
    );
    transform: translate3d(var(--bk-gloss-x, 0%), 0, 0);
  }

  /* ---- interior ---------------------------------------------------------
     The one non-surface face: a dark panel standing in for the back board's
     outside and for the case interior seen through the corner reveals. It
     sits 0.8px BEHIND the whole solid and inset from its sides — clear of
     every other face's plane (rule 3 above). */
  .bk-inner {
    /* Full-size bar an --bk-eps of plane clearance: this panel IS the back
       board's silhouette. A book turned in any direction shows its back
       cover as one continuous rounded outline offset behind the front —
       assembling that outline from strips and a shrunken panel instead
       leaves gaps that read as broken ghost hairlines at the edges and
       corners. Full and board-radiused, every strip end and tilt overshoot
       lands on its dark mass, and corners close with a single arc. */
    width: calc(var(--bk-w) - var(--bk-eps) * 2);
    height: calc(var(--bk-h) - var(--bk-eps) * 2);
    border-radius: 2px var(--bk-r) var(--bk-r) 2px;
    background:
      radial-gradient(120% 80% at 70% 50%, rgba(46, 62, 66, 0.45), rgba(0, 0, 0, 0) 70%),
      linear-gradient(to right, #0d1f1b, #142823 45%, #0c1a16);
    transform: translate(-50%, -50%) translateZ(calc(var(--bk-d) / -2 - 0.8px));
  }

  /* ---- board edges --------------------------------------------------------
     The six exposed edges of the two board slabs — fore, head, tail of each —
     so the case has real thickness that catches light as the book turns. Each
     strip runs bright at the outer face into shadow at the inner one; the two
     boards mirror each other, the back one sitting deeper. Strips stop short
     of the corners by the corner radius, so the thickness visibly tapers away
     where a rounded board actually thins. */

  .bk-bedge {
    background-color: var(--bk-board-face);
  }

  .bk-be-fr,
  .bk-be-br {
    width: var(--bk-board);
    height: calc(var(--bk-h) - var(--bk-r) * 2);
  }
  .bk-be-ft,
  .bk-be-fb,
  .bk-be-bt,
  .bk-be-bb {
    width: calc(var(--bk-w) - var(--bk-r) * 2);
    height: var(--bk-board);
  }

  /* Spine head and tail edges — the case's top and bottom surfaces across
     the spine's depth. Without them, from fore-side views (where the spine
     face itself is correctly backface-culled) the head and tail bands stop
     a corner-radius short of the hinge and the top-left / bottom-left
     corners read as broken. */
  .bk-sp-t,
  .bk-sp-b {
    width: var(--bk-board);
    height: var(--bk-d);
    border-radius: 2px;
  }
  .bk-sp-t {
    background-image: linear-gradient(
      to bottom,
      rgba(var(--bk-shadow-core), 0.55) 0,
      rgba(255, 255, 255, 0.04) 72%,
      rgba(255, 255, 255, 0.2) 100%
    );
    transform: translate(-50%, -50%) rotateX(90deg)
      translateZ(calc(var(--bk-h) / 2))
      translateX(calc((var(--bk-w) - var(--bk-board)) / -2));
  }
  .bk-sp-b {
    background-image: linear-gradient(
      to bottom,
      rgba(255, 255, 255, 0.12) 0,
      rgba(255, 255, 255, 0.02) 30%,
      rgba(var(--bk-shadow-core), 0.6) 100%
    );
    transform: translate(-50%, -50%) rotateX(-90deg)
      translateZ(calc(var(--bk-h) / 2))
      translateX(calc((var(--bk-w) - var(--bk-board)) / -2));
  }

  /* front board: outer face at +z (bright edge toward it) */
  .bk-be-fr {
    background-image: linear-gradient(
      to right,
      rgba(255, 255, 255, 0.22) 0,
      rgba(255, 255, 255, 0.04) 22%,
      rgba(var(--bk-shadow-core), 0.55) 100%
    );
    transform: translate(-50%, -50%) rotateY(90deg)
      translateZ(calc(var(--bk-w) / 2)) translateX(calc(var(--bk-zf) * -1));
  }
  .bk-be-ft {
    background-image: linear-gradient(
      to bottom,
      rgba(var(--bk-shadow-core), 0.5) 0,
      rgba(255, 255, 255, 0.05) 78%,
      rgba(255, 255, 255, 0.24) 100%
    );
    transform: translate(-50%, -50%) rotateX(90deg)
      translateZ(calc(var(--bk-h) / 2)) translateY(var(--bk-zf));
  }
  .bk-be-fb {
    background-image: linear-gradient(
      to bottom,
      rgba(255, 255, 255, 0.16) 0,
      rgba(255, 255, 255, 0.02) 24%,
      rgba(var(--bk-shadow-core), 0.6) 100%
    );
    transform: translate(-50%, -50%) rotateX(-90deg)
      translateZ(calc(var(--bk-h) / 2)) translateY(calc(var(--bk-zf) * -1));
  }

  /* back board: mirrored, deeper in shadow */
  .bk-be-br {
    background-image: linear-gradient(
      to right,
      rgba(var(--bk-shadow-core), 0.6) 0,
      rgba(255, 255, 255, 0.03) 78%,
      rgba(255, 255, 255, 0.14) 100%
    );
    transform: translate(-50%, -50%) rotateY(90deg)
      translateZ(calc(var(--bk-w) / 2)) translateX(var(--bk-zf));
  }
  .bk-be-bt {
    background-image: linear-gradient(
      to bottom,
      rgba(255, 255, 255, 0.13) 0,
      rgba(255, 255, 255, 0.02) 24%,
      rgba(var(--bk-shadow-core), 0.62) 100%
    );
    transform: translate(-50%, -50%) rotateX(90deg)
      translateZ(calc(var(--bk-h) / 2)) translateY(calc(var(--bk-zf) * -1));
  }
  .bk-be-bb {
    background-image: linear-gradient(
      to bottom,
      rgba(var(--bk-shadow-core), 0.66) 0,
      rgba(255, 255, 255, 0.02) 78%,
      rgba(255, 255, 255, 0.1) 100%
    );
    transform: translate(-50%, -50%) rotateX(-90deg)
      translateZ(calc(var(--bk-h) / 2)) translateY(var(--bk-zf));
  }

  /* ---- spine --------------------------------------------------------- */

  .bk-spine {
    width: var(--bk-d);
    height: var(--bk-h);
    border-radius: 2px 0 0 2px;
    overflow: hidden;
    background-color: var(--bk-spine-deep);
    /* Baked strip: the painting wrapping around the hinge, already shaded.
       See build-book-render.mjs — doing it there keeps the tone predictable
       whatever the artwork happens to contain at the fold. */
    background-image: var(--bk-spine-tex);
    background-size: 100% 100%;
    transform: translate(-50%, -50%) rotateY(-90deg) translateZ(calc(var(--bk-w) / 2));
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* static crease at both edges */
  .bk-spine::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
      to right,
      rgba(var(--bk-shadow-core), 0.34) 0%,
      rgba(var(--bk-shadow-core), 0) 26%,
      rgba(var(--bk-shadow-core), 0) 76%,
      rgba(var(--bk-shadow-core), 0.3) 100%
    );
  }

  /* animated specular, opacity only */
  .bk-lit {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    opacity: 0;
  }
  .bk-spine .bk-lit {
    background: linear-gradient(
      to right,
      transparent 12%,
      rgba(255, 255, 255, 0.07) 48%,
      rgba(255, 255, 255, 0.04) 76%,
      transparent 96%
    );
    opacity: var(--bk-spine-lit, 0);
  }

  .bk-spine-type {
    position: relative;
    transform: rotate(90deg);
    white-space: nowrap;
    display: flex;
    align-items: baseline;
    gap: calc(var(--bk-w) * 0.09);
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 300;
    font-size: calc(var(--bk-d) * 0.3);
    letter-spacing: 0.13em;
    color: rgba(255, 255, 255, 0.9);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  }
  .bk-spine-type .bk-who {
    font-size: calc(var(--bk-d) * 0.26);
    letter-spacing: 0.18em;
    color: rgba(255, 255, 255, 0.72);
  }

  /* ---- page block ---------------------------------------------------------
     Recessed --bk-square behind the boards on the three open sides, flush at
     the spine — the stepped profile of a real casebound book. Striations are
     baked textures (one anti-aliased line per leaf, jittered) instead of
     sub-pixel CSS combs; the AO — the shadow slot under each overhanging
     board, the gutter at the spine — layers on top in CSS.

     Local-axis orientation: on the fore-edge, local LEFT is the front of the
     book; on the head (ptop) the front is local BOTTOM; on the tail (pbot),
     local TOP. */

  .bk-pages {
    background-color: var(--bk-paper);
    border-radius: 1px;
  }

  .bk-foredge {
    width: var(--bk-pd);
    height: calc(var(--bk-h) - var(--bk-square) * 2 - var(--bk-eps) * 2);
    background-image:
      /* shadow slots where the boards overhang the block */
      linear-gradient(to right, rgba(var(--bk-shadow-core), 0.5), rgba(var(--bk-shadow-core), 0) 30%),
      linear-gradient(to left, rgba(var(--bk-shadow-core), 0.46), rgba(var(--bk-shadow-core), 0) 30%),
      /* head and tail of the block sit a touch deeper */
      linear-gradient(
        to bottom,
        rgba(var(--bk-shadow-core), 0.28) 0%,
        transparent 7%,
        transparent 93%,
        rgba(var(--bk-shadow-core), 0.3) 100%
      ),
      var(--bk-pages-fore-tex);
    background-size: auto, auto, auto, 100% 100%;
    transform: translate(-50%, -50%) rotateY(90deg)
      translateZ(calc(var(--bk-w) / 2 - var(--bk-square)));
  }
  .bk-foredge .bk-lit {
    background: radial-gradient(
      130% 62% at 46% 26%,
      rgba(255, 255, 255, 0.18),
      transparent 72%
    );
    opacity: var(--bk-page-lit, 0);
  }

  .bk-ptop,
  .bk-pbot {
    width: calc(var(--bk-w) - var(--bk-square) - var(--bk-eps) * 2);
    height: var(--bk-pd);
  }
  .bk-ptop {
    background-image:
      /* front slot at local bottom, back slot at local top */
      linear-gradient(to top, rgba(var(--bk-shadow-core), 0.48), rgba(var(--bk-shadow-core), 0) 32%),
      linear-gradient(to bottom, rgba(var(--bk-shadow-core), 0.44), rgba(var(--bk-shadow-core), 0) 32%),
      /* gutter darkens toward the spine */
      linear-gradient(
        to right,
        rgba(var(--bk-shadow-core), 0.5) 0%,
        rgba(var(--bk-shadow-core), 0.05) 22%,
        rgba(var(--bk-shadow-core), 0.12) 100%
      ),
      var(--bk-pages-head-tex);
    background-size: auto, auto, auto, 100% 100%;
    transform: translate(-50%, -50%) rotateX(90deg)
      translateZ(calc(var(--bk-h) / 2 - var(--bk-square)))
      translateX(calc(var(--bk-square) / -2));
  }
  .bk-pbot {
    background-image:
      /* front slot at local top, back slot at local bottom */
      linear-gradient(to bottom, rgba(var(--bk-shadow-core), 0.5), rgba(var(--bk-shadow-core), 0) 32%),
      linear-gradient(to top, rgba(var(--bk-shadow-core), 0.46), rgba(var(--bk-shadow-core), 0) 32%),
      linear-gradient(
        to right,
        rgba(var(--bk-shadow-core), 0.54) 0%,
        rgba(var(--bk-shadow-core), 0.12) 22%,
        rgba(var(--bk-shadow-core), 0.18) 100%
      ),
      /* the tail sits deeper than the head */
      linear-gradient(rgba(var(--bk-shadow-core), 0.12), rgba(var(--bk-shadow-core), 0.12)),
      var(--bk-pages-head-tex);
    background-size: auto, auto, auto, auto, 100% 100%;
    transform: translate(-50%, -50%) rotateX(-90deg)
      translateZ(calc(var(--bk-h) / 2 - var(--bk-square)))
      translateX(calc(var(--bk-square) / -2));
  }
  .bk-ptop .bk-lit,
  .bk-pbot .bk-lit {
    background: radial-gradient(
      90% 150% at 62% 50%,
      rgba(255, 255, 255, 0.17),
      transparent 76%
    );
  }
  .bk-ptop .bk-lit { opacity: var(--bk-top-lit, 0); }
  .bk-pbot .bk-lit { opacity: var(--bk-bot-lit, 0); }

  /* ---- entrance ------------------------------------------------------ */

  /* Visible by default: with the script blocked or failed this still renders as
     a static posed book rather than nothing. The script marks the stage `js`
     synchronously to opt into the fade, then `ready` plays it. */
  .bk-stage.bk-js .bk-book { opacity: 0; }
  .bk-stage.bk-js.bk-ready .bk-book {
    opacity: 1;
    transition: opacity 0.7s ease;
  }
  .bk-stage.bk-js .bk-cast { opacity: 0; }
  .bk-stage.bk-js.bk-ready .bk-cast {
    opacity: var(--bk-cast-o, 0.97);
    transition: opacity 0.9s ease;
  }

  /* ---- reduced motion ------------------------------------------------ */

  @media (prefers-reduced-motion: reduce) {
    .bk-stage.bk-js.bk-ready .bk-book,
    .bk-stage.bk-js.bk-ready .bk-cast { transition: none; }
  }
