/* ════════════════════════════════════════════════════════════
 * LANDING INTRO OVERLAY
 * Verbatim port from prototype 01-homepage.html lines 2078-2374.
 * WebGL lens shader overlay shown before homepage. Scroll-driven
 * exit. Removes from DOM after threshold. Body class `intro-active`
 * controls nav visibility while overlay is shown.
 * ════════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════════
   LANDING INTRO — WebGL overlay shown before the homepage.
   ▸ #landing-intro-spacer sits in the document flow to hold 100vh
     of scroll room so the browser scrollbar reflects real progress.
   ▸ #landing-intro is position:fixed over the spacer, so the
     homepage content below is pushed down naturally.
   ▸ While body.intro-active is set, the homepage nav is hidden
     and its scroll-handler is short-circuited.
   ▸ After the exit animation completes, both overlay & spacer
     are removed from the DOM and scroll is reset to 0, so the
     scrollbar precisely represents the remaining homepage length.
═══════════════════════════════════════════════════════════════ */

/* Nav stays in its final homepage state the entire time.
   The intro overlay (z-index:10000) covers it; the homepage's own scroll
   handler is guarded against running during the intro phase, so the nav
   won't change appearance on its own. When the overlay fades away at the
   end of the exit window, the nav is simply revealed already in place —
   no separate slide-in animation needed.
   We still force pointer-events:none during intro so any mis-clicks at
   the edges can't reach a nav item through the overlay stack. */
body.intro-active nav#nav,
body.intro-exiting nav#nav{
  pointer-events:none;
}
body:not(.intro-active):not(.intro-exiting) nav#nav{
  pointer-events:auto;
}
/* Prevent horizontal overflow from the fixed intro on any viewport */
body.intro-active,body.intro-exiting{overflow-x:hidden}
/* Disable smooth scroll during the jump-to-top reset */
html.intro-reset{scroll-behavior:auto}

/* 100vh spacer — creates real document height so the native
   scrollbar thumb position is meaningful during the intro phase. */
#landing-intro-spacer{
  height:100vh;
  width:100%;
  flex-shrink:0;
  pointer-events:none;
}

/* Fixed intro overlay — sits on top of the spacer + everything else.

   Exit sequence: single 2.5s window, all in-place, no movement.
   ─────────────────────────────────────────────────────────────────
   0s   → 2.4s ── shader u_progress ramps 0 → 1, driving the image's
                  chroma aberration, lens bulge, and bokeh blur to
                  peak defocus. Driven by a custom 2.4s ease-in-out
                  cubic animation in JS (see triggerExit).
   1.3s → 2.5s ── logo, tagline, enter button, and marquee logos
                  blur 0 → 32px and fade opacity 1 → 0 in place.
                  1.2s duration overlapping the back half of the
                  image defocus so the composition dissolves as a
                  coherent whole.
   2.0s → 2.5s ── the entire overlay (shader canvas + dark background
                  + tone/grain) fades opacity 1 → 0. At t=2.5s every-
                  thing is gone, revealing the hero + nav that were
                  sitting in place the whole time.
   ─────────────────────────────────────────────────────────────────

   No transform — nothing slides. DOM cleanup at t=2.7s. */
#landing-intro{
  position:fixed;
  inset:0;
  z-index:10000;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:space-between;
  /* bumped padding for bigger logo + rebalanced top/bottom rhythm.
     64px top sits the logo with breathing room from the viewport edge;
     bottom 36px keeps the marquee anchored. */
  padding:64px 0 36px;
  overflow:hidden;
  background:#080808;
  color:#fff;
  font-family:var(--font-title);
  /* gap added between flex children for consistent vertical rhythm.
     With justify-content:space-between, this acts as a MINIMUM gap — items
     still spread to fill the container, but won't crowd each other on
     short viewports. */
  gap:40px;
  /* Overall overlay fade — happens in the final 0.5s of the window */
  transition:opacity 0.5s ease 2.0s;
  will-change:opacity;
}
#landing-intro.exiting{
  opacity:0;
  pointer-events:none;
}

