/* ==========================================================================
   Intro — the loading surface that becomes the header
   ==========================================================================

   The loader and the pill header are treated as one object. A full-viewport
   blue surface contracts, via clip-path, onto the exact rectangle of
   .nav__inner, while the JC monogram flies from screen-centre onto the
   monogram already sitting in the header. Both handoffs happen when the two
   states are geometrically identical, so nothing is seen to swap.

   Layering is what makes that work:

     page content        auto
     .intro__surface     1500   the blue field, clipped down to the pill
     .nav                2000   header contents sit ON the surface as it forms
     .intro__logo        2100   the travelling monogram, above everything

   Because .nav sits above the surface, the header's own pill background has
   to be suppressed during the intro — the surface is providing that fill.
   ========================================================================== */

:root {
  /* --- Customise here ---------------------------------------------------- */
  /* Electric blue — the same #007ae5 the pill lands on, so the surface holds
     one colour the whole way down and the handoff is purely geometric. */
  --intro-bg: var(--color-accent, #007ae5);
  --intro-ink: #F7F9FC;         /* monogram stroke */
  /* The mark is sized by HEIGHT — its aspect (389:645) is fixed by the
     artwork and must never be altered, so width follows. */
  --intro-logo-h: clamp(120px, 24vh, 230px);
  /* ----------------------------------------------------------------------- */
}

/* -------------------------------- Surface --------------------------------- */

.intro { position: fixed; inset: 0; z-index: 1500; pointer-events: none; }
html.intro-active .intro { pointer-events: auto; }   /* blocks the page while up */

.intro__surface {
  position: absolute;
  inset: 0;
  background: var(--intro-bg);
  /* Set inline by intro.js. Full-bleed to start; contracts to the pill. */
  clip-path: inset(0 0 0 0 round 0px);
  will-change: clip-path, background-color;
}

/* ------------------------------- Monogram --------------------------------- */

/* Fixed and centred by transform, so the flight to the header is pure
   translate + scale — no layout properties animate. */
.intro__logo {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 2100;
  height: var(--intro-logo-h);
  transform: translate(-50%, -50%);
  will-change: transform;
  pointer-events: none;
}

/* Height-driven, width auto: the artwork's aspect ratio is never touched. */
.jc { display: block; height: 100%; width: auto; overflow: visible; }
.nav__logo .jc__solid { fill: currentColor; }

/* --------------------------------------------------------------------------
   The reveal.

   The exact contour is applied as a CSS mask — a static image, rasterised once
   and cached — over a centreline pen that draws the mark one letter at a time.
   The silhouette can never deviate from the approved artwork, because the mask
   decides which pixels exist and the pen only decides when they arrive.

   Replaced twice. First an SVG <mask> whose stroke-dashoffset was rewritten
   from JS every frame: that re-rasterised a ~700-command path per frame AND
   read layout straight after writing style (measured: 1,091 layouts in one 2s
   run). Then five scaling blocks, which were cheap but cut the curved
   letterforms with square edges on every intermediate frame.
   ------------------------------------------------------------------------ */
.jc-mask {
  position: relative;
  height: var(--intro-logo-h);
  aspect-ratio: 389 / 645;      /* locked to the artwork */
}

/* The contour used to be applied here as a CSS mask image (a data URI, to
   dodge the CORS block on file://). It is now a real filled path in the
   markup instead — see .jc-mask .jc__solid above for why. */


/* The pen. Round caps and joins are the whole point: they are what makes the
   travelling edge curved instead of the square edge the old scaling blocks
   left across the letterforms. */
.jc-pen {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;            /* the 130-wide stroke spills past the viewBox */
}

/* The mark itself: an ordinary filled path, so its edge is resolved by the SVG
   rasteriser once. Measured at dpr 2, 10-90% edge transition:
     plain SVG fill, whole-pixel position   1.22 device px
     CSS mask image, whole-pixel position   1.67
     either one at a FRACTIONAL position    2.00
   Both losses are now avoided — the fill is real, and intro.js snaps the box
   to a whole device pixel before anything is drawn. */
.jc-mask .jc__solid { fill: var(--intro-ink); }

/* The pen lives inside <mask id="jcPenMask">, so it paints luminance, not ink:
   white shows the mark through, black hides it. */
#jcPenMask path {
  fill: none;
  stroke: #fff;
  stroke-width: 130;            /* measured: full coverage of the mark */
  stroke-linecap: round;
  stroke-linejoin: round;
  /* Hidden until intro.js drives it. Set here too so there is no flash of the
     finished mark if the script is slow.

     The gap MUST exceed pathLength. A single-value dasharray means "dash 1000,
     gap 1000", so the pattern repeats and the next dash starts exactly at the
     path's end — which a round cap renders as a dot. That put a stray blob at
     the C's tail through the entire J stroke. A longer gap never repeats. */
  stroke-dasharray: 1000 1100;
  stroke-dashoffset: 1000;
}

