/* How the top of the home page comes in when a visitor arrives: the 12 openings of the Motion row.
   Shared by the front door (index.html) and the builder (builder.html). The words and timings for each one are in
   window.ADG_MOTIONS (data.js, made by tools/make-data.py); the total ms there must match the rules below.

   How to use it:
   - the root is any element with data-mo="<key>"; adding the class mo-play starts its opening (js/motion.js does this);
   - the parts inside it: .mo-hero (the top section), .mo-pic (a positioned, overflow-hidden frame; its img is the photo
     that moves, so the frame, its shape and its shadow stay still), .mo-over, .mo-h, .mo-p and .mo-btn;
   - set on the root: --mo-u (the distance unit), --mo-t (the time scale, 1 = normal) and --mo-a, --mo-b (two accent colors);
   - js/motion.js also sets, each time it plays: --mo-ho on .mo-h (the middle of its words, for Stamp and Soft focus) and
     --mo-n on .mo-over and .mo-h (how many letters, for Type out). Without them: the left-middle, and 10 and 14 steps.
   Only opacity, translate, scale, filter, clip-path, mask-image and text-shadow move (plus transform on the photo for Flip),
   so any transform a button or picture already has keeps working. Nothing loops. Nothing moves for anyone who has asked
   their device for less movement.

   Section 1 is theme-ready: it can be copied into the theme as it is, swapping '[data-mo="<key>"].mo-play' for '.adg-mo-<key>'.
   Section 2 is for this site only (the wave between two looks). */


/* ==== 1. THEME-READY ==== */

