/* =====================================================================
   BOARD GAMES UNFOLD: the transition into Board games (the owner's "Mench Unfold, crisp", 3 November 2026, from the
   Board game section transitions page: docs/design/unfold-crisp/ on the board-games-transitions branch)
   Sits between Perfect for and Board games in index.html. As you scroll, a folded game board rises in, opens out
   twice (each fold a picture turning on its hinge), zooms until it fills the screen, then splits down the middle and
   swings open like two doors onto Board games. Script: js/board-unfold.js (it paints the board's pictures once and
   sets --p, 0..1, from the scroll position; everything else is worked out here from --p).

   How it fits together, the same way as the birthday mix (css/page/30-birthday-mix.css): the run is tall and its
   stage sticks to the screen. Board games sits after the run inside the same wrapper, pulled up under the stage, and
   sticks to the top too, so it waits under the board and the doors open onto it in place. The cover (the page
   background) hides it until the board fills the screen. The tail keeps the wrapper long enough for Board games to
   ride down to where the run ends; after that it scrolls on as normal.
   Only transform and opacity change while you scroll: the pictures are painted once, and the graphics card just
   turns and moves them. Everything switches on only once the script has set up (.is-ready).
   ===================================================================== */
.bunfold {
  /* scroll length of the effect (also places the #games anchor and sizes the tail): one screen while the stage
     scrolls into place (the board rides up with it), then 194vh while it's held, the design's 220vh minus the
     rise-in the stage scrolling in now replaces */
  --bu-len: 294vh;
  position: relative;
}
.bunfold__run {
  --p: 0;
  position: relative;
  z-index: 2;
  height: var(--bu-len);
  pointer-events: none;
}
.bunfold__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  contain: strict; /* nothing inside can change the size or layout of anything outside */
}
.bunfold__cover {
  position: absolute;
  inset: 0;
  background: var(--bg);
  /* the page, until the board fills the screen (--zm reaches 1); then Board games shows behind the doors */
  opacity: calc(1 - clamp(0, (var(--zm) - 0.999) * 1000, 1));
}
.bunfold:not(.is-ready) {
  --bu-len: 0px;
}
/* the board waits, hidden, until the script has painted it: otherwise only the fold shading would show */
.bunfold:not(.is-painted) .bunfold__board {
  visibility: hidden;
}
.bunfold:not(.is-ready) .bunfold__run {
  display: none;
}

/* Board games: waits under the stage while the effect plays, then scrolls on as normal */
.bunfold.is-ready .bunfold__run ~ .section {
  position: sticky;
  top: 0;
  z-index: 1;
  margin-top: calc(var(--bu-len) * -1);
}
/* Board games is at least a screen tall here: a shorter section stays pinned at the top until the wrapper's end
   reaches it, which left a strip of page background under it on wide screens */
.bunfold.is-ready .bunfold__run ~ .section {
  min-height: 100vh;
}
.bunfold.is-ready .bunfold__tail {
  height: calc(var(--bu-len) - 100vh);
}
/* #games links (the menus, What's inside, Perfect for) land here, where the doors have just opened. The section
   can't be the target itself: while it waits under the stage the browser would scroll to where it is waiting. */
.bunfold__anchor {
  position: absolute;
  left: 0;
  top: max(0px, calc(var(--bu-len) - 100vh));
  width: 1px;
  height: 1px;
  /* cancels the page's 16px scroll-padding-top (css/page/01-base.css), so a jump lands with the doors open */
  scroll-margin-top: calc(-1 * (env(safe-area-inset-top, 0px) + 16px));
}
/* the divider lines between sections (css/page/02-sections.css) match .section + .section, which no longer applies
   on either side of the wrapper: put one back above the transition (after it comes a tile map, which has none) */
.section + .bunfold {
  border-top: var(--line) solid var(--edge);
}
[data-mode="night"] .section + .bunfold {
  border-top: 1px solid var(--hair);
}

/* less motion: no effect at all, the page scrolls straight on to Board games */
@media (prefers-reduced-motion: reduce) {
  .bunfold {
    --bu-len: 0px;
  }
  .bunfold__run {
    display: none;
  }
  .bunfold.is-ready .bunfold__run ~ .section {
    position: relative;
    margin-top: 0;
  }
}

/* ---------- the crisp Unfold. Everything is built at --N, the board's size once zoomed in (set by the script),
   and shrunk at the start with --s0: the browser draws each picture once at full size and only ever shrinks it,
   so nothing is stretched (stretching a small picture up is what made the flat version blurry).
   Each fold is one finished picture turning on its hinge (rotateY / rotateX with its own perspective): the
   graphics card tilts it, and nothing is redrawn while you scroll. */
