/* Local PL study: sky background layer, placed beneath the transparent WebGL
   canvas. The same drifting-cloud clip loops behind the FAQ and contact acts
   below, and it is shown here exactly as it is there: unfiltered, at cover
   scale. The 5% bleed is only headroom for the parallax in pl-sky-motion.js. */
#pl-sky-layer {
  --sky-x: 0px;
  --sky-y: 0px;
  --sky-scale: 1;
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

#pl-sky-layer::before {
  content: "";
  position: absolute;
  inset: -5%;
  background: url("/pl-sky.png") 50% 50% / cover no-repeat;
  transform: translate3d(var(--sky-x), var(--sky-y), 0) scale(var(--sky-scale));
  transform-origin: center;
  will-change: transform;
}

/* The looping cloud clip (see PLHeroIntro's ensureSkyVideo) sits in front of
   the static photo above — ::before paints before real children, so the
   photo is already there the instant the layer exists, and the video just
   plays over it once it's ready. Same inset/transform treatment so the
   parallax stays identical to the photo it replaces. */
#pl-sky-layer video {
  position: absolute;
  inset: -5%;
  width: 110%;
  height: 110%;
  object-fit: cover;
  transform: translate3d(var(--sky-x), var(--sky-y), 0) scale(var(--sky-scale));
  transform-origin: center;
  will-change: transform;
}

/* No dark overlay on the sky: this used to paint a black/navy gradient
   (top-to-bottom tint + a radial vignette) over the photo via ::after. */

/* Keep the original layers for the white-scene transition, but do not cover the sky. */
#background-black {
  background: transparent;
}

#background-black .noise {
  opacity: 0.16;
  mix-blend-mode: multiply;
}

/* main.css ships a magenta scroll indicator; brand green is the only accent on this site. */
.hero__indicator-fill {
  background: var(--brand);
}

/* THE ACADEMY STATEMENT opens the intro. bundle.js tweens exactly three
   ids here — #hero__small and #hero__title / #hero__text fade and lift as
   the timeline starts, and it word-splits #hero__title into .hero__title-item
   boxes that rise in — so the eyebrow, the headline and the sub-line + brand
   block take those three ids, and the type is restyled to the homepage's
   own display setting. The id selectors outrank every main.css breakpoint. */
#hero .hero__small {
  display: block;
  position: relative;
  bottom: auto;
  margin: 0 0 28px;
  font-family: var(--font-ui);
  font-size: 10px;
  line-height: 1.5;
  letter-spacing: .19em;
  text-transform: uppercase;
}

#hero .hero__small span {
  margin-inline: 12px;
}

/* The entire Hero is released only after the first WebGL frame is ready, so
   these labels no longer need their own delayed entrance. They appear in the
   same frame as the model and headline; the timeline can still animate their
   opacity on scroll. */
#hero .hero__small,
#hero .hero__small span {
  transition: none;
}

#hero .hero__small {
  color: #fff;
}

#hero .hero__small span {
  color: #c6f299;
}

#hero .hero__title {
  width: min(100%, 1280px);
  max-width: none;
  margin: 0 auto;
  padding: 0 clamp(24px, 6vw, 100px);
  font-weight: 400;
  font-size: clamp(40px, 5.5vw, 88px);
  line-height: 1.04;
  letter-spacing: -.045em;
  text-align: center;
  text-wrap: balance;
  text-shadow: none;
}

/* Keep the desktop statement on the intended two-line lockup regardless of
   the exact full-screen viewport width. Small screens return to natural text
   wrapping so the line does not overflow. */
#hero .hero__title-line {
  display: block;
  width: 100%;
  text-align: center;
  white-space: nowrap;
}

@media (max-width: 767px) {
  #hero .hero__title-line {
    display: inline;
    width: auto;
    white-space: normal;
  }
}

/* Until bundle.js has built and positioned its timeline, every sibling after
   the opening Hero would otherwise briefly render at its raw document
   position and overlap the headline. */
