/* All In House — arrival and heading rises for the /yachts and /destinations
   pages. The home page's motion (/assets/motion.css), fitted to this template:
   the first section opens on its own photograph's horizon, the page title
   rises from behind its line, then the crumb, lede and header settle. Further
   down, section titles rise word by word as they arrive. Body copy never
   moves (Django, 24 Sep 2026).

   The full arrival belongs to the full-height heroes (.hero: Miami, /yachts,
   every yacht). The shorter page heroes (.phero: charter and both destination
   indexes) show the page beneath them from the first frame, so a black opening
   there reads as loading: they get the title rise only (Django).

   Keyed to classes the head script and motion.js set:
     .m        motion allowed (no reduced-motion, IntersectionObserver present)
     .m-intro  the first load of this page in this tab: the full arrival
     .m-brief  a return to this page in the same tab: the title rise only
     .m-go     the hero photograph is ready; the arrival runs
   No script or reduced motion: none of these exist and the page is the page.
   Nothing is pinned, nothing follows the scroll position. */

:root {
  --m-out: cubic-bezier(0.165, 0.84, 0.44, 1);
  --m-inout: cubic-bezier(0.76, 0, 0.24, 1);
}

/* ---------- the arrival: the first section of the page ---------- */

/* --hz is the photograph's horizon, found by motion.js; --hz-t / --hz-b are
   the insets of a 2px sliver on it. Until the horizon is known the window is
   shut (50% / 50%), so no line shows and then jumps. Keyframes use plain
   percentages only: WebKit misreads calc() inside clip-path keyframes. */
main > .hero:first-child {
  --hz: 50%; --hz-t: 50%; --hz-b: 50%; --side: 34%;
}
@media (max-width: 700px) {
  main > .hero:first-child { --side: 19%; }
}

/* before the photograph is ready: black, the hero's words and the header held */
html.m-intro main > .hero:first-child {
  clip-path: inset(var(--hz-t) var(--side) var(--hz-b) var(--side));
}
html.m-intro main > .hero:first-child .hero__body > :not(h1) { opacity: 0; }
/* on its own: a browser without :has() drops only this rule, and the header
   simply stays in place */
html.m-intro:has(main > .hero:first-child) .hd { opacity: 0; }
html:is(.m-intro, .m-brief):not(.m-go) main > :is(.hero, .phero):first-child h1 {
  visibility: hidden;
}

/* a sliver on the horizon opens into a window, the window widens to the frame */
html.m-intro.m-go main > .hero:first-child {
  animation: m-window 1400ms linear both;
}
html.m-intro.m-go main > .hero:first-child .plate {
  transform-origin: 50% var(--hz);
  animation: m-push 2400ms var(--m-out) both;
}

/* the title rises word by word, swept in from the left, once the frame is open */
html:is(.m-intro, .m-brief) main > :is(.hero, .phero):first-child h1 {
  --m-t: 1300ms;
  -webkit-mask-image: linear-gradient(90deg, #000 40%, transparent 60%);
          mask-image: linear-gradient(90deg, #000 40%, transparent 60%);
  -webkit-mask-size: 300% 100%;
          mask-size: 300% 100%;
}
html.m-brief main > :is(.hero, .phero):first-child h1,
html:is(.m-intro, .m-brief) main > .phero:first-child h1 { --m-t: 100ms; }
html:is(.m-intro, .m-brief).m-go main > :is(.hero, .phero):first-child h1 {
  animation: m-sweep 1300ms cubic-bezier(0.45, 0, 0.2, 1) var(--m-t) both;
}
/* the title's words carry .m-title, never .m-split, so the scroll rule below
   can't hold them or replay them once the arrival's classes come off */
html:is(.m-intro, .m-brief).m-go .m-title .m-wi {
  animation: m-lift 1150ms var(--m-out) calc(var(--m-t) + var(--i) * 80ms) both;
}

/* the crumb, the lede, the specifications and the header settle last,
   the way the reference's date, contents and navigation do */
html.m-intro.m-go main > .hero:first-child .hero__body > :not(h1) {
  animation: m-drop 800ms var(--m-out) 1950ms both;
}
html.m-intro.m-go:has(main > .hero:first-child) .hd {
  animation: m-drop 800ms var(--m-out) 1950ms both;
}

@keyframes m-window {
  0% {
    clip-path: inset(var(--hz-t) var(--side) var(--hz-b) var(--side));
    animation-timing-function: var(--m-inout);
  }
  45% { clip-path: inset(0 var(--side) 0 var(--side)); }
  52% {
    clip-path: inset(0 var(--side) 0 var(--side));
    animation-timing-function: var(--m-inout);
  }
  100% { clip-path: inset(0 0 0 0); }
}
@keyframes m-push { from { transform: scale(1.12); } to { transform: scale(1); } }
@keyframes m-sweep {
  from { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
  to   { -webkit-mask-position: 0 0;    mask-position: 0 0; }
}
@keyframes m-lift {
  from { transform: translate3d(0, 130%, 0); filter: blur(10px); }
  to   { transform: translate3d(0, 0, 0);    filter: blur(0); }
}
@keyframes m-drop {
  from { opacity: 0; transform: translate3d(0, -10px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* ---------- section titles, on the way down ---------- */

/* held until motion.js has split them into words */
html.m main :is(h2.title, .itin__title, .why__label):not(.m-split) { opacity: 0; }

/* every split word rides in its own clip, open above and to the sides,
   cut just under the line, so it rises from behind its own baseline */
.m-w {
  display: inline-block;
  clip-path: inset(-0.5em -0.3em -0.12em -0.3em);
}
.m-wi { display: inline-block; }
html.m .m-split:not(.is-in) .m-wi { transform: translate3d(0, 130%, 0); opacity: 0; }
html.m .m-split.is-in .m-wi {
  animation: m-word 1100ms var(--m-out) calc(var(--d, 0ms) + var(--i) * 70ms) backwards;
}

@keyframes m-word {
  from { transform: translate3d(0, 130%, 0); filter: blur(8px); opacity: 0; }
  45%  { opacity: 1; }
  to   { transform: translate3d(0, 0, 0); filter: blur(0); opacity: 1; }
}
