/* ============================================================
 * van-lusion.css — animation layer for
 * van-sales-automation-lusion.html
 *
 *   1. a four-stage hero scene — load-out, route, sale, sync —
 *      over one lit track the van drives, lighting each stage
 *   2. a van lapping the foot of the "What it is" intro
 *   3. the USP grid becomes a sticky deck with content and an
 *      animated illustration per card
 *
 * Purely additive. Every rule is scoped under a class the script
 * adds, 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.
 * ========================================================== */

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

/* ============================================================
 * 1. Hero scene
 *
 * Four numbered stages — load-out, route, sale, sync — sit over one
 * lit track, and the van runs that track. Each stage lights exactly
 * as the van reaches its node, so one cycle length (--vl-cyc) drives
 * everything and each stage only differs by its --dly.
 *
 * The van is 218 units wide at 1.05, so its centre sits 114.45 units
 * in front of its own origin. It travels -230 -> 600, a span of 830,
 * so it reaches the stage at centre cx when the cycle is (cx - 114.45
 * + 230) / 830 through. Each --dly below is (that fraction - 1) x the
 * cycle, which is the same instant one cycle earlier. Stage centres
 * are 75 / 225 / 375 / 525.
 *
 * Every rule is scoped to .van-scene so nothing here reaches the
 * card illustrations further down the page. The page's own keyframes
 * still drive .van-move, .van-wheel, .van-road and .van-speed.
 * ========================================================== */

.van-scene{--vl-cyc:16s;}

/* Four stages above a track is a taller frame than the lone van was.
   The SVG is width-constrained, so rather than guess a fixed height
   per breakpoint the stage simply hugs whatever the scene measures —
   no dead band under it on a narrow column, no clipping on a wide
   one. .van-glow is absolutely positioned, so it still tracks this. */
.van-stage{height:auto;min-height:340px;padding:18px 0;}
@media (max-width:900px){.van-stage{min-height:240px;}}

/* ---------- the van working the track ---------- */
.van-scene .vl-travel{animation:vlTravel var(--vl-cyc) linear infinite;}
@keyframes vlTravel{
  from{transform:translateX(-230px);}
  to{transform:translateX(600px);}
}

/* stock in the van, worked down call by call */
.van-scene .vl-crate{
  transform-box:fill-box;transform-origin:50% 100%;
  animation:vlCrate var(--vl-cyc) ease-in-out infinite;
}
.van-scene .vl-crate.c2{animation-delay:-5.33s;}
.van-scene .vl-crate.c3{animation-delay:-10.66s;}
@keyframes vlCrate{
  0%,8%{transform:scaleY(1);opacity:1;}
  26%,70%{transform:scaleY(.42);opacity:.75;}
  88%,100%{transform:scaleY(1);opacity:1;}
}

/* ---------- a stage lighting as the van arrives ---------- */
.van-scene .vl-st{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:vlStage var(--vl-cyc) ease-in-out infinite;
  animation-delay:var(--dly,0s);
}
.van-scene .vl-st.s1{--dly:-12.327s;}
.van-scene .vl-st.s2{--dly:-9.435s;}
.van-scene .vl-st.s3{--dly:-6.544s;}
.van-scene .vl-st.s4{--dly:-3.652s;}
@keyframes vlStage{
  0%{opacity:1;transform:scale(1.045);}
  10%{opacity:1;transform:scale(1.03);}
  24%,92%{opacity:.56;transform:scale(1);}
  100%{opacity:1;transform:scale(1.045);}
}

/* the halo behind a stage, on the same beat (--dly is inherited) */
.van-scene .vl-st-halo{
  opacity:0;
  animation:vlHalo var(--vl-cyc) ease-in-out infinite;
  animation-delay:var(--dly,0s);
}
@keyframes vlHalo{
  0%{opacity:1;} 14%{opacity:.8;} 30%,94%{opacity:0;} 100%{opacity:1;}
}

/* the node the stage hangs from, pulsing on the same beat */
.van-scene .vl-node2-ring{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:vlRing 2s ease-out infinite;
  animation-delay:var(--dly,0s);
}
.van-scene .vl-node2.s1{--dly:-12.327s;}
.van-scene .vl-node2.s2{--dly:-9.435s;}
.van-scene .vl-node2.s3{--dly:-6.544s;}
.van-scene .vl-node2.s4{--dly:-3.652s;}

