/* =====================================================================
   MENCH BIRTHDAY MIX (handoff, 2 November 2026): the transition into Birthdays
   Sits between How it works and Birthdays in index.html, and replaces the balloon lift.
   Six colour bands with pixel edges slide in from alternating sides, each saying happy birthday in a language you
   hear around Vancouver. When they slide away, a pixel birthday scene is on the screen (a cake with flickering
   candles, HAPPY BIRTHDAY, "Make a wish", balloons floating up, confetti falling). Then the scene splits into seven
   columns with pixel tips that slide up off the screen, the middle one first, and Birthdays is underneath (owner's
   change, 3 November 2026: the bands used to come back a second time instead).
   Script: js/birthday-mix.js. Markup: see the comment above .bday-mix in index.html.

   How it fits together: the run is tall, and the stage inside it sticks to the screen while you scroll through it.
   Birthdays sits after the run inside the same wrapper, but pulled up to start where the run starts, under the stage.
   It sticks to the top of the screen too, so it waits under the stage and the bands uncover it in place. The tail
   after it keeps the wrapper long enough for Birthdays to ride down to where the run ends; then it scrolls on.
   (Birthdays never goes above the top of the run, so it can't cover How it works.)
   Inside the stage, bottom to top: the cover (page background, until the bands first fill the screen), the scene's
   columns (shown from then until they have slid away), and the bands.
   All of this switches on only once the script has set up (.is-ready), so without it the page just scrolls on.
   Everything that moves only changes transform or opacity, written straight onto the moving pieces.
   ===================================================================== */
.bday-mix {
  /* scroll length of the effect (also places the #birthdays anchor and sizes the tail): one screen for the stage,
     the moving part, 360vh, and a 30vh pause on the birthday scene before the columns lift (HOLD in
     js/birthday-mix.js; change both together) */
  --bm-len: calc(490vh + 200px); /* + the 200px pause before the ribbons start (PRE in js/birthday-mix.js) */
  --bm-edge: 7vh; /* width of a band's pixel edge */
  --bm-game: #0b0717; /* the scene's background: a game screen, dark by day too */
  --font-world: "Big Shoulders Display", "Vazirmatn", "Noto Sans SC", "Noto Sans Gurmukhi", "Arial Narrow", sans-serif;
  --font-pixel: "Press Start 2P", ui-monospace, "Courier New", monospace;
  position: relative;
}
[data-mode="night"] .bday-mix {
  --bm-game: #1d1440; /* a little lighter than the night page, so the scene reads as its own screen */
}
.bday-mix__run {
  position: relative;
  z-index: 2;
  height: var(--bm-len);
  pointer-events: none;
}
.bday-mix__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}
.bday-mix__scene,
.bday-mix__bands {
  position: absolute;
  inset: 0;
}
/* How it works stops when its bottom reaches the bottom of the screen and the bands come in over it: the wrapper
   starts one screen earlier, overlapping How it works' last screen, so the stage reaches the top of the screen at
   that very moment (the script holds How it works still from then on). The stage is see-through until the bands
   cover the screen; Birthdays, waiting under it, stays hidden until then (.is-before). Hidden with opacity, not
   visibility: visibility: hidden would also take its buttons out of the Tab order and its text away from screen
   readers, so keyboard and screen-reader visitors could never reach it. js/birthday-mix.js jumps past the effect
   when something in Birthdays gets keyboard focus. */
.bday-mix.is-ready {
  margin-top: -100vh;
  /* the wrapper lies over How it works' last screen, and an element catches clicks even where it's see-through:
     let them through to How it works ("Pick another path" sits there on desktops). Only Birthdays takes them back,
     and the .is-before rule below (same specificity, later in the file) still switches it off while it's hidden. */
  pointer-events: none;
}
.bday-mix.is-ready .bday-mix__run ~ .section {
  pointer-events: auto;
}
.bday-mix.is-before .bday-mix__run ~ .section {
  opacity: 0;
  pointer-events: none;
}
.bday-mix:not(.is-ready) {
  --bm-len: 0px;
}
.bday-mix:not(.is-ready) .bday-mix__run {
  display: none;
}

