/* Dopa micro-interactions.
 *
 * Everything here belongs to nodes that motion.js invents for the length of one
 * motion and then takes off the page. No existing component is restyled, every
 * selector is namespaced `mx-`, and nothing in this file is visible at rest -
 * which is what keeps the screenshot baselines pixel-identical.
 *
 * The two durations that live in CSS rather than in motion.js:
 *   .mx-shelf and .mx-threshold   520ms and 560ms (land, level)
 *   .mx-tick                      240ms (mission)
 * They mirror DURATIONS in public/js/motion.js; change both together.
 */

/* ------------------------------------------------------------- the pieces -- */

/* A fixed copy of something already on the page: the heart's fill for save and
 * unsave, the travelling piece for flyPiece. Fixed so it can never depend on
 * whether an ancestor happens to be positioned.
 *
 * This node is a wrapper of the module's own making rather than the element
 * itself, because the wipe clips it: a clip-path on an outer SVG element is not
 * reliably painted, but one on an HTML node is. */
.mx-ghost {
  pointer-events: none;
  z-index: 90;
  will-change: clip-path, transform, opacity;
}

/* The copy fills its wrapper, whatever size the app gave the original. */
.mx-ghost svg,
.mx-ghost img {
  display: block;
  width: 100%;
  height: 100%;
}

/* The overlay is a filled heart whichever way the button is currently set, so
 * save wipes the fill in and unsave wipes it away. */
.mx-ghost.mx-fill svg,
.mx-ghost.mx-fill {
  fill: var(--sale);
  stroke: var(--sale);
  color: var(--sale);
}

/* A travelling piece keeps the dressings the app gives a flying card. */
.mx-ghost.mx-flyer {
  border-radius: var(--r-md);
  overflow: hidden;
}

/* --------------------------------------------------------------- the rules -- */

/* The ring a control gives off when something landed: save, dopa and a committed
 * pick. It is created at the element's box and expands past it, so it reads as
 * coming from the control without the control itself moving. */
.mx-ring {
  position: fixed;
  margin: 0;
  border: 2px solid var(--brand);
  border-radius: 999px;
  pointer-events: none;
  z-index: 91;
  will-change: transform, opacity;
}

/* One pixel, laid along the bottom of a piece or across its width. It is
 * created at the element's box, so it never touches layout. */
.mx-line {
  position: fixed;
  height: 1px;
  pointer-events: none;
  z-index: 90;
  transform-origin: left center;
  will-change: transform, opacity;
}

/* land: the shelf a piece is put down onto. Lilac, because it is Dopa's own
 * furniture, and it fades rather than sitting there. */
.mx-line.mx-shelf {
  background: var(--brand);
}

.mx-line.mx-run.mx-shelf {
  animation: mx-shelf 520ms cubic-bezier(.22, 1, .36, 1) both;
}

@keyframes mx-shelf {
  from { transform: scaleX(0); opacity: 1; }
  55% { transform: scaleX(1); opacity: 1; }
  to { transform: scaleX(1); opacity: 0; }
}

/* level: a threshold crossed. Ink, once, across the whole element. */
.mx-line.mx-threshold {
  background: var(--ink);
}

.mx-line.mx-run.mx-threshold {
  animation: mx-threshold 560ms cubic-bezier(.22, 1, .36, 1) both;
}

@keyframes mx-threshold {
  from { transform: scaleX(0); opacity: 0; }
  18% { transform: scaleX(0.18); opacity: 1; }
  to { transform: scaleX(1); opacity: 0; }
}

/* ---------------------------------------------------------------- the tick -- */

/* mission: a tick drawn beside the thing that was completed. */
.mx-tick {
  position: fixed;
  pointer-events: none;
  z-index: 90;
  color: var(--ink);
  will-change: opacity;
}

.mx-tick path {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 24;
  stroke-dashoffset: 24;
}

.mx-tick.mx-run {
  animation: mx-tick-hold 240ms cubic-bezier(.22, 1, .36, 1) both;
}

.mx-tick.mx-run path {
  animation: mx-tick-draw 240ms cubic-bezier(.22, 1, .36, 1) both;
}

@keyframes mx-tick-draw {
  from { stroke-dashoffset: 24; }
  55% { stroke-dashoffset: 0; }
  to { stroke-dashoffset: 0; }
}

@keyframes mx-tick-hold {
  from { opacity: 1; }
  60% { opacity: 1; }
  to { opacity: 0; }
}

/* --------------------------------------------------------------- stillness -- */

/* The module checks this setting itself before it schedules anything. This is
 * the second half of the same promise: if a node is somehow already on the page
 * when the setting changes, it leaves rather than animating. */
@media (prefers-reduced-motion: reduce) {
  .mx-ghost,
  .mx-ring,
  .mx-line,
  .mx-tick {
    display: none;
  }
}
