/* =============================================================================
   Page transitions — studied from mouthwash.studio.

   Their grammar, read off their own stylesheet (Nuxt build, `_nuxt/css/*.css`)
   rather than guessed at:

     .fade-page-enter-active,.fade-page-leave-active{transition:opacity .5s ease .66s}
     .fade-page-leave-active{transition-delay:0s!important}
     .fade-page-enter,.fade-page-leave-to{opacity:0}
     .fade-page-enter{transition-delay:.66s}

   Read as a timeline: the outgoing page fades out over 500ms starting
   immediately (the leave delay is forced to 0), and the incoming page waits
   .66s before fading in over 500ms. The two never overlap — you are never
   looking at two pages at once, and that pause is what makes it read as mellow
   rather than as a crossfade. Opacity only; nothing slides. Their header never
   takes part: it holds still while the body swaps underneath.

   WHY THIS IS JAVASCRIPT NOW, AND WAS NOT BEFORE
   The first cut of this file used the native cross-document View Transitions
   API, on the reasoning that it costs no JavaScript. It half-worked: the
   outgoing page reliably started a transition (`pageswap` carried a
   ViewTransition) but the arriving page reported it skipped (`pagereveal` got
   null), so you got a fade-out into a hard cut. That reproduced with
   spec-minimal CSS on two blank pages, headed and headless — so it was not our
   markup, and not something a CSS fix in here could reach.

   The reference does not use that API either. It is a Vue app, so its
   transition is JavaScript driving classes on a timeline. This is the same
   idea for a multi-page site: intercept the click, run the leave, navigate,
   and run the enter on arrival. Deterministic, no dependency on a browser
   feature that may or may not engage, and it degrades to a plain navigation
   the moment JS is off — see transitions.js.

   Pace is theirs: 500 / 160 / 500. Their full cycle is ~1.16s because their
   .66s enter delay is measured from the START of the leave, so the actual gap
   between the two fades is 160ms.
   ========================================================================== */

:root{
  --page-out: 500ms;   /* outgoing fade — brisk; you are leaving */
  --page-beat: 160ms;  /* the pause. The whole point. */
  --page-in: 760ms;    /* incoming fade — the arrival gets the time */

  /* The leave and the arrival do not want the same curve. Going out, plain
     `ease` is right: it commits and goes. Coming in, `ease` starts at a slope
     and the page is half-present almost immediately, which is what makes an
     arrival feel abrupt however long you run it.

     This is mouthwash's own signature curve — the one on almost everything
     they move. Its first control point sits at (0,.01), so it leaves zero
     essentially flat: nothing happens for a beat, then the page gathers and
     settles long. Lengthening the duration alone would not have fixed this;
     the shape is what reads as mellow. */
  --page-out-ease: ease;
  --page-in-ease: cubic-bezier(0,.01,.38,.95);
}

/* Everything on the page takes part EXCEPT the header, which holds still the
   way theirs does. Naming it this way rather than wrapping the content in a
   div keeps the markup of every page untouched. */
.smd-anim body > *:not(header){
  transition: opacity var(--page-in) var(--page-in-ease) var(--page-beat);
}

/* arrival: held at zero with no transition, until the boot script hands over */
.smd-entering body > *:not(header){
  opacity: 0;
  transition: none;
}

/* departure: straight out, no delay — their `transition-delay:0s!important` */
.smd-leaving body > *:not(header){
  opacity: 0;
  transition: opacity var(--page-out) var(--page-out-ease) 0s;
}

/* Nothing should be clickable while the page is on its way out. */
.smd-leaving body{ pointer-events: none; }

@media (prefers-reduced-motion: reduce){
  :root{ --page-out: 0ms; --page-beat: 0ms; --page-in: 0ms; }
  .smd-entering body > *:not(header),
  .smd-leaving body > *:not(header){ opacity: 1; }
}

/* =============================================================================
   The reveal family — the rest of their transition vocabulary.

   mouthwash names a transition per motion and reuses it everywhere; these are
   their exact durations, distances and easings, lifted from the same
   stylesheets. In Vue these are enter/leave classes on v-if; here they are
   applied on scroll by transitions.js, which is the static-page equivalent.

   Signature easing: cubic-bezier(0,.01,.38,.95) — fast out of the gate, long
   settle. It is on almost everything they move.

   Usage:  <div data-t="up">   or   data-t="up-short" | "left" | "right" | "in"
   ========================================================================== */

/* Hidden ONLY once the boot script has confirmed JS is running. A stylesheet
   that hides content unconditionally and waits for a script to reveal it is
   how you ship a blank page to anyone whose JS failed to load. */
.smd-js [data-t]{ opacity: 0; }
/* Lands on the element's OWN resting opacity, not a flat 1.

   A flat `opacity: 1` here is a trap, and it caught "Our work.": that line is
   `.dim`, deliberately at 50%, and `.smd-js [data-t].is-in` outranks
   `.hero-copy .dim` on specificity — so the reveal quietly finished the fade at
   full strength and the headline came out solid. Anything with a resting
   opacity of its own sets --t-opacity next to it. */
.smd-js [data-t].is-in{ opacity: var(--t-opacity, 1); }

/* .fade-up — transition:opacity .25s, transform .33s <ease>; translateY(1.5rem) */
[data-t="up"]{
  transform: translateY(1.5rem);
  transition: opacity .25s, transform .33s cubic-bezier(0,.01,.38,.95);
}
/* .fade-up-short — .15s / .15s; translateY(.66em) */
[data-t="up-short"]{
  transform: translateY(.66em);
  transition: opacity .15s, transform .15s cubic-bezier(0,.01,.38,.95);
}
/* .fade-up-delay — .25s / .25s, delay .2s; translateY(1em) */
[data-t="up-delay"]{
  transform: translateY(1em);
  transition: opacity .25s .2s, transform .25s cubic-bezier(0,.01,.38,.95) .2s;
}
/* .fade-left — .25s; translateX(3rem) */
[data-t="left"]{
  transform: translateX(3rem);
  transition: opacity .25s, transform .25s cubic-bezier(0,.01,.38,.95);
}
/* .fade-right — .25s; translateX(-1em) */
[data-t="right"]{
  transform: translateX(-1em);
  transition: opacity .25s, transform .25s cubic-bezier(0,.01,.38,.95);
}
/* .fade-delay-in — opacity .25s, delay .66s. No movement at all. */
[data-t="in"]{
  transition: opacity .25s .66s;
}

.smd-js [data-t].is-in{ transform: none; }

@media (prefers-reduced-motion: reduce){
  .smd-js [data-t]{ opacity: 1; transform: none; transition: none; }
}
