/* agc-motion.css — styles for the four figures in agc-motion.js.

   Every rule here has to survive the script never running: with JavaScript off
   the markup is plain text and none of these classes are ever added, so the
   text renders normally. That is why nothing below hides anything by default
   except inside a class the script itself applies. */

/* ── (1) 3D stagger flip ─────────────────────────────────────────────── */
.fxf{perspective:900px;perspective-origin:50% 50%}
.fxf-w{display:inline-flex;transform-style:preserve-3d;white-space:nowrap}
.fxf-sp{white-space:pre}
.fxf-c{display:inline-block;transform-style:preserve-3d;position:relative;
  transition:transform .62s cubic-bezier(.2,.75,.2,1)}
.fxf-f,.fxf-b{display:block;backface-visibility:hidden;-webkit-backface-visibility:hidden}
.fxf-b{position:absolute;inset:0}

/* ── (2) text morph ──────────────────────────────────────────────────── */
.fxm{position:relative;display:inline-flex;align-items:center;justify-content:center;
  line-height:1.2;min-height:1.2em;vertical-align:baseline}
/* an invisible copy of the longest word reserves the width, so the line around
   it never reflows as the words swap — the reference's own trick */
.fxm-anchor{visibility:hidden;white-space:nowrap;display:inline-block}
.fxm-w{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  white-space:nowrap;opacity:0;will-change:opacity,filter,transform}

/* ── (3) neon border ─────────────────────────────────────────────────── */
/* The arc is one conic-gradient rotated by a CSS animation and clipped to a
   border band with mask-composite. Two copies half a lap apart. Where
   mask-composite is unsupported the element simply keeps its own border and
   nothing is drawn — @supports guards the whole thing. */
.fxn{position:relative;isolation:isolate}
@supports ((mask-composite: exclude) or (-webkit-mask-composite: xor)){
  .fxn::before,.fxn::after{
    content:'';position:absolute;inset:-1px;border-radius:inherit;padding:1.5px;
    background:conic-gradient(from var(--fxn-a,0deg),
      transparent 0deg,
      var(--fxn-c,#4DA6FF) calc(var(--fxn-band,26%) * 0.35),
      color-mix(in srgb, var(--fxn-c,#4DA6FF) 100%, white 40%) var(--fxn-band,26%),
      transparent calc(var(--fxn-band,26%) * 1.9),
      transparent 360deg);
    -webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
    -webkit-mask-composite:xor;
    mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
    mask-composite:exclude;
    animation:fxnSpin var(--fxn-t,7s) linear infinite;
    pointer-events:none;
  }
  /* the glow: the same band, blurred and additive */
  .fxn::after{filter:blur(7px);opacity:.75;animation-delay:calc(var(--fxn-t,7s) / -2)}
  .fxn::before{animation-delay:0s}
}
@property --fxn-a{syntax:'<angle>';inherits:false;initial-value:0deg}
@keyframes fxnSpin{to{--fxn-a:360deg}}
/* Firefox has no @property, so --fxn-a never animates and the arc would sit
   still. Rotating the whole pseudo-element is the fallback: same motion, one
   extra compositor layer. */
@supports not (background: paint(x)){
  @keyframes fxnSpin{to{transform:rotate(360deg)}}
}

/* ── (4) scroll reveal — headings only ───────────────────────────────── */
/* The mask is the ONLY thing that clips, and it clips a single line box, so a
   descender is never sliced. The inner span is what moves; the mask never does.
   Once .fxr-on lands the transform is cleared for good — this never reverses,
   because text that re-hides when you scroll back is text you cannot re-read. */
.fxr .fxr-m{display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-bottom:.14em;margin-bottom:-.14em}
/* FAIL-OPEN. This is the same guarantee _shared.css makes for .reveal, and
   shipping .fxr without it was a real bug: on /industries every heading stayed
   at opacity 0 because the IntersectionObserver never fired for them, and the
   page rendered as a blank screen with only the ::before counters visible.
   A CSS animation cannot be blocked by a script that failed, a browser without
   IntersectionObserver, or an observer that simply never fires — so after 1.8s
   the text is visible no matter what happened. When the observer DOES fire, it
   is long finished before this ever runs. */
.fxr .fxr-i{display:inline-block;transform:translateY(112%);opacity:0;
  transition:transform .55s cubic-bezier(.22,.75,.2,1),opacity .4s linear;
  animation:fxrSafety 1ms linear 1.8s forwards;
  will-change:transform,opacity}
@keyframes fxrSafety{to{opacity:1;transform:none}}
.fxr.fxr-on .fxr-i{transform:translateY(0);opacity:1;animation:none}
/* the no-JS / reduced-motion state: nothing hidden, nothing moved */
.fxr-static .fxr-i{transform:none!important;opacity:1!important}

/* ── page transitions ────────────────────────────────────────────────── */
/* A short cross-fade, on the whole document. Deliberately asymmetric: 220ms
   out so a click feels answered immediately, 420ms in so the arrival settles.
   Opacity only — sliding a whole page moves the text on it. */
html.agc-pt body{opacity:0}
html.agc-pt.agc-pt-in body{opacity:1;transition:opacity .42s ease}
html.agc-pt.agc-pt-out body{opacity:0;transition:opacity .22s ease}

/* Native cross-document view transitions where they exist. Same timing. */
@view-transition{navigation:auto}
::view-transition-old(root){animation:fxFadeOut .22s ease both}
::view-transition-new(root){animation:fxFadeIn .42s ease both}
@keyframes fxFadeOut{to{opacity:0}}
@keyframes fxFadeIn{from{opacity:0}}

/* ── nothing moves for anyone who asked for that ─────────────────────── */
@media (prefers-reduced-motion: reduce){
  .fxf-c,.fxr .fxr-i{transition:none!important;transform:none!important}
  .fxr .fxr-i{opacity:1!important}
  .fxm-w{animation:none!important}
  .fxm-w:not(:first-of-type){display:none}
  .fxn::before,.fxn::after{animation:none!important}
  html.agc-pt body{opacity:1!important;transition:none!important}
  @view-transition{navigation:none}
}
