/* Playpen Version 1 · the preloader overlay and its parts only (E2, final-spec §4, §10.2).
   Loaded before main.css so the sheet is painted before any script runs: the screen is paper
   from the first frame and the page underneath never flashes. Tokens come from main.css; every
   var() carries the same value as a fallback so this file also stands on its own.

   Markup (E1, spec §11):
     #preloader[role=status][aria-live=polite]
       .preloader__line                       the ink datum line across the centre
       .preloader__crest > img#preloader-crest the mark, masked by its wrapper
       .preloader__word                       "The Playpen School"
       .preloader__ticks > i.tick ×10         ten storey ticks, G at the bottom (first in the DOM)
       button#preloader-skip                  focusable from 0 ms, visible from 1,000 ms
     #preloader-flip                          empty fixed layer for the crest clone during the FLIP

   Classes toggled by js/preloader.js: #preloader.is-live (JS has taken over; cancels the CSS
   auto-hide), .is-skippable, .is-exiting; .preloader__ticks.is-drawn; .preloader__crest.is-sweep;
   .tick.is-filled. */

#preloader {
  --pp-paper: var(--paper, #F5F1EA);
  --pp-ink: var(--ink, #1C1715);
  --pp-ink-2: var(--ink-2, #4A413C);
  --pp-maroon: var(--maroon, #8A0204);
  --pp-gold: var(--gold, #9A6F1E);
  --pp-clay: var(--clay, #D9C7B2);
  /* the crest and the ticks scale with the viewport (a 2560-wide screen is not an empty page with
     a 128 px speck for two seconds): 128 px at 1600 wide, 220 px from 2750 */
  --pp-crest-w: clamp(128px, 8vw, 220px);
  --pp-tick-gap: clamp(24px, 1.6vw, 40px);
  --pp-tick-w: clamp(28px, 1.8vw, 48px);
  --pp-tick-step: clamp(4px, 0.3vw, 7px);

  position: fixed;
  inset: 0;
  z-index: 90;
  box-sizing: border-box;
  overflow: hidden;
  margin: 0;
  background: var(--pp-paper);
  color: var(--pp-ink);
  border-bottom: 1px solid var(--pp-clay); /* the edge of the sheet, seen only while it lifts */
  font-family: Newsreader, Georgia, "Times New Roman", serif;
  -webkit-font-smoothing: antialiased;
}

#preloader.is-exiting {
  will-change: transform;
}

/* Safety: if no script ever takes over (JavaScript off, or main.js failed), the sheet fades
   out by itself after 3 s so the page is never trapped. start() adds .is-live and cancels it. */
@keyframes pp-autohide {
  to { opacity: 0; visibility: hidden; }
}
#preloader:not(.is-live) {
  animation: pp-autohide 400ms ease-out 3s forwards;
}
#preloader.is-live {
  animation: none;
}

/* Live region text, visually hidden (defined here so the overlay needs nothing from main.css). */
#preloader .visually-hidden,
#preloader .preloader__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The datum line: 1 px ink across the centre of the viewport. Drawn left to right by GSAP. */
#preloader .preloader__line {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: var(--pp-ink);
  transform-origin: 0 50%;
  pointer-events: none;
}

/* The crest: its wrapper is the mask. The bottom edge of the mask sits on the datum line, so the
   mark rises out of the line. The wrapper's ::after is the light sweep, cut to the mark's shape. */
#preloader .preloader__crest {
  position: absolute;
  left: 50%;
  bottom: 50%;
  width: var(--pp-crest-w);
  margin-left: calc(var(--pp-crest-w) / -2);
  overflow: hidden;
  line-height: 0;
}
#preloader .preloader__crest img {
  display: block;
  width: 100%;
  height: auto;
  margin: 0;
  user-select: none;
  -webkit-user-drag: none;
}
#preloader .preloader__crest::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background-image: linear-gradient(108deg,
    rgba(255, 255, 255, 0) 38%,
    rgba(255, 250, 240, 0.62) 50%,
    rgba(255, 255, 255, 0) 62%);
  background-size: 320% 100%;
  background-position: 100% 0;
  -webkit-mask: url("../assets/brand/logo-crest-512.webp") center / 100% auto no-repeat;
  mask: url("../assets/brand/logo-crest-512.webp") center / 100% auto no-repeat;
}
@keyframes pp-sweep {
  0%   { opacity: 1; background-position: 100% 0; }
  100% { opacity: 1; background-position: 0% 0; }
}
#preloader .preloader__crest.is-sweep::after {
  animation: pp-sweep 650ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

/* The wordmark settles under the mark. Newsreader 22 px, ink. */
#preloader .preloader__word {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(50% + clamp(20px, 1.4vw, 32px));
  margin: 0;
  text-align: center;
  font: 400 clamp(22px, 1.5vw, 34px)/1.2 Newsreader, Georgia, "Times New Roman", serif;
  letter-spacing: 0;
  color: var(--pp-ink);
  font-optical-sizing: auto;
}

