/* ── Script Write — handwriting reveal (pairs with js/script-write.js) ──
   Each line is wiped in left → right with clip-path. Top/bottom/left insets
   are negative so cursive swashes and descenders never get cut. Hidden
   state only applies once the script has run (html.script-write-ready);
   otherwise the text shows as normal. */
.script-write-ready .script-write .script-write__line {
  display: inline-block;
  clip-path: inset(-50% 100% -50% -5%);
}
/* A transition, not a keyframe animation: it only runs when the class flips, so
   iOS Safari can't replay it on a repaint (address bar show/hide, scroll-back). */
.script-write-ready .script-write.is-writing .script-write__line {
  clip-path: inset(-50% -5% -50% -5%); /* right -5%: revealed */
  transition: clip-path var(--sw-dur, 0.8s) cubic-bezier(0.45, 0.05, 0.55, 0.95) var(--sw-delay, 0s);
}

/* ≤767px — forced <br> breaks are composed for desktop; on phones the heading
   wraps on its own. Lines flow inline so the next line can share a row.
   (Not a phone-only content variant in Divi: swapping content after load
   rebuilds the module and the write would jump straight to its end.) */
@media (max-width: 767px) {
  .script-write-ready .script-write br { display: none; }
  /* Inline lines can't be clipped reliably once they wrap (Chrome clips a
     wrapped inline as one strip and cuts the second row), so on phones the
     wipe runs on the whole heading block instead: rows reveal together. */
  .script-write-ready .script-write .script-write__line,
  .script-write-ready .script-write.is-writing .script-write__line { display: inline; clip-path: none; transition: none; }
  .script-write-ready .script-write .et_pb_text_inner > * {
    clip-path: inset(-50% 100% -50% -5%);
  }
  .script-write-ready .script-write.is-writing .et_pb_text_inner > * {
    clip-path: inset(-50% -5% -50% -5%);
    transition: clip-path 1s cubic-bezier(0.45, 0.05, 0.55, 0.95);
  }
}

/* reduced motion: no reveal, text always visible */
@media (prefers-reduced-motion: reduce) {
  .script-write-ready .script-write .script-write__line,
  .script-write-ready .script-write .et_pb_text_inner > * {
    clip-path: none;
    transition: none;
  }
}

/* ── Draw Reveal — sketch art drawn in left → right (add class `draw-reveal` to an Image module) ──
   A feathered mask edge sweeps across so the art looks pencilled in rather
   than wiped. Decorative only; with reduced motion or no JS it simply shows. */
.script-write-ready .draw-reveal img {
  -webkit-mask-image: linear-gradient(100deg, #000 40%, rgba(0, 0, 0, 0.35) 50%, transparent 60%);
          mask-image: linear-gradient(100deg, #000 40%, rgba(0, 0, 0, 0.35) 50%, transparent 60%);
  -webkit-mask-size: 250% 100%;
          mask-size: 250% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: 100% 0;
          mask-position: 100% 0;
}
.script-write-ready .draw-reveal.is-drawing img {
  animation: draw-reveal 2.4s cubic-bezier(0.33, 0, 0.2, 1) 1s forwards;
}
@keyframes draw-reveal {
  to { -webkit-mask-position: 0 0; mask-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .script-write-ready .draw-reveal img { -webkit-mask-image: none; mask-image: none; animation: none; }
}

/* ── Wipe Reveal — module wiped in left → right (add class `wipe-reveal` to e.g. a button's Code module) ──
   Same direction and easing as the buttons' hover sweep. Waits for the heading
   above to finish writing and the text below it to start fading in.
   The clip sits on the module's inner wrapper: a clipped observed element never
   counts as visible to IntersectionObserver, so it would never trigger.
   Hidden state is fully closed (no sliver); the revealed state's negative
   insets leave room for the keyboard focus ring. */
.script-write-ready .wipe-reveal > * { clip-path: inset(0 100% 0 0); }
.script-write-ready .wipe-reveal.is-revealed > * {
  clip-path: inset(-6px);
  transition: clip-path 0.7s cubic-bezier(0.65, 0, 0.35, 1) 1.6s;
}

/* ── Stamp Reveal — pressed in from large, like a branding iron (add class `stamp-reveal` to a small Icon module) ──
   One quick beat after the buttons land. Keep it to a single accent per section. */
.script-write-ready .stamp-reveal {
  opacity: 0;
  transform: scale(1.8);
}
.script-write-ready .stamp-reveal.is-revealed {
  opacity: 1;
  transform: none;
  transition: opacity 0.25s ease-out 2.5s, transform 0.45s cubic-bezier(0.2, 0.9, 0.3, 1) 2.5s;
}

/* ── Fade Reveal — quiet opacity fade for body copy (add class `fade-reveal` to a Text module) ──
   No movement. Waits for an ink-wipe heading above it to finish writing (~1.2s). */
.script-write-ready .fade-reveal { opacity: 0; }
.script-write-ready .fade-reveal.is-revealed {
  opacity: 1;
  transition: opacity 1s ease-out 1.2s;
}

/* ≤980px — stacked layouts: heading, buttons and art are each reached by scrolling,
   so scroll order sets the sequence. Drop the desktop delays. */
@media (max-width: 980px) {
  .script-write-ready .wipe-reveal.is-revealed > * { transition-delay: 0.1s; }
  .script-write-ready .fade-reveal.is-revealed { transition-delay: 0.5s; }
  .script-write-ready .stamp-reveal.is-revealed { transition-delay: 0.3s; }
  .script-write-ready .draw-reveal.is-drawing img { animation-delay: 0s; }
}

@media (prefers-reduced-motion: reduce) {
  .script-write-ready .wipe-reveal > * { clip-path: none; }
  .script-write-ready .stamp-reveal { opacity: 1; transform: none; }
  .script-write-ready .fade-reveal { opacity: 1; }
}

/* ── Already played — a module Divi re-rendered (or a slider clone) after its
   reveal ran shows the finished state at once instead of replaying. ── */
.script-write-ready .reveal-instant,
.script-write-ready .reveal-instant * {
  animation-delay: 0s !important;
  animation-duration: 0.01s !important;
  transition-delay: 0s !important;
  transition-duration: 0s !important;
}

/* ── Finished — after the image draws, the animation is dropped and the end
   state is held as plain styles (js adds the class). ── */
.script-write-ready .draw-reveal.is-drawn img { animation: none; -webkit-mask-image: none; mask-image: none; }
