/* ── Scroll reveals ──────────────────────────────────────────────────────────
   Two movements, taken from the reference the owner picked out.

   HEADINGS rise out of their own baseline. Each visual line sits in a block
   that clips whatever leaves it, and the line itself starts one line-height
   below. Sliding it up looks like the words are being written into place, and
   nothing is ever seen outside its line box.

   EVERYTHING ELSE rises a short distance and fades, staggered down the group
   so a section arrives in order rather than all at once.

   AND BOTH GO BACK. Scroll up far enough that a block sits below the fold
   again and it resets to where it started, ready to play a second time. It
   only resets DOWNWARD: something that leaves past the TOP of the screen keeps
   its finished state, because content disappearing behind you as you read on
   is a different and much worse effect.

   NOTHING IS HIDDEN BY THIS FILE ALONE. The hidden state hangs off .r-armed on
   <html>, which reveal.js sets only once it is running and only when the reader
   has not asked for reduced motion. If the script fails to load, is blocked, or
   throws, every one of these rules stops matching and the page is simply a
   page. A reveal must never be able to eat the content it reveals.
   ────────────────────────────────────────────────────────────────────────── */

/* The line splitter's own boxes. These are inert until armed, and they carry
   no visual change of their own, so a split heading reads identically to an
   unsplit one at rest. */
.r-line { display: block; overflow: clip; overflow-clip-margin: 0.32em; }
.r-line-in { display: inline-block; will-change: transform; }

.r-armed .r-line-in {
  transform: translateY(105%);
  transition: transform 900ms cubic-bezier(.25, .46, .45, .94);
  transition-delay: var(--rd, 0ms);
}
.r-armed .r-in .r-line-in,
.r-armed .r-line-in.r-in { transform: none; }

/* The block movement. 22px is deliberately small: the reveal should be felt
   at the edge of attention, not watched. */
.r-armed [data-r="up"] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 620ms cubic-bezier(.25, .46, .45, .94),
              transform 780ms cubic-bezier(.25, .46, .45, .94);
  transition-delay: var(--rd, 0ms);
}
.r-armed [data-r="up"].r-in { opacity: 1; transform: none; }

/* Images get the same rise with a little scale off it, which is what stops a
   photograph from looking like it slid in on rails. */
.r-armed [data-r="img"] {
  opacity: 0;
  transform: translateY(26px) scale(1.03);
  transition: opacity 700ms cubic-bezier(.25, .46, .45, .94),
              transform 1000ms cubic-bezier(.25, .46, .45, .94);
  transition-delay: var(--rd, 0ms);
}
.r-armed [data-r="img"].r-in { opacity: 1; transform: none; }

/* A scroll-linked drift for anything asking for one. Unlike the reveals this
   is tied to scroll position rather than to an event, so it runs backwards
   exactly as far as you scroll back. reveal.js writes --rp. */
[data-r-par] { will-change: transform; }
.r-armed [data-r-par] { transform: translate3d(0, var(--rp, 0px), 0); }

/* Reduced motion: reveal.js never arms, so none of the above applies and the
   page renders exactly as it is written. This is a second, belt-and-braces
   guard for anything that set the class before the query was read. */
@media (prefers-reduced-motion: reduce) {
  .r-armed .r-line-in,
  .r-armed [data-r="up"],
  .r-armed [data-r="img"],
  .r-armed [data-r-par] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}
