/* ===========================================================================
 *  Loyal Sathi — the scroll-told story on the home page
 *
 *  Six beats, in the order they happen at a counter, each with a drawing of
 *  the screen involved and one plain sentence naming what the drawing shows.
 *  The section explains the product; it does not decorate it.
 *
 *  THE FOUR RULES FROM motion.css, KEPT HERE TOO
 *
 *  1. transform and opacity only. Nothing in this file animates a width, a
 *     height, a colour or a position — those repaint, and this page has to
 *     hold up on the cheap Android most of Nepal browses on.
 *  2. Fast. Every animation here is 300–400ms, staggers capped at 350ms.
 *  3. Attached to something. Every animation fires on arrival, once, and is
 *     never re-run. Nothing loops and nothing moves on its own.
 *  4. prefers-reduced-motion turns all of it OFF, not down. That block is at
 *     the bottom, it mirrors the animation block above it selector for
 *     selector, and tests/test-story.php fails if the two drift apart.
 *
 *  WHAT IS EVER HIDDEN, AND WHY THAT IS SAFE
 *
 *  Only elements carrying an sfx- class are ever held back, and every one of
 *  them lives inside a drawing marked aria-hidden. No heading, sentence or
 *  number is pre-hidden anywhere in this file, so a script that fails to load
 *  cannot cost a reader a single word of the story — it can only leave the
 *  drawings looking sparse.
 *
 *  The arming class is .js-reveal on <html>, set before first paint by the
 *  inline line in platform/partials/head.php and only when IntersectionObserver
 *  exists. That is the same guarantee site.css's .reveal relies on: a browser
 *  that cannot run the observer never hides anything it could not bring back.
 * ======================================================================== */

/* ------------------------------------------------------------- section ----
   Its own dark ground. The section sits between two light bands, and the six
   little cream screens read like lit phones held in a dark room — which is
   also the fastest way to say "this part is a different kind of thing from the
   feature grid above it". */