#wrapper.pl-booting > :not(#background-white):not(#background-black):not(#pl-sky-layer) {
  visibility: hidden !important;
}

/* Each word box clips to its own line height so the rise-in stays hidden
   below; the padding/negative margin pair gives descenders room without
   loosening the line spacing. */
#hero .hero__title .hero__title-item {
  line-height: 1.04;
  padding-bottom: .16em;
  margin-bottom: -.16em;
}

/* The headline is part of the first paint. The legacy loader still splits it
   into word boxes, but those boxes must stay visible while the WebGL assets
   initialise instead of waiting for the loader's delayed animateIn call. */
#hero .hero__title:not(.hero__title--ready) .blast span {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  transition: none;
}

#hero .hero__title span {
  top: 0;
}

/* Opaque by default rather than main.css's opacity:0 — the timeline's own
   fade-out tween records its start value on the first scroll. The boot gate
   already prevents an early flash, so this block needs no second delay. */
#hero .hero__text {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: auto;
  min-width: 0;
  margin: 0;
  padding: 0 24px;
  font-family: var(--font-body);
  font-size: inherit;
  text-align: center;
  text-shadow: none;
  opacity: 1;
  filter: opacity(1);
  transition: none;
}

#hero .hs-sub {
  margin-top: 24px;
  max-width: 60ch;
  font-size: clamp(14px, 1.25vw, 18px);
}

#hero .hs-brand {
  margin-top: 30px;
}

/* The prototype is now a self-contained visual journey, without site navigation. */
.header {
  display: none;
}

/* The source cursor is a triangular SVG. Hide the whole original cursor and
   render only the PL mark as a separate, simple pointer layer. */
#cursor,
#cursor-text,
.loading__path-1,
.loading__path-2 {
  display: none !important;
}

/* No loading splash: bundle.js tracks its own asset-load percentage purely
   in JS (setting #loading__completion's text, toggling a --out class once
   done) and never listens for a CSS transitionend on it to move on, so
   hiding it outright doesn't stall anything downstream. */
#loading,
#loading__transition {
  display: none !important;
}

/* bundle.js builds its own fixed, full-height scrollbar for each virtual
   scroller it creates (this intro, its nav menu, its contact form) and
   appends every one of them straight to document.body — outside this
   root, so releasing the intro never removes them. The real page already
   scrolls natively and shows its own (styled) scrollbar; a second bar
   sitting right next to it read as two overlapping sidebars. */
#vsh-scrollbar-0,
#vsh-scrollbar-1,
#vsh-scrollbar-2 {
  display: none !important;
}

.pl-loader-mark {
  opacity: 0.96;
  transform-origin: center;
}

.pl-loader-mark {
  display: none;
}

#pl-pointer-mark {
  position: fixed;
  top: 0;
  left: 0;
  width: 36px;
  height: 36px;
  z-index: 101;
  pointer-events: none;
  opacity: 0;
  filter: drop-shadow(0 0 7px rgba(255, 255, 255, 0.3));
  transition: opacity 140ms ease;
  will-change: transform, opacity;
}

#pl-pointer-mark.is-visible {
  opacity: 0.96;
}

.pl-loading-mark {
  position: absolute;
  width: 150px;
  height: 150px;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 14px rgba(255, 255, 255, 0.25));
  animation: pl-mark-breathe 1.25s ease-in-out infinite alternate;
}

@keyframes pl-mark-breathe {
  from { opacity: 0.5; transform: translate(-50%, -50%) scale(0.92); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1.04); }
}

@media (max-width: 640px) {
  #pl-pointer-mark {
    display: none;
  }

  .pl-loading-mark {
    width: 104px;
    height: 104px;
  }

  #pl-sky-layer::before {
    inset: -20%;
    background-position: 50% 42%;
  }

  #pl-sky-layer video {
    inset: -20%;
    width: 140%;
    height: 140%;
    object-position: 50% 42%;
  }
}