/* Birthdays: waits under the stage while the effect plays, then scrolls on as normal */
.bday-mix.is-ready .bday-mix__run ~ .section {
  position: sticky;
  top: 0;
  z-index: 1;
  margin-top: calc(var(--bm-len) * -1);
}
.bday-mix.is-ready .bday-mix__tail {
  height: calc(var(--bm-len) - 100vh);
}

/* #birthdays links (the menus, What's inside, Perfect for, the footer) land here: the spot where the effect has just
   finished and Birthdays sits at the top of the screen. The section itself can't be the target, because while it
   waits under the stage the browser would scroll to where it is waiting. */
.bday-mix__anchor {
  position: absolute;
  left: 0;
  top: max(0px, calc(var(--bm-len) - 100vh));
  width: 1px;
  height: 1px;
  /* the page keeps jumps 16px short of their target (scroll-padding-top on <html>, css/page/01-base.css), which
     would stop just before the last band has left: this cancels it, so a jump lands with the effect finished */
  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 doesn't apply on
   either side of the wrapper: put them back above Birthdays and above the section after it */
.bday-mix__run ~ .section,
.bday-mix + .section {
  border-top: var(--line) solid var(--edge);
}
[data-mode="night"] .bday-mix__run ~ .section,
[data-mode="night"] .bday-mix + .section {
  border-top: 1px solid var(--hair);
}

/* ---------- the bands ---------- */
.bday-mix__band {
  position: absolute;
  left: 0;
  right: 0;
  margin: 0;
  background: var(--c);
  color: var(--on-c);
  will-change: transform;
}
/* the pixel edges, on both ends: a solid stripe, then a checkerboard dither, in the band's own colour */
.bday-mix__band::before,
.bday-mix__band::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--bm-edge);
  background:
    linear-gradient(var(--c), var(--c)) no-repeat,
    conic-gradient(var(--c) 25%, transparent 0 50%, var(--c) 0 75%, transparent 0) 0 0 / 2vh 2vh;
  background-size:
    2vh 100%,
    2vh 2vh;
}
.bday-mix__band::before {
  right: 100%;
  background-position:
    right top,
    right top;
}
.bday-mix__band::after {
  left: 100%;
  background-position:
    left top,
    left top;
}
.bday-mix__band-in {
  position: absolute;
  inset: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
}
/* the sixth colour: ink on page background (black by day, white by night) */
.bday-mix .is-k {
  --c: var(--edge);
  --on-c: var(--bg);
}
.bday-mix__line {
  display: flex;
  align-items: center;
  gap: min(5vh, 6vw);
  padding-left: min(5vh, 6vw);
  white-space: nowrap;
  /* each band can set --fs (size by screen height) and --fsw (size by screen width); the smaller one wins */
  font: 900 min(var(--fs, 13vh), var(--fsw, 15vw)) / 1 var(--font-world);
  text-transform: uppercase;
  will-change: transform;
}
.bday-mix__line i {
  flex: none;
  width: min(2.4vh, 3vw);
  height: min(2.4vh, 3vw);
  border-radius: 50%;
  background: currentColor;
  opacity: 0.6;
}

/* ---------- the scene ---------- */
.bday-mix__scene {
  /* always the bright night colours, since it sits on a dark game screen */
  --yellow: #ffd731;
  --blue: #4fa6ff;
  --red: #ff5b52;
  --green: #35e08b;
  --purple: #b977ff;
  display: grid;
  place-items: center;
  padding: 6vmin max(16px, 5vmin);
  background: repeating-linear-gradient(0deg, rgba(240, 235, 255, 0.04) 0 2px, transparent 2px 5px), var(--bm-game);
  color: #f0ebff;
  opacity: 0;
}
.bday-mix__px {
  shape-rendering: crispEdges; /* keeps the pixel art sharp at any size */
}

