/* The arches hero — the home page (front matter `hero: arches`, home.md).
   A 240vh runway (.arches) with a sticky 100vh stage: three arch-topped panels
   in a row — spring, summer, fall — the page's `image:` in the centre; scrolling
   opens the centre arch into the full-bleed scene, slides the others away, and
   the title blossoms over it word by word. The eyebrow/h1/lead/buttons (the
   layout's .hero-body) follow below the scene, on paper, as on every other page.
   Modelled on a commercial scroll component, written here from scratch.

   One number drives everything: --p, the scroll progress 0..1 on the runway.
   Browsers with CSS scroll-driven animations animate it from a view() timeline;
   others get it from arches.js (scroll position); everything visual is derived
   from it below, so the two paths cannot drift apart. Without JavaScript, and
   under prefers-reduced-motion, --p is 1: the finished scene, no motion.
   A second number, --q, carries on where --p stops: 0..1 while the scene and
   the menu scroll up together, until the menu's band reaches the top. The title
   flies to the band on it (see "The flight"). */

@property --p { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --q { syntax: '<number>'; inherits: true; initial-value: 0; }

.has-arches { --band: clamp(72px, 14vh, 128px); }   /* the header's strip of meadow, where the title lands */

.has-arches .hero { max-width: none; margin: 0; padding: 0; }   /* the runway is full-bleed */
.has-arches .hero-art { display: none; }                         /* the stage carries the picture */
/* The menu bar beneath the scene: the name and tagline are already on the
   picture, so only the links remain, centred. Other pages keep the wordmark. */
.has-arches .wordmark { display: none; }
.has-arches .site-header { justify-content: center; }
.has-arches .site-nav { justify-content: center; }

.arches {
  --p: 1;                                  /* no JavaScript: the finished scene */
  /* The runway, in p: the finger hint fades by .04; "Welcome to" writes itself
     .02–.20; a pause; the window and side panels move .27–.63; the title's three
     parts blossom .49–.9; then the finished scene holds until the stage lets go. */
  --g: clamp(0, (var(--p) - 0.27) / 0.36, 1);   /* the geometry, after the greeting's pause */
  --e: calc(var(--g) * var(--g) * (3 - 2 * var(--g)));   /* …eased (smoothstep); then the title */
  /* panel geometry: three arches across the stage, the centre one the scene */
  --pw: clamp(96px, 22vw, 300px);
  --ph: min(calc(var(--pw) * 1.9), 58vh);
  --gap: clamp(10px, 2.4vw, 32px);
  --step: calc(var(--pw) + var(--gap));
  --rb: calc(var(--pw) * 0.24);            /* the gentler bottom corners */
  --scrim: 18, 21, 14;                     /* forest dusk, as the meadow's scrim was */

  position: relative;
  height: 240vh;                           /* 140vh of scrolling for the sequence */
}
@media (scripting: enabled) { .arches { --p: 0; } }
.arches { -webkit-user-select: none; user-select: none; }   /* a double-click on the scene skips it (arches.js), never selects "Welcome" */
@supports (animation-timeline: view()) {
  .arches {
    animation: arches-progress linear both, arches-travel linear both;
    animation-timeline: view(), view();
    /* --p: exactly the sticky stretch. --q: from the stage letting go to the
       runway's foot (the band's foot) standing --band below the top */
    animation-range: contain, exit 0% exit calc(100% - var(--band));
  }
  @media (prefers-reduced-motion: reduce) {
    .arches { animation-name: none, arches-travel; }   /* the scene holds; the title's crossfade to the band still follows the scroll */
  }
}
@keyframes arches-progress { from { --p: 0; } to { --p: 1; } }
@keyframes arches-travel { from { --q: 0; } to { --q: 1; } }

/* ---- the stage ------------------------------------------------------------- */
.arches-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--paper-2);
}
.arch {
  position: absolute;
  left: 50%; top: 50%;
  width: var(--pw); height: var(--ph);
  margin: calc(var(--ph) / -2) 0 0 calc(var(--pw) / -2);
  border-radius: calc(var(--pw) / 2) calc(var(--pw) / 2) var(--rb) var(--rb);
  overflow: hidden;
  background: var(--lichen);
  transform: translateX(calc(var(--k) * var(--step) * (1 + 1.8 * var(--e)))) scale(calc(1 + 0.35 * var(--e)));
  opacity: clamp(0, 1 - var(--e) * 1.7, 1);
}
.arch img, .arch-scene img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
.arch-2 { --k: -1; }                       /* spring, to the left */
.arch-4 { --k: 1; }                        /* fall, to the right */
/* the centre arch (summer) is a window onto the full scene, opening as you scroll */
.arch-scene {
  position: absolute; inset: 0; z-index: 2;
  --ix: calc((100% - var(--pw)) / 2 * (1 - var(--e)));
  --iy: calc((100% - var(--ph)) / 2 * (1 - var(--e)));
  --r: calc(var(--pw) / 2 * (1 - var(--e)));
  --r2: calc(var(--rb) * (1 - var(--e)));
  clip-path: inset(var(--iy) var(--ix) round var(--r) var(--r) var(--r2) var(--r2));
}
.arches-stage::after {                     /* a soft scrim behind the title, arriving with the scene */
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  opacity: var(--e);
  background:
    radial-gradient(ellipse 64% 38% at 50% 47%, rgba(var(--scrim), .36), transparent 70%),
    linear-gradient(to top, rgba(var(--scrim), .3) 0%, transparent 36%, rgba(var(--scrim), .14) 100%);
}