/* Ten storey ticks to the right of the mark: 28 × 2 px, 4 px gaps, G at the bottom, standing on
   the datum line beside a 1 px hairline that draws upward (the engraver's rule, spec §2.5). */
#preloader .preloader__ticks {
  position: absolute;
  left: calc(50% + var(--pp-crest-w) / 2 + var(--pp-tick-gap));
  bottom: calc(50% + 9px);
  display: flex;
  flex-direction: column-reverse;
  gap: var(--pp-tick-step);
  margin: 0;
  padding: 0 0 0 10px;
  list-style: none;
  pointer-events: none;
}
#preloader .preloader__ticks::before {
  content: "";
  position: absolute;
  left: 0;
  bottom: -9px;
  width: 1px;
  height: calc(100% + 9px);
  background: var(--pp-clay);
  transform: scaleY(0);
  transform-origin: 50% 100%;
  transition: transform 700ms var(--ease-mask, cubic-bezier(0.16, 1, 0.3, 1));
}
#preloader .preloader__ticks.is-drawn::before {
  transform: scaleY(1);
}
#preloader .preloader__ticks .tick {
  display: block;
  width: var(--pp-tick-w);
  height: 2px;
  margin: 0;
  background: var(--pp-clay);
  transition: background-color 150ms ease-out;
}
#preloader .preloader__ticks .tick.is-filled {
  background: var(--pp-maroon);
}

/* Skip: a label-style text button, bottom right on the page margin. Focusable from 0 ms (opacity,
   never display: none); visible from 1,000 ms (.is-skippable) or as soon as it receives focus. */
#preloader #preloader-skip {
  position: absolute;
  right: clamp(20px, 6vw, 120px);
  bottom: max(clamp(20px, 4vw, 48px), env(safe-area-inset-bottom, 0px));
  min-width: 44px;
  min-height: 44px;
  margin: 0;
  padding: 15px 2px;
  border: 0;
  border-radius: 0;
  background: transparent;
  background-image: linear-gradient(var(--pp-gold), var(--pp-gold));
  background-repeat: no-repeat;
  background-size: 100% 1px;
  background-position: 0 calc(100% - 13px);
  color: var(--pp-ink-2);
  font: 500 11.5px/1.2 "Hanken Grotesk", Arial, Helvetica, sans-serif;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  opacity: 0;
  transition: opacity 200ms ease-out, background-size 150ms ease-out, color 150ms ease-out;
  -webkit-tap-highlight-color: transparent;
}
#preloader.is-skippable #preloader-skip,
#preloader #preloader-skip:focus-visible {
  opacity: 1;
}
#preloader #preloader-skip:hover {
  background-size: 100% 2px;
  color: var(--pp-ink);
}
#preloader #preloader-skip:focus-visible {
  outline: 2px solid var(--pp-maroon);
  outline-offset: 3px;
}

/* Before main.js takes over, on a motion tier and a first visit: the parts wait under their masks
   (the storyboard's 0 ms frame). GSAP writes the same values inline in start(), then adds .is-live. */
html.js:not([data-tier="still"]):not(.intro-seen) #preloader:not(.is-live) .preloader__line {
  transform: scaleX(0);
}
html.js:not([data-tier="still"]):not(.intro-seen) #preloader:not(.is-live) .preloader__crest img {
  transform: translateY(110%);
}
html.js:not([data-tier="still"]):not(.intro-seen) #preloader:not(.is-live) .preloader__word {
  opacity: 0;
}

/* Still tier: the crest and wordmark are there at once; no datum line; nothing moves. */
html[data-tier="still"] #preloader .preloader__line {
  display: none;
}
html[data-tier="still"] #preloader .preloader__ticks::before {
  transition: none;
  transform: scaleY(1);
}

/* Return visit in the same session: paper and the crest only, gone in a 300 ms fade. */
html.intro-seen #preloader .preloader__line,
html.intro-seen #preloader .preloader__ticks,
html.intro-seen #preloader .preloader__word {
  display: none;
}

/* The FLIP layer above the sheet: holds the travelling crest clone for 600 ms. */
#preloader-flip {
  position: fixed;
  inset: 0;
  z-index: 95;
  pointer-events: none;
  overflow: visible;
}
#preloader-flip > img {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  margin: 0;
  max-width: none;
  transform-origin: 0 0;
  user-select: none;
  -webkit-user-drag: none;
}

@media (max-width: 767px) {
  #preloader {
    --pp-crest-w: 96px;
    --pp-tick-gap: 20px;
    --pp-tick-w: 28px;
    --pp-tick-step: 4px;
  }
}

@media (prefers-reduced-motion: reduce) {
  #preloader .preloader__ticks::before,
  #preloader .preloader__ticks .tick,
  #preloader #preloader-skip {
    transition: none;
  }
  #preloader .preloader__crest.is-sweep::after {
    animation: none;
  }
}
