/* ============================================================
 * inf-lusion.css — animation layer for
 * influencers-application-lusion.html
 *
 *   1. the hero scene is rebuilt as an isometric glass composition:
 *      the phone at centre, a product with a QR coupon feeding it a
 *      scan beam, rewards cascading out the other side, and an
 *      enterprise-sync panel behind
 *   2. the "how it works" row cards move onto the brand gradient and
 *      pick up the CTA band's dotted corners
 *   3. the USP grid becomes a sticky deck with content and an
 *      animated illustration per card
 *   4. the module band runs two to a row on a brand-tinted ground,
 *      with the about page's card entrance
 *
 * Sections 2-4 are carried over from van-lusion.css so the two pages
 * behave identically; only the prefix changes (if- rather than vl-).
 * The hero is this page's own, since its subject is not a van.
 *
 * Purely additive. Every rule is scoped under a class the script
 * adds, or under an id only this stylesheet targets, so nothing
 * outside those sections is touched and no copy changes. Loaded last,
 * so two-class selectors win over the page's own rules without
 * !important.
 * ========================================================== */

/* ============================================================
 * 1. Hero scene
 *
 * One loop, 12s, shared by every part so the beat lines up:
 *
 *   0.0-2.2s   the scan — beam travels the coupon into the lens
 *   2.2-4.4s   the award — "+100 points" lands on the phone
 *   4.4-7.0s   the cascade — coins climb to the wallet
 *   7.0-9.2s   the tier badge turns over, silver to gold
 *   9.2-12s    the payout card drops in, sync pulses to the panel
 *
 * Everything is driven off --ifh-cyc, so retiming the whole scene is
 * one number. Each element's own delay is a fraction of it.
 * ========================================================== */

.inf-scene{--ifh-cyc:12s;}

/* The rebuilt scene carries a product, a phone, a reward cascade and
   a sync panel where the page had one phone, so it is given the full
   width of its column rather than the 420px cap the lone phone used.
   The stage then hugs whatever the scene measures, instead of holding
   a fixed height with a dead band under it. */
.inf-scene{width:min(520px,100%);}
.inf-stage{height:auto;min-height:360px;padding:16px 0;}
@media (max-width:900px){.inf-stage{min-height:300px;}}
@media (max-width:480px){.inf-stage{min-height:240px;}}

/* ---------- glass panels ---------- */
.inf-scene .ifh-glass{
  fill:rgba(255,255,255,.10);
  stroke:rgba(255,255,255,.26);
  stroke-width:1.4;
}
.inf-scene .ifh-glass-deep{
  fill:rgba(255,255,255,.06);
  stroke:rgba(255,255,255,.18);
  stroke-width:1.2;
}

/* ---------- the phone, breathing on the spot ---------- */
.inf-scene .ifh-phone{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:ifhFloat 6s ease-in-out infinite;
}
@keyframes ifhFloat{
  0%,100%{transform:translateY(0);}
  50%{transform:translateY(-7px);}
}

/* ---------- 1. the scan ----------
   The beam wipes along the ribbon from coupon to lens, then the
   scanner frame on screen flashes to confirm the read. */
.inf-scene .ifh-beam{
  stroke-dasharray:14 170;
  animation:ifhBeam var(--ifh-cyc) linear infinite;
}
@keyframes ifhBeam{
  0%{stroke-dashoffset:184;opacity:0;}
  3%{opacity:1;}
  18%{stroke-dashoffset:0;opacity:1;}
  22%,100%{stroke-dashoffset:0;opacity:0;}
}
.inf-scene .ifh-scanline{
  animation:ifhScan var(--ifh-cyc) ease-in-out infinite;
}
@keyframes ifhScan{
  0%{transform:translateY(0);opacity:0;}
  2%{opacity:.95;}
  16%{transform:translateY(52px);opacity:.95;}
  20%,100%{transform:translateY(52px);opacity:0;}
}
.inf-scene .ifh-qr-glow{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:ifhQr var(--ifh-cyc) ease-out infinite;
}
@keyframes ifhQr{
  0%{transform:scale(.8);opacity:.9;}
  14%{transform:scale(1.5);opacity:0;}
  100%{transform:scale(1.5);opacity:0;}
}