/* Blinds: the slat width, as a real percentage so it can move smoothly */
@property --mo-slat { syntax: '<percentage>'; inherits: false; initial-value: 12.5%; }

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

  /* shared: rise into place, and the smaller rise for the words that follow a picture */
  @keyframes adg-up { from { opacity: 0; translate: 0 calc(28 * var(--mo-u, 1px)); } }
  @keyframes adg-words { from { opacity: 0; translate: 0 calc(16 * var(--mo-u, 1px)); } }

  /* 1. Rise (1000 ms): the words rise in turn, the photo fades in from a touch larger */
  @keyframes adg-rise-pic { from { opacity: 0; scale: 1.02; } to { opacity: 1; scale: 1; } }
  [data-mo="rise"].mo-play .mo-pic img { animation: adg-rise-pic calc(900ms * var(--mo-t, 1)) ease-out both; }
  [data-mo="rise"].mo-play .mo-over { animation: adg-up calc(700ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) both; }
  [data-mo="rise"].mo-play .mo-h { animation: adg-up calc(700ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(90ms * var(--mo-t, 1)) both; }
  [data-mo="rise"].mo-play .mo-p { animation: adg-up calc(700ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(180ms * var(--mo-t, 1)) both; }
  [data-mo="rise"].mo-play .mo-btn { animation: adg-up calc(700ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(270ms * var(--mo-t, 1)) both; }

  /* 2. Slow zoom (2400 ms): the photo starts close and settles back, like the start of a film */
  @keyframes adg-zoom-pic { 0% { opacity: 0; scale: 1.16; } 20% { opacity: 1; } 100% { opacity: 1; scale: 1; } }
  [data-mo="zoom"].mo-play .mo-pic img { animation: adg-zoom-pic calc(2400ms * var(--mo-t, 1)) cubic-bezier(.15, .6, .2, 1) both; }
  [data-mo="zoom"].mo-play .mo-over { animation: adg-words calc(700ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(250ms * var(--mo-t, 1)) both; }
  [data-mo="zoom"].mo-play .mo-h { animation: adg-words calc(700ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(320ms * var(--mo-t, 1)) both; }
  [data-mo="zoom"].mo-play .mo-p { animation: adg-words calc(700ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(390ms * var(--mo-t, 1)) both; }
  [data-mo="zoom"].mo-play .mo-btn { animation: adg-words calc(700ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(460ms * var(--mo-t, 1)) both; }

  /* 3. Curtain (1260 ms): the photo opens from the middle */
  @keyframes adg-curtain-pic { from { clip-path: inset(0 50% 0 50%); } to { clip-path: inset(0 0 0 0); } }
  [data-mo="curtain"].mo-play .mo-pic img { animation: adg-curtain-pic calc(1000ms * var(--mo-t, 1)) cubic-bezier(.7, 0, .2, 1) both; }
  [data-mo="curtain"].mo-play .mo-over { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(450ms * var(--mo-t, 1)) both; }
  [data-mo="curtain"].mo-play .mo-h { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(520ms * var(--mo-t, 1)) both; }
  [data-mo="curtain"].mo-play .mo-p { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(590ms * var(--mo-t, 1)) both; }
  [data-mo="curtain"].mo-play .mo-btn { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(660ms * var(--mo-t, 1)) both; }

  /* 4. Color sweep (1410 ms): a band of the accent color crosses the frame and uncovers the photo halfway */
  @keyframes adg-sweep-band {
    0% { scale: 0 1; transform-origin: left center; }
    45% { scale: 1 1; transform-origin: left center; }
    55% { scale: 1 1; transform-origin: right center; }
    100% { scale: 0 1; transform-origin: right center; }
  }
  @keyframes adg-sweep-pic { 0% { opacity: 0; } 50%, 100% { opacity: 1; } }
  /* the frame keeps the band to itself, so a marker or tick laid over the picture (z-index 2) stays on top of it */
  [data-mo="sweep"].mo-play .mo-pic { isolation: isolate; }
  [data-mo="sweep"].mo-play .mo-pic::before { content: ""; position: absolute; inset: 0; z-index: 3; background: var(--mo-a, currentColor); pointer-events: none;
    animation: adg-sweep-band calc(1100ms * var(--mo-t, 1)) cubic-bezier(.77, 0, .18, 1) both; }
  [data-mo="sweep"].mo-play .mo-pic img { animation: adg-sweep-pic calc(1100ms * var(--mo-t, 1)) steps(1, end) both; }
  [data-mo="sweep"].mo-play .mo-over { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(600ms * var(--mo-t, 1)) both; }
  [data-mo="sweep"].mo-play .mo-h { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(670ms * var(--mo-t, 1)) both; }
  [data-mo="sweep"].mo-play .mo-p { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(740ms * var(--mo-t, 1)) both; }
  [data-mo="sweep"].mo-play .mo-btn { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(810ms * var(--mo-t, 1)) both; }

  /* 5. Type out (1550 ms): the line above and the headline type themselves out, then a caret blinks twice.
     The clip reaches a little past the box so tall, low or slanted letters are never cut off. The caret takes no room.
     --mo-n is the number of letters (one step each; js/motion.js counts them). On this site motion.js also types a headline
     that wraps one line after the other, letter by letter, on top of this plain wipe. */
  @keyframes adg-typed { from { clip-path: inset(-.5em 100% -.5em -.5em); } to { clip-path: inset(-.5em -.5em -.5em -.5em); } }
  @keyframes adg-typed-caret { 0% { opacity: 1; } 50%, 100% { opacity: 0; } }
  @keyframes adg-typed-pic { from { opacity: 0; } to { opacity: 1; } }
  [data-mo="typed"].mo-play .mo-over { animation: adg-typed calc(400ms * var(--mo-t, 1)) steps(var(--mo-n, 10), end) both; }
  [data-mo="typed"].mo-play .mo-h { animation: adg-typed calc(900ms * var(--mo-t, 1)) steps(var(--mo-n, 14), end) calc(150ms * var(--mo-t, 1)) both; }
  [data-mo="typed"].mo-play .mo-h::after { content: ""; display: inline-block; width: .08em; height: .72em; margin-right: -.08em; vertical-align: baseline; background: currentColor;
    animation: adg-typed-caret calc(200ms * var(--mo-t, 1)) steps(1, end) calc(1050ms * var(--mo-t, 1)) 2 both; }
  [data-mo="typed"].mo-play .mo-pic img { animation: adg-typed-pic calc(500ms * var(--mo-t, 1)) steps(4, end) both; }
  [data-mo="typed"].mo-play .mo-p { animation: adg-words calc(500ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(950ms * var(--mo-t, 1)) both; }
  [data-mo="typed"].mo-play .mo-btn { animation: adg-words calc(500ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(1030ms * var(--mo-t, 1)) both; }

  /* 6. Soft focus (1100 ms): the photo and headline drift from soft to sharp.
     The headline grows from --mo-ho, the middle of its words (js/motion.js measures it; left-middle without it). */
  @keyframes adg-focus { from { opacity: .4; scale: 1.04; filter: blur(calc(12 * var(--mo-u, 1px))); } to { opacity: 1; scale: 1; filter: blur(0px); } }
  [data-mo="focus"].mo-play .mo-pic img { animation: adg-focus calc(1100ms * var(--mo-t, 1)) ease-out both; }
  [data-mo="focus"].mo-play .mo-h { transform-origin: var(--mo-ho, 0 50%); animation: adg-focus calc(1100ms * var(--mo-t, 1)) ease-out both; }
  [data-mo="focus"].mo-play .mo-over { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(200ms * var(--mo-t, 1)) both; }
  [data-mo="focus"].mo-play .mo-p { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(300ms * var(--mo-t, 1)) both; }
  [data-mo="focus"].mo-play .mo-btn { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(380ms * var(--mo-t, 1)) both; }

  /* 7. Float (4950 ms, never loops): the words rise in; the photo rises in (0 to 600 ms), bobs twice (600 to 4600 ms,
     2000 ms each) and settles to its normal size (4600 to 4950 ms). One track, so its three parts never fight.
     The bob is a share of the photo's own height (2.5%), and the photo is 6% larger while it moves (3% spare at each edge),
     so its edge never comes away from the frame, whatever the frame's size. */
  @keyframes adg-float-pic {
    0% { opacity: 0; translate: 0 2.8%; scale: 1.06; animation-timing-function: ease-out; }
    12.12% { opacity: 1; translate: 0 0; scale: 1.06; animation-timing-function: ease-in-out; }
    32.32% { translate: 0 -2.5%; animation-timing-function: ease-in-out; }
    52.53% { translate: 0 0; animation-timing-function: ease-in-out; }
    72.73% { translate: 0 -2.5%; animation-timing-function: ease-in-out; }
    92.93% { translate: 0 0; scale: 1.06; animation-timing-function: ease-out; }
    100% { opacity: 1; translate: 0 0; scale: 1; }
  }
  [data-mo="float"].mo-play .mo-pic img { animation: adg-float-pic calc(4950ms * var(--mo-t, 1)) linear both; }
  [data-mo="float"].mo-play .mo-over { animation: adg-up calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) both; }
  [data-mo="float"].mo-play .mo-h { animation: adg-up calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(80ms * var(--mo-t, 1)) both; }
  [data-mo="float"].mo-play .mo-p { animation: adg-up calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(160ms * var(--mo-t, 1)) both; }
  [data-mo="float"].mo-play .mo-btn { animation: adg-up calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(240ms * var(--mo-t, 1)) both; }

  /* 8. Flip (1110 ms): the photo swings in from its left edge like a card turning over.
     The turn has its own gentler curve, so it is still turning at 400 ms instead of nearly flat by 200 ms;
     the last 30% is the small swing past flat and back. */
  @keyframes adg-flip-pic {
    0% { transform: perspective(1000px) rotateY(-80deg); opacity: 0; animation-timing-function: cubic-bezier(.35, .1, .25, 1); }
    30% { opacity: 1; }
    70% { transform: perspective(1000px) rotateY(6deg); }
    100% { transform: perspective(1000px) rotateY(0deg); opacity: 1; }
  }
  [data-mo="flip"].mo-play .mo-pic img { transform-origin: left center; animation: adg-flip-pic calc(900ms * var(--mo-t, 1)) cubic-bezier(.2, .8, .2, 1) both; }
  [data-mo="flip"].mo-play .mo-over { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(300ms * var(--mo-t, 1)) both; }
  [data-mo="flip"].mo-play .mo-h { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(370ms * var(--mo-t, 1)) both; }
  [data-mo="flip"].mo-play .mo-p { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(440ms * var(--mo-t, 1)) both; }
  [data-mo="flip"].mo-play .mo-btn { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(510ms * var(--mo-t, 1)) both; }

  /* 9. Stamp (920 ms): the headline thumps down, the button pops, the photo gives one short shake.
     The headline lands on --mo-ho, the middle of its words (js/motion.js measures it; left-middle without it). */
  @keyframes adg-stamp-h { 0% { opacity: 0; scale: 1.5; } 70% { opacity: 1; scale: .96; } 100% { opacity: 1; scale: 1; } }
  @keyframes adg-stamp-btn { 0% { scale: 0; } 60% { scale: 1.08; } 100% { scale: 1; } }
  @keyframes adg-stamp-fade { from { opacity: 0; } to { opacity: 1; } }
  @keyframes adg-stamp-shake {
    0% { translate: 0 0; scale: 1.03; }
    33% { translate: calc(-4 * var(--mo-u, 1px)) 0; }
    66% { translate: calc(3 * var(--mo-u, 1px)) 0; }
    100% { translate: 0 0; scale: 1; }
  }
  [data-mo="stamp"].mo-play .mo-h { transform-origin: var(--mo-ho, 0 50%); animation: adg-stamp-h calc(520ms * var(--mo-t, 1)) cubic-bezier(.2, .9, .3, 1) both; }
  [data-mo="stamp"].mo-play .mo-btn { animation: adg-stamp-btn calc(380ms * var(--mo-t, 1)) cubic-bezier(.2, .9, .3, 1) calc(300ms * var(--mo-t, 1)) both; }
  [data-mo="stamp"].mo-play .mo-pic img { animation: adg-stamp-fade calc(300ms * var(--mo-t, 1)) ease-out both, adg-stamp-shake calc(300ms * var(--mo-t, 1)) ease-out calc(420ms * var(--mo-t, 1)) both; }
  [data-mo="stamp"].mo-play .mo-over { animation: adg-words calc(400ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(450ms * var(--mo-t, 1)) both; }
  [data-mo="stamp"].mo-play .mo-p { animation: adg-words calc(400ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(520ms * var(--mo-t, 1)) both; }

  /* 10. Glitch (850 ms): two jumps with a jolt of color, then clean. Brightness never flashes: the only change
     in opacity is the one appearance. */
  @keyframes adg-glitch-pic {
    0% { opacity: 0; }
    10% { opacity: 1; translate: calc(-6 * var(--mo-u, 1px)) 0; clip-path: inset(12% 0 55% 0); filter: hue-rotate(30deg); }
    35% { translate: calc(5 * var(--mo-u, 1px)) 0; clip-path: inset(58% 0 10% 0); filter: hue-rotate(-30deg); }
    60% { translate: 0 0; clip-path: inset(30% 0 38% 0); filter: none; }
    80%, 100% { opacity: 1; translate: 0 0; clip-path: inset(0 0 0 0); filter: none; }
  }
  @keyframes adg-glitch-h {
    0% { opacity: 0; }
    15% { opacity: 1; translate: calc(-4 * var(--mo-u, 1px)) 0; text-shadow: calc(-3 * var(--mo-u, 1px)) 0 var(--mo-a, currentColor), calc(3 * var(--mo-u, 1px)) 0 var(--mo-b, currentColor); }
    40% { translate: calc(3 * var(--mo-u, 1px)) 0; }
    65%, 100% { opacity: 1; translate: 0 0; text-shadow: none; }
  }
  [data-mo="glitch"].mo-play .mo-pic img { animation: adg-glitch-pic calc(600ms * var(--mo-t, 1)) steps(1, end) both; }
  [data-mo="glitch"].mo-play .mo-h { animation: adg-glitch-h calc(600ms * var(--mo-t, 1)) steps(1, end) both; }
  [data-mo="glitch"].mo-play .mo-over { animation: adg-words calc(300ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(450ms * var(--mo-t, 1)) both; }
  [data-mo="glitch"].mo-play .mo-p { animation: adg-words calc(300ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(500ms * var(--mo-t, 1)) both; }
  [data-mo="glitch"].mo-play .mo-btn { animation: adg-words calc(300ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(550ms * var(--mo-t, 1)) both; }

  /* 11. Spotlight (1210 ms): the photo opens out from a small circle in the middle */
  @keyframes adg-spot-pic { from { clip-path: circle(0% at 50% 50%); } to { clip-path: circle(75% at 50% 50%); } }
  [data-mo="spot"].mo-play .mo-pic img { animation: adg-spot-pic calc(1100ms * var(--mo-t, 1)) cubic-bezier(.6, 0, .2, 1) both; }
  [data-mo="spot"].mo-play .mo-over { animation: adg-words calc(500ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(500ms * var(--mo-t, 1)) both; }
  [data-mo="spot"].mo-play .mo-h { animation: adg-words calc(500ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(570ms * var(--mo-t, 1)) both; }
  [data-mo="spot"].mo-play .mo-p { animation: adg-words calc(500ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(640ms * var(--mo-t, 1)) both; }
  [data-mo="spot"].mo-play .mo-btn { animation: adg-words calc(500ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(710ms * var(--mo-t, 1)) both; }

  /* 12. Blinds (1160 ms): the photo appears through eight slats that widen until they close up.
     Where the slat width cannot move smoothly, it becomes a fade with one jump. */
  @keyframes adg-blinds-pic { from { --mo-slat: 0%; opacity: .2; } to { --mo-slat: 12.5%; opacity: 1; } }
  [data-mo="blinds"].mo-play .mo-pic img {
    -webkit-mask-image: repeating-linear-gradient(to bottom, #000 0 var(--mo-slat), transparent var(--mo-slat) 12.5%);
    mask-image: repeating-linear-gradient(to bottom, #000 0 var(--mo-slat), transparent var(--mo-slat) 12.5%);
    animation: adg-blinds-pic calc(900ms * var(--mo-t, 1)) cubic-bezier(.65, 0, .35, 1) both;
  }
  [data-mo="blinds"].mo-play .mo-over { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(350ms * var(--mo-t, 1)) both; }
  [data-mo="blinds"].mo-play .mo-h { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(420ms * var(--mo-t, 1)) both; }
  [data-mo="blinds"].mo-play .mo-p { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(490ms * var(--mo-t, 1)) both; }
  [data-mo="blinds"].mo-play .mo-btn { animation: adg-words calc(600ms * var(--mo-t, 1)) cubic-bezier(.16, 1, .3, 1) calc(560ms * var(--mo-t, 1)) both; }
}


/* ==== 2. SITE ONLY ==== */

/* Held: an opening frozen on its first frame. js/motion.js holds a whole row of openings at once (photos hidden, words
   not yet in), then lets each one go at its turn, so a row ripples in instead of blinking out one picture at a time. */
@media (prefers-reduced-motion: no-preference) {
  .mo-hold.mo-play .mo-pic img, .mo-hold.mo-play .mo-pic::before,
  .mo-hold.mo-play .mo-over, .mo-hold.mo-play .mo-h, .mo-hold.mo-play .mo-h::after,
  .mo-hold.mo-play .mo-p, .mo-hold.mo-play .mo-btn { animation-play-state: paused !important; }
}

/* The wave: when a new look arrives, the old one (the ghost, on top) dissolves in a widening circle from the headline.
   js/motion.js sets --wx and --wy (the circle's middle) and moves --wr (its size) from 0 to past the far corner. */
@property --wr { syntax: '<length>'; inherits: false; initial-value: 0px; }
.wave-ghost {
  -webkit-mask-image: radial-gradient(circle at var(--wx) var(--wy), transparent var(--wr), #000 calc(var(--wr) + 64px));
  mask-image: radial-gradient(circle at var(--wx) var(--wy), transparent var(--wr), #000 calc(var(--wr) + 64px));
  pointer-events: none;
}
