/* =============================================================================
   UR Invited — Motion Design System
   motion-tokens.css  v1.0.0
   =============================================================================
   Single source of truth for every animation decision across cielito-lindo-v2,
   cielito-cinema, hundred-acre-wood, and the marketing site.

   HOW TO USE:
     1. <link rel="stylesheet" href="/motion-tokens.css"> once, early in <head>.
     2. Consume tokens in component CSS:  animation-duration: var(--uv-dur-l);
     3. Add utility classes directly in HTML:  class="uv-anim-fade-up uv-delay-2"
     4. For scroll-driven entry:  class="uv-reveal"  +  load reveal-on-scroll.js
        The JS adds .uv-in-view when the element crosses the viewport threshold;
        entry animations fire only then (keeps page load clean, no flash-of-motion).
   ============================================================================= */


/* =============================================================================
   §1  DURATION TOKENS
   -----------------------------------------------------------------------------
   Rhythm is perception. Too fast feels cheap; too slow feels broken.
   Pick a tier based on how much spatial/contextual change the motion carries.
   ============================================================================= */

:root {

  /* 120ms — Instant, sub-perceptual.
     Use for hover/press state feedback: button backgrounds, icon color shifts,
     checkbox toggles, link underlines. Anything that confirms "I heard you." */
  --uv-dur-xs: 120ms;

  /* 200ms — Snappy and responsive.
     Use for hover/press feedback with slight movement: pill scale, small badge pop,
     tooltip appear, chip selection. Still feels instant, just slightly more tactile. */
  --uv-dur-s: 200ms;

  /* 320ms — In-place state change.
     Use for content that swaps without leaving the screen: accordion open/close,
     tab panel crossfade, chip group reorder, color-palette swap, error message
     appearing in a form. The eye registers "something changed here." */
  --uv-dur-m: 320ms;

  /* 520ms — Scene entry / exit.
     The primary duration for elements entering or leaving the viewport on scroll.
     Fade-up text blocks, illustration slides, card reveals. Long enough to feel
     deliberate, short enough that it never delays the reader. */
  --uv-dur-l: 520ms;

  /* 820ms — Hero entrances and significant transitions.
     Use for the opening scene of a template, envelope opening choreography,
     page-level route transitions, the paper-letter slide-up. The motion carries
     *narrative* weight — it deserves a little stage time. */
  --uv-dur-xl: 820ms;

  /* 1400ms — Cinematic reveal.
     Reserve for the one or two crown-jewel moments per template: papel-picado
     burst after seal breaks, the full cover-title stagger, dramatic parallax
     entrance on the hero spread. Never use more than twice per screen load. */
  --uv-dur-2xl: 1400ms;


/* =============================================================================
   §2  EASING TOKENS
   -----------------------------------------------------------------------------
   Every easing curve has a personality. Match the curve to the emotion.
   All curves start with CSS cubic-bezier(x1,y1,x2,y2).
   ============================================================================= */

  /* Standard decelerate. Objects entering the screen from offscreen or fading in.
     They arrive quickly then settle. The default choice for 90% of entry animation. */
  --uv-ease-out: cubic-bezier(.2, .7, .2, 1);

  /* Standard accelerate. Objects leaving the screen: they linger, then vanish.
     Use on exit keyframes (opacity: 0 at 100%) and on-hide transitions. */
  --uv-ease-in: cubic-bezier(.7, 0, .84, 0);

  /* Symmetric. Elements that both enter and exit symmetrically (shared-axis
     transitions, sliding drawers, tab-to-tab panel swaps). */
  --uv-ease-inout: cubic-bezier(.65, 0, .35, 1);

  /* Material-style soft curve. Calm, confident.
     Use for any ambient idle animation (cloud drift, bunting sway, floating
     illustration), gentle hover lifts on cards, and most UI micro-interactions
     where you want refinement without drama. */
  --uv-ease-soft: cubic-bezier(.4, .0, .2, 1);

  /* Spring — slight overshoot then settle.
     Use for confirmation moments: a badge count incrementing, the RSVP submit
     success icon, a heart ❤ toggle, a notification pill appearing. Makes the UI
     feel alive and responsive. Never use on full-screen transitions. */
  --uv-ease-spring: cubic-bezier(.34, 1.56, .64, 1);

  /* Emphasized deceleration — the big-moment curve.
     Inspired by Material You's "emphasized" easing. Fast start, long tail.
     Use for hero title reveals, envelope-open letter slide, scene-to-scene
     transitions, anything where you want the viewer to feel a deliberate arrival. */
  --uv-ease-emphasized: cubic-bezier(.22, 1, .36, 1);


/* =============================================================================
   §3  DISTANCE TOKENS
   -----------------------------------------------------------------------------
   Translation offsets for entering/exiting elements.
   Smaller elements move smaller distances; heroes move further to feel weightier.
   ============================================================================= */

  /* 4px — Micro-lift. Button press feedback, tooltip nudge. */
  --uv-dist-xs: 4px;

  /* 8px — Small step. Chip badge pop, label shift, inline status change. */
  --uv-dist-s: 8px;

  /* 16px — Standard body entry. Paragraphs, list items, small cards. */
  --uv-dist-m: 16px;

  /* 28px — Mid-weight entry. Section headings, medium illustrations, date ribbons. */
  --uv-dist-l: 28px;

  /* 48px — Hero / feature entry. Full-width banners, envelope animations,
     large illustration reveals, cover-title lines entering from below. */
  --uv-dist-xl: 48px;


/* =============================================================================
   §4  STAGGER TOKENS
   -----------------------------------------------------------------------------
   When multiple sibling elements animate in sequence, stagger their delays so
   they cascade rather than fire all at once. The JS reveal script reads these
   via data-uv-delay="1..6" and applies them as animation-delay offsets.
   ============================================================================= */

  /* 60ms — Tight stagger. Use for dense lists, icon rows, small badge groups
     where items are visually close and you want a rapid ripple. */
  --uv-stagger-tight: 60ms;

  /* 90ms — Normal stagger. The default for most cascades: paragraphs within
     a section, signpost arrows, registry store rows, RSVP field labels. */
  --uv-stagger-normal: 90ms;

  /* 140ms — Loose stagger. Use when elements are well-separated or large:
     full-scene illustrations, hero-spread text lines, scene-level reveals
     where each beat deserves its own breath. */
  --uv-stagger-loose: 140ms;

} /* end :root */


