/* wa-pulse.css — looping "look at me" attention ring + icon wiggle for WhatsApp CTAs, generalised
   from the nav's old .nav-cta::after ctaRing keyframe (ROUND-2 item 15).
   Markup contract: add class="wa-pulse" to any button/link that contains an <i class="wa"> icon
   (usually an <a data-wa>, but works on any positioned-or-not element — a pseudo-element ring is
   added regardless). No JS, no other markup change required.
   Tokens used: --amber (via color-mix() — no literal rgba() colours, FIX-2 #21).
   Reduced motion: both the ring and the icon wiggle are disabled; the element renders static.
   Init: none — pure CSS. Just link this file after site.css. */
/* The ring below only ever needed a positioned ancestor. But this file loads AFTER site.css and
   `.wa-pulse` has the same specificity as site.css:465's `.wa-fab{position:fixed}`, so on the one
   element carrying BOTH classes (the floating WhatsApp button, `class="wa-fab wa-pulse"`, on every
   page) `relative` won the cascade and the fab dropped back into normal flow as a 56px block under
   the footer: invisible on desktop (`.wa-fab{display:none}` at >=1024px), a blank band under the
   footer on phone. `:not(.wa-fab)` means this rule never speaks about an element that already
   positions itself, and `fixed` is just as good an ancestor for the ring. */
.wa-pulse:not(.wa-fab) { position: relative; }
/* FINISHER FIX (battery: probe-clipped-text FAIL 390x844, .hero-card scrollWidth 397 vs
   clientWidth 390): Codex's b61a448 swapped this ring from a box-shadow spread to a
   `transform:scale(1.16)` on an `inset:0` pseudo-element, "the same visual effect achieved more
   cheaply" (compositor-only paint). It IS cheaper, but a `transform` on an unclipped, unbounded
   pseudo-element counts toward its ancestor's CSS "scrollable overflow" region — even though
   `.hero-card{overflow:clip}` correctly hides the resulting overflow from PAINT (nothing was ever
   visible to a user), `scrollWidth` still reports it, up to ~28px wider than the button's own box
   during the ring's grow phase, every 2.4s, forever (confirmed via getAnimations().cancel() on the
   pseudo: scrollWidth drops from 378 to the correct 350 the instant the transform is removed).
   Reverted to the original box-shadow technique, which the CSS Overflow spec explicitly excludes
   from scrollable-overflow calculations — identical visual (a ring growing and fading), zero
   layout-overflow side effect. */
.wa-pulse::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  animation: waPulseRing 2.4s ease-out infinite;
}
@keyframes waPulseRing {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--amber) 35%, transparent); }
  70%, 100% { box-shadow: 0 0 0 12px transparent; }
}
.wa-pulse .wa { animation: waWiggle 6s ease-in-out infinite; transform-origin: 50% 50%; }
@keyframes waWiggle {
  0%, 92%, 100% { transform: rotate(0); }
  94% { transform: rotate(-12deg); }
  96% { transform: rotate(10deg); }
  98% { transform: rotate(-5deg); }
}
/* Offscreen calls to action used to keep six infinite animation pairs alive across the whole
   document. site.js marks only non-intersecting buttons; visible buttons keep looping the same
   ring and wiggle (owner-approved, never one-shot), while hidden ones pause on their current
   frame without consuming paint/ticker work, resuming exactly where they left off on return. */
.wa-pulse.wa-pulse-offscreen::after, .wa-pulse.wa-pulse-offscreen .wa { animation-play-state: paused; }
.wa-pulse:not(.wa-pulse-offscreen) .wa { will-change: transform; }
@media (prefers-reduced-motion: reduce) {
  .wa-pulse::after { animation: none; box-shadow: none; }
  .wa-pulse .wa { animation: none; }
}