/* ---------- 2. the award on screen ---------- */
.inf-scene .ifh-award{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:ifhAward var(--ifh-cyc) cubic-bezier(.34,1.32,.44,1) infinite;
}
@keyframes ifhAward{
  0%,17%{opacity:0;transform:translateY(14px) scale(.86);}
  23%,52%{opacity:1;transform:translateY(0) scale(1);}
  58%,100%{opacity:0;transform:translateY(-10px) scale(.95);}
}

/* ---------- 3. coins climbing to the wallet ---------- */
.inf-scene .ifh-coin{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:ifhCoin var(--ifh-cyc) ease-in-out infinite;
}
.inf-scene .ifh-coin.k2{animation-delay:calc(var(--ifh-cyc) * -0.955);}
.inf-scene .ifh-coin.k3{animation-delay:calc(var(--ifh-cyc) * -0.910);}
.inf-scene .ifh-coin.k4{animation-delay:calc(var(--ifh-cyc) * -0.865);}
/* The coins start at (344,268) and have to arrive at the wallet's
   centre, (440,145) — so the end of the path is +96,-123, not a round
   number. Change either position and this has to move with it. */
@keyframes ifhCoin{
  0%,34%{opacity:0;transform:translate(0,0) scale(.6);}
  40%{opacity:1;transform:translate(22px,-30px) scale(1);}
  56%{opacity:1;transform:translate(70px,-95px) scale(1);}
  62%,100%{opacity:0;transform:translate(96px,-123px) scale(.72);}
}
.inf-scene .ifh-wallet-pulse{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:ifhPulse var(--ifh-cyc) ease-out infinite;
}
@keyframes ifhPulse{
  0%,52%{transform:scale(.85);opacity:0;}
  58%{transform:scale(1);opacity:.75;}
  68%,100%{transform:scale(1.5);opacity:0;}
}

/* ---------- 4. the tier badge turning over ---------- */
.inf-scene .ifh-tier{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:ifhTier var(--ifh-cyc) ease-in-out infinite;
}
@keyframes ifhTier{
  0%,56%{transform:rotateY(0deg) scale(1);}
  62%{transform:rotateY(90deg) scale(1.06);}
  68%{transform:rotateY(0deg) scale(1.06);}
  76%,100%{transform:rotateY(0deg) scale(1);}
}
/* the gold face is hidden until the flip is edge-on, so the swap
   reads as one badge turning rather than two badges crossfading */
.inf-scene .ifh-tier-gold{
  opacity:0;
  animation:ifhTierGold var(--ifh-cyc) steps(1,end) infinite;
}
@keyframes ifhTierGold{
  0%,61%{opacity:0;}
  62%,100%{opacity:1;}
}
.inf-scene .ifh-tier-silver{
  opacity:1;
  animation:ifhTierSilver var(--ifh-cyc) steps(1,end) infinite;
}
@keyframes ifhTierSilver{
  0%,61%{opacity:1;}
  62%,100%{opacity:0;}
}

/* ---------- 5. the payout card ---------- */
.inf-scene .ifh-payout{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:ifhPayout var(--ifh-cyc) cubic-bezier(.34,1.32,.44,1) infinite;
}
@keyframes ifhPayout{
  0%,72%{opacity:0;transform:translateY(16px) scale(.88);}
  79%,94%{opacity:1;transform:translateY(0) scale(1);}
  99%,100%{opacity:0;transform:translateY(-8px) scale(.96);}
}

/* ---------- 6. enterprise sync behind ----------
   The link lines march continuously; the panel's bars step up on the
   beat so the sync reads as caused by the payout, not decorative. */
.inf-scene .ifh-link{
  stroke-dasharray:5 9;
  animation:ifhLink 1.4s linear infinite;
}
@keyframes ifhLink{to{stroke-dashoffset:-14;}}

.inf-scene .ifh-bar{
  transform-box:fill-box;transform-origin:50% 100%;
  animation:ifhBar var(--ifh-cyc) ease-in-out infinite;
}
.inf-scene .ifh-bar.b2{animation-delay:calc(var(--ifh-cyc) * -0.03);}
.inf-scene .ifh-bar.b3{animation-delay:calc(var(--ifh-cyc) * -0.06);}
.inf-scene .ifh-bar.b4{animation-delay:calc(var(--ifh-cyc) * -0.09);}
@keyframes ifhBar{
  0%,74%{transform:scaleY(.42);}
  84%{transform:scaleY(1);}
  96%,100%{transform:scaleY(.42);}
}
.inf-scene .ifh-node{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:ifhNode 2.6s ease-out infinite;
}
.inf-scene .ifh-node.n2{animation-delay:-.9s;}
.inf-scene .ifh-node.n3{animation-delay:-1.8s;}
@keyframes ifhNode{
  0%{transform:scale(.7);opacity:.8;}
  100%{transform:scale(1.7);opacity:0;}
}

