/* Hero motion: owned by the hero agent.
   Plain CSS only — transform, filter:blur, opacity, stroke-dash. No SMIL, no feTurbulence /
   feDisplacementMap anywhere (dropped per owner direction: it read as static, not wool
   or water). A pen draws the symbol at the exact centre of the hero — the same spot the
   whole lockup rests in once assembled, at its resting size throughout; as the last stroke
   (the stem) is drawn it is already gliding left into its normal place, and the wordmark
   arrives from the right with the live hero's own blur-in once the symbol has cleared its path. Then the tagline, then the one place the landscape itself moves: the mountain
   ridges drawing in, left to right, like a horizon being found. On scroll the whole hero
   copy drifts up and loses focus, the way a thing in the middle distance softens as your
   eye moves past it. */

:root{
  --hero-ease: cubic-bezier(.16,1,.3,1);      /* strong ease-out, settles, never overshoots */
  --ease-curl: cubic-bezier(.22,.61,.36,1);   /* gentler settle, for the pen's hooks/curls */
  --hero-travel: clamp(28px,6vw,64px);        /* the wordmark's own small arrival slide */
  /* The symbol's glide distance, from hero-centre to its resting spot in the lockup, read
     off the lockup's own geometry instead of a magic pixel figure: half the gap-plus-wordmark
     width it has to clear to meet the wordmark. The lockup is centred on the hero (site.css's
     .hero is a centred flex column, .hero-copy shrinks to its widest child and text-align
     centres the lockup within it), so the finished lockup's centre already sits on the hero's
     centre — which means the symbol's own centre, once assembled, sits left of that by exactly
     half of (gap + wordmark width). --pen-k is that ratio to --s: the lockup's gap is a fixed
     .35 of --s already (site.css), and "kelsuu" in Jost at the wordmark's .93*--s size renders
     at a fixed 2.3955... of --s (text scales exactly linearly with font-size, measured once
     against the real font — see tools/lib/cdp.mjs review scripts); half their sum is --pen-k.
     Because both terms are proportional to --s, this holds at every viewport, not just the one
     it was measured at. translateX is unaffected by the scale() below it never moves the
     centre, since scale composes inside translate, both about the symbol's own centre (its
     default transform-origin) — so --pen-k lands the symbol's centre on the hero's centre while
     it draws. */
  --pen-k: 1.372754;
}

/* ---------- symbol + wordmark sizing ---------- */
.lockup .mark{height:var(--s);width:auto;display:block}
.lk-small .mark{height:var(--s)}

/* the glide/slide travels past the lockup's own box; contain it so it can never push the
   document wider than the viewport (was producing a brief horizontal scrollbar at load). */
.hero{overflow-x:clip}

/* ---------- 1. the lockup arrives: a pen draws the symbol at hero-centre, then swaps to
   the real glyph and glides left as the wordmark arrives from the right ----------
   Seven strokes from the logo-lab kit, in the order below. The pen then crossfades into the real filled
   glyph in 180ms, and the glide begins: same duration and ease as the wordmark's own
   arrival, so the two meet exactly as today's lockup does, just starting later.
   The fill fades in first (1.7s–1.88s) and is fully opaque — it paints over the pen group,
   later in source order — before the pen itself starts fading out (1.88s–2.06s): no frame
   ever has both at partial opacity, so there's no instant where the stroke's true width shows
   through a half-transparent fill, or the glyph dims before it's covered. */
.pen{fill:none;stroke:var(--kelsuu);opacity:1;animation:hero-pen-out .18s var(--hero-ease) both;animation-delay:1.88s}
.fill-swap{opacity:0;animation:hero-fill-in .18s var(--hero-ease) both;animation-delay:1.7s}
@keyframes hero-pen-out{to{opacity:0}}
@keyframes hero-fill-in{to{opacity:1}}