/* shared expanding-ring pulse */
@keyframes vlRing{
  0%{transform:scale(.7);opacity:.85;}
  100%{transform:scale(1.6);opacity:0;}
}

/* ---------- stage 1: stock load-out ---------- */
.van-scene .vl-box{
  transform-box:fill-box;transform-origin:50% 100%;
  animation:vlBoxOut 4.4s ease-in-out infinite;
}
.van-scene .vl-box.b2{animation-delay:-1.5s;}
.van-scene .vl-box.b3{animation-delay:-3s;}
@keyframes vlBoxOut{
  0%,18%{transform:scaleY(1);opacity:1;}
  46%,74%{transform:scaleY(.5);opacity:.7;}
  94%,100%{transform:scaleY(1);opacity:1;}
}
.van-scene .vl-scan{animation:vlScan 2.6s ease-in-out infinite;}
@keyframes vlScan{
  0%{transform:translateY(0);opacity:0;}
  12%,88%{opacity:.95;}
  100%{transform:translateY(59px);opacity:0;}
}
.van-scene .vl-beam{animation:vlBeam .9s linear infinite;}
@keyframes vlBeam{to{stroke-dashoffset:-14;}}
.van-scene .vl-ship{animation:vlShip 2.6s ease-in infinite;}
@keyframes vlShip{
  0%{transform:translate(0,0);opacity:0;}
  14%,74%{opacity:1;}
  100%{transform:translate(26px,34px);opacity:0;}
}

/* ---------- stage 2: the optimised run ---------- */
.van-scene .vl-route2{
  stroke-dasharray:var(--len,96);
  animation:vlDraw2 4s ease-in-out infinite;
}
@keyframes vlDraw2{
  0%{stroke-dashoffset:var(--len,96);}
  38%,86%{stroke-dashoffset:0;}
  100%{stroke-dashoffset:calc(var(--len,96) * -1);}
}
.van-scene .vl-ping{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:vlRing 2.2s ease-out infinite;
}
.van-scene .vl-pin{
  transform-box:fill-box;transform-origin:50% 100%;
  animation:vlPin 2.4s ease-in-out infinite;
}
@keyframes vlPin{
  0%,100%{transform:translateY(0) scale(1);}
  50%{transform:translateY(-7px) scale(1.06);}
}

/* ---------- stage 3: the sale at the counter ---------- */
.van-scene .vl-slip{animation:vlSlip 4s ease-in-out infinite;}
@keyframes vlSlip{
  0%,10%{transform:translateY(26px);opacity:0;}
  30%,74%{transform:translateY(0);opacity:1;}
  92%,100%{transform:translateY(-10px);opacity:0;}
}
.van-scene .vl-tick{
  stroke-dasharray:var(--len,34);stroke-dashoffset:var(--len,34);
  animation:vlTick 4s ease-out infinite;
}
@keyframes vlTick{
  0%,32%{stroke-dashoffset:var(--len,34);}
  48%,88%{stroke-dashoffset:0;}
  100%{stroke-dashoffset:var(--len,34);}
}
.van-scene .vl-pay{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:vlPay 4s ease-out infinite;
}
@keyframes vlPay{
  0%,42%{opacity:0;transform:translateY(10px) scale(.6);}
  56%{opacity:1;transform:translateY(0) scale(1);}
  86%,100%{opacity:0;transform:translateY(-20px) scale(.88);}
}

/* ---------- stage 4: sync and the end-of-day read ---------- */
.van-scene .vl-cloud{animation:vlFloat 4.2s ease-in-out infinite;}
@keyframes vlFloat{
  0%,100%{transform:translateY(0);} 50%{transform:translateY(-5px);}
}
.van-scene .vl-arrows .a1{animation:vlArrowDown 1.8s ease-in-out infinite;}
.van-scene .vl-arrows .a2{animation:vlArrowUp 1.8s ease-in-out infinite;animation-delay:-.9s;}
@keyframes vlArrowDown{
  0%{opacity:0;transform:translateY(-5px);}
  40%{opacity:1;transform:translateY(0);}
  100%{opacity:0;transform:translateY(5px);}
}
@keyframes vlArrowUp{
  0%{opacity:0;transform:translateY(5px);}
  40%{opacity:1;transform:translateY(0);}
  100%{opacity:0;transform:translateY(-5px);}
}
.van-scene .vl-bar{
  transform-box:fill-box;transform-origin:50% 100%;
  animation:vlGrow 3.2s ease-in-out infinite;
}
.van-scene .vl-bar.k2{animation-delay:-.4s;}
.van-scene .vl-bar.k3{animation-delay:-.8s;}
.van-scene .vl-bar.k4{animation-delay:-1.2s;}
@keyframes vlGrow{
  0%,100%{transform:scaleY(.38);}
  50%{transform:scaleY(1);}
}