@media (prefers-reduced-motion:reduce){
  .inf-scene .ifh-phone,.inf-scene .ifh-beam,.inf-scene .ifh-scanline,
  .inf-scene .ifh-qr-glow,.inf-scene .ifh-award,.inf-scene .ifh-coin,
  .inf-scene .ifh-wallet-pulse,.inf-scene .ifh-tier,.inf-scene .ifh-payout,
  .inf-scene .ifh-link,.inf-scene .ifh-bar,.inf-scene .ifh-node,
  .inf-scene .ifh-tier-gold,.inf-scene .ifh-tier-silver{
    animation:none !important;transform:none !important;
  }
  /* the finished state: awarded, gold tier, payout shown */
  .inf-scene .ifh-award,.inf-scene .ifh-payout,
  .inf-scene .ifh-tier-gold{opacity:1 !important;}
  .inf-scene .ifh-beam,.inf-scene .ifh-scanline,.inf-scene .ifh-qr-glow,
  .inf-scene .ifh-coin,.inf-scene .ifh-wallet-pulse,.inf-scene .ifh-node,
  .inf-scene .ifh-tier-silver{opacity:0 !important;}
}

.if-stacked{
  --if-top: 104px;      /* where every card pins, clearing the header */
  --if-gap: 15vh;       /* scroll distance between one pin and the next */
  --if-min: 52vh;       /* card height — no dead frame under a pinned card */
  --if-tail: 22vh;      /* the LAST card's stick room, plus the surplus
                           that keeps the FIRST pinned until it arrives */
  --if-ease: cubic-bezier(.22,.8,.3,1);
  --if-back: cubic-bezier(.34,1.32,.44,1);
}

/* ============================================================
 * 3. The sticky deck (USP grid)
 * ========================================================== */

/* ---------- vortex backdrop ----------
 * The same swirl the integration page runs behind its deck.
 * isolation:isolate keeps the canvas's z-index local to this section,
 * so it can sit under the cards without reaching past the section.
 * Deliberately NOT overflow:hidden — that would make this a scroll
 * container and kill the sticky canvas and the sticky cards with it. */
.if-stage{
  position:relative;
  background:#fff;
  isolation:isolate;
}

/* Pinned to the viewport while the section scrolls past, so the viewer
   stays inside the swirl instead of watching a slice of one enormous
   circle. The negative margin takes it back out of flow, so it adds no
   layout height; without it a 100vh block would push the deck down.
   It also keeps the canvas viewport-sized rather than as tall as the
   whole deck — far fewer pixels a frame. */
.if-vortex{
  position:sticky;
  top:0;
  height:100vh;
  margin-bottom:-100vh;
  z-index:0;
  pointer-events:none;
  opacity:0;
  transition:opacity 1.3s var(--if-ease,ease);
}
.if-stage.if-on-stage .if-vortex{opacity:1;}
.if-vortex canvas{display:block;width:100%;height:100%;}

/* On a white ground the arcs need lifting off the page rather than
   darkening down — a white veil, falling off toward the centre where
   the deck sits, so the strokes stay strongest at the margins. */
.if-vortex::after{
  content:"";
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(118% 78% at 50% 45%,
    rgba(255,255,255,.88), rgba(255,255,255,.52) 62%, rgba(255,255,255,.18) 100%);
}
.if-stage > .container{position:relative;z-index:2;}

@media (prefers-reduced-motion:reduce){.if-vortex{display:none;}}
.if-stack.bento{display:block;margin-top:8px;}

/* A real in-flow spacer. A sticky box is constrained by its
   containing block's CONTENT box, so padding-bottom on .bento would
   not extend it and a margin on the last card collapses out of the
   parent entirely. Without this the final card has exactly zero
   stick room, never pins, and the cards above release early. */
.if-stack-tail{
  display:block;
  height:var(--if-tail,22vh);
  pointer-events:none;
}