.stroke{
  stroke-linecap:round;stroke-linejoin:round;
  animation-name:hero-stroke-draw;animation-fill-mode:both;
}
@keyframes hero-stroke-draw{to{stroke-dashoffset:0}}
/* Written like a character (owner's order): the upper stroke (right curl first, right to left), then the middle and the lower, each one
   continuous line left to right (the left half runs backwards along its kit path, curl tip to
   centre, easing in; the right half continues out to its curl, easing out), then the connecting
   stem last, top to bottom. A short pen-lift between strokes; 1.3s in all.
   Each path carries its own real-length stroke-dasharray/stroke-dashoffset as presentation
   attributes (measured once with getTotalLength(), in src/site/index.html) instead of the
   pathLength="1" + dasharray:1 trick: WebKit doesn't normalise dashing to pathLength the way
   Chromium and Firefox do, so with pathLength every dash was 1 user-unit long regardless of a
   path's real length — on these paths (hundreds of units long) that rendered as a fine dotted
   texture across the whole stroke instead of a single drawn line, i.e. the symbol's full shape
   flashing in at each stroke's very first frame. Real units dash and animate identically in
   every engine. */
.s-up-r{animation-duration:0.23s;animation-delay:0s;animation-timing-function:cubic-bezier(.5,0,1,1)}
.s-up-l{animation-duration:0.23s;animation-delay:0.23s;animation-timing-function:cubic-bezier(0,0,.4,1)}
.s-mid-l{animation-duration:0.13s;animation-delay:0.52s;animation-timing-function:cubic-bezier(.5,0,1,1)}
.s-mid-r{animation-duration:0.13s;animation-delay:0.65s;animation-timing-function:cubic-bezier(0,0,.4,1)}
.s-low-l{animation-duration:0.23s;animation-delay:0.83s;animation-timing-function:cubic-bezier(.5,0,1,1)}
.s-low-r{animation-duration:0.23s;animation-delay:1.06s;animation-timing-function:cubic-bezier(0,0,.4,1)}
.s-stem{animation-duration:0.46s;animation-delay:1.34s;animation-timing-function:cubic-bezier(.45,0,.3,1)}

/* the symbol itself: written at its resting size at the hero's centre (its drawing layer sits
   --pen-k * --s right of the symbol's in-flow box), one size throughout. As the last stroke (the
   stem) is drawn it is already gliding back over its box, its ordinary place in the lockup.
   The glide is a translate on the drawing layer: at one size nothing is ever resampled. */
.lk-hero .mark{position:relative;display:block;width:var(--s);height:var(--s)}
.lk-hero .mark-art{
  position:absolute;left:50%;top:50%;width:auto;height:var(--s);aspect-ratio:1;overflow:visible;
  translate:calc(-50% + var(--s) * var(--pen-k)) -50%;
  animation:hero-mark-glide 1.5s var(--hero-ease) 1.32s both;
}
@keyframes hero-mark-glide{to{translate:-50% -50%}}

/* the wordmark: the live hero's own arrival — a short slide and blur-fade from the right —
   timed to start the moment the gliding symbol has cleared its path (measured at every
   width), so the two never overlap and still land together. */
.wm{
  display:inline-block;
  opacity:0;filter:blur(10px);
  transform:translateX(var(--hero-travel));
  animation:hero-word-in 1.5s var(--hero-ease) both;
  animation-delay:1.42s;
}
@keyframes hero-word-in{to{opacity:1;filter:blur(0);transform:translateX(0)}}

/* clientry's GradientText, ported, under the owner's rule (2026-10-13): Kel-Suu #3D6566 is the colour;
   black only as a blend, never much and never for long. The symbol and "suu" stay Kel-Suu, and every
   few seconds a shadow (at most about three-quarters of the way to the ink of "kel") passes through
   and is gone. site.js sets --sweep-shade and --sweep-x and moves the symbol's #hero-sweep gradient;
   without it (or with reduced motion) every stop falls back to Kel-Suu, exactly as before. */
