/* ==========================================================================
   Alma Caleña · protótipo — motion
   --------------------------------------------------------------------------
   Follows Proscenium's motion dial (frozen.md; static/css/input.css, P12-H):

   1. Everything that moves is inside @media (prefers-reduced-motion:
      no-preference). A visitor who asked for less motion gets the still page.
   2. Everything that moves is also under body:not([data-motion="none"]);
      "none" is the instant page.
   3. What goes beyond the platform's cross-fade (a rise, a slide, a stagger,
      the stamp drops, the float, the hover lifts, the menu's circle) is drawn
      under body[data-motion="lively"]. "calm" (attribute absent) only sets the
      pace: --reveal-ms and --reveal-rise; its reveals are the platform's fade
      with an 8 px rise, all together.
   4. Content is visible without JavaScript: [data-reveal] is hidden only under
      html.js-motion, which motion.js adds. No script, no hiding.

   Opt-in API for pages (see the summary in index.html's head comment):
     data-reveal                 fade + rise (default)
     data-reveal="fade|left|right|pop|title|stamp|postmark|postcard|slab|sun|ticket"
     data-reveal="drop"          a photo/word stamp falls onto a card and squashes as it lands
     data-thump                  on a data-reveal="postcard": the card jolts when a stamp lands
                                 on it, at --thump-k x its own delay + --thump-c (defaults 1, 640ms)
     data-float                  the composition breathes after its entrance (lively)
     data-halo                   a sun whose ::before ring breathes (lively)
     data-delay="300"            fixed delay in ms (lively only), skips the batch stagger
     style="--i:2"               fixed stagger slot (otherwise: order within the batch)
     .lift                       hover lift on any card-like block (lively)
   motion.js drops the fixed delays inside the URL fragment's target, so the
   destination of a link (aulas.html#reservar) is never empty on arrival.
   The individual transform properties (translate, rotate, scale) carry every
   movement, so the components' own tilts (transform: rotate(...)) are kept.
   ========================================================================== */

/* Groups inside an inline SVG (the map) move around their own box. */
svg [data-reveal]{transform-box:fill-box;transform-origin:50% 50%}

/* Stillness by default for view-transition pseudo-elements (the platform's rule). */
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*){animation:none}

@media print{
  [data-reveal]{opacity:1!important;animation:none!important}
}

