/* ==========================================================================
   JANET TRAVEL — MOTION SYSTEM
   One motion language for the whole site, in four tiers.

     MICRO      buttons, links, icons            120–240ms
     COMPONENT  cards, deal tiles, Janet blocks  380–620ms, staggered
     SECTION    image reveals, scroll transitions 700–1100ms
     SIGNATURE  the 3D destination gallery        (assets/janet_hero_v4.*)

   Rules this sheet keeps:
     · Only transform, opacity, clip-path and filter animate. Nothing that
       triggers layout is on a scroll path.
     · Nothing is hidden unless JS is present to reveal it — every hiding rule
       is behind html.js, so a page with no JS is fully visible and indexable.
     · prefers-reduced-motion removes movement, never content.
     · No scroll hijacking anywhere. Scroll drives values; it never takes over.
   ========================================================================== */

:root {
  --m-fast:   .18s;
  --m-mid:    .42s;
  --m-slow:   .78s;
  --m-scene: 1.05s;
  --m-ease:     cubic-bezier(.22, .61, .36, 1);
  --m-ease-out: cubic-bezier(.16, 1, .3, 1);
  --m-ease-in:  cubic-bezier(.55, 0, 1, .45);
}

/* == MICRO ================================================================ */

.m-link {
  position: relative;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1.5px;
  background-position: right bottom;
  background-repeat: no-repeat;
  transition: background-size var(--m-mid) var(--m-ease), color var(--m-fast) var(--m-ease);
}
.m-link:hover, .m-link:focus-visible { background-size: 100% 1.5px; }
.m-link:dir(ltr) { background-position: left bottom; }

/* == COMPONENT / SECTION ENTRANCES ======================================== */

/* Every entrance is one of these three. More than three and a page stops
   having a motion language and starts having motion decisions. */
html.js .m-rise,
html.js .m-tilt,
html.js .m-mask { will-change: transform, opacity; }

html.js .m-rise {
  opacity: 0;
  transform: translate3d(0, 30px, 0);
  transition: opacity var(--m-slow) var(--m-ease-out), transform var(--m-slow) var(--m-ease-out);
}

/* Cards arrive at a slight angle so a row of them does not read as one slab
   sliding up. The angle is small on purpose: 6deg is a card, 20deg is a trick. */
html.js .m-tilt {
  opacity: 0;
  transform: perspective(900px) translate3d(0, 38px, -40px) rotateX(6deg);
  transform-origin: 50% 100%;
  transition: opacity var(--m-slow) var(--m-ease-out), transform var(--m-slow) var(--m-ease-out);
}

/* Photography wipes open rather than fading in — a fade on a large image just
   looks like a slow network.

   The clip goes on the picture INSIDE .m-mask, never on .m-mask itself. An
   element clipped to zero height has an empty intersection rectangle, so an
   IntersectionObserver watching it never fires and the image stays hidden for
   good — which is exactly what happened when the clip lived on the wrapper. */
html.js .m-mask > img,
html.js .m-mask > picture > img {
  clip-path: inset(0 0 100% 0);
  transform: scale(1.06);
  transition: clip-path var(--m-scene) var(--m-ease-out), transform 1.4s var(--m-ease-out);
}

html.js .m-rise.is-in { opacity: 1; transform: none; }
html.js .m-tilt.is-in { opacity: 1; transform: perspective(900px) translate3d(0, 0, 0) rotateX(0); }
html.js .m-mask.is-in > img,
html.js .m-mask.is-in > picture > img { clip-path: inset(0 0 0 0); transform: scale(1); }

/* Stagger. Set by the observer from the element's index within its group, so
   a rail of six cards does not need six hand-written delay classes. */
html.js [data-m-delay] { transition-delay: calc(var(--m-i, 0) * 90ms); }

/* Once an entrance has played, drop the hint — a page holding will-change on
   forty elements is a page that has given the compositor forty layers. */
html.js .is-in { will-change: auto; }

/* == SCROLL-LINKED ======================================================== */

/* --sy is written by the motion script: -1 above the viewport centre, +1 below,
   updated only while the element is on screen. */
[data-m-parallax] { --sy: 0; }

[data-m-parallax="slow"]  { transform: translate3d(0, calc(var(--sy) *  22px), 0); }
[data-m-parallax="lead"]  { transform: translate3d(0, calc(var(--sy) * -16px), 0); }
[data-m-parallax="deep"]  { transform: translate3d(0, calc(var(--sy) *  46px), 0) scale(1.08); }

/* == SECTION OVERLAP ====================================================== */

/* Sections lift over the one before them instead of butting against it. */
.m-overlap {
  position: relative;
  z-index: 1;
  margin-block-start: clamp(-88px, -6vw, -40px);
  border-start-start-radius: clamp(24px, 3vw, 44px);
  border-start-end-radius: clamp(24px, 3vw, 44px);
  box-shadow: 0 -24px 60px -40px rgba(88, 52, 26, .5);
}

/* == REDUCED MOTION ======================================================= */

@media (prefers-reduced-motion: reduce) {
  html.js .m-rise,
  html.js .m-tilt,
  html.js .m-mask,
  html.js .m-mask > img,
  html.js .m-mask > picture > img {
    opacity: 1;
    transform: none;
    clip-path: none;
    transition: none;
  }
  [data-m-parallax] { transform: none !important; }
  .m-link { transition: none; background-size: 100% 1.5px; }
}