/* ---- the words that blossom: "Welcome to" above the arches, then the title ---- */
.arches-welcome, .arches-title, .arches-lockup {
  display: flex; flex-wrap: wrap; align-content: center; justify-content: center;
  gap: 0 0.2em;                            /* the space between the words (flex drops the text one) */
  margin: 0; padding: 0 1rem;
  text-align: center;
  font-family: var(--font-flourish, var(--font-display));
  font-weight: 400;
  line-height: 1.25;
}
/* "Welcome to" sits on the paper a little above the arch tops and writes itself as
   soon as the scroll starts (p .02–.20); after a pause the centre window grows
   over it (it is under .arch-scene) — the scene swallows the greeting before the
   title arrives. */
.arches-welcome {
  position: absolute; left: 0; right: 0; z-index: 1;
  bottom: calc(50% + var(--ph) / 2 + 0.5em);
  --w0: 0.02; --wstep: 0.055; --wdur: 0.125;
  font-size: clamp(1.7rem, 5vw, 4.4rem);
  color: var(--moss);
}
.arches-title {
  position: absolute; inset: 0 0 auto; height: 94vh;   /* the stage's box, less 6vh at its foot (it is in .arches-lift, over the stage) */
  --w0: 0.49; --wstep: 0.09; --wdur: 0.225;  /* three parts, done by .9: the scene then holds */
  font-size: clamp(2.7rem, 9.5vw, 8.6rem);
  color: #fff;
  text-shadow: 0 2px 26px rgba(var(--scrim), .6), 0 0 3px rgba(var(--scrim), .35);
}
/* Each word opens from a bud and is written on, left to right, under a soft mask.
   Words, not letters: Playwrite is a joined cursive, and a letter in its own box
   loses its joins. Part i opens from p = --w0 + --wstep·i over --wdur of the runway. */