/* =============================================================================
   §5  @KEYFRAMES
   -----------------------------------------------------------------------------
   All keyframes are prefixed uv- to avoid collisions with any template CSS.
   Keyframes only define the motion geometry; duration/easing/delay live in the
   utility classes below so they can be overridden per-context with tokens.
   ============================================================================= */

/* --- Entry frames (used with .uv-anim-* and .uv-reveal + .uv-in-view) ------- */

/* Plain opacity fade. No translate. Good for overlays, text crossfades,
   palette-swap reveals, and any element where position is irrelevant. */
@keyframes uv-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* The workhorse: fade while rising from below.
   Use for body copy, cards, illustrations entering from the bottom of their
   natural position. The most common entry animation on the site. */
@keyframes uv-fade-up {
  from { opacity: 0; transform: translateY(var(--uv-dist-l)); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Fade while descending from above. Use for dropdown menus, notification banners,
   header elements that "land" into place on page load. */
@keyframes uv-fade-down {
  from { opacity: 0; transform: translateY(calc(-1 * var(--uv-dist-l))); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Fade in from the left. Use for signpost arrows pointing left, left-aligned
   scene decorations, left-to-right reading-order reveals. */
@keyframes uv-fade-left {
  from { opacity: 0; transform: translateX(calc(-1 * var(--uv-dist-l))); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Fade in from the right. Use for signpost arrows pointing right, right-aligned
   illustrations, slide-in panels from the right edge. */
@keyframes uv-fade-right {
  from { opacity: 0; transform: translateX(var(--uv-dist-l)); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Scale up from slightly smaller. Clean, modern entry for cards, badge pops,
   modal appearances. Pairs well with --uv-ease-spring for confirmation moments. */
@keyframes uv-scale-in {
  from { opacity: 0; transform: scale(0.88); }
  to   { opacity: 1; transform: scale(1); }
}

/* Overshoot scale — the "ta-da" moment.
   RSVP success, purchase confirmation, badge unlock, heart toggle. Keep the
   element small (< 80px) for best effect; large elements feel violent. */
@keyframes uv-pop {
  0%   { opacity: 0; transform: scale(0.72); }
  60%  { opacity: 1; transform: scale(1.12); }
  80%  {             transform: scale(0.96); }
  100% {             transform: scale(1);    }
}


/* --- Ambient / idle frames (looping) ----------------------------------------- */

/* Slow, gentle pulse — for elements that need to signal "alive" without
   distracting from content. Use on the seal before the envelope opens,
   the RSVP submit button before it's been tapped. */
@keyframes uv-breathe {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%       { transform: scale(1.04); opacity: 0.88; }
}

/* Vertical oscillation — for cloud-like elements, baby illustrations,
   decorative props that should feel weightless. Keep amplitude small. */
@keyframes uv-float {
  0%, 100% { transform: translateY(0); }
  50%       { transform: translateY(calc(-1 * var(--uv-dist-s))); }
}

/* Gentle left-right rotation — for bunting, papel-picado flags, signpost
   arrows on idle, hanging decorations. Origin should be set to top center
   in the consumer CSS: transform-origin: top center; */
@keyframes uv-sway {
  0%, 100% { transform: rotate(-2.5deg); }
  50%       { transform: rotate( 2.5deg); }
}

/* Shimmer / sweep — for loading skeletons, subtle "premium" glow on
   the gold accent (#c89a4a), or a soft highlight sweep on hover over
   the envelope or a card. Use via background-position animation. */
@keyframes uv-shimmer {
  0%   { background-position: -200% center; }
  100% { background-position:  200% center; }
}


/* =============================================================================
   §6  UTILITY CLASSES
   -----------------------------------------------------------------------------
   Drop these directly in HTML or compose them in template CSS.
   Every property references a token — never a hard-coded value.

   Entry animations (.uv-anim-*) are paused by default when used standalone.
   When paired with the .uv-reveal + .uv-in-view scroll pattern, the JS adds
   .uv-in-view which triggers the animation via the animation-play-state trick
   (see §7 for reveal scaffolding).

   If you need an element to animate on load without scroll detection, simply
   add both the utility class AND ensure the element is not also a .uv-reveal.
   ============================================================================= */

/* Fade up — primary scroll-entry for body content */
.uv-anim-fade-up {
  animation-name: uv-fade-up;
  animation-duration: var(--uv-dur-l);         /* 520ms — scene entry */
  animation-timing-function: var(--uv-ease-out);
  animation-fill-mode: both;
}

/* Plain fade — for overlays, crossfades, palette transitions */
.uv-anim-fade-in {
  animation-name: uv-fade-in;
  animation-duration: var(--uv-dur-l);
  animation-timing-function: var(--uv-ease-out);
  animation-fill-mode: both;
}

/* Scale in — cards, modals, dialog elements */
.uv-anim-scale-in {
  animation-name: uv-scale-in;
  animation-duration: var(--uv-dur-l);
  animation-timing-function: var(--uv-ease-emphasized);
  animation-fill-mode: both;
}

/* Pop — confirmation / success moments */
.uv-anim-pop {
  animation-name: uv-pop;
  animation-duration: var(--uv-dur-m);         /* 320ms — feels instant but satisfying */
  animation-timing-function: var(--uv-ease-spring);
  animation-fill-mode: both;
}

/* Breathe — looping ambient pulse (seal, CTA button before first tap) */
.uv-anim-breathe {
  animation-name: uv-breathe;
  animation-duration: var(--uv-dur-2xl);       /* 1400ms per breath cycle */
  animation-timing-function: var(--uv-ease-soft);
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

/* Float — looping vertical bob (clouds, baby illustrations, decorative props) */
.uv-anim-float {
  animation-name: uv-float;
  animation-duration: 3200ms;                  /* Not a standard token: ambient timing
                                                  lives outside the entry-exit system */
  animation-timing-function: var(--uv-ease-soft);
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

/* Sway — looping rotation (bunting, papel picado, signpost arrows on idle)
   Always set transform-origin: top center in the component layer. */
.uv-anim-sway {
  animation-name: uv-sway;
  animation-duration: 4800ms;
  animation-timing-function: var(--uv-ease-soft);
  animation-iteration-count: infinite;
  animation-direction: alternate;
}


/* =============================================================================
   §6b  STAGGER DELAY MODIFIERS
   -----------------------------------------------------------------------------
   Apply .uv-delay-1 through .uv-delay-6 to stagger sibling elements.
   Designed for use with --uv-stagger-normal (90ms) by default.
   The JS reveal-on-scroll.js also reads data-uv-delay="N" and maps to these.

   Example in HTML:
     <p class="uv-reveal uv-anim-fade-up uv-delay-1">Line one</p>
     <p class="uv-reveal uv-anim-fade-up uv-delay-2">Line two</p>
     <p class="uv-reveal uv-anim-fade-up uv-delay-3">Line three</p>
   ============================================================================= */

.uv-delay-1 { animation-delay: calc(1 * var(--uv-stagger-normal)); }   /*  90ms */
.uv-delay-2 { animation-delay: calc(2 * var(--uv-stagger-normal)); }   /* 180ms */
.uv-delay-3 { animation-delay: calc(3 * var(--uv-stagger-normal)); }   /* 270ms */
.uv-delay-4 { animation-delay: calc(4 * var(--uv-stagger-normal)); }   /* 360ms */
.uv-delay-5 { animation-delay: calc(5 * var(--uv-stagger-normal)); }   /* 450ms */
.uv-delay-6 { animation-delay: calc(6 * var(--uv-stagger-normal)); }   /* 540ms */


/* =============================================================================
   §7  SCROLL-REVEAL SCAFFOLDING
   -----------------------------------------------------------------------------
   Elements tagged .uv-reveal start invisible. The IntersectionObserver in
   reveal-on-scroll.js adds .uv-in-view once the element crosses the threshold.
   The animation is then triggered via animation-play-state.

   This means animations NEVER fire on load for off-screen elements, which:
     (a) prevents a flash-of-motion on fast scrolls,
     (b) keeps above-the-fold paint clean,
     (c) allows accurate first-contentful-paint measurement.
   ============================================================================= */

/* Initial hidden state — set before JS runs so no FOUC */
.uv-reveal {
  opacity: 0;
  /* animation-play-state is paused until .uv-in-view is added */
  animation-play-state: paused;
}

/* JS adds this class when the element enters the viewport */
.uv-reveal.uv-in-view {
  animation-play-state: running;
}

/* Ensure the element is visible even if animation somehow never fires
   (e.g., JS disabled, very fast scroll to bottom of page) */
.uv-reveal.uv-in-view:not([class*="uv-anim-"]) {
  opacity: 1;
}


/* =============================================================================
   §8  PREFERS-REDUCED-MOTION
   -----------------------------------------------------------------------------
   Users who opt into reduced motion have vestibular disorders, epilepsy, or
   simply strong preferences. We NEVER fight that preference.

   Strategy:
     — All looping ambient animations (breathe, float, sway, shimmer) are
       completely disabled. Static is fine; perpetual motion is not.
     — All entry animations are replaced with a simple opacity fade
       (0 → 1, no translate, no scale). Motion is gone; content still reveals.
     — Stagger delays are preserved at 50% value so sequencing still reads.
     — JS reveal-on-scroll.js also reads prefers-reduced-motion and immediately
       marks elements .uv-in-view (no threshold wait) so content is never hidden.
   ============================================================================= */

@media (prefers-reduced-motion: reduce) {

  /* Neutralize all custom animation keyframes — replace with a plain fade.
     The !important here is intentional: we must win over inline styles and
     any component-level animation declarations. */
  .uv-anim-fade-up,
  .uv-anim-fade-in,
  .uv-anim-scale-in,
  .uv-anim-pop {
    animation-name: uv-fade-in !important;    /* opacity 0→1, no spatial motion */
    animation-duration: var(--uv-dur-m) !important;  /* 320ms — still perceptible */
    animation-timing-function: ease !important;
    animation-delay: 0ms !important;          /* No stagger delays under reduced motion */
  }

  /* Completely stop all looping/ambient animations. Static is the correct
     resting state for users who need it. */
  .uv-anim-breathe,
  .uv-anim-float,
  .uv-anim-sway {
    animation: none !important;
    /* Restore visibility — looping animations don't use fill-mode: both,
       so without animation the element would render at its natural state. */
    opacity: 1 !important;
    transform: none !important;
  }

  /* Shimmer is purely decorative — disable it entirely */
  .uv-shimmer-target {
    animation: none !important;
    background-image: none !important;
  }

  /* Stagger delays: collapse to 0 so content doesn't feel withheld */
  .uv-delay-1, .uv-delay-2, .uv-delay-3,
  .uv-delay-4, .uv-delay-5, .uv-delay-6 {
    animation-delay: 0ms !important;
  }

  /* Reveal elements: make immediately visible — JS also does this,
     but CSS is the safety net when JS is slow or absent */
  .uv-reveal {
    opacity: 1 !important;
    animation: none !important;
  }

  /* Global catch-all: ensure no transition exceeds 0.2s for anything not
     caught above. This complements base.css which already sets 0.01ms on
     *, but scopes it to our motion system specifically for clarity. */
  .uv-anim-fade-up *,
  .uv-anim-fade-in *,
  .uv-anim-scale-in *,
  .uv-anim-pop * {
    transition-duration: 0.01ms !important;
  }

}


/* =============================================================================
   §9  SHIMMER UTILITY (bonus — for premium glows and loading states)
   -----------------------------------------------------------------------------
   Apply .uv-shimmer to any element you want to sweep a highlight across.
   Set the background in the component; this class drives the animation timing.

   Example component usage:
     .envelope-seal.uv-shimmer {
       background: linear-gradient(
         105deg,
         var(--uv-gold) 20%, #fff6 50%, var(--uv-gold) 80%
       ) 200% center / 200% auto no-repeat;
     }
   ============================================================================= */

.uv-shimmer {
  animation-name: uv-shimmer;
  animation-duration: 2400ms;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}


/* =============================================================================
   §10  BRAND COLOR REFERENCE (read-only, do not override here)
   -----------------------------------------------------------------------------
   These are the UR Invited palette values — referenced in comments throughout
   this file and available to any template that imports motion-tokens.css.
   They live here as documentation; canonical color tokens are in palettes.css.

   Cream   #f7f1e6   — primary background
   Navy    #1d2438   — primary text
   Gold    #c89a4a   — accent (CTAs, highlights, shimmer, seal)
   Sky     #aac6e6   — accent (secondary, boy-palette sky tones)
   ============================================================================= */