@media (prefers-reduced-motion: no-preference){

  /* Page to page: the document-level opt-in (inert without the gated animations). */
  @view-transition{navigation:auto}

  /* ---- Pace ---------------------------------------------------------------- */
  body:not([data-motion="none"]){
    --reveal-ms:340ms;      /* calm: the platform's pace, a touch softer */
    --reveal-rise:8px;
    --stagger:0ms;
    --choreo:0;             /* fixed delays (data-delay) only count when lively */
  }
  body[data-motion="lively"]{
    --reveal-ms:760ms;
    --reveal-rise:28px;
    --stagger:85ms;
    --choreo:1;
  }

  /* ---- Reveals --------------------------------------------------------------
     Hidden until revealed, only while motion.js runs the show. */
  html.js-motion body:not([data-motion="none"]) [data-reveal]:not(.is-in){opacity:0}

  /* calm and lively: fade + rise by --reveal-rise; lively staggers by batch. */
  body:not([data-motion="none"]) [data-reveal].is-in{
    animation:m-rise var(--reveal-ms) var(--ease-out) backwards;
    animation-delay:calc(var(--i,0) * var(--stagger) + var(--d,0ms) * var(--choreo));
  }

  /* lively: named entrances */
  body[data-motion="lively"] [data-reveal="fade"].is-in{animation-name:m-fade}
  body[data-motion="lively"] [data-reveal="left"].is-in{animation-name:m-left}
  body[data-motion="lively"] [data-reveal="right"].is-in{animation-name:m-right}
  body[data-motion="lively"] [data-reveal="pop"].is-in{animation-name:m-pop;animation-timing-function:var(--ease-back)}
  body[data-motion="lively"] [data-reveal="title"].is-in{animation-name:m-title;animation-duration:calc(var(--reveal-ms) * 1.1)}
  body[data-motion="lively"] [data-reveal="stamp"].is-in{animation-name:m-stamp;animation-duration:680ms;animation-timing-function:cubic-bezier(.3,.7,.3,1)}
  body[data-motion="lively"] [data-reveal="postmark"].is-in{animation-name:m-postmark;animation-duration:420ms;animation-timing-function:cubic-bezier(.2,.9,.3,1)}
  body[data-motion="lively"] [data-reveal="postcard"].is-in{animation-name:m-postcard;animation-duration:900ms}
  body[data-motion="lively"] [data-reveal="slab"].is-in{animation-name:m-slab;animation-duration:620ms;animation-timing-function:var(--ease-io)}
  body[data-motion="lively"] [data-reveal="sun"].is-in{animation-name:m-sun;animation-duration:1100ms;animation-timing-function:var(--ease-back)}
  body[data-motion="lively"] [data-reveal="ticket"].is-in{animation-name:m-ticket;animation-duration:820ms}

  /* ---- A stamp drops onto a card (any page) ------------------------------------
     data-reveal="drop": falls, then squashes as it lands at --d + 640 ms.
     data-thump on the card: jolts when the stamp lands. Every delay derives from
     the element's own --d, so a late reveal (motion.js scales --d) stays in sync. */
  body[data-motion="lively"] [data-reveal="drop"].is-in{
    animation:m-drop 640ms cubic-bezier(.45,0,.75,.35) backwards, m-squash 300ms ease-out;
    animation-delay:var(--d,0ms), calc(var(--d,0ms) + 640ms);
  }
  body[data-motion="lively"] [data-reveal="postcard"][data-thump].is-in{
    animation:m-postcard 900ms var(--ease-out) backwards, m-thump 340ms ease-out;
    animation-delay:var(--d,0ms), calc(var(--d,0ms) * var(--thump-k,1) + var(--thump-c,640ms));
  }

  /* ---- Home hero: one choreography (lively) ---------------------------------
     sun rises → headline → slab wipes → postcard drops → the 13B stamp lands on
     its corner (stamp --d 660 → lands at 1300), the postcard takes the "thump"
     (1330 = 300 x 2.2 + 670), the postmark strikes (--d + 700 = 1360) → ticket. */
  .hero-art .postcard{--thump-k:2.2;--thump-c:670ms}
  body[data-motion="lively"] .hero-stamp.is-in svg{animation:m-postmark 380ms cubic-bezier(.2,.9,.3,1) backwards;animation-delay:calc(var(--d,0ms) + 700ms)}
  /* after the entrance, the whole composition breathes */
  body[data-motion="lively"] .hero-art{animation:m-float 7s ease-in-out 2.4s infinite alternate}
  body[data-motion="lively"] .hero-art .sun::before{animation:m-halo 5.5s ease-in-out 2.4s infinite alternate}
  /* the same breath for the inner pages' hero art and suns */
  body[data-motion="lively"] [data-float]{animation:m-float 7s ease-in-out 2.6s infinite alternate}
  body[data-motion="lively"] :is([data-halo],.page-hero-sun)::before{animation:m-halo 5.5s ease-in-out 2.4s infinite alternate}

  /* the "em breve" dot keeps a slow pulse: something is on its way. The ring is a
     pseudo-element that scales and fades (no repaint of a box-shadow per frame). */
  body[data-motion="lively"] .soon i::after{content:"";position:absolute;inset:0;border-radius:50%;background:inherit;animation:m-pulse 2.4s ease-out infinite}

  /* ---- Questions that open (.qa details): a soft height, where ::details-content exists */
  body[data-motion="lively"] .qa{interpolate-size:allow-keywords}
  body[data-motion="lively"] .qa details::details-content{height:0;overflow:clip;transition:height .42s var(--ease-out),content-visibility .42s allow-discrete}
  body[data-motion="lively"] .qa details[open]::details-content{height:auto}
  body[data-motion="lively"] .qa summary::after{transition:transform .38s var(--ease-back)}

  /* ---- Header ---------------------------------------------------------------- */
  body:not([data-motion="none"]) .site-head{transition:box-shadow .3s}
  body:not([data-motion="none"]) .head-bar{transition:height .35s var(--ease-out)}
  body:not([data-motion="none"]) .logo img{transition:height .35s var(--ease-out)}
  body[data-motion="lively"] .nav-links a::after{transition:transform .35s var(--ease-out)}
  body:not([data-motion="none"]) .menu-btn i{transition:top .25s var(--ease-out),transform .3s var(--ease-out),opacity .2s}

  /* ---- Mobile menu ----------------------------------------------------------- */
  @media (max-width:1199.98px){
    /* calm: a cross-fade */
    body:not([data-motion="none"]) .nav{transition:opacity .25s ease,visibility 0s linear .25s}
    html.menu-open body:not([data-motion="none"]) .nav{transition:opacity .25s ease,visibility 0s}
    /* lively: the panel opens as a circle from the menu button; the links rise in turn */
    html.js body[data-motion="lively"] .nav{opacity:1;clip-path:circle(0 at var(--mx,92%) var(--my,0));transition:clip-path .5s var(--ease-io),visibility 0s linear .5s}
    html.js.menu-open body[data-motion="lively"] .nav{clip-path:circle(150vmax at var(--mx,92%) var(--my,0));transition:clip-path .65s var(--ease-io),visibility 0s}
    html.js body[data-motion="lively"] .nav-links li,
    html.js body[data-motion="lively"] .nav-extra{opacity:0;translate:0 26px;transition:opacity .2s,translate .2s}
    html.js.menu-open body[data-motion="lively"] .nav-links li,
    html.js.menu-open body[data-motion="lively"] .nav-extra{opacity:1;translate:0 0;transition:opacity .45s var(--ease-out) calc(140ms + var(--n,0) * 45ms),translate .6s var(--ease-out) calc(140ms + var(--n,0) * 45ms)}
    .nav-links li:nth-child(1){--n:0}.nav-links li:nth-child(2){--n:1}.nav-links li:nth-child(3){--n:2}
    .nav-links li:nth-child(4){--n:3}.nav-links li:nth-child(5){--n:4}.nav-links li:nth-child(6){--n:5}
    .nav-links li:nth-child(7){--n:6}.nav-extra{--n:7}
  }

  /* ---- Hover lifts (lively, pointer devices) --------------------------------- */
  @media (hover:hover){
    body[data-motion="lively"] .btn{transition:translate .18s var(--ease-out),box-shadow .18s var(--ease-out)}
    body[data-motion="lively"] .btn-gold:hover{translate:-2px -2px;box-shadow:6px 6px 0 var(--ink)}
    body[data-motion="lively"] .btn-gold:active{translate:2px 2px;box-shadow:1px 1px 0 var(--ink);transition-duration:.06s}
    body[data-motion="lively"] :is(.btn-ink,.btn-line,.btn-line-ink,.btn-paper):hover{translate:0 -2px}
    body[data-motion="lively"] :is(.btn-ink,.btn-line,.btn-line-ink,.btn-paper):active{translate:0 1px;transition-duration:.06s}
    body[data-motion="lively"] :is(.btn,.link-arrow,.link-txt) .ic{transition:translate .25s var(--ease-out)}
    body[data-motion="lively"] :is(.btn,.link-arrow,.link-txt):hover .ic{translate:3px -1px}

    body[data-motion="lively"] :is(.lift,.st-wrap,.news-card,.addr,.guest,.postal,.portrait-wrap,.hero-art .postcard,.ticket-shadow,.nl-event){transition:translate .45s var(--ease-out),rotate .45s var(--ease-out),scale .45s var(--ease-out),box-shadow .45s var(--ease-out)}
    body[data-motion="lively"] .lift:hover{translate:0 -6px}
    body[data-motion="lively"] .st-wrap:hover{translate:0 -10px;scale:1.015}
    body[data-motion="lively"] .news-card:hover{translate:0 -8px;rotate:calc(-1 * var(--tilt,0deg));box-shadow:0 28px 48px rgba(20,19,19,.18)}
    body[data-motion="lively"] .addr:hover{translate:-3px -4px;box-shadow:clamp(11px,.4vw + 9.5px,15px) clamp(12px,.4vw + 10.5px,16px) 0 var(--ink)}
    body[data-motion="lively"] .guest:hover{translate:-3px -4px;rotate:-1deg}
    body[data-motion="lively"] .portrait-wrap:hover{rotate:-2.5deg;translate:0 -4px}
    body[data-motion="lively"] .hero-art .postcard:hover{rotate:2.5deg;translate:0 -6px}
    body[data-motion="lively"] .ticket-shadow:hover{translate:0 -4px}
    body[data-motion="lively"] .day-on .perf{transition:rotate .4s var(--ease-back),scale .4s var(--ease-back)}
    body[data-motion="lively"] .day-on:hover .perf{rotate:4deg;scale:1.04}
    body[data-motion="lively"] .ws-sticker{transition:rotate .5s var(--ease-back)}
    body[data-motion="lively"] .ws-sticker:hover{rotate:-18deg}
    body[data-motion="lively"] .qa summary:hover::after{transform:rotate(90deg)}
    body[data-motion="lively"] .qa details[open] summary:hover::after{transform:rotate(45deg)}
    body[data-motion="lively"] .news-img img,
    body[data-motion="lively"] .stamp-img img{transition:scale .7s var(--ease-out)}
    body[data-motion="lively"] .news-card:hover .news-img img,
    body[data-motion="lively"] .st-wrap:hover .stamp-img img{scale:1.04}
  }

  /* ---- Page transitions ----------------------------------------------------- */
  /* calm and lively: the platform's 200 ms cross-fade, root and named groups alike */
  :root:has(> body:not([data-motion="none"]))::view-transition-old(*){animation:m-vt-out 200ms ease-out both}
  :root:has(> body:not([data-motion="none"]))::view-transition-new(*){animation:m-vt-in 200ms ease-out both}
  /* lively: the page lifts away and the next one rises in under the still header */
  :root:has(> body[data-motion="lively"])::view-transition-old(root){animation:m-vt-leave 260ms cubic-bezier(.4,0,1,1) both}
  :root:has(> body[data-motion="lively"])::view-transition-new(root){animation:m-vt-enter 560ms var(--ease-out) 60ms both}

  /* Fallback where cross-document view transitions do not run (motion.js adds
     html.no-vt): the leaving page fades, the arriving page rises in. Only after a
     click inside the site (html.vt-arrive), never on a first load or a refresh. */
  html.no-vt.vt-arrive body:not([data-motion="none"]) > :is(main,.site-foot){animation:m-vt-in 260ms ease-out backwards}
  html.no-vt.vt-arrive body[data-motion="lively"] > :is(main,.site-foot){animation:m-vt-enter 560ms var(--ease-out) backwards}
  html.no-vt.is-leaving body:not([data-motion="none"]) > :is(main,.site-foot){opacity:0;transition:opacity .2s ease-in}
  html.no-vt.is-leaving body[data-motion="lively"] > :is(main,.site-foot){translate:0 -14px;transition:opacity .22s ease-in,translate .22s ease-in}
}