.arches-welcome .w, .arches-title .w, .arches-lockup .w {
  --i: 0;
  --t: clamp(0, (var(--p) - var(--w0) - var(--i) * var(--wstep)) / var(--wdur), 1);
  --rot: -9deg;
  --pen: calc(var(--t) * 135%);            /* where the pen is: ink behind it, nothing ahead */
  --bloom: translateY(calc((1 - var(--t)) * 0.3em)) rotate(calc((1 - var(--t)) * var(--rot))) scale(calc(0.3 + 0.7 * var(--t)));
  display: inline-block;
  /* The mask stops at the box, so the box must hold all the ink: Playwrite's
     descenders reach 0.36em below the line box, its swashes 0.17em past the
     sides. Padding makes room; the matching negative margins keep the layout. */
  padding: 0.2em 0.25em 0.45em;
  margin: -0.2em -0.09em -0.45em;
  transform-origin: 50% 100%;
  opacity: clamp(0, var(--t) * 3, 1);
  transform: var(--bloom);
  -webkit-mask-image: linear-gradient(to right, #000 calc(var(--pen) - 35%), transparent var(--pen));
  mask-image: linear-gradient(to right, #000 calc(var(--pen) - 35%), transparent var(--pen));
}
.arches-welcome .w:nth-child(2), .arches-title .w:nth-child(2) { --i: 1; --rot: 9deg; }
.arches-title .w:nth-child(3) { --i: 2; }
.arches-title .by { flex: 0 0 100%; font-size: .55em; margin-bottom: .15em; }   /* "Dr. Juliane Dmyterko's", its own line, with air below (its .45em padding + .15em) */

/* ---- the flight: the title to the menu's band --------------------------------
   The title has its own layer (.arches-lift) that keeps still on the screen: over
   the pinned scene it is where the stage's title was; then, while the scene and
   the menu scroll up together (--q), each word glides and shrinks to its place in
   the lockup on the band — the same words, laid out small and kept invisible as
   landing places, with "Assessment & Consultation" written in beneath — and the
   band comes up under them as they settle. Nothing in the layer rides the
   scrolling page, so nothing has to chase it: the layer is fixed where the menu
   sticks; on phones, where the menu scrolls on, it is sticky in the runway, whose
   foot is the band's foot, so it leaves with the menu. arches.js measures each
   word's move (--fx, --fy, --fs) and sets .is-flying; until then, and without
   JavaScript or under prefers-reduced-motion, the title fades out and the lockup
   fades in instead. */
.arches-lift {
  position: sticky; top: 0; z-index: 55;   /* over the menu (50), under the theme toggle (60) */
  height: var(--band);
  margin-top: -100vh;                       /* from the runway's top, over the stage */
  pointer-events: none;
}
@media (scripting: enabled) and (width > 40rem) {
  .arches-lift { position: fixed; left: 0; right: 0; margin: 0; }
}
.arches-lockup {
  position: absolute; inset: 0 0 auto; height: var(--band);
  isolation: isolate;
  font-size: min(calc(var(--band) * 0.27), 4.6vw);   /* "Neurodivergent Flourishing" on one line, clear of the theme toggle */
  row-gap: 0.2em;                                    /* room for the cursive's descenders */
  color: #fff;
  text-shadow: 0 1px 8px rgba(var(--scrim), .7), 0 0 2px rgba(var(--scrim), .45);
  opacity: 0;
}
.arches-lockup::before {                     /* a shade under the lockup, so the small words read over the flowers */
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(10em 80% at 50% 50%, rgba(var(--scrim), .5), transparent);
}
.arches-lockup .by, .arches-lockup .svc { flex: 0 0 100%; font-size: max(.5em, 13px); }
.arches-lockup .svc { display: flex; justify-content: center; gap: 0 0.2em; }
.arches-lockup .w { --t: 1; }                /* placed, not blossoming */
.arches-lockup .svc .w:nth-child(2) { --i: 1; --rot: 9deg; }
.arches-lockup .svc .w:nth-child(3) { --i: 2; }
.arches-title { opacity: clamp(0, 1 - var(--q) * 2.5, 1); }            /* the fallback: the title fades … */
@media (scripting: enabled) {
  .arches-lockup { opacity: clamp(0, var(--q) * 2.5 - 1.5, 1); }      /* … and the lockup fades in on the band */
}
.arches.is-flying .arches-title, .arches.is-flying .arches-lockup { opacity: 1; }
.arches.is-flying .arches-lockup > .w { visibility: hidden; }          /* the landing places */
.arches.is-flying .arches-lockup::before { opacity: clamp(0, var(--q) * 2 - 1, 1); }
.arches.is-flying .arches-lockup .svc .w {   /* written in, word by word, once the title is clear of it: three words, the last done by q .96 */
  --t: clamp(0, (var(--q) - 0.76 - var(--i) * 0.04) / 0.12, 1);
}
.arches-title .w {
  --g: clamp(0, (var(--q) - var(--lag, 0)) / 0.8, 1);    /* the later words a little behind; all down by q .9 */
  --f: calc(var(--g) * var(--g) * (3 - 2 * var(--g)));   /* eased: it lifts off still and settles still */
  transform: translate(calc(var(--fx, 0px) * var(--f)), calc(var(--fy, 0px) * var(--f))) scale(calc(1 + (var(--fs, 1) - 1) * var(--f))) var(--bloom);
}
.arches.is-measuring .arches-title .w { transform: none; }   /* arches.js reads the resting layout */

/* ---- the finger: hover over the centre arch, then swipe up — "the page scrolls" */
/* Time-based keyframes (not the scroll timeline), gone the moment the visitor
   scrolls: opacity falls to 0 within the first 4% of the runway. */
.arches-hint {
  position: absolute; left: 50%; top: 50%; z-index: 5;
  width: 84px; height: 84px;
  margin: -42px 0 0 -42px;
  color: #fff;
  pointer-events: none;
  opacity: clamp(0, 1 - var(--p) * 25, 1);
  filter: drop-shadow(0 2px 10px rgba(var(--scrim), .7));
}
.arches-hint svg { display: block; width: 100%; height: 100%; overflow: visible; }
.hint-hand, .hint-ring, .hint-trail { animation: 3.6s cubic-bezier(.45, 0, .2, 1) 0.8s infinite both; }
.hint-hand { animation-name: hint-hand; }
.hint-ring { animation-name: hint-ring; transform-box: fill-box; transform-origin: center; }
.hint-trail {                              /* the stroke the finger leaves behind */
  position: absolute; left: calc(50% - 1px); bottom: calc(50% + 24px);
  width: 2px; height: 72px;
  border-radius: 1px;
  background: linear-gradient(to top, rgba(255,255,255,.75), transparent);
  transform-origin: 50% 100%;
  animation-name: hint-trail;
}
@keyframes hint-hand {                     /* arrive and hover … press … swipe up … lift off … rest */
  0%        { transform: translateY(6px); opacity: 0; }
  10%, 22%  { transform: translateY(0); opacity: 1; }
  16%       { transform: translateY(-4px); }
  30%       { transform: translateY(2px) scale(.94); opacity: 1; }
  58%       { transform: translateY(-72px) scale(.94); opacity: 1; }
  68%       { transform: translateY(-88px) scale(1); opacity: 0; }
  100%      { transform: translateY(6px); opacity: 0; }
}
@keyframes hint-ring {                     /* the touch: a ring that pops from the fingertip and spreads */
  0%, 28%   { transform: scale(.25); opacity: 0; }
  31%       { transform: scale(.4); opacity: .9; }
  50%       { transform: scale(1.5); opacity: 0; }
  100%      { transform: scale(1.5); opacity: 0; }
}
@keyframes hint-trail {
  0%, 30%   { transform: scaleY(0); opacity: 0; }
  34%       { opacity: .9; }
  58%       { transform: scaleY(1); opacity: .9; }
  70%       { transform: scaleY(1); opacity: 0; }
  100%      { transform: scaleY(0); opacity: 0; }
}

/* ---- the words: eyebrow, h1, lead, buttons below the scene, on paper -------- */
.has-arches .hero-body {
  max-width: var(--measure);               /* the prose column, so the two line up */
  margin: 0 auto;
  padding: clamp(2.4rem, 6vh, 4rem) 1.5rem 0;
}

@media (max-width: 40rem) {
  .arches { --pw: 26vw; --gap: 3vw; }
  .arches-hint { width: 56px; height: 56px; margin: -28px 0 0 -28px; }
  .arches-title { font-size: clamp(1.7rem, 9.5vw, 3.4rem); }
  .arches-welcome { font-size: clamp(1.4rem, 7vw, 2rem); }
  .has-arches .hero-body { padding-left: 1.2rem; padding-right: 1.2rem; }
}
@media (prefers-reduced-motion: reduce) {
  .arches { --p: 1; }               /* (its animations: the @supports block above) */
  .arches-hint { display: none; }   /* nothing moves, and there is nothing to hint at */
}
/* ---- after the scene: the meadow's foot stays with the menu ------------------
   The header carries a band of the same photo above the links: the scene's
   bottom, sized exactly as the stage sizes it (100vw × 100vh, cover, anchored at
   the bottom) under the same scrim. The header is pulled up by the band's height
   so the band lies over the stage's last pixels — the same pixels — and the two
   are one picture while the stage slides out; then the header sticks, and the
   flowers and the menu stay put while the page scrolls beneath them. */
.has-arches .site-header {
  position: sticky; top: 0; z-index: 50;
  margin: calc(-1 * var(--band)) auto 0;
  padding-top: calc(var(--band) + 0.9rem);   /* the band's room */
  background: linear-gradient(transparent var(--band), var(--paper) var(--band));   /* the band's strip unpainted: see "The seam" */
}
.arch-band {
  --scrim: 18, 21, 14;
  /* full-bleed from the viewport's centre (the header's padding is asymmetric:
     it leaves room for the theme toggle), so the crop matches the stage's */
  position: absolute; top: 0; left: 50%;
  width: 100vw; height: var(--band);
  margin-left: -50vw;
  overflow: hidden;
  background: var(--paper-2);
}
.arch-band img, .arch-band::after {
  position: absolute; left: 0; bottom: 0;
  width: 100vw; height: 100vh;
}
.arch-band img { display: block; object-fit: cover; object-position: center; }
.arch-band::after {                        /* the stage's scrim, as it stands once the scene has arrived */
  content: ''; pointer-events: none;
  background:
    radial-gradient(ellipse 64% 38% at 50% 47%, rgba(var(--scrim), .36), transparent 70%),
    linear-gradient(to top, rgba(var(--scrim), .3) 0%, transparent 36%, rgba(var(--scrim), .14) 100%);
}
/* The seam. For the last --band px of the runway the stage is still pinned while
   the header rises from the bottom of the screen, so the band would lie over a
   picture that is not moving with it: the scene's foot, shown up to --band px
   higher than the stage shows it underneath, its top edge a line climbing the
   meadow. So the band stays transparent until it has fully entered (its view()
   entry range, which ends exactly as the stage lets go), and the header leaves
   its band strip unpainted: until then the stage's own pixels show through.
   From that moment the band and the stage are the same pixels, so the band
   arrives unseen. Without scroll-driven animations, arches.js throws the same
   switch. */
@supports (animation-timeline: view()) {
  .arch-band {
    animation: arch-band-in steps(1, end) both;
    animation-timeline: view();
    animation-range: entry 0% entry 100%;
  }
}
@keyframes arch-band-in { from { opacity: 0; } to { opacity: 1; } }
@media (max-width: 40rem) {
  /* a phone's menu wraps to three rows: the band stays for the colour, but
     pinning both would take a third of the screen, so here the header scrolls.
     Relative, not static: it still holds the band (absolute) and the title's
     landing, and the seam above applies as on wider screens. */
  .has-arches .site-header { position: relative; }
}

@media print {
  .arches, .arch-band { display: none; }
  .has-arches .site-header { position: static; margin-top: 0; }
}