.lk-hero .sw-base{stop-color:var(--kelsuu)}
.lk-hero .sw-band{stop-color:var(--sweep-shade,var(--kelsuu))}
.lk-hero .wm .suu{
  background-image:linear-gradient(to right,var(--kelsuu) 28%,var(--sweep-shade,var(--kelsuu)) 50%,var(--kelsuu) 72%);
  background-size:300% 300%;
  background-position:var(--sweep-x,0%) 50%;
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}

/* ---------- 2. the tagline settles after it, a quiet blur-fade ----------
   It follows the wordmark in, settling as the lockup lands. */
.tagline{
  opacity:0;filter:blur(4px);
  animation:hero-tagline-in .8s ease-out both;
  animation-delay:1.8s;
}
@keyframes hero-tagline-in{to{opacity:1;filter:blur(0)}}

/* the quiet route to the collection follows the tagline in, the same blur-fade, a beat later. */
.hero-arrow{
  opacity:0;filter:blur(4px);
  animation:hero-tagline-in .8s ease-out both;
  animation-delay:2.1s;
}

/* ---------- 3. the lake: ridge lines draw in, left to right, slow and staggered ----------
   The one place the landscape moves. Everything around it — the reflection below — stays
   still: no shimmer, no noise, just a quiet mirror once the ridges have found their line. */
/* A long, even draw (ease-in-out, not the lockup's sharp ease-out, which made the lines all but
   appear at once), starting while the lockup is still landing (now the pen draw + glide, 0 to
   3.4s) so the eye catches it, same as live. Shorter than live's 4.2s only so the whole
   entrance still settles by ~6s instead of nearly 8 — the lockup itself now takes longer to
   land (it's drawn first), so the ridges have less room left to stay unhurried in. */
/* Each ridge is its own SVG, revealed left to right like a pen line (a clip on the element, not
   stroke dashes: dash maths on non-scaling strokes isn't drawn the same in every browser, and on
   some it simply didn't animate). Vertical slack in the clip keeps the 1px stroke whole. */
.horizon .ridge{position:absolute;inset:0;width:100%;height:100%;overflow:visible;
  clip-path:inset(-12px 100% -12px 0);
  animation:hero-ridge-draw 3.4s cubic-bezier(.45,.05,.35,1) both}
.horizon .ridge-1{animation-delay:2.16s}
.horizon .ridge-2{animation-delay:2.52s}
.horizon .ridge-3{animation-delay:2.88s}
@keyframes hero-ridge-draw{to{clip-path:inset(-12px 0 -12px 0)}}
/* Then depth: as the page scrolls, the nearer ridges rise faster than the far one, like the
   view shifting as you move. Scroll-linked where supported; elsewhere they simply stay put. */
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    .horizon .ridge{
      animation:hero-ridge-draw 3.4s cubic-bezier(.45,.05,.35,1) both, hero-ridge-depth linear both;
      animation-timeline:auto, scroll(root);
      animation-range:normal, 0 100vh;
    }
    .horizon .ridge-1{animation-delay:2.16s, 0s;--ridge-rise:-10px}
    .horizon .ridge-2{animation-delay:2.52s, 0s;--ridge-rise:-30px}
    .horizon .ridge-3{animation-delay:2.88s, 0s;--ridge-rise:-56px}
    @keyframes hero-ridge-depth{to{transform:translateY(var(--ridge-rise))}}
  }
}


/* ---------- 4. scroll hint = a drop of water ----------
   A droplet travels the 48px thread and dies into one faint ripple where it meets the
   lake. Loops quietly every 5s, starting once everything above has settled (retimed to
   follow the later ridge draw below, same lead-in before the last ridge's finish as live). */