/* ---------- the scene's columns (built by the script) ----------
   Seven windows side by side, each showing its own copy of the scene, lined up into one picture (the script sets
   each window's left and width, and slides its copy left to match). They slide up one by one to show Birthdays. */
.bday-mix__cols {
  position: absolute;
  inset: 0;
  opacity: 0;
}
.bday-mix__col {
  position: absolute;
  top: 0;
  bottom: 0;
  will-change: transform;
}
.bday-mix__col-in {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.bday-mix__col .bday-mix__scene {
  right: auto;
  opacity: 1;
}
/* the pixel tip under each column: the same edge as the bands' ends (a solid stripe, then a checkerboard dither),
   turned to hang down, in the scene's colour */
.bday-mix__col::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: var(--bm-edge);
  background:
    linear-gradient(var(--bm-game), var(--bm-game)) no-repeat,
    conic-gradient(var(--bm-game) 25%, transparent 0 50%, var(--bm-game) 0 75%, transparent 0);
  background-size:
    100% 2vh,
    2vh 2vh;
  background-position:
    left top,
    left top;
}
.bday-mix__sky,
.bday-mix__confetti {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.bday-mix__balloon {
  position: absolute;
  top: 100%;
  width: var(--bw, 9vmin);
  height: auto;
  color: var(--c);
  will-change: transform;
}
.bday-mix__bit {
  position: absolute;
  top: -4vh;
  width: 1.6vmin;
  height: 1.6vmin;
  min-width: 6px;
  min-height: 6px;
  background: var(--c);
  opacity: 0;
  will-change: transform;
}
.bday-mix__hello {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, auto);
  align-items: center;
  justify-content: center;
  gap: 3vh 6vmin;
}
.bday-mix__cake {
  width: min(40vh, 27vw);
  height: auto;
  transform-origin: 50% 100%;
  opacity: 0;
  will-change: transform;
}
.bday-mix__cake .fl-b {
  opacity: 0;
}
/* the flames flicker between two pixel shapes */
.bday-mix__cake .fl-a {
  animation: bday-mix-flick 0.5s steps(1) infinite;
}
.bday-mix__cake .fl-b {
  animation: bday-mix-flick 0.5s steps(1) infinite reverse;
}
/* only while the scene is showing */
.bday-mix__scene:not(.is-on) .bday-mix__cake g {
  animation-play-state: paused;
}
@keyframes bday-mix-flick {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}
.bday-mix__words {
  display: grid;
  gap: 2.4vh;
  justify-items: start;
}
.bday-mix__title {
  display: grid;
  margin: 0;
  font: 900 min(18vh, 12vw) / 0.82 var(--font-letters);
  text-transform: uppercase;
}
.bday-mix__title span {
  display: block;
  opacity: 0;
  will-change: transform;
}
.bday-mix__title span:first-child {
  color: var(--yellow);
}
.bday-mix__wish {
  margin: 0;
  font: 400 max(10px, 1.9vmin) / 1.4 var(--font-pixel);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--yellow);
  opacity: 0;
}
@media (orientation: portrait) {
  .bday-mix__hello {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    text-align: center;
  }
  .bday-mix__cake {
    width: min(34vh, 62vw);
  }
  .bday-mix__words {
    justify-items: center;
  }
  .bday-mix__title {
    font-size: min(13vh, 21vw);
  }
}

/* less motion: no effect at all, the page scrolls straight on to Birthdays */
@media (prefers-reduced-motion: reduce) {
  .bday-mix {
    --bm-len: 0px;
  }
  .bday-mix__run {
    display: none;
  }
  .bday-mix.is-ready .bday-mix__run ~ .section {
    position: relative;
    margin-top: 0;
    opacity: 1;
    pointer-events: auto;
  }
  .bday-mix.is-ready {
    margin-top: 0;
  }
}
