/*
 * The comic coming forward -- see product-lift.mjs for why it is two halves
 * across two documents.
 *
 * Loaded beside catalog.css, whose scope is already "pages that print product
 * cards", plus the product page it lands on. Nothing here applies to a page
 * with no cards and no poster.
 *
 * The seven themes are repeated rather than resolved from --accent for the
 * same reason the wipe repeats them: the ghost is appended to <body>, which on
 * a category page is wearing the page's theme and not necessarily the card's.
 * A related shelf under a Flower poster is full of Edibles covers, and reading
 * --accent would pull every one of them forward in purple. Same list as the
 * card themes in catalog.css; same source values.
 */
.product-lift-ghost {
  position: fixed;
  z-index: 9998;
  /* Never a click target, not even for the quarter second it exists. */
  pointer-events: none;
  overflow: hidden;
  /* Top left, because that is the corner page-lift.mjs does its arithmetic
     from -- translate puts the corner in place and the scale grows out of it. */
  transform-origin: top left;
  will-change: transform;
  background: var(--lift, var(--brand, #877ebc));
  border-bottom: 3px solid var(--ink, #1a181d);
}

.product-lift-ghost[data-theme="purple"] { --lift: var(--brand, #877ebc); }
.product-lift-ghost[data-theme="red"]    { --lift: var(--red, #c8393f); }
.product-lift-ghost[data-theme="ink"]    { --lift: #343139; }
.product-lift-ghost[data-theme="gold"]   { --lift: var(--gold, #e9c577); }
.product-lift-ghost[data-theme="blue"]   { --lift: var(--blue, #b7cfdc); }
.product-lift-ghost[data-theme="green"]  { --lift: var(--green, #8aa683); }
.product-lift-ghost[data-theme="paper"]  { --lift: var(--brand-tint-deep, #ded8cd); }

/*
 * The copy fills the ghost. It was cut out of a grid cell or a poster and no
 * longer has either to size it, so without this it keeps the min-height of
 * wherever it came from and hangs out of the box the arithmetic drew.
 */
.product-lift-ghost > * {
  width: 100%;
  height: 100%;
  min-height: 0;
  margin: 0;
  border: 0;
}

/*
 * Going: the cover comes off the shelf. A small scale and a shadow that grows
 * with it -- the shadow is what makes it read as coming toward the reader
 * rather than simply getting bigger.
 */
.product-lift-ghost[data-state="pulled"] {
  box-shadow: 16px 18px 0 var(--ink, #1a181d);
  transition: transform 240ms cubic-bezier(.32, 0, .1, 1),
              box-shadow 240ms cubic-bezier(.32, 0, .1, 1);
}
.product-lift-ghost:not([data-state]) { box-shadow: 5px 5px 0 var(--ink, #1a181d); }

/* Arriving: the same cover, carrying on growing into the poster's own. */
.product-lift-ghost[data-state="arriving"] { box-shadow: 16px 18px 0 var(--ink, #1a181d); }
.product-lift-ghost[data-state="arrived"] {
  box-shadow: 9px 9px 0 var(--ink, #1a181d);
  transition: transform 380ms cubic-bezier(.2, .7, .2, 1),
              box-shadow 380ms cubic-bezier(.2, .7, .2, 1);
}

/*
 * Everything that is not the cover steps back, so one thing is coming toward
 * the reader rather than several things moving at once.
 *
 * Opacity rather than a transform on <body>: a transformed ancestor is a
 * containing block for fixed positioning, and the ghost's whole geometry is
 * fixed against the viewport. The ghost is excluded from the selector for the
 * same reason -- it must not be inside anything the rule touches.
 */
body.is-lifting > *:not(.product-lift-ghost) {
  opacity: .5;
  transition: opacity 240ms ease;
}

/*
 * The real cover stands down while the ghost is standing in for it.
 *
 * Without this the reader watches two of the same comic, one sliding over the
 * other. `visibility` rather than `display` or `opacity`: the poster has to
 * keep its size, because the ghost's whole journey was measured against it and
 * product-dock.mjs sizes a WebGL frustum inside it.
 */
.product-poster.is-opening .product-poster-art { visibility: hidden; }

/*
 * Arriving: the first page of the comic, revealed by the cover coming off it.
 *
 * An animation rather than a transition because there is no starting frame to
 * get into the layout first -- the poster is already drawn and this plays from
 * a state that never has to be painted on its own.
 */
@keyframes product-lift-open {
  from { opacity: 0; transform: perspective(1200px) rotateX(-18deg) translateY(-10px); }
  to   { opacity: 1; transform: none; }
}
.product-poster.is-opening .product-poster-copy {
  transform-origin: top center;
  animation: product-lift-open 380ms cubic-bezier(.2, .7, .2, 1) both;
}

/*
 * A second lock on the same door. Neither half binds under reduced motion, so
 * nothing should ever build a ghost -- but if one is built anyway it must not
 * travel, and it must not sit over the page either.
 */
@media (prefers-reduced-motion: reduce) {
  .product-lift-ghost { display: none; }
  body.is-lifting > *:not(.product-lift-ghost) { opacity: 1; transition: none; }
  .product-poster.is-opening .product-poster-copy { animation: none; }
  .product-poster.is-opening .product-poster-art { visibility: visible; }
}