/* ---------- 5. on scroll, the hero copy drifts up and loses focus ----------
   A camera's depth of field: sharp and centred, progressively blurred and faded as it
   nears the top. The scroll-timeline animation lives on the WRAPPER (.hero-copy) only —
   the symbol/wordmark/tagline load-in animations above live on the inner elements, so the
   two never fight over the same element's transform/filter. Uses var(--press), the same
   easing token the page-motion agent uses for section arrivals (motion-page.css), and the
   same "sharp in the middle, soft toward the top" language, so scrolling past the hero
   into the sections below reads as one continuous idea rather than two different effects. */
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    .hero-copy{
      animation:hero-copy-defocus 1s var(--press,ease) both;
      animation-timeline:scroll(root);
      /* A buffer before the softening starts: the first third of a viewport of scroll keeps
         the copy sharp, so the small line under the lockup can be read mid-scroll. */
      animation-range:30vh 95vh;
    }
    @keyframes hero-copy-defocus{
      from{filter:blur(0);opacity:1;transform:translateY(0)}
      to{filter:blur(12px);opacity:.22;transform:translateY(-48px)}
    }
  }
}

/* ---------- header: a small lockup appears once past the hero ----------
   Frosted paper bar + hairline, revealed by the user's own scroll rather than a timer.
   Progressive enhancement only: without scroll-timeline support the header stays exactly
   as site.css left it (transparent, mark hidden). */
/* site.css pins the header with position:absolute (it only needs to overlay the hero at
   y=0), which scrolls off with the document — a header that is meant to reappear once the
   user has scrolled past the hero has to stay put. Overriding just the position here (this
   file loads after site.css, so the cascade favours it) keeps everything else — the inset
   shorthand, the nav layout — exactly as site.css defined it. */
.site-header{position:fixed;isolation:isolate}
.site-header .pill{white-space:nowrap}
/* Frosted glass: translucent paper, a strong blur and a little saturation, over a 1px hairline.
   Without scroll-timeline support (Firefox, older Safari) the glass simply stays on, so the
   header never disappears; where supported it fades in as the hero leaves. */
.site-header::before{
  content:"";position:absolute;inset:0;z-index:-1;
  background:rgba(245,243,238,.68);
  -webkit-backdrop-filter:saturate(1.4) blur(18px);backdrop-filter:saturate(1.4) blur(18px);
  border-bottom:1px solid rgba(222,218,209,.9);
}
@supports (animation-timeline:scroll()){
  .site-header::before,.header-mark{
    animation:hero-header-reveal .35s linear both;
    animation-timeline:scroll(root block);
    animation-range:62vh 94vh;
  }
  .header-mark{visibility:visible}
  /* Phones: there's no room for the lockup and all four links, so the three text links step
     aside as the lockup arrives, leaving lockup + Notify me. */
  @media (max-width:600px){
    .site-header nav a:not(.pill){
      animation:hero-nav-out .35s linear both;
      animation-timeline:scroll(root block);
      animation-range:62vh 94vh;
    }
  }
}
@keyframes hero-header-reveal{from{opacity:0}to{opacity:1}}
@keyframes hero-nav-out{from{opacity:1;visibility:visible}to{opacity:0;visibility:hidden}}
/* Phones: the hidden lockup still took its width in the row, pushing "Notify me" past the
   right edge (5px at 360, 45px at 320). It's taken out of the row and pinned left, so the
   nav alone sets the width; the smallest screens also get a slightly tighter nav. */
@media (max-width:600px){
  .site-header .header-mark{position:absolute;left:var(--side);top:50%;transform:translateY(-50%)}
  .site-header nav{margin-left:auto}
}
@media (max-width:380px){
  .site-header nav{gap:14px;font-size:14px}
  .site-header .pill{padding-inline:14px}
}

/* ---------- reduced motion: final, still state, nothing moving ---------- */
@media (prefers-reduced-motion:reduce){
  .mark,.wm{opacity:1;filter:none;transform:none;animation:none}
  .lk-hero .mark-art{translate:-50% -50%;animation:none}
  .pen{opacity:0;animation:none}
  .fill-swap{opacity:1;animation:none}
  .stroke{stroke-dashoffset:0;animation:none}
  .tagline{opacity:1;filter:none;animation:none}
  .hero-arrow{opacity:1;filter:none;animation:none}
  .horizon .ridge{clip-path:none;transform:none;animation:none}
  .hero-copy{animation:none;filter:none;opacity:1;transform:none}
}