/* Atmosphere is its own element, faded out before the collapse starts, so a
   full-viewport gradient is not repainted inside the clip on every frame. */
.intro__atmos {
  position: absolute;
  inset: 0;
  background: radial-gradient(60% 55% at 50% 46%,
    rgba(255,255,255,.07) 0%, rgba(255,255,255,.025) 45%, transparent 72%);
  will-change: opacity;
}

/* Debug overlay (js/intro.js: DEBUG_INTRO_ANIMATION). Never ships enabled. */
html.intro-debug .intro__surface { outline: 2px dashed #ff3b6b; outline-offset: -2px; }
html.intro-debug .intro__logo    { outline: 2px dashed #23d18b; }
html.intro-debug .nav__inner     { outline: 2px dashed #ffd166; }
html.intro-debug .nav__logo      { outline: 2px dashed #4cc9f0; }

/* ------------------------- Header during the intro ------------------------ */

html.intro-active { overflow: hidden; }
html.intro-active body { overflow: hidden; }

/* The header has to sit ON the surface, so its contents are visible inside the
   pill as it forms. Its own z-index (100) puts it underneath, which leaves the
   finished pill empty. Raised for as long as the overlay exists — not merely
   while .intro-active is set, since that comes off before the surface does. */
html.intro-running .nav { z-index: 2000; }

/* The surface is the pill's fill until the handoff. Colour is pinned to the
   monogram's own ink so the flying mark and the header's mark are identical
   at the moment they swap. */
html.intro-active .nav { pointer-events: none; color: var(--intro-ink); }
html.intro-active .nav__inner { background: transparent; }

/* Everything in the bar starts hidden and is staggered in by the timeline.
   Applied by JS, never by default — if scripting fails the header must not be
   left invisible. */
html.intro-active .nav__logo,
html.intro-active .nav__left .nav__menu,
html.intro-active .nav__mark,
html.intro-active .nav__cta { opacity: 0; }

/* ------------------------------ Header logo ------------------------------- */

.nav__left { justify-self: start; display: flex; align-items: center; gap: 1.4rem; }

.nav__logo {
  display: block;
  height: 3.8rem;              /* flight target — intro.js measures this box */
  color: currentColor;
  transition: opacity .3s var(--ease-snappy);
}
.nav__logo:hover { opacity: .75; }

@media (max-width: 700px) {
  .nav__logo { height: 3rem; }
  .nav__left { gap: .8rem; }
}

/* ----------------------------- Page reveal -------------------------------- */

/* Depth opens underneath the contracting surface. Only the hero is treated —
   it is the only thing on screen, and blurring the whole 17,000px document
   would cost far more than it shows. The properties are cleared afterwards so
   no filter/transform containing block is left behind for the sticky sections
   inside the hero. */
.hero[data-intro-reveal] { will-change: transform, opacity; }

/* --------------------------------------------------------------------------
   Reduced motion — no tracing, no flight. The finished mark shows briefly and
   the surface crossfades out. intro.js caps the whole thing under 400ms.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .intro__surface { transition: opacity .18s linear; }
  .jc-pen path { stroke-dashoffset: 0 !important; }
}

/* No JS means nothing can dismiss the overlay, so it is never shown. */
html.no-js .intro { display: none; }

@media (max-width: 700px) {
  :root { --intro-logo-h: clamp(110px, 18vh, 150px); }
}
