/* ===========================================================================
   F21 MOTION — stylesheet, version 1.4.0
   ---------------------------------------------------------------------------
   Ships with f21-motion.js and depends on nothing else. No custom property
   from a host project is required, no class name from one is referenced, and
   nothing here paints until JavaScript adds a state class. With scripts off,
   every selector below is inert and the authored content is untouched.

   THE PHOTOGRAPH STAYS; THE CHANNELS ADD TO IT
   Version 1.4.0, 8 September, replaces the compositing this package shipped
   with in 1.3.0. That construction hid the photograph behind an opaque black
   backdrop for the length of the event and screened a red channel and a blue
   channel over the black: arithmetically (R,0,B) — green zero at every pixel
   of the frame — which is a magenta wash over the whole picture with a blue
   plate slipping across it, and exactly what the direction rules out.

   The break is now two channel-isolated layers laid over the untouched
   photograph and blended with `lighten`:

     - the base is never hidden and never filtered. Faces, hands and the whole
       neutral tonal range stay as they are through the event, because the
       layers can only ADD to a pixel, never take from it
     - the red layer is the photograph with green and blue removed (its
       feColorMatrix zeroes both rows: the displaced green output is zero, by
       construction, not by tuning). Blended with lighten over the neutral
       base it raises the red channel only where the displaced copy is
       brighter than what is under it — which is a luminance edge, displaced.
       The blue layer does the same for blue in the other direction
     - so what appears is a red fringe on one side of every contour and a blue
       fringe on the other, at the strength of the contour and nowhere else.
       A flat wall stays grey. The two can meet only on a bright edge, where
       they read as the references do
     - the layers are at partial opacity, which mixes the fringe toward the
       base rather than toward saturation, and they exist only for the length
       of the event. Between events the photograph is whatever it was — for
       the sequences, a derivative that already carries the fine authored
       registration; the event is the momentary shift on top of it

   The transient: red left, blue right, five pixels at the peak, back to zero
   inside 250ms. No colour is applied to the frame as a whole at any point.
   =========================================================================== */

/* ------------------------------------------------------------ typographic */

.f21-g {
  /* Inline, so line breaking is identical to the authored text and a glyph can
     never become a flex or grid item of a host container. A host stylesheet
     that styles descendant spans, which is common, would otherwise stack every
     letter on its own line. The package promises no layout shift, so this one
     declaration is worth forcing. */
  display: inline !important;
  visibility: visible;
}

.f21-g.is-out {
  /* Hidden, not removed. The glyph keeps its box, so nothing on the line
     moves and the word arrives at its final position from the first frame. */
  visibility: hidden;
}

/* The slice variant is opt in, because the films resolve type mainly by
   dropping glyphs rather than by sliding them. See the spec. */
[data-f21-slice] .f21-g {
  display: inline-block !important;
  transform: translate(var(--f21-gx, 0), var(--f21-gy, 0));
  transition: transform 160ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

[data-f21-slice].is-f21-resolving .f21-g {
  transition: none;
}

[data-f21-slice][data-f21-settled] .f21-g {
  transform: none;
}

/* The displacement of a recurring run: the whole declaration, one frame, in
   transform alone. The variable is written and removed by the module, so a
   settled declaration carries no transform at all. transition: none, because a
   host may transition transform on the same element for its own reveal and a
   one frame jog must not be smoothed into a slide. */
[data-f21-type].is-f21-resolving {
  /* A 2D translate on purpose: a 3D one promotes the declaration to its own
     layer and snaps its box to the pixel grid, which reads as a size change. */
  transform: translate(var(--f21-shift, 0px), 0);
  transition: none;
}

/* --------------------------------------------------------- registration */

[data-f21-registration] {
  position: relative;
}

/* The host sizes its own image. The package only needs the box to be a
   containing block, and the layers match it by absolute positioning. */

/* The stack sits OVER the plate and hides nothing. It is transparent; the
   photograph underneath is the base the layers add to. It inherits the host's
   radius and clips to it, so a framed image keeps its shape and nothing
   reaches past the figure. */

.f21-reg__stack {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  background: transparent;
  pointer-events: none;
}

/* One isolated channel, full frame, blended with lighten: it can raise its
   own channel where it is brighter than the base and can do nothing else.
   Partial opacity mixes the fringe toward the base, which is what keeps a
   strong edge from going to a saturated line. */
.f21-reg__layer {
  position: absolute;
  inset: 0;
  mix-blend-mode: lighten;
  opacity: 0.8;
}

/* The channel itself. The movement is here, inside the fixed frame. */
.f21-reg__layer > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: inherit;
  will-change: transform;
  transition: transform 60ms linear;
}

/* The isolation. feColorMatrix, defined once per document by the package, so
   what moves is a real red and a real blue version of the photograph rather
   than a coloured rectangle. */
.f21-reg__layer--r > img { filter: url(#f21-chan-r); }
.f21-reg__layer--b > img { filter: url(#f21-chan-b); }

/* ------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  .f21-g,
  .f21-g.is-out {
    visibility: visible !important;
    transform: none !important;
    transition: none !important;
  }

  /* No stack, so no separation and no black backdrop: the stable, fully
     registered photograph is what a reduced-motion reader sees, at every
     moment, which is the whole narrative with nothing lost. */
  .f21-reg__stack {
    display: none !important;
  }
}