/* Text + logos: defocus (blur) + fade together with a 1.3s delay.
   The delay isn't laziness — it's deliberate choreography: the shader
   chroma starts ramping at t=0 and peaks around t=2.4s. Text starts its
   blur+fade at t=1.3 and finishes at t=2.5s, so they reach peak intensity
   together, then the overlay fades out 2.0s→2.5s. Removing the delay
   makes the text finish before the chroma even gets going, which feels
   weird (everything's already gone, then the chroma ramps in vain). */
#landing-intro .intro-logo,
#landing-intro .intro-tagline,
#landing-intro .enter-cue,
#landing-intro .trusted-label,
#landing-intro .marquee-outer{
  transition:filter 1.2s cubic-bezier(.32,.72,.31,.9) 1.3s,
             opacity 1.2s cubic-bezier(.32,.72,.31,.9) 1.3s;
  will-change:filter,opacity;
}
#landing-intro.exiting .intro-logo,
#landing-intro.exiting .intro-tagline,
#landing-intro.exiting .enter-cue,
#landing-intro.exiting .trusted-label,
#landing-intro.exiting .marquee-outer{
  filter:blur(32px);
  opacity:0;
}
#landing-intro *,#landing-intro *::before,#landing-intro *::after{
  box-sizing:border-box;margin:0;padding:0;
}

/* WebGL canvas */
#landing-intro #glCanvas{
  position:absolute;inset:0;width:100%;height:100%;z-index:0;display:block;
}
/* Tone overlay + grain */
#landing-intro .intro-overlay{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(
    to bottom,
    rgba(8,8,8,.62) 0%,
    rgba(8,8,8,.08) 20%,
    rgba(8,8,8,.02) 50%,
    rgba(8,8,8,.28) 75%,
    rgba(8,8,8,.92) 100%
  );
}
#landing-intro .intro-grain{
  position:absolute;inset:0;z-index:2;opacity:.09;pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px;
  animation:landingGrain .35s steps(1) infinite;
}
@keyframes landingGrain{
  0%{background-position:0 0}25%{background-position:-40px -15px}
  50%{background-position:20px -35px}75%{background-position:-15px 40px}
}

/* Top logo (logogram only) — v34 bumped from 80px → clamp(88px, 8.5vw, 116px).
   ~45% bigger on desktop, with a sensible floor on small phones. */
#landing-intro .intro-logo{
  position:relative;z-index:10;
  width:clamp(88px, 8.5vw, 116px);height:auto;
  opacity:0;
  animation:landingFadeDown .9s .25s cubic-bezier(.16,1,.3,1) forwards;
}

/* Tagline — direct child of #landing-intro now (no more intro-center wrapper).
   Horizontal padding moved here from the removed wrapper to keep line width
   constrained on mobile. */
#landing-intro .intro-tagline{
  position:relative;z-index:10;
  font-family:var(--font-title);
  font-size:clamp(2.8rem,7vw,6.5rem);
  font-weight:900;
  letter-spacing:-0.045em;
  line-height:.92;
  text-align:center;
  color:#fff;
  padding:0 32px;
  opacity:0;
  animation:landingFadeUp 1s .55s cubic-bezier(.16,1,.3,1) forwards;
}

/* Enter button — the CTA that triggers the exit sequence.
   Styled as a pill: Neue Black uppercase with wide tracking, rounded border,
   subtle backdrop tint. Pulse uses TWO box-shadow ripples played in
   alternating sequence: white at 0% → orange at 50% → white again, so the
   button gently breathes between brand orange and clean white. The bigger
   expansion radius (32px) and brighter peak opacities make it more
   noticeable than the v33 white-only ripple. */