.if-stack > .feat{
  position:sticky;
  top:var(--if-top,104px);
  margin-bottom:var(--if-gap,15vh);
  min-height:var(--if-min,52vh);
  width:100%;
  display:flex;
  flex-direction:column;
  justify-content:center;
  grid-column:auto;
  padding:38px 44px;
  background:var(--white,#fff);
  border:1px solid #EDF1F7;
  border-radius:var(--radius,18px);

  /* The pin IS the entrance, so the page's own .reveal offset has to
     be cleared: a transform on a sticky box fights the pin. */
  opacity:1;
  transform:none;
  transition:none;

  box-shadow:
    0 1px 2px rgba(16,31,56,.030),
    0 4px 10px rgba(16,31,56,.032),
    0 12px 26px rgba(16,31,56,.038),
    0 28px 58px rgba(16,31,56,.045);
}
.if-stack > .feat:hover{transform:none;border-color:#E2D7F2;}
.if-stack > .feat.if-last{margin-bottom:0;}
.if-stack > .feat.span2,
.if-stack > .feat.span3,
.if-stack > .feat.span6{grid-column:auto;}

/* The heading scrolls away with the page like any other section head,
   matching the other two decks. Pinning it makes it hang over the
   cards passing beneath, so it stays plain flow content, with no
   background band — nothing travels under it. The first card simply
   rises over it, which is what the deck is meant to look like.

   .section-head also carries the page's .reveal, which would fade the
   whole block in on top of the per-element entrances this layer gives
   the pill, the h2 and the lede. Cleared, so those play alone. */
.if-stage .section-head{
  margin-bottom:26px;
  opacity:1;
  transform:none;
  transition:none;
}

/* ---------- card layout: copy left, illustration right ---------- */
.if-stack > .feat.if-has-vec{
  display:grid;
  grid-template-columns:minmax(0,1.04fr) minmax(0,.96fr);
  gap:46px;
  align-items:center;
}
.if-card-text{min-width:0;}
.if-card-vec{min-width:0;display:flex;align-items:center;justify-content:center;}
.if-card-vec svg{width:100%;height:auto;max-height:290px;overflow:visible;}

.if-points{list-style:none;margin:18px 0 0;padding:0;}
.if-points .if-point{
  position:relative;
  padding:11px 0 11px 26px;
  margin:0;
  border-top:1px solid var(--line-soft,#EDF1F6);
  font-size:14.5px;line-height:1.55;font-weight:600;
  color:var(--ink-soft,#5B6675);
}
.if-points .if-point::before{
  content:"";position:absolute;left:3px;top:19px;
  width:8px;height:8px;border-radius:50%;
  background:var(--grad,linear-gradient(135deg,#701893,#1308AD));
}

/* ---------- card entrance — one class plays the sequence ---------- */
.if-stack .if-noanim,
.if-stack .if-noanim *{transition:none !important;animation:none !important;}

.if-stack > .feat .feat-ico{
  opacity:0;transform:scale(.66) rotate(-10deg);
  transition:opacity .5s var(--if-ease), transform .62s var(--if-back);
  transition-delay:60ms;
}
.if-stack > .feat.if-in .feat-ico{opacity:1;transform:none;}

.if-stack > .feat h3{
  opacity:0;transform:translateY(16px);clip-path:inset(0 0 100% 0);
  transition:opacity .55s var(--if-ease), transform .7s var(--if-ease), clip-path .7s var(--if-ease);
  transition-delay:150ms;
}
.if-stack > .feat.if-in h3{opacity:1;transform:none;clip-path:inset(0 0 0 0);}

.if-stack > .feat .tag{
  opacity:0;clip-path:inset(0 100% 0 0 round 999px);
  transition:opacity .35s var(--if-ease), clip-path .65s var(--if-ease);
  transition-delay:320ms;
}
.if-stack > .feat.if-in .tag{opacity:1;clip-path:inset(0 0 0 0 round 999px);}

.if-stack > .feat > p{
  opacity:0;transform:translateY(10px);
  transition:opacity .5s var(--if-ease), transform .6s var(--if-ease);
  transition-delay:260ms;
}
.if-stack > .feat.if-in > p{opacity:1;transform:none;}

.if-stack > .feat .if-points .if-point{
  opacity:0;transform:translateY(12px);
  transition:opacity .5s var(--if-ease), transform .6s var(--if-ease);
  transition-delay:calc(420ms + var(--i,0) * 95ms);
}
.if-stack > .feat.if-in .if-points .if-point{opacity:1;transform:none;}

/* ---------- illustration animations ---------- */
.if-card-vec [data-if-draw]{
  stroke-dashoffset:var(--len,0);
  transition:stroke-dashoffset 1.3s var(--if-ease);
  transition-delay:var(--dd,0ms);
}
.if-in .if-card-vec [data-if-draw]{stroke-dashoffset:0;}

.if-card-vec .if-pop{
  opacity:0;transform:scale(.68);
  transform-box:fill-box;transform-origin:50% 50%;
  transition:opacity .5s var(--if-ease), transform .62s var(--if-back);
  transition-delay:calc(260ms + var(--p,0) * 100ms);
}
.if-in .if-card-vec .if-pop{opacity:1;transform:none;}

.if-card-vec .if-bar{
  transform:scaleY(0);
  transform-box:fill-box;transform-origin:50% 100%;
  transition:transform .8s var(--if-ease);
  transition-delay:calc(320ms + var(--p,0) * 95ms);
}
.if-in .if-card-vec .if-bar{transform:none;}

.if-card-vec .if-flow{opacity:0;transition:opacity .5s ease .7s;}
.if-in .if-card-vec .if-flow{opacity:1;}

.if-card-vec .if-float,
.if-card-vec .if-ring,
.if-card-vec .if-spin{animation-play-state:paused;}
.if-in .if-card-vec .if-float,
.if-in .if-card-vec .if-ring,
.if-in .if-card-vec .if-spin{animation-play-state:running;}

.if-card-vec .if-float{
  animation:ifFloat 4.4s ease-in-out infinite;
  transform-box:fill-box;transform-origin:50% 50%;
}
@keyframes ifFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}

.if-card-vec .if-ring{
  fill:none;animation:ifRing 3s ease-out infinite;
  transform-box:fill-box;transform-origin:50% 50%;
}

.if-card-vec .if-spin{
  transform-box:view-box;animation:ifSpin 24s linear infinite;
}
@keyframes ifSpin{to{transform:rotate(360deg)}}

/* the scan bar sweeping the QR on the verification card */
.if-card-vec .if-scanbar{
  animation:ifScanbar 2.8s ease-in-out infinite;
}
@keyframes ifScanbar{
  0%{transform:translateY(0);opacity:0;}
  8%{opacity:.95;}
  48%{transform:translateY(108px);opacity:.95;}
  56%,100%{transform:translateY(108px);opacity:0;}
}

/* ============================================================
 * 4. Smaller screens — the deck unstacks into a normal column
 * ========================================================== */
@media (max-width:991px){
  .if-stack.bento{display:grid;grid-template-columns:1fr;gap:26px;}
  .if-stack > .feat{position:relative;min-height:0;margin-bottom:0;padding:28px 26px;}
  .if-stack > .feat.if-last{margin-bottom:0;}
  .if-stack-tail{display:none;}
  .if-stack > .feat.if-has-vec{grid-template-columns:1fr;gap:24px;}
  .if-card-vec{order:2;}
  .if-card-vec svg{max-height:210px;}
  .if-stage .section-head{margin-bottom:34px;}
}
@media (max-width:575px){
  .if-stack > .feat{padding:24px 22px;}
  .if-points .if-point{font-size:13.5px;padding:9px 0 9px 22px;}
  .if-points .if-point::before{top:16px;width:7px;height:7px;}
  .if-card-vec{display:none;}   /* copy wins the space on a phone */
}

/* ============================================================
 * 5. Reduced motion
 * ========================================================== */
@media (prefers-reduced-motion:reduce){
  .if-stack > .feat{position:relative;min-height:0;margin-bottom:26px;}
  .if-stack-tail{display:none;}
  .if-stack > .feat .feat-ico,
  .if-stack > .feat h3,
  .if-stack > .feat .tag,
  .if-stack > .feat > p,
  .if-stack > .feat .if-points .if-point,
  .if-card-vec .if-pop,.if-card-vec .if-flow{
    opacity:1 !important;transform:none !important;
    clip-path:none !important;transition:none !important;
  }
  .if-card-vec .if-bar{transform:none !important;transition:none !important;}
  .if-card-vec [data-if-draw]{stroke-dashoffset:0 !important;transition:none !important;}
  .if-card-vec .if-float,.if-card-vec .if-ring,.if-card-vec .if-spin,
  .if-card-vec .if-scanbar{animation:none !important;}
}
/* ============================================================
 * 2. The "how it works" band
 * ========================================================== */

/* ---------- the row cards, on the brand gradient ----------
 * The page ships these white. On --grad they have to carry their own
 * contents: everything inside was coloured for a white card, and left
 * alone the ink, the faint sub-labels and the gradient-filled bars
 * would all but disappear. Each is restated below against the dark
 * ground, so only the surface changes and no copy moves. */
.if-flow-sec .flow-visual{
  background:var(--grad,linear-gradient(135deg,#701893,#1308AD));
  border-color:rgba(255,255,255,.16);
  box-shadow:
    0 2px 6px rgba(32,10,70,.14),
    0 14px 34px rgba(32,10,70,.20),
    0 30px 64px rgba(32,10,70,.16);

  /* the dot corners below are absolutely positioned and bleed past the
     edges, so the card has to position and clip them itself — the page
     sets neither on .flow-visual */
  position:relative;
  overflow:hidden;
}

/* ---------- the CTA band's dotted corners, on these cards ----------
 * Same recipe the page uses for .cta: a 16px grid of 1.5px dots, laid
 * in two patches and masked to a soft blob so the texture fades out
 * rather than stopping at a hard edge. One patch top-left, one
 * bottom-right, exactly as the band does it.
 *
 * Dot size, spacing, colour and mask shape are the band's own values,
 * so the texture matches across the page. Only the patch offsets are
 * pulled in, because these cards are a fraction of the band's width
 * and the band's -30/-40px would push most of the pattern out of
 * sight. The percentages size themselves. */
.if-flow-sec .flow-visual::before,
.if-flow-sec .flow-visual::after{
  content:"";
  position:absolute;
  width:min(52%,260px);
  height:84%;
  z-index:0;
  pointer-events:none;
  background-image:radial-gradient(circle,
    rgba(255,255,255,.32) 1.5px, transparent 1.6px);
  background-size:16px 16px;
}
.if-flow-sec .flow-visual::before{
  left:-18px;top:-22px;
  -webkit-mask-image:radial-gradient(circle at 22% 30%, #000 0%, #000 40%, transparent 70%);
          mask-image:radial-gradient(circle at 22% 30%, #000 0%, #000 40%, transparent 70%);
}
.if-flow-sec .flow-visual::after{
  right:-18px;bottom:-22px;
  -webkit-mask-image:radial-gradient(circle at 78% 70%, #000 0%, #000 40%, transparent 70%);
          mask-image:radial-gradient(circle at 78% 70%, #000 0%, #000 40%, transparent 70%);
}

/* the rows ride above the texture. .flow-visual is a flex container,
   so this also keeps the pseudo-elements from being treated as items —
   they are absolutely positioned, which takes them out of flow. */
.if-flow-sec .flow-visual > *{position:relative;z-index:1;}

/* the icon tile was a pale lavender chip with purple glyph — invisible
   logic on a purple card, so it becomes a frosted chip instead */
.if-flow-sec .flow-visual .fv-ico{
  background:rgba(255,255,255,.16);
  color:#fff;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.18);
}

.if-flow-sec .flow-visual .fv-txt{color:#fff;}
.if-flow-sec .flow-visual .fv-txt small{color:rgba(255,255,255,.68);}

/* the track was light grey on white; the fill was --grad, which would
   now be gradient on gradient. They swap roles: a translucent well
   with a bright fill. */
.if-flow-sec .flow-visual .fv-bar{background:rgba(255,255,255,.18);}
.if-flow-sec .flow-visual .fv-bar > i{
  background:linear-gradient(90deg,#ffffff,#d9c6ff);
}

/* ============================================================

 * 6. The module band — two cards to a row, on brand colour
 *
 * Scoped to #modules, which only this stylesheet targets, so the id
 * selector outranks the page's own .mod-list / .mod-card / .stats-band
 * rules without needing !important and without touching them.
 * ========================================================== */

/* The page ships this band as neutral grey (--bg-alt: #F5F7FA).
   Replaced with the brand's own light tints, running purple into
   indigo in the same direction as --grad, so the strip reads as part
   of the theme instead of generic page furniture. */
#modules.stats-band{
  background:linear-gradient(180deg,#F8F3FD 0%,#F0E7F9 52%,#E9E7FB 100%);
}

/* Two to a row. The page's rule is a bare single-column grid, so only
   the column track and the gap need stating. Six cards divide into
   three even rows, and stretch keeps the pair in each row level. */
#modules .mod-list{
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:22px;
  align-items:stretch;
}

/* Each card carries its bullets in two columns. At half width those
   columns come out near 150px and most items wrap to a second line,
   so the list runs single column here and the card grows taller
   instead. */
#modules .mod-card ul{columns:1;}

/* White cards need a slightly warmer edge against a tinted ground
   than they do against grey. */
#modules .mod-card{border-color:#E7DCF3;}

/* The eyebrow pill's own background is --red-soft (#F2E9F8), which is
   inside the range of the new band — it would melt into it, so it
   gets a white chip here and keeps its brand-purple text. */
#modules .section-head .eyebrow{background:var(--white,#fff);}

/* Below this the pair would be too narrow to carry a heading, a badge
   and the bullets, so the band goes back to one card per row. */
@media (max-width:900px){
  #modules .mod-list{grid-template-columns:1fr;}
}

/* ---------- the about page's card entrance, on these cards ----------
 * Lifted from lusion-hero.css rather than reinvented, so the two pages
 * share the same easings and durations. Scoped to .if-mods, a class the
 * script adds, so none of it reaches the deck or the hero.
 * The script strips these classes ~1.5s after a card lands, which is
 * what hands :hover back to the page's own rule. */
.if-mods{
  --ifm-ease:cubic-bezier(.22,.8,.3,1);
  --ifm-pop:cubic-bezier(.34,1.32,.44,1);
}

/* rewinding must not play the entrance backwards */
.if-mods .if-noanim,
.if-mods .if-noanim *{transition:none !important;animation:none !important;}

/* the ghost number needs a positioned card, the sheen needs a clipped
   one — neither is true of .mod-card by default */
.if-mods .mod-card{position:relative;overflow:hidden;}

/* --- card: hinges up from its bottom edge in perspective --- */
.if-mods .if-mcard{
  opacity:0;
  transform:perspective(1300px) rotateX(11deg) translateY(50px) scale(.955);
  transform-origin:50% 100%;
  transition:opacity .8s var(--ifm-ease), transform 1.05s var(--ifm-ease);
  transition-delay:var(--d,0ms);
  will-change:opacity,transform;
}
.if-mods .if-mcard.if-min{opacity:1;transform:none;}

/* --- sheen sweeping across as the card lands --- */
.if-mods .if-mcard::before{
  content:"";position:absolute;inset:0;z-index:3;pointer-events:none;
  background:linear-gradient(115deg,transparent 38%,rgba(104,60,220,.16) 50%,transparent 62%);
  transform:translateX(-130%);opacity:0;
}
.if-mods .if-mcard.if-min::before{
  animation:ifSheen 1.15s var(--ifm-ease) forwards;
  animation-delay:calc(var(--d,0ms) + 260ms);
}
@keyframes ifSheen{
  0%  {transform:translateX(-130%);opacity:0;}
  28% {opacity:1;}
  100%{transform:translateX(130%);opacity:0;}
}

/* --- icon: pops in --- */
.if-mods .if-mico{
  opacity:0;transform:scale(.42) rotate(-24deg);
  transition:opacity .5s var(--ifm-ease), transform .75s var(--ifm-pop);
  transition-delay:var(--d,0ms);
}
.if-mods .if-mico.if-min{opacity:1;transform:none;}

/* --- badge: wipes in from the left without distorting its text --- */
.if-mods .if-mtag{
  opacity:0;clip-path:inset(0 100% 0 0 round 999px);
  transition:opacity .35s var(--ifm-ease), clip-path .7s var(--ifm-ease);
  transition-delay:var(--d,0ms);
}
.if-mods .if-mtag.if-min{opacity:1;clip-path:inset(0 0 0 0 round 999px);}

/* --- the ghost index, dropping in out of focus --- */
.if-mods .if-num{
  position:absolute;right:26px;bottom:18px;
  font-size:34px;font-weight:900;letter-spacing:-.03em;line-height:1;
  color:var(--bg-alt-2,#EEF2F7);
  pointer-events:none;user-select:none;
}
.if-mods .if-mnum{
  opacity:0;transform:translateY(-16px) scale(1.35);filter:blur(7px);
  transition:opacity .75s var(--ifm-ease), transform .9s var(--ifm-ease),
             filter .75s var(--ifm-ease);
  transition-delay:var(--d,0ms);
}
.if-mods .if-mnum.if-min{opacity:1;transform:none;filter:blur(0);}

/* --- heading: each word hinges up out of a clip mask in 3D. The
       padding/margin pair keeps descenders (g, y, p) off the mask. --- */
.if-mods .if-w{
  display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-bottom:.2em;margin-bottom:-.2em;
  perspective:680px;
}
.if-mods .if-w > i{
  display:inline-block;font-style:inherit;
  transform:translateY(116%) rotateX(-68deg);
  transform-origin:50% 0%;
  opacity:0;filter:blur(5px);
  transition:transform 1.05s var(--ifm-ease),
             opacity .62s var(--ifm-ease),
             filter .62s var(--ifm-ease);
  transition-delay:var(--d,0ms);
  will-change:transform,opacity,filter;
}
.if-mods .if-split.if-min .if-w > i{transform:none;opacity:1;filter:blur(0);}

/* --- bullets: follow the heading, one after another --- */
.if-mods .if-mli{
  opacity:0;transform:translateY(10px);
  transition:opacity .5s var(--ifm-ease), transform .6s var(--ifm-ease);
  transition-delay:var(--d,0ms);
}
.if-mods .if-mli.if-min{opacity:1;transform:none;}

@media (prefers-reduced-motion:reduce){
  .if-mods .if-mcard,.if-mods .if-mico,.if-mods .if-mtag,
  .if-mods .if-mnum,.if-mods .if-mli,.if-mods .if-w > i{
    opacity:1 !important;transform:none !important;filter:none !important;
    clip-path:none !important;transition:none !important;
  }
  .if-mods .if-mcard::before{display:none !important;}
}

/* ============================================================
 * 6b. The connected-ecosystem tiles, on the brand gradient
 *
 * Scoped to #ecosystem, which only this stylesheet targets, so the id
 * outranks the page's own .eco-tile rules without !important and
 * without touching them.
 *
 * These tiles are links, and everything in them was coloured for a
 * white card: a teal kicker, navy heading and grey body. Left alone on
 * --grad the teal would muddy and the rest would all but vanish, so
 * each is restated against the dark ground. Only colour changes — no
 * copy, no layout, and the hover lift still works.
 * ========================================================== */
#ecosystem .eco-tile{
  background:var(--grad,linear-gradient(135deg,#701893,#1308AD));
  border-color:rgba(255,255,255,.16);
  box-shadow:
    0 2px 6px rgba(32,10,70,.14),
    0 12px 30px rgba(32,10,70,.18);
}

/* the page lifts the tile and turns its border --red on hover, which
   is the card's own purple and so invisible here — a light edge reads
   the lift instead */
#ecosystem .eco-tile:hover{
  border-color:rgba(255,255,255,.5);
  box-shadow:
    0 4px 10px rgba(32,10,70,.18),
    0 18px 42px rgba(32,10,70,.26);
}

/* teal at --teal is too dark to sit on this gradient; the lighter mint
   the page already uses on its dark hero chips carries over */
#ecosystem .eco-tile .k{color:#8fe9d5;}
#ecosystem .eco-tile h4{color:#ffffff;}
#ecosystem .eco-tile p{color:rgba(255,255,255,.72);}

/* ============================================================

 * 7. Support for lusion-motion.js
 *
 * That script is shared across the demo pages, where these rules
 * live in lusion-hero.css. This page does not load that file, so the
 * three things it depends on are repeated here. They are not
 * optional: without the .lx-roll rules the letter-roll leaves BOTH
 * copies of every character in the flow and the nav reads doubled.
 * ========================================================== */

/* The page stylesheet sets html{scroll-behavior:smooth}. Left in
   place it makes every scrollTo() in the lerp start a NEW native
   smooth animation that the next frame cancels — the page stalls,
   then lurches. */
html.lx-smooth{scroll-behavior:auto !important;}

.lx-roll{
  display:inline-block;
  overflow:hidden;
  vertical-align:top;
  line-height:inherit;
}
.lx-roll__c{
  display:inline-block;
  position:relative;
  white-space:pre;
  transition:transform .52s cubic-bezier(.22,.61,.36,1);
  transition-delay:calc(var(--i) * 18ms);
  will-change:transform;
}
.lx-roll__c span{display:block;}
.lx-roll__c span:last-child{position:absolute;left:0;top:100%;}
.lx-roll:hover .lx-roll__c,
a:hover .lx-roll .lx-roll__c,
button:hover .lx-roll .lx-roll__c{transform:translateY(-100%);}

.lx-mag{will-change:transform;}
.lx-mag__inner{display:inline-flex;align-items:center;gap:inherit;will-change:transform;}

@media (prefers-reduced-motion:reduce){
  .lx-roll__c{transition:none;}
}