/* ---------- the chevrons between stages ---------- */
.van-scene .vl-link path{animation:vlChev 2.4s ease-in-out infinite;}
.van-scene .vl-link .g2{animation-delay:-.5s;}
.van-scene .vl-link .g3{animation-delay:-1s;}
@keyframes vlChev{
  0%,100%{opacity:.3;transform:translateX(-3px);}
  50%{opacity:1;transform:translateX(3px);}
}

@media (prefers-reduced-motion:reduce){
  .van-scene .vl-travel{animation:none !important;transform:translateX(160px);}
  .van-scene .vl-st,.van-scene .vl-crate,.van-scene .vl-box,.van-scene .vl-pin,
  .van-scene .vl-slip,.van-scene .vl-pay,.van-scene .vl-cloud,.van-scene .vl-bar,
  .van-scene .vl-link path,.van-scene .vl-arrows path{
    animation:none !important;opacity:1 !important;transform:none !important;
  }
  .van-scene .vl-st-halo,.van-scene .vl-scan,.van-scene .vl-ping,
  .van-scene .vl-node2-ring,.van-scene .vl-beam,.van-scene .vl-ship{
    animation:none !important;opacity:0 !important;
  }
  .van-scene .vl-route2,.van-scene .vl-tick{
    animation:none !important;stroke-dashoffset:0 !important;
  }
}

/* ============================================================
 * 2. Intro section
 * (the route watermark that used to sit behind this copy has
 *  been removed on request)
 * ========================================================== */

/* ---------- van running along the bottom of the intro ----------
 * A full-width strip at the foot of the section. The strip clips its
 * own overflow, so the van can start and finish well off screen
 * without the page ever gaining a horizontal scrollbar.
 *
 * The strip is absolutely positioned in the section's bottom band and
 * sits BEHIND the content, so the section has to reserve at least its
 * height as padding. The page's own 80px was less than the strip's
 * 132px, which left the route-load card hanging 52px over the van and
 * clipping its roof. Height and padding are driven off one variable
 * here so resizing the van cannot reintroduce that. */
.vl-intro-sec{
  --vl-drive-h:132px;
  position:relative;
  padding-bottom:calc(var(--vl-drive-h) + 12px);
}
.vl-intro-sec > .container{position:relative;z-index:1;}

.vl-drive{
  position:absolute;
  left:0;right:0;bottom:0;
  height:var(--vl-drive-h);
  overflow:hidden;
  pointer-events:none;
  z-index:0;
  opacity:0;
  transition:opacity 1s var(--vl-ease,ease);
}
.vl-on-sec .vl-drive{opacity:1;}

/* The lane sits low in the section, and the van straddles it so the
   dashes run through the wheel centres. The runner's negative offset
   is deliberate: the artwork carries 5 viewBox units of empty space
   below the wheels, which is 5 x width/150 in px, so the offset has
   to be re-derived whenever the width changes or the tyres drift off
   the lane. At 280px that empty band is 9.3px, and -7.4px leaves the
   tyres the same ~2px above the strip floor they had at 208px. */
.vl-drive .vl-lane{
  position:absolute;
  left:0;right:0;bottom:14px;
  height:3px;
  background:repeating-linear-gradient(90deg,
    rgba(112,24,147,.22) 0 22px, transparent 22px 42px);
}

.vl-drive .vl-runner{
  position:absolute;
  bottom:-7.4px;left:0;
  width:280px;
  will-change:transform;
  animation:vlDrive 17s linear infinite;
  animation-play-state:paused;
}
.vl-on-sec .vl-drive .vl-runner{animation-play-state:running;}
.vl-drive .vl-runner svg{display:block;width:100%;height:auto;}

/* starts and ends clear of the frame, so it never pops in or out */
@keyframes vlDrive{
  from{transform:translateX(-300px);}
  to{transform:translateX(calc(100vw + 300px));}
}

.vl-drive .vl-rw{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:vlSpin 1.1s linear infinite;
  animation-play-state:paused;
}
.vl-on-sec .vl-drive .vl-rw{animation-play-state:running;}

