/* ---------------------------------------------------------------------------
   Motion layer
   ---------------------------------------------------------------------------
   Reverse-engineered from the Framer "Trillo" export in
   landing-page/htmlversion. Every number here was measured in a real browser;
   the derivation is in landing-page/motion-audit.md.

   Contract
   --------
   * Opt-in only. An element animates because a fragment put `data-motion` on
     it. Nothing is global.
   * The hidden state lives behind `.js-motion` on <html>, which the inline
     snippet in index.html adds before the body is parsed. No JS (or a blocked
     motion.js) => no `.js-motion` => everything renders in its final state.
   * `prefers-reduced-motion: reduce` disables all of it, in CSS *and* in JS.
   * Only `opacity` + `transform` (or `translate`/`scale`) are ever animated,
     so reveals cannot move layout and cannot contribute to CLS.

   Two hazards, two answers
   ------------------------
   1. Element already has its own `transform`  -> add
      `data-motion-prop="translate"`. We then compose via the individual
      `translate`/`scale` properties and never touch its `transform`.
   2. Element already has its own individual `translate`/`scale` -- that is
      `.sec-more-feature__widget*`, `.sec-feature-grid__panel-inner`,
      `.sec-feature-grid__card-bg`, `.sec-features-intro__stage` -- put the
      `data-motion` on a wrapper or an ancestor instead. Never on those.
--------------------------------------------------------------------------- */

:root {
  /* Measured: best fit to the reference reveal curve, RMSE 0.0025 over 11
     sample points. The reference is a bounce-free spring; this bezier is
     visually indistinguishable from it. */
  --motion-ease: cubic-bezier(0.24, 0.85, 0.29, 0.97);

  --motion-duration: 700ms;   /* reference reveal: 690-700ms */
  --motion-y: 100px;          /* reference section reveal travel */
  --motion-scale: 0.5;        /* reference zoom-in start */
  --motion-stagger: 100ms;    /* reference sibling stagger */

  --motion-hover: 400ms;      /* reference button colour transition */
  --motion-hover-slow: 500ms; /* reference nav underline sweep */

  --motion-marquee-speed: 50; /* reference logo ticker: 50 px/s */

  --color-accent-hover: #ff6130; /* measured on the reference primary button */
}

/* --------------------------------------------------------------------------
   Reveal: hidden state
   -------------------------------------------------------------------------- */

.js-motion [data-motion] {
  opacity: 0;
  transition:
    opacity var(--m-dur, var(--motion-duration)) var(--motion-ease) var(--m-delay, 0ms),
    transform var(--m-dur, var(--motion-duration)) var(--motion-ease) var(--m-delay, 0ms);
}

.js-motion [data-motion="fade-up"]:not([data-motion-prop]) {
  transform: translate3d(0, var(--m-y, var(--motion-y)), 0);
}

.js-motion [data-motion="zoom-in"]:not([data-motion-prop]) {
  transform: scale(var(--m-scale, var(--motion-scale)));
}

/* Composition mode: leave `transform` alone, drive the individual properties. */
.js-motion [data-motion][data-motion-prop="translate"] {
  transition:
    opacity var(--m-dur, var(--motion-duration)) var(--motion-ease) var(--m-delay, 0ms),
    translate var(--m-dur, var(--motion-duration)) var(--motion-ease) var(--m-delay, 0ms),
    scale var(--m-dur, var(--motion-duration)) var(--motion-ease) var(--m-delay, 0ms);
}

.js-motion [data-motion="fade-up"][data-motion-prop="translate"] {
  translate: 0 var(--m-y, var(--motion-y));
}

.js-motion [data-motion="zoom-in"][data-motion-prop="translate"] {
  scale: var(--m-scale, var(--motion-scale));
}

/* --------------------------------------------------------------------------
   Reveal: resting state (added once by motion.js, never removed)
   -------------------------------------------------------------------------- */

.js-motion [data-motion].is-in {
  opacity: 1;
}

.js-motion [data-motion].is-in:not([data-motion-prop]) {
  transform: none;
}

.js-motion [data-motion].is-in[data-motion-prop="translate"] {
  translate: none;
  scale: none;
}