#landing-intro .enter-cue{
  position:relative;z-index:10;
  display:inline-flex;
  align-items:center;
  padding:18px 38px;
  border:1.5px solid rgba(255,255,255,.4);
  border-radius:999px;
  background:rgba(255,255,255,.04);
  cursor:pointer;
  opacity:0;
  /* Two animations: one-shot fade-up entrance, then infinite white ripple. */
  animation:
    landingFadeUp 1s 1.1s cubic-bezier(.16,1,.3,1) forwards,
    enterRipple 2.4s 1.8s ease-out infinite;
  user-select:none;
  transition:border-color .3s ease, background .3s ease, transform .3s ease;
}
#landing-intro .enter-cue:hover{
  border-color:rgba(255,255,255,.85);
  background:rgba(255,255,255,.10);
  transform:scale(1.05);
}
#landing-intro .enter-cue:focus-visible{
  outline:none;
  border-color:rgba(255,255,255,.95);
  background:rgba(255,255,255,.12);
}
#landing-intro .enter-label{
  font-family:'NHG',var(--font-title);
  font-size:1.5rem;
  font-weight:900;
  letter-spacing:.01em;
  color:#fff;
  line-height:1;
}
/* Beacon ripple — soft halo expanding outward.
   white-only ripple with blurred edge for a softer, more organic glow.
   The box-shadow's blur radius (third value) feathers the ring instead of
   the hard sharp ring. Slightly slower (3s) for breathing room. */
@keyframes enterRipple{
  0%   { box-shadow: 0 0 12px  0    rgba(255,255,255,.55); }
  100% { box-shadow: 0 0 24px  36px rgba(255,255,255,0); }
}

/* Bottom "trusted by" marquee */
#landing-intro .intro-bottom{
  position:relative;z-index:10;
  width:100%;
  padding-bottom:28px;
  opacity:0;
  animation:landingFadeUp 1s .9s cubic-bezier(.16,1,.3,1) forwards;
}
#landing-intro .trusted-label{
  font-family:'NHG',var(--font-title);
  text-align:center;
  font-size:1.3rem;font-weight:900;letter-spacing:.04em;
  text-transform:lowercase;color:#fff;margin-bottom:22px;
}
#landing-intro .marquee-outer{
  overflow:hidden;
  mask-image:linear-gradient(to right,transparent 0%,black 5%,black 95%,transparent 100%);
  -webkit-mask-image:linear-gradient(to right,transparent 0%,black 5%,black 95%,transparent 100%);
}
#landing-intro .marquee-track{
  display:flex;align-items:center;
  animation:landingMarquee 36s linear infinite;
  width:max-content;
}
/* v0.18.1 — fixed-width slot.
   Previously each .ml-item sized itself organically (padding-only) and the
   inner <img> rendered at its natural aspect ratio capped to max-width:200.
   That made each slot's total width depend on the image — a wide wordmark
   (e.g. BANDAI) and a square logogram (e.g. Kodansha) gave different slot
   widths, so when the 3x duplicated track translated by -100%/3 the
   browser's sub-pixel rounding accumulated drift over the 36-second loop
   and the "second copy" landed mid-item, surfacing as logos appearing to
   jump from logo A to logo F at the loop boundary.
   Locking each slot to a fixed 232px guarantees the 3 copies have
   identical pixel widths, so translateX(-100%/3) lands exactly on the
   first slot every cycle. The image inside still object-fit:contains
   within the slot, so logo aspect is preserved, just framed in a
   uniform pill. */
#landing-intro .ml-item{
  display:flex;align-items:center;justify-content:center;
  width:232px;height:110px;
  border-right:1px solid rgba(255,255,255,.22);
  flex-shrink:0;
}
/* v0.18.2 — Per-aspect size caps for the intro marquee.
   ─────────────────────────────────────────────────────
   v0.18.1 used flat max-height:100 / max-width:200 here, which made
   wide wordmarks (NAVER) tower over square logograms (Minto) — Vic
   flagged this on 2026-05-05 along with "they're too big" overall.

   v0.18.3 (2026-05-05) — converted all caps from PIXEL VALUES to
   PERCENTAGES of the slot. v0.18.2 used pixel values per breakpoint
   that drifted from desktop proportions on tab/mobile (e.g. ultra-
   wide on tab was 84% slot width vs 74% on desktop, making tab/mobile
   logos visibly wider than desktop's). With percentages, the same
   proportion holds at every breakpoint — only the slot's pixel size
   scales (via the @media .ml-item rules below). Vic explicitly asked
   for "desktop scale" on tab/mobile.

   Each bucket caps to a similar visible-content size; the per-Client
   `client_logo_scale` ACF (50–200%) is wired through as `--logo-scale`
   for outlier tuning (Pract pill, Webtoon icon, etc.). The transform:
   scale uses the same variable applied to .vt-logo on the homepage
   strip, so editors get one knob covering both placements. */