.bunfold__run {
  --in: clamp(0, var(--p) / 0.12, 1);
  --in-e: calc(1 - (1 - var(--in)) * (1 - var(--in)) * (1 - var(--in)));
  --a: clamp(0, (var(--p) - 0.13) / 0.16, 1);
  --a-e: calc(var(--a) * var(--a) * (3 - 2 * var(--a)));
  --b: clamp(0, (var(--p) - 0.31) / 0.16, 1);
  --b-e: calc(var(--b) * var(--b) * (3 - 2 * var(--b)));
  --zm: clamp(0, (var(--p) - 0.5) / 0.18, 1);
  --zm-e: calc(var(--zm) * var(--zm) * (3 - 2 * var(--zm)));
  --d: clamp(0, (var(--p) - 0.71) / 0.17, 1);
  --d-e: calc(var(--d) * var(--d));
  --N: 1000px;
  --s0: 0.5;
  --pp: calc(var(--N) * 2.2); /* perspective distance for the turning pieces */
}
.bunfold__board {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--N);
  height: var(--N);
  margin: calc(var(--N) / -2) 0 0 calc(var(--N) / -2);
  /* lift in from below, shrink to the starting size, and keep what's showing in the middle of the screen */
  transform: translateY(calc((1 - var(--in-e)) * 70vh)) scale(calc(var(--s0) + var(--zm-e) * (1 - var(--s0))))
    translate(calc(var(--N) / 4 * (1 - var(--a-e))), calc(var(--N) / 4 * (1 - var(--b-e))));
}
.bunfold__run .bu-pc,
.bunfold__run .bu-s-grp {
  position: absolute;
  display: block;
  will-change: transform;
}
/* each piece's picture: a canvas the script fills with the piece's part of the board, drawn at the zoomed-in size */
.bunfold__run .bu-pc > canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}
/* (The design had a soft shadow under the board, on its own see-through box stretched as the folds open. While a
   fold turns, that flat box doesn't match the board's shape, and by day it showed as a grey frame around a cream
   sheet, so it's gone: owner, 3 November 2026.) */
/* each piece darkens as it turns away from flat, the way a real fold catches less light */
.bunfold__run .bu-pc::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(var(--sh-dir, 90deg), rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0.15));
  opacity: var(--dim, 0);
  will-change: opacity; /* its own layer: changing the shade must not make the board picture under it redraw */
}
.bunfold__run .bu-f-top {
  left: 0;
  top: 0;
  width: var(--N);
  height: calc(var(--N) / 2);
  opacity: calc(clamp(0, var(--b) * 1000, 1) * (1 - clamp(0, var(--d) * 1000, 1)));
}
.bunfold__run .bu-f-bot {
  left: 0;
  top: calc(var(--N) / 2);
  width: var(--N);
  height: calc(var(--N) / 2);
  --t: clamp(0, 2 * var(--b-e) - 1, 1);
  transform-origin: 50% 0;
  transform: perspective(var(--pp)) rotateX(calc((1 - var(--t)) * 90deg));
  --sh-dir: 0deg;
  --dim: calc(1 - var(--t));
  opacity: calc(clamp(0, (var(--b) - 0.5) * 1000, 1) * (1 - clamp(0, var(--d) * 1000, 1)));
}
.bunfold__run .bu-s-grp {
  left: 0;
  top: 0;
  width: var(--N);
  height: calc(var(--N) / 2);
  --t: clamp(0, 2 * var(--b-e), 1);
  transform-origin: 50% 100%;
  transform: perspective(var(--pp)) rotateX(calc(var(--t) * -90deg));
  opacity: calc(1 - clamp(0, (var(--b) - 0.5) * 1000, 1));
}
.bunfold__run .bu-s-grp .bu-pc {
  will-change: auto;
}
.bunfold__run .bu-s-l,
.bunfold__run .bu-s-r,
.bunfold__run .bu-s-grp .bu-cov {
  top: 0;
  width: calc(var(--N) / 2);
  height: calc(var(--N) / 2);
  --sh-dir: 180deg;
  --dim: calc(var(--t, 0) * 0.9);
}
.bunfold__run .bu-s-l {
  left: 0;
}
.bunfold__run .bu-s-r {
  left: calc(var(--N) / 2);
  --u: clamp(0, 2 * var(--a-e) - 1, 1);
  transform-origin: 0 50%;
  transform: perspective(var(--pp)) rotateY(calc((1 - var(--u)) * -90deg));
  --sh-dir: 90deg;
  --dim: calc(1 - var(--u));
  opacity: clamp(0, (var(--a) - 0.5) * 1000, 1);
}
.bunfold__run .bu-s-grp .bu-cov {
  left: 0;
  --u: clamp(0, 2 * var(--a-e), 1);
  transform-origin: 100% 50%;
  transform: perspective(var(--pp)) rotateY(calc(var(--u) * 90deg));
  --sh-dir: 270deg;
  --dim: var(--u);
  opacity: calc(1 - clamp(0, (var(--a) - 0.5) * 1000, 1));
}
/* the doors: the open board splits down the middle and both halves swing out toward you */
.bunfold__run .bu-d-l,
.bunfold__run .bu-d-r {
  top: 0;
  width: calc(var(--N) / 2);
  height: var(--N);
  opacity: clamp(0, var(--d) * 1000, 1);
  --dim: calc(var(--d) * 0.8);
}
.bunfold__run .bu-d-l {
  left: 0;
  transform-origin: 0 50%;
  transform: perspective(var(--pp)) rotateY(calc(var(--d-e) * 110deg));
  --sh-dir: 270deg;
}
.bunfold__run .bu-d-r {
  left: calc(var(--N) / 2);
  transform-origin: 100% 50%;
  transform: perspective(var(--pp)) rotateY(calc(var(--d-e) * -110deg));
  --sh-dir: 90deg;
}