/* --------------------------------------------------------------------------
   Marquee: continuous horizontal loop
   --------------------------------------------------------------------------
   Markup: <div data-motion-marquee><div class="…__track">…items…items…</div></div>
   The track content must be duplicated exactly once; the keyframe travels
   -50% so the seam is invisible. motion.js rewrites --m-marquee-dur so the
   speed is a constant 50 px/s no matter how wide the track is.
   Attribute value overrides the speed, e.g. data-motion-marquee="80".
   -------------------------------------------------------------------------- */

[data-motion-marquee] {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 12.5%, #000 87.5%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, #000 12.5%, #000 87.5%, transparent 100%);
}

[data-motion-marquee] > * {
  width: max-content;
  animation: motion-marquee var(--m-marquee-dur, 40s) linear infinite;
}

@keyframes motion-marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* --------------------------------------------------------------------------
   Hover / focus
   --------------------------------------------------------------------------
   Scoped to the sections that have been migrated. When another agent applies
   the vocabulary to a further section, add its root class to these selectors.
   -------------------------------------------------------------------------- */

.sec-header .btn,
.sec-hero .btn {
  transition:
    background-color var(--motion-hover) var(--motion-ease),
    border-color var(--motion-hover) var(--motion-ease),
    color var(--motion-hover) var(--motion-ease);
}

.sec-hero .btn--primary:hover,
.sec-hero .btn--primary:focus-visible {
  background: var(--color-accent-hover);
}

.sec-hero .btn--outline:hover,
.sec-hero .btn--outline:focus-visible {
  background: var(--color-white);
}

.sec-header__cta:hover,
.sec-header__cta:focus-visible {
  border-color: rgba(91, 91, 91, 0.45);
}

/* Nav link underline: sweeps in from the left, exactly as the reference does.
   Absolutely positioned, so it can never move the header layout. */
.sec-header__link {
  position: relative;
}

.sec-header__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2px;
  height: 2px;
  border-radius: 2px;
  background: var(--color-accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--motion-hover-slow) var(--motion-ease);
}

.sec-header__link:hover::after,
.sec-header__link:focus-visible::after {
  transform: scaleX(1);
}

/* Hero badge links -- the same vocabulary as the nav links: colour fade to the
   accent (400ms) plus a left-anchored underline wipe (500ms). The underline is
   an absolutely positioned pseudo-element and the focus ring is an `outline`,
   so neither can move the pill, whose geometry is Figma-QA'd to the pixel. */
.sec-hero__badge-link {
  position: relative;
  border-radius: 4px; /* shapes the focus ring only -- no background, no border */
  transition: color var(--motion-hover) var(--motion-ease);
}

.sec-hero__badge-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2px;
  height: 2px;
  border-radius: 2px;
  background: var(--color-accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--motion-hover-slow) var(--motion-ease);
}

.sec-hero__badge-link:hover,
.sec-hero__badge-link:focus-visible {
  color: var(--color-accent);
}

.sec-hero__badge-link:hover::after,
.sec-hero__badge-link:focus-visible::after {
  transform: scaleX(1);
}

.sec-hero__badge-link:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

/* Phones: the pill is only ~31px tall and the type drops to ~11px, so pull the
   ring and the underline in -- otherwise the ring fouls the pill edge and the
   underline crowds the descenders. */
@media (max-width: 560px) {
  .sec-hero__badge-link::after {
    bottom: 1px;
    height: 1.5px;
  }

  .sec-hero__badge-link:focus-visible {
    outline-width: 1.5px;
    outline-offset: 2px;
  }
}

/* --------------------------------------------------------------------------
   Reduced motion
   --------------------------------------------------------------------------
   Note the deliberate absence of a blanket `transform: none !important` --
   that would wipe out layout transforms such as the 390px
   `.sec-hero__mockup { transform: translateX(-50%) scale(0.5) }`. Only the
   properties this file sets are reset.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .js-motion [data-motion] {
    opacity: 1;
    transition: none;
  }

  .js-motion [data-motion="fade-up"]:not([data-motion-prop]),
  .js-motion [data-motion="zoom-in"]:not([data-motion-prop]) {
    transform: none;
  }

  .js-motion [data-motion][data-motion-prop="translate"] {
    translate: none;
    scale: none;
  }

  [data-motion-marquee] > * {
    animation: none;
  }

  /* Hover feedback stays (it is state, not motion); it just arrives instantly. */
  .sec-header .btn,
  .sec-hero .btn,
  .sec-header__link::after,
  .sec-hero__badge-link,
  .sec-hero__badge-link::after {
    transition: none;
  }
}