/* ---- Keyframes (each states only its starting point, ending on the element's own state) */
@keyframes m-rise{from{opacity:0;translate:0 var(--reveal-rise,8px)}}
@keyframes m-fade{from{opacity:0}}
@keyframes m-left{from{opacity:0;translate:calc(-1.6 * var(--reveal-rise,8px)) 0}}
@keyframes m-right{from{opacity:0;translate:calc(1.6 * var(--reveal-rise,8px)) 0}}
@keyframes m-pop{from{opacity:0;scale:.86}}
@keyframes m-title{from{opacity:0;translate:0 .42em}}
@keyframes m-stamp{
  0%{opacity:0;scale:1.4;rotate:-10deg;translate:0 -22px}
  55%{opacity:1;scale:.965;rotate:1.5deg;translate:0 0}
  78%{scale:1.012;rotate:-.4deg}
}
@keyframes m-postmark{
  0%{opacity:0;scale:1.22}
  55%{opacity:1;scale:.965}
  80%{scale:1.01}
}
@keyframes m-postcard{
  0%{opacity:0;translate:0 -70px;rotate:-9deg}
  60%{opacity:1;translate:0 6px;rotate:1.2deg}
  82%{translate:0 -2px;rotate:-.3deg}
}
@keyframes m-thump{
  0%{translate:0 0}
  25%{translate:0 5px;rotate:-.6deg}
  60%{translate:0 -1px}
  100%{translate:0 0}
}
@keyframes m-drop{
  0%{opacity:0;translate:28% -70%;rotate:22deg;scale:1.55}
  60%{opacity:1}
}
@keyframes m-squash{
  0%{scale:1}
  30%{scale:1.06 .94}
  65%{scale:.985 1.015}
  100%{scale:1}
}
@keyframes m-slab{from{clip-path:inset(-10% 100% -10% 0)}}
@keyframes m-sun{from{opacity:0;scale:.55}}
@keyframes m-ticket{from{opacity:0;translate:0 70px}}
@keyframes m-float{to{translate:0 -10px}}
@keyframes m-halo{to{scale:1.025;opacity:.55}}
@keyframes m-pulse{
  from{scale:1;opacity:.5}
  70%,to{scale:2.4;opacity:0}
}
@keyframes m-vt-out{to{opacity:0}}
@keyframes m-vt-in{from{opacity:0}}
@keyframes m-vt-leave{to{opacity:0;translate:0 -16px}}
@keyframes m-vt-enter{from{opacity:0;translate:0 26px}}