@media (max-width:700px){
  /* the section's reserved padding follows this down with it */
  .vl-intro-sec{--vl-drive-h:98px;}
  .vl-drive .vl-lane{bottom:10px;}
  /* offset rescales with the artwork, so the tyres still meet the lane */
  .vl-drive .vl-runner{width:200px;bottom:-5.7px;}
}
@media (prefers-reduced-motion:reduce){
  .vl-drive{display:none;}
}

/* ============================================================
 * 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. */
.vl-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. */
.vl-vortex{
  position:sticky;
  top:0;
  height:100vh;
  margin-bottom:-100vh;
  z-index:0;
  pointer-events:none;
  opacity:0;
  transition:opacity 1.3s var(--vl-ease,ease);
}
.vl-stage.vl-on-stage .vl-vortex{opacity:1;}
.vl-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. */
.vl-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%);
}
.vl-stage > .container{position:relative;z-index:2;}

@media (prefers-reduced-motion:reduce){.vl-vortex{display:none;}}

.vl-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. */
.vl-stack-tail{
  display:block;
  height:var(--vl-tail,22vh);
  pointer-events:none;
}

.vl-stack > .feat{
  position:sticky;
  top:var(--vl-top,104px);
  margin-bottom:var(--vl-gap,15vh);
  min-height:var(--vl-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);
}
.vl-stack > .feat:hover{transform:none;border-color:#E2D7F2;}
.vl-stack > .feat.vl-last{margin-bottom:0;}
.vl-stack > .feat.span2,
.vl-stack > .feat.span3,
.vl-stack > .feat.span6{grid-column:auto;}

/* The heading scrolls away with the page like any other section head.
   It was pinned above the deck at one point; that made it hang over
   the cards passing beneath it, so it is plain flow content now. No
   background either — the cards no longer travel under it, and a
   white band would only mask the vortex behind 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. */
.vl-stage .section-head{
  margin-bottom:26px;
  opacity:1;
  transform:none;
  transition:none;
}

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

.vl-points{list-style:none;margin:18px 0 0;padding:0;}
.vl-points .vl-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);
}
.vl-points .vl-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 ---------- */
.vl-stack .vl-noanim,
.vl-stack .vl-noanim *{transition:none !important;animation:none !important;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* ============================================================
 * 5b. The "how it works" band
 * ========================================================== */
.vl-flow-sec{
  position:relative;
  isolation:isolate;
}

/* the rows and the heading ride above the backdrop layer */
.vl-flow-sec > .container{position:relative;z-index:2;}

/* ---- RING BACKDROP: COMMENTED OUT ON REQUEST ----------------
 * Kept for later, alongside the Rings renderer in van-lusion.js and
 * the commented buildFlow() block that injects the canvas. Uncomment
 * both to switch it back on. Nothing below runs today: the .vl-rings
 * element is never created while that block stays commented.
 *
 * Notes worth keeping, since they are not obvious from the rules:
 *   - sticky + height:100vh + margin-bottom:-100vh is what keeps the
 *     canvas viewport-sized rather than as tall as the whole band, so
 *     it costs one screen of pixels a frame, and keeps the viewer
 *     inside the rings instead of watching a slice of one huge circle
 *   - .vl-flow-sec must NOT get overflow:hidden; that would make it a
 *     scroll container and the sticky canvas would stop sticking
 *   - the ::after veil is not decoration. The reference clip is neon
 *     on near-black and this band carries dark copy on a light ground,
 *     so the veil is what keeps the body text readable: heaviest in
 *     the middle where the rows are, thinnest at the margins.

.vl-rings{
  position:sticky;
  top:0;
  height:100vh;
  margin-bottom:-100vh;
  z-index:0;
  pointer-events:none;
  opacity:0;
  transition:opacity 1.3s var(--vl-ease,ease);
}
.vl-flow-sec.vl-rings-on .vl-rings{opacity:1;}
.vl-rings canvas{display:block;width:100%;height:100%;}

.vl-rings::after{
  content:"";
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(120% 82% at 50% 50%,
    rgba(245,247,250,.93), rgba(245,247,250,.74) 55%, rgba(245,247,250,.34) 100%);
}

@media (prefers-reduced-motion:reduce){.vl-rings{display:none;}}

 * ----------------------------------------------------------- */

/* ---------- 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. */
.vl-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. */
.vl-flow-sec .flow-visual::before,
.vl-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;
}
.vl-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%);
}
.vl-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. */
.vl-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 */
.vl-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);
}

