/**
 * Motion layer.
 *
 * Loaded last so it can animate the finished design without specificity fights.
 *
 * Two rules govern everything here:
 *
 * 1. Nothing is hidden until JavaScript confirms it can animate. The hidden
 *    states live behind `html.tm-anim-ready`, which `animations.js` adds only
 *    after it has wired the observer. If the script is blocked, throws, or the
 *    visitor prefers reduced motion, the class is never added and every element
 *    renders in its final state. Authoring these rules unscoped would hide the
 *    whole page behind a script.
 *
 * 2. Only `transform` and `opacity` are animated. Both are compositor-only, so
 *    reveals stay off the main thread and cause no layout shift.
 *
 * @package TrendMix
 */

/* ==========================================================================
   1. KEYFRAMES
   ========================================================================== */

@keyframes tm-fade-up {
  from { opacity: 0; transform: translate3d(0, 18px, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes tm-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes tm-scale-in {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: none; }
}

/* Start/end are driven by a custom property so the travel direction follows the
   document: in RTL the start edge is the right, so the offset is positive. */
@keyframes tm-slide-start {
  from { opacity: 0; transform: translate3d(var(--tm-from, 34px), 0, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes tm-slide-end {
  from { opacity: 0; transform: translate3d(calc(var(--tm-from, 34px) * -1), 0, 0); }
  to   { opacity: 1; transform: none; }
}

/*
 * The overshoot is what makes an item look like it pounces into place rather
 * than sliding. A back-out curve on the transform alone is enough; a scale
 * change on top of it reads as a bounce too eagerly at these distances.
 */
@keyframes tm-pounce {
  from { opacity: 0; transform: translate3d(var(--tm-from, 34px), 0, 0); }
  to   { opacity: 1; transform: none; }
}

:root {
  --tm-from: 34px;
}

[dir="ltr"] {
  --tm-from: -34px;
}

@keyframes tm-float {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -7px, 0); }
}

/* A slow sheen for accent rules and dividers. */
@keyframes tm-sheen {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

@keyframes tm-pulse-ring {
  0%   { box-shadow: 0 0 0 0 rgba(var(--ui-primary-rgb), 0.35); }
  70%  { box-shadow: 0 0 0 12px rgba(var(--ui-primary-rgb), 0); }
  100% { box-shadow: 0 0 0 0 rgba(var(--ui-primary-rgb), 0); }
}

/* ==========================================================================
   2. REVEAL SYSTEM

   `animations.js` assigns these attributes to structural blocks, so pages gain
   motion without every template being edited. Items travel in from the side
   they sit on and overshoot slightly on the way to rest, which reads as a
   pounce rather than a slide. Templates can also set them by hand:

   `<div data-tm-anim="slide-start" style="--tm-anim-delay: 120ms">`
   ========================================================================== */

:root {
  /* Back-out: leaves fast, overshoots, settles. */
  --tm-anim-ease: cubic-bezier(0.34, 1.42, 0.52, 1);
  --tm-anim-dur: 660ms;
}

.tm-anim-ready [data-tm-anim] {
  opacity: 0;
  transition:
    opacity var(--tm-anim-dur) var(--tm-anim-ease) var(--tm-anim-delay, 0ms),
    transform var(--tm-anim-dur) var(--tm-anim-ease) var(--tm-anim-delay, 0ms);
  will-change: opacity, transform;
}

.tm-anim-ready [data-tm-anim="fade-up"]  { transform: translate3d(0, 26px, 0); }
.tm-anim-ready [data-tm-anim="fade-in"]  { transform: none; }
.tm-anim-ready [data-tm-anim="scale-in"] { transform: scale(0.94); }

.tm-anim-ready [data-tm-anim="slide-start"],
.tm-anim-ready [data-tm-anim="slide-end"],
.tm-anim-ready [data-tm-anim="pounce"] {
  transform: translate3d(var(--tm-from, 34px), 0, 0);
}

.tm-anim-ready [data-tm-anim].is-animated {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/*
 * Staggered children: `animations.js` only sets --tm-anim-delay, so the number
 * of steps stays fixed and a long grid reuses the last value instead of
 * drifting arbitrarily far behind.
 */
.tm-anim-stagger > * {
  transition-delay: var(--tm-anim-delay, 0ms);
}

/* ==========================================================================
   3. PAGE LOAD

   The hero is above the fold, so it is animated on load rather than on scroll
   and gets a shorter distance — a large travel reads as a loading glitch when
   the content is already on screen.
   ========================================================================== */

.tm-anim-ready .tm-anim-hero > * {
  animation: tm-fade-up 640ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
  animation-delay: var(--tm-anim-delay, 0ms);
}

.tm-anim-ready .tm-anim-hero-fade > * {
  animation: tm-fade-in 760ms ease-out both;
  animation-delay: var(--tm-anim-delay, 0ms);
}

/* ==========================================================================
   4. HOVER MICRO-INTERACTIONS

   Opt-in only. These are not applied automatically: reveals already touch every
   structural block on the page, and a hover state on all of them turned the
   whole site into a field of moving boxes. A template adds `tm-anim-lift` to a
   specific interactive card to opt it in.

   Scoped to devices that actually hover, so the lift is not left behind on
   touch after a tap.
   ========================================================================== */

@media (hover: hover) and (pointer: fine) {
  .tm-anim-lift {
    transition:
      transform var(--pf-dur, 220ms) var(--pf-ease, ease),
      box-shadow var(--pf-dur, 220ms) var(--pf-ease, ease),
      border-color var(--pf-dur, 220ms) var(--pf-ease, ease);
  }

  .tm-anim-lift:hover {
    transform: translate3d(0, -5px, 0);
    box-shadow: var(--ui-elev-4, 0 12px 28px rgba(31, 20, 22, 0.14));
  }

  /* Links sweep an underline in from the inline start edge. */
  .tm-anim-underline {
    position: relative;
    text-decoration: none;
  }

  .tm-anim-underline::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    inset-block-end: -2px;
    height: 1.5px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: inline-start;
    transition: transform var(--pf-dur, 220ms) var(--pf-ease, ease);
  }

  .tm-anim-underline:hover::after,
  .tm-anim-underline:focus-visible::after {
    transform: scaleX(1);
  }
}

/* ==========================================================================
   5. AMBIENT

   Decorative loops. These run only once the element has been seen, so nothing
   animates off screen, and they stop entirely under reduced motion.
   ========================================================================== */

.tm-anim-float {
  animation: tm-float 5.5s ease-in-out infinite;
}

.tm-anim-sheen {
  transform-origin: inline-start;
  animation: tm-sheen 900ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

.tm-anim-pulse {
  animation: tm-pulse-ring 2.4s ease-out infinite;
}

/* ==========================================================================
   6. REDUCED MOTION

   `animations.js` bails out early for these visitors, so no reveal is ever
   withheld. This block covers the ambient loops and hover lifts, which would
   otherwise keep moving regardless of what the script decided.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .tm-anim-float,
  .tm-anim-sheen,
  .tm-anim-pulse,
  .tm-anim-ready .tm-anim-hero > *,
  .tm-anim-ready .tm-anim-hero-fade > * {
    animation: none !important;
  }

  .tm-anim-ready [data-tm-anim] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  .tm-anim-lift,
  .tm-anim-lift:hover {
    transform: none !important;
    transition: none !important;
  }

  .tm-anim-underline::after {
    display: none;
  }

  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
  }
}
