/* Reign Wala: the arrival system. Loaded last on every page; remove this file and js/motion.js and everything is
   simply there, still.

   Below the opening, things arrive once, as they come into view, in one language: headings and their first lines
   rise 12px and fade in, photographs develop (a fade and a slight settle), a section's hairline draws in from the
   left, and the two display lines rise word by word from a mask. Inside a [data-stagger] group each follows the last
   by 80ms. Nothing replays on the way back up and nothing is tied to the scroll position.

   Markup: data-reveal ("" rise, "draw", "words"), data-ph, data-stagger (see js/motion.js). motion.js adds .is-in
   when one arrives, .is-done once its arrival has finished (from then on the element's own transitions apply
   again), and .is-now for the moment it is shown without motion. Everything held back here waits on html.js (set by
   one line in the head), on a screen (a printed page shows everything), and on there being no wish for reduced
   motion: with JavaScript off, or reduced motion, every word and photograph is simply there. Arrivals move opacity, translate and scale, never transform, so whatever
   transform an element already has is left alone. */

[data-reveal="draw"]::after { transform-origin: 0 50%; }
.rw-w, .rw-w > span { display: inline-block; }

@media screen and (prefers-reduced-motion: no-preference) {
  /* rise, the default: 12px and a fade (--rise: 0px makes it a fade alone) */
  html.js :is([data-reveal=""], [data-reveal="rise"]):not(.is-in) { opacity: 0; translate: 0 var(--rise, 12px); }
  html.js :is([data-reveal=""], [data-reveal="rise"]).is-in:not(.is-done) { transition: opacity 800ms var(--ease) var(--d, 0ms), translate 1000ms var(--ease) var(--d, 0ms); }

  /* draw: the element's own ::after hairline grows from the left */
  html.js [data-reveal="draw"]:not(.is-in)::after { scale: 0 1; }
  html.js [data-reveal="draw"].is-in:not(.is-done)::after { transition: scale 1000ms var(--ease) var(--d, 0ms); }

  /* words: once the fonts are in, motion.js sets each word in a mask (.rw-w); until then the line waits unseen.
     The mask reaches past the line on every side, so descenders and quotation marks are never cut, and a waiting
     word sits wholly below it. Once the line has arrived it is plain text again. */
  html.js [data-reveal="words"]:not(.is-split):not(.is-in) { opacity: 0; }
  html.js [data-reveal="words"].is-in:not(.is-split):not(.is-done) { transition: opacity 800ms var(--ease) var(--d, 0ms); }
  html.js [data-reveal="words"] .rw-w { clip-path: inset(-0.4em -0.3em -0.34em); }
  html.js [data-reveal="words"]:not(.is-in) .rw-w > span { translate: 0 175%; }
  html.js [data-reveal="words"].is-in:not(.is-done) .rw-w > span { transition: translate 900ms var(--ease) calc(var(--d, 0ms) + var(--i, 0) * 40ms); }

  /* photographs develop: a soft fade and a slight settle, once the picture has loaded */
  html.js [data-ph]:not(.is-in) img { opacity: 0; scale: 1.05; }
  html.js [data-ph].is-in:not(.is-done) img { transition: opacity 1000ms var(--ease) var(--d, 0ms), scale 1600ms var(--ease) var(--d, 0ms); }

  /* the thread beneath the five steps sews itself through once, as the row arrives (.steps gets .is-in with its
     first photograph, and follows the photographs a beat behind, as a seam follows the needle): drawn left to right on a wide screen, down the photo column on a phone (--cut, in css/style.css) */
  html.js .steps:not(.is-in) + .thread { clip-path: inset(var(--cut)); }
  html.js .steps.is-in + .thread { transition: clip-path 1600ms cubic-bezier(0.45, 0, 0.3, 1) 450ms; }
  html.js .steps:has(.is-now) + .thread { transition: none; }

  /* shown without motion (already passed, or a return to the page), whatever other transitions say */
  html.js .is-now, html.js .is-now::after, html.js .is-now img, html.js .is-now .rw-w > span { transition: none !important; }

  /* the four promises: the cells and their rules fade in place, so the dividers never slide */
  .promises > li[data-reveal] { --rise: 0px; }
}

/* ================================================================ interactions
   Alive under the hand, never busy. Hovers 200 to 320ms, on the same ease as the arrivals. The icons' float is in
   css/value-icons.css, the bag card, notes, photographs and sign-up in css/style.css. Photograph and card hovers use
   `transform`, which arrivals never touch (they use translate and scale), and wait for .is-done. */

/* page to page: a soft cross-fade instead of a white flash (a browser without it just loads) */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 280ms; animation-timing-function: ease; }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }

/* a button's words roll up, a fresh copy rolls in from below (js/motion.js wraps them; the price stays put) */
.roll { position: relative; display: block; overflow: hidden; line-height: 1.7; }
.roll > span { display: block; }
.roll > span + span { position: absolute; left: 0; top: 100%; }
@media (prefers-reduced-motion: no-preference) {
  .roll > span { transition: transform 300ms var(--ease); }
  .btn:focus-visible .roll > span { transform: translateY(-100%); }
  @media (hover: hover) { .btn:hover .roll > span { transform: translateY(-100%); } }
}
@media (prefers-reduced-motion: reduce) { .roll > span + span { display: none; } }

/* the cart count bumps when a bag goes in (app.js adds .is-bump for 600ms) */
[data-cart-count] { display: inline-block; }
@keyframes rw-bump { 0% { transform: none; } 35% { transform: scale(1.3); } 100% { transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  [data-cart-count].is-bump { animation: rw-bump 600ms var(--ease); }
}