#landing-intro .ml-item img{
  /* default cap (no data-aspect, e.g. fallback hardcoded items): 69%h × 73%w */
  max-height:69%;max-width:73%;
  width:auto;height:auto;
  object-fit:contain;
  filter:brightness(0) invert(1);
  opacity:.42;
  transform:scale(var(--logo-scale, 1));
  transform-origin:center;
}
#landing-intro .ml-item img[data-aspect="ultra-wide"] { max-height:38%;max-width:74%; }
#landing-intro .ml-item img[data-aspect="wide"]       { max-height:49%;max-width:66%; }
#landing-intro .ml-item img[data-aspect="balanced"]   { max-height:65%;max-width:52%; }
#landing-intro .ml-item img[data-aspect="tall"]       { max-height:80%;max-width:34%; }

@keyframes landingMarquee{
  0%{transform:translateX(0)}
  100%{transform:translateX(calc(-100% / 3))}
}

@keyframes landingFadeUp{
  from{opacity:0;transform:translateY(22px)}
  to{opacity:1;transform:translateY(0)}
}
@keyframes landingFadeDown{
  from{opacity:0;transform:translateY(-18px)}
  to{opacity:1;transform:translateY(0)}
}

/* Responsive tweaks for the intro */
@media(max-width:860px){
  #landing-intro{padding:40px 0 24px}
  #landing-intro .intro-logo{width:64px}
  #landing-intro .intro-tagline{padding:0 24px}
  /* v0.18.3 — only the slot dimensions change at this breakpoint. The
     per-aspect percentage caps in the base block above apply uniformly,
     so tab logos render at the same proportions as desktop's. */
  #landing-intro .ml-item{width:154px;height:84px}
  #landing-intro .trusted-label{font-size:1.2rem;margin-bottom:16px}
  #landing-intro .intro-bottom{padding-bottom:20px}
}
@media(max-width:560px){
  #landing-intro .intro-tagline{font-size:clamp(2.2rem,9vw,3.4rem)}
  #landing-intro .enter-cue{padding:13px 26px}
  #landing-intro .enter-label{font-size:1.15rem}
  #landing-intro .trusted-label{font-size:1rem;margin-bottom:14px;letter-spacing:.06em}
  /* v0.18.3 — only the slot dimensions change at this breakpoint. The
     per-aspect percentage caps in the base block above apply uniformly. */
  #landing-intro .ml-item{width:124px;height:68px}
}
@media (prefers-reduced-motion: reduce){
  #landing-intro *{animation:none !important;transition:none !important}
  #landing-intro .enter-cue{box-shadow:none !important}
}

/* ═══════════════════════════════════════════════════════════════
   v0.32.233 — intro colours reverted to the all-white scheme (Vic is
   testing intro_003, a dimmer BG, against white type). The orange
   tagline/pill/ripple experiment from v0.32.231-232 is removed; the
   only surviving tweak is the trusted-by label dimmed to the marquee
   logos' 0.42 opacity. The .tagline-dot span (front-page.php) still
   renders but is white like the rest — kept for future re-colouring.
   ═══════════════════════════════════════════════════════════════ */
#landing-intro .trusted-label{color:rgba(255,255,255,.42)}
/* v0.32.234 — white title toned down slightly (alpha on color, so the
   entrance fade is untouched); trailing dot in brand orange via the
   .tagline-dot span wrapped server-side in front-page.php. */
#landing-intro .intro-tagline{color:rgba(255,255,255,.88)}
#landing-intro .intro-tagline .tagline-dot{color:var(--orange,#f2610f)}