.st-section{
  position: relative;
  overflow: hidden;                    /* clips the glow; also the overflow-x guard */
  background: var(--grad-plum, linear-gradient(155deg, #2A0B38 0%, #1D0328 45%, #0A020D 100%));
  color: var(--text-on-dark, #EFE5CA);

  /* One place to move the rail from. The marks are left-aligned in their own
     column, so the rail sits at half a mark's width. */
  --st-rail: 19px;
  --st-mark: 38px;
}

/* A soft, static wash behind the heading. No animation: something drifting
   about behind six paragraphs of explanation is exactly the sort of motion
   rule 3 exists to stop. */
.st-section::before{
  content: "";
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 60%;
  background: radial-gradient(60% 60% at 50% 0%,
              color-mix(in oklab, var(--cream-brand, #EFE5CA) 12%, transparent), transparent 70%);
  pointer-events: none;
}
.st-section > .wrap{ position: relative; z-index: 1; }

.st-head h2{ color: var(--cream-brand, #EFE5CA); }
.st-head p{
  color: color-mix(in oklab, var(--text-on-dark, #EFE5CA) 80%, transparent);
  margin-inline: auto;
  max-width: 54ch;
}

/* --------------------------------------------------------------- rail -----
   The spine the six beats hang off. The dim line is always there; the bright
   one on top of it grows as beats are reached, which is the only thing on the
   page that tells you how far through the story you are.

   Drawn as a scaled element rather than an animated height, because height is
   a layout property and this has to be free on a phone. */
.st-track{ position: relative; }

.st-track::before,
.st-fill{
  content: "";
  position: absolute;
  left: calc(var(--st-rail) - 1px);
  top: calc(var(--st-mark) / 2);
  bottom: calc(var(--st-mark) / 2);
  width: 2px;
  border-radius: 2px;
}
.st-track::before{
  background: color-mix(in oklab, var(--cream-brand, #EFE5CA) 16%, transparent);
}
.st-fill{
  background: linear-gradient(180deg,
              color-mix(in oklab, var(--cream-brand, #EFE5CA) 85%, transparent),
              color-mix(in oklab, var(--gold, #D9A93A) 90%, transparent));
  transform-origin: top;
  /* No script, no observer: a plain solid rail, which is what it should look
     like when nothing is tracking progress. */
  transform: scaleY(var(--st-fill, 1));
  transition: transform 320ms var(--ease-out, cubic-bezier(.33,1,.68,1));
}
.js-reveal .st-fill{ --st-fill: 0; }

/* --------------------------------------------------------------- beats ----
   mark | words | drawing. The mark column is fixed so the rail is straight;
   the other two are minmax(0, …) so a long word or a wide drawing can never
   push the grid past the wrap and start the page scrolling sideways. */
.st-beats{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(38px, 6vw, 64px);
}

.st-beat{
  display: grid;
  grid-template-columns: calc(var(--st-mark) + 14px) minmax(0, 1fr);
  column-gap: var(--s-3, .75rem);
  row-gap: var(--s-5, 1.25rem);
  align-items: start;
}

@media (min-width: 900px){
  .st-beat{
    grid-template-columns: calc(var(--st-mark) + 22px) minmax(0, 1fr) minmax(0, 0.92fr);
    column-gap: clamp(20px, 3vw, 40px);
    align-items: center;
  }
}

/* The number. Never hidden and never animated in — it is how a sighted reader
   knows this is step four of six, and that has to survive a dead script. */
.st-mark{
  grid-column: 1;
  width: var(--st-mark);
  height: var(--st-mark);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-family: var(--font-brand, inherit);
  font-weight: 800;
  font-size: var(--t-sm, .8125rem);
  color: var(--cream-brand, #EFE5CA);
  background: var(--plum-soft, #2E0B3D);
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--cream-brand, #EFE5CA) 26%, transparent);

  /* Transform only.
     This used to ease the background, the text colour and the ring as well,
     which looked marginally softer and broke rule 1 for the sake of it: those
     three are repaints, and this element changes while the page is scrolling —
     the one moment a phone has no frames to spare. The fill is a state, not a
     movement, so it simply changes; the 200ms that remains is the nudge in
     size, which the compositor does for free. */
  transition: transform 200ms var(--ease-back, cubic-bezier(.34,1.56,.64,1));
}

/* The beat you are level with. One at a time, and it follows the scroll both
   ways — this is the part that makes the section read as a sequence being
   stepped through rather than a list that happens to be numbered. */
.js-reveal .st-beat.is-current .st-mark{
  transform: scale(1.12);
  background: var(--grad-cream, linear-gradient(135deg,#F6EEDA 0%,#EFE5CA 55%,#E3D5B2 100%));
  color: var(--plum, #1D0328);
  box-shadow: 0 0 0 7px color-mix(in oklab, var(--cream-brand, #EFE5CA) 10%, transparent);
}

.st-body{ grid-column: 2; min-width: 0; }
.st-body h3{
  font-family: var(--font-brand, inherit);
  font-size: clamp(1.15rem, 2.6vw, 1.5rem);
  line-height: var(--lh-snug, 1.35);
  letter-spacing: var(--track-tight, -.02em);
  color: var(--cream-brand, #EFE5CA);
  margin: 0 0 var(--s-2, .5rem);
}
.st-body p{
  margin: 0;
  max-width: 46ch;
  color: color-mix(in oklab, var(--text-on-dark, #EFE5CA) 82%, transparent);
}

/* The drawing sits under the words on a phone and beside them on a desktop.
   On both it is aria-hidden: it repeats what the sentence already said. */
.st-art{
  grid-column: 2;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-3, .75rem);
}
@media (min-width: 900px){
  .st-art{ grid-column: 3; grid-row: 1; }
}

/* ------------------------------------------------------------- the phone --
   One shell, five of the six beats. Everything inside is sized in em off the
   shell's own font-size, so the whole drawing shrinks as one object on a
   narrow screen instead of coming apart. */
.st-phone{
  width: 100%;
  max-width: 268px;
  font-size: 14px;
  padding: .5em;
  border-radius: 1.6em;
  background: #0A020D;
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--cream-brand, #EFE5CA) 18%, transparent),
    0 18px 40px rgba(0, 0, 0, .45);
}

.st-url{
  display: flex;
  align-items: center;
  gap: .35em;
  margin: .15em .25em .5em;
  padding: .3em .6em;
  border-radius: 999px;
  background: color-mix(in oklab, var(--cream-brand, #EFE5CA) 12%, transparent);
  font-size: .72em;
  color: color-mix(in oklab, #EFE5CA 78%, transparent);
  overflow: hidden;
}
.st-url .i{ width: .95em; height: .95em; flex: none; }
.st-url span{ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.st-url b{ color: #EFE5CA; font-weight: 700; }

.st-scr{
  border-radius: 1.15em;
  padding: .9em .85em 1em;
  background: var(--surface-2, #F5EFE3);
  color: var(--text, #1A0A22);
}
.st-scr-won{
  background: linear-gradient(170deg, #FFF6E2 0%, #F5EFE3 60%);
}

.st-scr-top{ text-align: center; margin-bottom: .8em; }
.st-scr-top b{
  display: block;
  font-family: var(--font-brand, inherit);
  font-size: 1.02em;
  letter-spacing: var(--track-tight, -.02em);
  color: var(--plum, #1D0328);
}
.st-scr-top span{
  display: block;
  font-size: .74em;
  color: var(--text-muted, #5C4A66);
}

.st-dots{
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: .45em;
}
.st-dot{
  position: relative;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 1.5px dashed color-mix(in oklab, var(--plum, #1D0328) 26%, transparent);
}
.st-dot > b{
  position: absolute;
  inset: -1.5px;
  border-radius: 50%;
  background: var(--plum, #1D0328);
  display: flex;
  align-items: center;
  justify-content: center;
}
.st-dot > b::after{
  content: "✓";
  font-size: .62em;
  line-height: 1;
  color: var(--cream-brand, #EFE5CA);
}
/* The last stamp on the completed card is the one they came for. */
.st-dots-6 .st-dot:last-child > b{ background: var(--gold-ink, #7D5A1B); }

.st-line{
  margin: .75em 0 0;
  text-align: center;
  font-size: .74em;
  color: var(--text-muted, #5C4A66);
}

.st-reward{
  margin-top: .8em;
  padding: .7em .6em .75em;
  border-radius: .8em;
  text-align: center;
  background: color-mix(in oklab, var(--gold, #D9A93A) 20%, #FFFFFF);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gold-ink, #7D5A1B) 28%, transparent);
}
.st-gift{ display: block; color: var(--gold-ink, #7D5A1B); }
.st-gift .i{ width: 1.5em; height: 1.5em; }
.st-reward b{
  display: block;
  font-family: var(--font-brand, inherit);
  font-size: .98em;
  color: var(--plum, #1D0328);
}
.st-reward span:last-child{
  display: block;
  font-size: .7em;
  color: var(--text-muted, #5C4A66);
}

/* ---------------------------------------------------- the counter, beat 2 --
   Two small screens side by side: what the customer is holding out, and what
   the person on the till is looking at. Side by side is the point — the whole
   answer to "can this be faked" is that the two have to agree. */
.st-pair{
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-3, .75rem);
  width: 100%;
  max-width: 320px;
}
.st-mini{ min-width: 0; font-size: 13px; }
.st-cap{
  display: block;
  margin-bottom: .4em;
  text-align: center;
  font-size: .72em;
  letter-spacing: var(--track-wide, .08em);
  text-transform: uppercase;
  color: color-mix(in oklab, var(--text-on-dark, #EFE5CA) 62%, transparent);
}
.st-mini-scr{
  padding: .7em .55em;
  border-radius: .9em;
  background: var(--surface-2, #F5EFE3);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5em;
  min-height: 8.6em;
  justify-content: center;
}
.st-mini-dark{
  background: #120319;
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--cream-brand, #EFE5CA) 16%, transparent);
}

.st-qr{
  width: 4.6em;
  height: 4.6em;
  display: block;
  padding: .25em;
  border-radius: .35em;
  background: #FFFFFF;
  fill: var(--plum, #1D0328);
}

.st-pin{ display: flex; gap: .25em; }
.st-pin i{
  width: 1.35em;
  height: 1.6em;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: .25em;
  background: var(--plum, #1D0328);
  color: var(--cream-brand, #EFE5CA);
  font-style: normal;
  font-weight: 800;
  font-size: .82em;
}

.st-vf{
  position: relative;
  width: 4.4em;
  height: 4.4em;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: .5em;
  overflow: hidden;
  box-shadow: inset 0 0 0 2px color-mix(in oklab, var(--gold, #D9A93A) 65%, transparent);
  color: color-mix(in oklab, var(--cream-brand, #EFE5CA) 55%, transparent);
}
.st-vf .i{ width: 1.6em; height: 1.6em; }
.st-vf-line{
  position: absolute;
  left: .3em;
  right: .3em;
  height: 2px;
  border-radius: 2px;
  background: var(--gold, #D9A93A);
  box-shadow: 0 0 10px var(--gold, #D9A93A);
}
.st-vf-txt{
  font-size: .68em;
  color: color-mix(in oklab, var(--cream-brand, #EFE5CA) 62%, transparent);
}

/* ------------------------------------------------- chips, visits, choices --
   The small labels that name the thing the drawing is proving. Static and
   centred rather than floated over a corner: a badge hanging off a drawing is
   the first thing to overlap something else at 320px. */
.st-chip,
.st-visits span,
.st-choices span{
  display: inline-flex;
  align-items: center;
  gap: .4em;
  padding: .38em .8em;
  border-radius: 999px;
  font-size: var(--t-xs, .6875rem);
  font-weight: 700;
  letter-spacing: .01em;
  line-height: 1.3;
  color: var(--cream-brand, #EFE5CA);
  background: color-mix(in oklab, var(--cream-brand, #EFE5CA) 10%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--cream-brand, #EFE5CA) 24%, transparent);
}
.st-chip{ max-width: 100%; text-align: center; }
.st-chip .i,
.st-visits .i,
.st-choices .i{ width: 1em; height: 1em; flex: none; }
.st-chip-plus{
  color: var(--plum, #1D0328);
  background: var(--grad-cream, #EFE5CA);
  box-shadow: none;
}

.st-visits,
.st-choices{
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-2, .5rem);
  max-width: 300px;
}

/* ---------------------------------------------------- the panel, beat 6 ----
   No figures anywhere on this drawing, matching the report mock further down
   the home page. Bars with no scale say "this is a report"; a bar with a
   number on it would be a claim, and there is no data behind it. */
.st-panel{
  width: 100%;
  max-width: 300px;
  font-size: 13px;
  padding: .9em .9em 1em;
  border-radius: 1em;
  background: var(--surface-2, #F5EFE3);
  color: var(--text, #1A0A22);
  box-shadow: 0 14px 34px rgba(0, 0, 0, .35);
}
.st-panel-top{
  display: flex;
  align-items: center;
  gap: .35em;
  margin-bottom: .9em;
}
.st-pdot{
  width: .45em;
  height: .45em;
  border-radius: 50%;
  background: color-mix(in oklab, var(--plum, #1D0328) 22%, transparent);
}
.st-panel-top b{
  margin-left: auto;
  font-family: var(--font-brand, inherit);
  font-size: .82em;
  color: var(--plum, #1D0328);
}

.st-bars{
  display: flex;
  align-items: flex-end;
  gap: .35em;
  height: 5.4em;
}
.st-bars i{
  flex: 1 1 0;
  min-width: 0;
  border-radius: .25em .25em 0 0;
  transform-origin: bottom;
  background: linear-gradient(180deg,
              color-mix(in oklab, var(--gold, #D9A93A) 85%, #FFFFFF),
              var(--gold-ink, #7D5A1B));
}
.st-axis{
  display: flex;
  gap: .35em;
  margin-top: .35em;
}
.st-axis span{
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  font-size: .6em;
  color: var(--text-muted, #5C4A66);
}

.st-reports{
  list-style: none;
  margin: .9em 0 0;
  padding: .8em 0 0;
  border-top: 1px solid color-mix(in oklab, var(--plum, #1D0328) 12%, transparent);
  display: grid;
  gap: .45em;
}
.st-reports li{
  display: flex;
  align-items: center;
  gap: .5em;
  font-size: .78em;
  color: var(--text-muted, #5C4A66);
}
.st-reports .i{ width: 1em; height: 1em; flex: none; color: var(--gold-ink, #7D5A1B); }

/* --------------------------------------------------------------- the way out */
.st-act{ text-align: center; margin: clamp(36px, 6vw, 56px) 0 0; }

/* The site's buttons are white-space: nowrap, which is right for "Apply" and
   wrong for a label this long: measured at a 320px viewport it ran 26px past
   the edge and started the whole page scrolling sideways. The label is a
   sentence, so let it behave like one. */
.st-act .btn{
  max-width: 100%;
  white-space: normal;
  text-wrap: balance;
  line-height: var(--lh-snug, 1.35);
}
.st-act .btn:focus-visible{
  outline: 3px solid var(--cream-brand, #EFE5CA);
  outline-offset: 3px;
}

/* ------------------------------------------------------------- narrow ------ */
@media (max-width: 560px){
  .st-section{ --st-rail: 16px; --st-mark: 32px; }
  .st-phone{ font-size: 13px; max-width: 244px; }
  .st-mini{ font-size: 11.5px; }
  .st-panel{ font-size: 12px; }
}
@media (max-width: 360px){
  .st-pair{ gap: var(--s-2, .5rem); }
  .st-mini{ font-size: 10.5px; }
}

/* ===========================================================================
 *  MOTION
 *
 *  Four effects, nothing else. Every animated element in the section carries
 *  one of these four sfx- classes and no other animation is defined anywhere
 *  in this file — which is what makes the reduced-motion block below provably
 *  complete rather than complete by inspection.
 * ======================================================================== */

@keyframes sfx-in{
  from{ opacity: 0; transform: translate3d(0, 10px, 0); }
  to  { opacity: 1; transform: none; }
}
@keyframes sfx-pop{
  from{ opacity: 0; transform: scale(.55); }
  70% { opacity: 1; transform: scale(1.06); }
  to  { opacity: 1; transform: none; }
}
@keyframes sfx-grow{
  from{ transform: scaleY(0); }
  to  { transform: scaleY(1); }
}
@keyframes sfx-sweep{
  0%  { opacity: 0; transform: translate3d(0, -1.7em, 0); }
  22% { opacity: 1; }
  78% { opacity: 1; }
  100%{ opacity: 0; transform: translate3d(0, 1.7em, 0); }
}

/* The resting state before a beat has been reached. Under .js-reveal only, so
   a browser without IntersectionObserver — or without JavaScript at all —
   never hides a thing it cannot bring back. */
.js-reveal .st-beat .sfx-in   { opacity: 0; transform: translate3d(0, 10px, 0); }
.js-reveal .st-beat .sfx-pop  { opacity: 0; transform: scale(.55); }
.js-reveal .st-beat .sfx-grow { transform: scaleY(0); }
.js-reveal .st-beat .sfx-sweep{ opacity: 0; }

/* Arrival. assets/js/story.js adds .is-active once, as the beat comes into
   view, and then stops watching it — decoration should not keep a callback
   alive for the life of the page. */
.js-reveal .st-beat.is-active .sfx-in{
  animation: sfx-in 320ms var(--ease, cubic-bezier(.16,1,.3,1)) both;
}
.js-reveal .st-beat.is-active .sfx-pop{
  animation: sfx-pop 300ms var(--ease-back, cubic-bezier(.34,1.56,.64,1)) both;
}
.js-reveal .st-beat.is-active .sfx-grow{
  animation: sfx-grow 380ms var(--ease, cubic-bezier(.16,1,.3,1)) both;
}
.js-reveal .st-beat.is-active .sfx-sweep{
  animation: sfx-sweep 400ms var(--ease-out, cubic-bezier(.33,1,.68,1)) both;
}

/* Order inside a beat. The stamps land one after another because that is what
   stamps do; the chip that names the point arrives last, after the drawing it
   is describing has finished. Capped at 350ms — past that the last piece waits
   long enough to look broken. */
.js-reveal .st-beat.is-active .st-dot:nth-child(2) > .sfx-pop{ animation-delay:  70ms; }
.js-reveal .st-beat.is-active .st-dot:nth-child(3) > .sfx-pop{ animation-delay: 140ms; }
.js-reveal .st-beat.is-active .st-dot:nth-child(4) > .sfx-pop{ animation-delay: 210ms; }
.js-reveal .st-beat.is-active .st-dot:nth-child(5) > .sfx-pop{ animation-delay: 280ms; }
.js-reveal .st-beat.is-active .st-dot:nth-child(6) > .sfx-pop{ animation-delay: 350ms; }

.js-reveal .st-beat.is-active .st-pin i:nth-child(2){ animation-delay:  60ms; }
.js-reveal .st-beat.is-active .st-pin i:nth-child(3){ animation-delay: 120ms; }
.js-reveal .st-beat.is-active .st-pin i:nth-child(4){ animation-delay: 180ms; }

.js-reveal .st-beat.is-active .st-pair > .st-mini:nth-child(2){ animation-delay: 90ms; }
.js-reveal .st-beat.is-active .st-vf-line{ animation-delay: 260ms; }

.js-reveal .st-beat.is-active .st-visits  span:nth-child(2){ animation-delay:  80ms; }
.js-reveal .st-beat.is-active .st-visits  span:nth-child(3){ animation-delay: 160ms; }
.js-reveal .st-beat.is-active .st-visits  span:nth-child(4){ animation-delay: 240ms; }
.js-reveal .st-beat.is-active .st-choices span:nth-child(2){ animation-delay: 110ms; }

.js-reveal .st-beat.is-active .st-bars i:nth-child(2){ animation-delay:  45ms; }
.js-reveal .st-beat.is-active .st-bars i:nth-child(3){ animation-delay:  90ms; }
.js-reveal .st-beat.is-active .st-bars i:nth-child(4){ animation-delay: 135ms; }
.js-reveal .st-beat.is-active .st-bars i:nth-child(5){ animation-delay: 180ms; }
.js-reveal .st-beat.is-active .st-bars i:nth-child(6){ animation-delay: 225ms; }
.js-reveal .st-beat.is-active .st-bars i:nth-child(7){ animation-delay: 270ms; }

.js-reveal .st-beat.is-active .st-reports li:nth-child(1){ animation-delay: 220ms; }
.js-reveal .st-beat.is-active .st-reports li:nth-child(2){ animation-delay: 280ms; }
.js-reveal .st-beat.is-active .st-reports li:nth-child(3){ animation-delay: 340ms; }

.js-reveal .st-beat.is-active .st-reward{ animation-delay: 260ms; }
.js-reveal .st-beat.is-active .st-chip  { animation-delay: 300ms; }

/* ------------------------------------------------------ reduced motion ----
   Off, not slower — and, just as importantly, everything visible.
   An animation-delay left behind with nothing to clear it holds a drawing
   invisible, which is worse than the motion it was meant to replace.

   The four sfx- selectors below MUST stay in step with the four resting-state
   rules and the four arrival rules above. tests/test-story.php reads this file,
   collects every selector that carries an `animation:` declaration, and fails
   if any of them is not covered here — the same selector-matching check
   motion.css asks for in its own comment. Change one list, change both. */
@media (prefers-reduced-motion: reduce){
  .js-reveal .st-beat .sfx-in,
  .js-reveal .st-beat .sfx-pop,
  .js-reveal .st-beat .sfx-grow,
  .js-reveal .st-beat .sfx-sweep,
  .js-reveal .st-beat.is-active .sfx-in,
  .js-reveal .st-beat.is-active .sfx-pop,
  .js-reveal .st-beat.is-active .sfx-grow,
  .js-reveal .st-beat.is-active .sfx-sweep,
  .js-reveal .st-beat.is-active [class*="sfx-"],
  .js-reveal .st-beat.is-active .st-pair > .st-mini,
  .js-reveal .st-beat.is-active .st-dot > b,
  .js-reveal .st-beat.is-active .st-pin i,
  .js-reveal .st-beat.is-active .st-vf-line,
  .js-reveal .st-beat.is-active .st-visits span,
  .js-reveal .st-beat.is-active .st-choices span,
  .js-reveal .st-beat.is-active .st-bars i,
  .js-reveal .st-beat.is-active .st-reports li,
  .js-reveal .st-beat.is-active .st-reward,
  .js-reveal .st-beat.is-active .st-chip,
  .st-fill{
    animation: none !important;
    animation-delay: 0ms !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  /* The mark still changes colour on the beat you are level with — that is a
     state, not a movement — but it does not grow, and it does not ease. */
  .st-mark,
  .js-reveal .st-beat.is-current .st-mark{
    transition: none !important;
    transform: none !important;
  }
}

/* Printing never scrolls, so a beat that was never reached would come out of
   the printer as a blank rectangle. */
@media print{
  .js-reveal .st-beat [class*="sfx-"],
  .js-reveal .st-beat.is-active [class*="sfx-"]{
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .st-fill{ transform: none !important; }
  .st-section{ background: none !important; color: #000 !important; }
}