.vl-flow-sec .flow-visual .fv-txt{color:#fff;}
.vl-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. */
.vl-flow-sec .flow-visual .fv-bar{background:rgba(255,255,255,.18);}
.vl-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 .vl-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. */
.vl-mods{
  --vlm-ease:cubic-bezier(.22,.8,.3,1);
  --vlm-pop:cubic-bezier(.34,1.32,.44,1);
}

/* rewinding must not play the entrance backwards */
.vl-mods .vl-noanim,
.vl-mods .vl-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 */
.vl-mods .mod-card{position:relative;overflow:hidden;}

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

/* --- sheen sweeping across as the card lands --- */
.vl-mods .vl-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;
}
.vl-mods .vl-mcard.vl-min::before{
  animation:vlSheen 1.15s var(--vlm-ease) forwards;
  animation-delay:calc(var(--d,0ms) + 260ms);
}
@keyframes vlSheen{
  0%  {transform:translateX(-130%);opacity:0;}
  28% {opacity:1;}
  100%{transform:translateX(130%);opacity:0;}
}

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

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

/* --- the ghost index, dropping in out of focus --- */
.vl-mods .vl-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;
}
.vl-mods .vl-mnum{
  opacity:0;transform:translateY(-16px) scale(1.35);filter:blur(7px);
  transition:opacity .75s var(--vlm-ease), transform .9s var(--vlm-ease),
             filter .75s var(--vlm-ease);
  transition-delay:var(--d,0ms);
}
.vl-mods .vl-mnum.vl-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. --- */
.vl-mods .vl-w{
  display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-bottom:.2em;margin-bottom:-.2em;
  perspective:680px;
}
.vl-mods .vl-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(--vlm-ease),
             opacity .62s var(--vlm-ease),
             filter .62s var(--vlm-ease);
  transition-delay:var(--d,0ms);
  will-change:transform,opacity,filter;
}
.vl-mods .vl-split.vl-min .vl-w > i{transform:none;opacity:1;filter:blur(0);}

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

@media (prefers-reduced-motion:reduce){
  .vl-mods .vl-mcard,.vl-mods .vl-mico,.vl-mods .vl-mtag,
  .vl-mods .vl-mnum,.vl-mods .vl-mli,.vl-mods .vl-w > i{
    opacity:1 !important;transform:none !important;filter:none !important;
    clip-path:none !important;transition:none !important;
  }
  .vl-mods .vl-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);}

/* ============================================================
 * 6c. Responsiveness repairs
 *
 * These are the page's own, not this layer's: every one of them
 * measures identically on the untouched van-sales-automation.html.
 * They are corrected here rather than there, as overrides, so the
 * original file stays byte-for-byte unchanged.
 * ========================================================== */

/* The stats band runs FIVE across from 761px up — the page's inline
   <style> sets that, not industry-page.css, which is why it is not
   where you would look for it. A .stat's min-content width is about
   167px (38px bold numerals plus 26px padding each side), so five
   tracks plus four 20px gaps need ~915px of container and there is
   nowhere near that until ~992px. The grid pushes past the viewport
   and the WHOLE PAGE gains a horizontal scrollbar: measured 88px of
   overflow at 768 and 22px at 900, on the untouched page too.

   Three across fits the same band at 541px and reflows 5 items as
   3 + 2.

   The selector needs the element name. That five-column rule lives in
   a SECOND inline <style> further down the page — tucked into a block
   for the clients carousel, after this stylesheet is linked — so a
   matching .stats-band .stats-grid would tie on specificity and lose
   on order. section.stats-band wins outright. */
@media (min-width:761px) and (max-width:991px){
  section.stats-band .stats-grid{grid-template-columns:repeat(3,minmax(0,1fr));}
}

/* Same cause at the bottom end: the page's own two-up needs ~154px a
   column and a 320px viewport leaves 138px, which is the 33px of
   overflow there. 375px still fits two, so this starts below that. */
@media (max-width:374px){
  section.stats-band .stats-grid{grid-template-columns:1fr;}
}

/* The hero stage's floor was set for the four-stage scene at desktop
   width. On a 320px screen the scene measures 215px tall including
   its padding, so a 240px floor just adds a dead band under it. */
@media (max-width:480px){
  .van-stage{min-height:200px;}
}

/* ============================================================
 * 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;}
}
