/* ============================================================
 * alc-lusion.css — animation layer for alcobev-lusion.html
 *
 *   1. the hero route line is rebuilt as the state hub — a central
 *      depot tower with the states orbiting it
 *   2. #pillars gets an animated radial vortex behind it (canvas,
 *      injected by the script)
 *   3. its card grid becomes a sticky deck — every card pins at the
 *      same offset so the next rises up and covers it exactly
 *   4. the key takeaways move onto the brand gradient, with the CTA
 *      band's dotted corners
 *   5. choreographed entrances for the rest of the page
 *
 * 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.
 * ========================================================== */

/* ============================================================
 * 0. Hero scene — the Excise Corridor
 *
 * The chain the page describes, on one dimetric grid, left to right:
 *
 *   the distillery - block, two stills, cased stock on the pad
 *   the corridor out of it, neon, running blue
 *   the state border gate: scan bar drops, shield flares, tick draws
 *   past it the corridor turns magenta and forks
 *   up to the lounge, down to the retail vend
 *   three glass read-outs over the lot, on a slower clock
 *
 * One consignment per cycle, and the order is the whole point: the
 * branches are delayed past the gate, so the frame shows clearance
 * happening rather than two lines blinking at each other. No text
 * anywhere in the artwork - the shield's tick carries it.
 *
 * No panel behind any of it: the scene sits straight on the band, so
 * the hero belongs to the page instead of sitting on a card inside
 * it. What is left of the backdrop is the light alone - blue where
 * the stock starts, magenta where it ends up - masked out before the
 * frame edge, so it fades into the band rather than ending on a line.
 *
 * The 3D is not a drawn fake: a perspective camera on the <svg>
 * itself and three depth planes that parallax against it, over a
 * scene whose every box, cylinder and crate is built from one
 * projection. Keyed off --alh-cyc.
 * ========================================================== */

.alh-scene{--alh-cyc:6s;}

/* the scene is a 600x330 stage, not the 400x210 route line it
   replaces, so the card lets it set its own height */
.hero-card .alh-scene{
  display:block;width:100%;max-width:100%;height:auto;overflow:visible;
  transform-origin:50% 56%;
  animation:alhCam 19s ease-in-out infinite;
  will-change:transform;
}
/* A real perspective transform on the <svg> itself, not a fake tilt
   inside it: SVG child transforms are flattened to 2D in every engine,
   so the only place a genuine 3D rotation survives is the replaced
   element. The scale is the brief's forward sweep - a slow dolly in
   and back out, continuous, never a cut. 13s against the 6s content
   loop, so camera and scene never land on the same beat twice. */
/* A corridor is read along its length, so the camera travels along
   it rather than walking round it: rotateY swings gently while the
   origin sits left of centre, which slides the far end of the chain
   toward the viewer as it turns, and the push-in lands at the middle
   of the sweep. Kept shallow - a steep tilt would fight the grid the
   scene is drawn on and the isometric would stop reading as one.
   19s against the 6s content loop, so camera and scene never land on
   the same beat twice. */
@keyframes alhCam{
  0%,100%{transform:perspective(1200px) rotateX(3.4deg) rotateY(-7deg) scale(1);}
  50%{transform:perspective(1200px) rotateX(.6deg) rotateY(6deg) scale(1.05);}
}
/* a grid item's automatic minimum is its min-content width, which for
   a 600-unit scene would push the hero column past the viewport */
.hero-grid > .hero-card{min-width:0;}

/* ---------- the three depth planes ----------
 * Same clock as the camera, different travel: the ground barely
 * shifts, the stages shift a little, the overlays floating nearest
 * shift most. That difference is the parallax, and it is what makes
 * the sweep read as depth instead of as the picture sliding. */
.alh-scene .alh-plane{animation:alhDrift 19s ease-in-out infinite;}
.alh-scene .alh-plane.p1{--amp:2px;}
.alh-scene .alh-plane.p2{--amp:6px;}
.alh-scene .alh-plane.p3{--amp:13px;}
@keyframes alhDrift{
  0%,100%{transform:translateX(calc(var(--amp) * -1));}
  50%{transform:translateX(var(--amp));}
}

/* ---------- the lighting ----------
 * The two lamps breathe against each other rather than together:
 * blue up as magenta comes down, so the backdrop never goes flat and
 * never pulses as one block. */
.alh-scene .alh-glowA{animation:alhLamp 11s ease-in-out infinite;}
.alh-scene .alh-glowB{animation:alhLamp 11s ease-in-out infinite reverse;}
@keyframes alhLamp{
  0%,100%{opacity:.55;}
  50%{opacity:1;}
}
.alh-scene .alh-grid{animation:alhGrid 9s ease-in-out infinite;}
@keyframes alhGrid{
  0%,100%{opacity:.55;}
  50%{opacity:.9;}
}

/* ---------- the corridor ----------
 * One consignment per cycle. It leaves the distillery, reaches the
 * gate, and only then do the two branches run - the fork is delayed
 * by a third of the cycle, so the frame shows clearance happening
 * rather than two unrelated lines blinking. */
.alh-scene .alh-pulse{
  stroke-dasharray:26 460;
  animation:alhPulse var(--alh-cyc) cubic-bezier(.42,0,.5,1) infinite;
  animation-delay:calc(var(--alh-cyc) * var(--d, 0));
}
@keyframes alhPulse{
  0%{stroke-dashoffset:486;opacity:0;}
  8%,62%{opacity:1;}
  76%,100%{stroke-dashoffset:0;opacity:0;}
}
.alh-scene .alh-forkdot{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:alhFork var(--alh-cyc) ease-out infinite;
}
@keyframes alhFork{
  0%,28%{opacity:.4;transform:scale(1);}
  38%{opacity:1;transform:scale(1.7);}
  56%,100%{opacity:.4;transform:scale(1);}
}

/* ---------- the gate ----------
 * The scan bar drops through the opening, the shield flares, the
 * tick draws itself. That order is the whole point of the gate, so
 * the three are keyed a beat apart rather than together. */
.alh-scene .alh-scanbar{
  opacity:0;
  animation:alhScan var(--alh-cyc) cubic-bezier(.4,0,.5,1) infinite;
}
@keyframes alhScan{
  0%,14%{opacity:0;transform:translateY(0);}
  20%{opacity:.95;transform:translateY(0);}
  30%{opacity:.95;transform:translateY(30px);}
  38%,100%{opacity:0;transform:translateY(34px);}
}
.alh-scene .alh-shieldglow{
  animation:alhShieldGlow var(--alh-cyc) ease-out infinite;
}
@keyframes alhShieldGlow{
  0%,28%{opacity:.25;}
  38%{opacity:1;}
  64%,100%{opacity:.25;}
}
/* the tick is drawn, not faded: a line that writes itself reads as
   a decision being taken, where a fade reads as decoration */
.alh-scene .alh-tick{
  stroke-dasharray:18;
  animation:alhTick var(--alh-cyc) ease-out infinite;
}
@keyframes alhTick{
  0%,30%{stroke-dashoffset:18;}
  44%,100%{stroke-dashoffset:0;}
}
.alh-scene .alh-shield{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:alhBob 6.5s ease-in-out infinite;
}
@keyframes alhBob{
  0%,100%{transform:translateY(0);}
  50%{transform:translateY(-6px);}
}

/* ---------- the distillery ----------
 * Stock is cased before it moves, so the crates lift in sequence on
 * the beat the corridor lights, and the still vents on its own
 * slower clock so the left of the frame is never still. */
.alh-scene .alh-crate{
  transform-box:fill-box;transform-origin:50% 100%;
  animation:alhLift var(--alh-cyc) cubic-bezier(.4,0,.3,1) infinite;
}
.alh-scene .alh-crate.k2{animation-delay:calc(var(--alh-cyc) * -0.1);}
.alh-scene .alh-crate.k3{animation-delay:calc(var(--alh-cyc) * -0.2);}
@keyframes alhLift{
  0%,54%,100%{transform:translateY(0);}
  16%{transform:translateY(-7px);}
  30%{transform:translateY(0);}
}
.alh-scene .alh-vent{animation:alhVent 3.4s linear infinite;}
@keyframes alhVent{
  0%{stroke-dashoffset:0;opacity:.7;}
  100%{stroke-dashoffset:-20;opacity:0;}
}
.alh-scene .alh-win{animation:alhWin 4.6s ease-in-out infinite;}
.alh-scene .alh-win.w2{animation-delay:-1.5s;}
.alh-scene .alh-win.w3{animation-delay:-3s;}
@keyframes alhWin{
  0%,100%{opacity:.35;}
  50%{opacity:.85;}
}

/* ---------- the two channels ----------
 * Each lights as its own branch arrives, a beat apart, so the eye is
 * walked lounge then vend instead of being shown both at once. */
.alh-scene .alh-warm{animation:alhWarm calc(var(--alh-cyc) * 1.5) ease-in-out infinite;}
@keyframes alhWarm{
  0%,100%{opacity:.7;}
  50%{opacity:1;}
}
.alh-scene .alh-lamp{
  transform-box:fill-box;transform-origin:50% 0%;
  animation:alhLampSwing var(--alh-cyc) ease-out infinite;
}
@keyframes alhLampSwing{
  0%,52%{opacity:.6;transform:scale(1);}
  62%{opacity:1;transform:scale(1.22);}
  80%,100%{opacity:.6;transform:scale(1);}
}
.alh-scene .alh-bottle{animation:alhBottle var(--alh-cyc) ease-out infinite;}
.alh-scene .alh-bottle.b2{animation-delay:calc(var(--alh-cyc) * 0.05);}
.alh-scene .alh-bottle.b3{animation-delay:calc(var(--alh-cyc) * 0.1);}
.alh-scene .alh-bottle.b4{animation-delay:calc(var(--alh-cyc) * 0.15);}
@keyframes alhBottle{
  0%,56%,100%{opacity:.55;}
  68%{opacity:1;}
}
.alh-scene .alh-stool{
  transform-box:fill-box;transform-origin:50% 100%;
  animation:alhBob 7.4s ease-in-out infinite;
}
.alh-scene .alh-stool.s2{animation-delay:-3.7s;}
.alh-scene .alh-licence{animation:alhLicence var(--alh-cyc) ease-out infinite;}
@keyframes alhLicence{
  0%,62%,100%{opacity:.45;}
  74%{opacity:1;}
}

/* ---------- the read-outs ----------
 * They hover and fill on a slower clock than the corridor, so the
 * frame keeps a second rhythm running under the first and never
 * lands every beat at once. */
.alh-scene .alh-gauge{
  transform-box:fill-box;transform-origin:0% 50%;
  animation:alhGauge calc(var(--alh-cyc) * 1.5) ease-in-out infinite;
}
.alh-scene .alh-gauge.g2{animation-delay:-1.2s;}
.alh-scene .alh-gauge.g3{animation-delay:-2.4s;}
@keyframes alhGauge{
  0%,100%{transform:scaleX(calc(var(--gw) * 0.42));}
  50%{transform:scaleX(var(--gw));}
}
.alh-scene .alh-panel{animation:alhHover 7s ease-in-out infinite;}
.alh-scene .alh-panel.q2{animation-delay:-3.4s;animation-duration:8.6s;}
.alh-scene .alh-panel.q3{animation-delay:-1.8s;animation-duration:9.4s;}
@keyframes alhHover{
  0%,100%{transform:translateY(0);}
  50%{transform:translateY(-7px);}
}

@media (prefers-reduced-motion:reduce){
  .hero-card .alh-scene,
  .alh-scene .alh-plane,.alh-scene .alh-glowA,.alh-scene .alh-glowB,
  .alh-scene .alh-grid,.alh-scene .alh-pulse,.alh-scene .alh-forkdot,
  .alh-scene .alh-scanbar,.alh-scene .alh-shield,.alh-scene .alh-shieldglow,
  .alh-scene .alh-tick,.alh-scene .alh-crate,.alh-scene .alh-vent,
  .alh-scene .alh-win,.alh-scene .alh-warm,.alh-scene .alh-lamp,
  .alh-scene .alh-bottle,.alh-scene .alh-stool,.alh-scene .alh-licence,
  .alh-scene .alh-gauge,.alh-scene .alh-panel{
    animation:none !important;transform:none !important;
  }
  /* the settled state: the corridor lit end to end, the consignment
     cleared, both channels stocked, nothing moving */
  .alh-scene .alh-pulse{stroke-dasharray:none !important;opacity:.6 !important;}
  .alh-scene .alh-tick{stroke-dashoffset:0 !important;}
  .alh-scene .alh-gauge{transform:scaleX(var(--gw)) !important;}
  .alh-scene .alh-win,.alh-scene .alh-bottle,.alh-scene .alh-warm,
  .alh-scene .alh-lamp,.alh-scene .alh-licence,
  .alh-scene .alh-forkdot{opacity:1 !important;}
  .alh-scene .alh-scanbar,.alh-scene .alh-vent{opacity:0 !important;}
  .alh-scene .alh-shieldglow{opacity:.3 !important;}
}
/* ============================================================
 * 0b. Key takeaways, on the brand gradient
 *
 * The page ships these as plain numbered lines in a light box. They
 * become cards on --grad, matching the connected-platform tiles on
 * the other pages. Everything inside was coloured for a light ground,
 * so each piece is restated here; only colour changes, no copy moves.
 * ========================================================== */
.al-tk .takeaways{background:transparent;border:0;box-shadow:none;padding:0;}
/* Four across instead of two. The page's own rule only steps down to
   one column at 700px, which would leave four cramped columns through
   the whole tablet range, so the two intermediate steps are added
   here: 4 -> 2 at 1199, 2 -> 1 where the page already does it. */
.al-tk .tk-grid{
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:16px;
}
@media (max-width:1199px){
  .al-tk .tk-grid{grid-template-columns:repeat(2,minmax(0,1fr));}
}
@media (max-width:700px){
  .al-tk .tk-grid{grid-template-columns:1fr;}
}

.al-tk .tk{
  background:var(--grad,linear-gradient(135deg,#701893,#1308AD));
  border:1px solid rgba(255,255,255,.16);
  border-radius:var(--radius,18px);
  padding:22px 20px;
  box-shadow:
    0 2px 6px rgba(32,10,70,.14),
    0 12px 30px rgba(32,10,70,.18);
  /* the dot corners below bleed past the edges, so the card has to
     position and clip them itself */
  position:relative;
  overflow:hidden;
}

/* the index chip was a pale lavender pill with purple numerals —
   invisible logic on a purple card, so it becomes a frosted chip */
.al-tk .tk .mk{
  background:rgba(255,255,255,.18);
  color:#ffffff;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.2);
}
.al-tk .tk p,
.al-tk .tk span:not(.mk){color:rgba(255,255,255,.82);}
/* centred over the four cards, as the reference lays it out — done
   here rather than in the markup so the heading's own text is left
   exactly as the page wrote it */
.al-tk .takeaways > h3,
.al-tk .takeaways > h2{color:var(--navy,#101F38);text-align:center;}

/* ---------- the CTA band's dotted corners, on these cards ----------
 * Same recipe the page uses for .cta: a 16px grid of 1.5px dots in
 * two patches, masked to a soft blob so the texture fades out rather
 * than stopping at a hard edge. */
.al-tk .tk::before,
.al-tk .tk::after{
  content:"";
  position:absolute;
  width:min(52%,240px);
  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;
}
.al-tk .tk::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%);
}
.al-tk .tk::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 text rides above the texture */
.al-tk .tk > *{position:relative;z-index:1;}


.al-stacked{
  --al-top: 104px;      /* where every card pins, clearing the header */
  --al-gap: 15vh;       /* scroll distance between one pin and the next */
  --al-min: 52vh;       /* card height — no dead frame under a pinned card */
  /* The LAST card's entire stick room, and the surplus that keeps the
     FIRST card pinned until the last one arrives. This page needs far
     more of it than its siblings because the Influencer App card runs
     773px against the other four's ~500-570, and that one outlier sets
     the distance the whole deck has to cover. Swept and measured: 54vh
     stacks four of the five, 55vh and up stacks all five. Set to 62vh,
     comfortably past the edge rather than sitting on it. */
  --al-tail: 62vh;

  --al-ease: cubic-bezier(.22,.8,.3,1);
  --al-back: cubic-bezier(.34,1.32,.44,1);
}

/* ============================================================
 * 1. Dark section + vortex backdrop
 * ========================================================== */
.al-stage{
  position:relative;
  background:#fff;
  isolation:isolate;
  padding-bottom:0;
  /* deliberately NOT overflow:hidden — that would make this element a
     scroll container and kill the sticky vortex below. The vortex is
     viewport-sized and bounded by this box, so nothing can bleed out. */
}

/* 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 removes it from flow, so it occupies no
   layout space; without it a 100vh block would push the section down.
   It also keeps the canvas viewport-sized rather than as tall as the
   whole deck — ~0.9M pixels a frame instead of 3.4M. */
.al-vortex{
  position:sticky;
  top:0;
  height:100vh;
  margin-bottom:-100vh;
  z-index:0;
  pointer-events:none;
  opacity:0;
  transition:opacity 1.3s var(--al-ease,ease);
}
.al-stage.al-on .al-vortex{opacity:1;}
.al-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. */
.al-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%);
}
.al-stage > .container{position:relative;z-index:2;}

/* ---------- the heading scrolls away with the page ----------
 * It was pinned above the deck at one point; that left it hanging
 * over the cards passing beneath it, so it is plain flow content now,
 * matching van-sales-automation-lusion.html. 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. */
.al-stage .section-head{
  margin-bottom:26px;
  opacity:1;
  transform:none;
  transition:none;
}

/* ============================================================
 * 2. The sticky deck
 * ========================================================== */
.al-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. */
.al-stack-tail{
  display:block;
  height:var(--al-tail,12vh);
  pointer-events:none;
}

.al-stack > .feat{
  position:sticky;
  top:var(--al-top,104px);
  margin-bottom:var(--al-gap,15vh);
  min-height:var(--al-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;

  /* Soft ambient depth — four very low-alpha layers rather than one
     heavy drop, so the covering edge stays clean on a white ground. */
  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);
}
/* the stylesheet's lift-on-hover would fight the pin */
.al-stack > .feat:hover{transform:none;border-color:#E2D7F2;}
/* the tail already provides the run-out */
.al-stack > .feat.al-last{margin-bottom:0;}

/* the page's own grid-span rules are inert once this is block flow,
   but clear them so nothing re-applies at a breakpoint */
.al-stack > .feat.span2,
.al-stack > .feat.span3,
.al-stack > .feat.span6{grid-column:auto;}

/* number sits large in the corner of a tall card */
.al-stack > .feat .num{top:28px;right:34px;font-size:42px;}

/* ============================================================
 * 3. Card entrance — one class (.al-in) plays the whole sequence
 * ========================================================== */

/* suppress transitions while a card is rewound off screen, or a
   quick scroll back catches it mid-fade */
.al-stack .al-noanim,
.al-stack .al-noanim *{transition:none !important;animation:none !important;}

.al-stack > .feat .feat-ico{
  opacity:0;transform:scale(.66) rotate(-10deg);
  transition:opacity .5s var(--al-ease), transform .62s var(--al-back);
  transition-delay:60ms;
}
.al-stack > .feat.al-in .feat-ico{opacity:1;transform:none;}

.al-stack > .feat h3{
  opacity:0;transform:translateY(16px);
  clip-path:inset(0 0 100% 0);
  transition:opacity .55s var(--al-ease), transform .7s var(--al-ease), clip-path .7s var(--al-ease);
  transition-delay:150ms;
}
.al-stack > .feat.al-in h3{opacity:1;transform:none;clip-path:inset(0 0 0 0);}

.al-stack > .feat .tag{
  opacity:0;clip-path:inset(0 100% 0 0 round 999px);
  transition:opacity .35s var(--al-ease), clip-path .65s var(--al-ease);
  transition-delay:320ms;
}
.al-stack > .feat.al-in .tag{opacity:1;clip-path:inset(0 0 0 0 round 999px);}

.al-stack > .feat .num{
  opacity:0;transform:translateY(-14px) scale(1.3);filter:blur(6px);
  transition:opacity .7s var(--al-ease), transform .85s var(--al-ease), filter .7s var(--al-ease);
  transition-delay:90ms;
}
.al-stack > .feat.al-in .num{opacity:1;transform:none;filter:blur(0);}

.al-stack > .feat > p{
  opacity:0;transform:translateY(10px);
  transition:opacity .5s var(--al-ease), transform .6s var(--al-ease);
  transition-delay:260ms;
}
.al-stack > .feat.al-in > p{opacity:1;transform:none;}

.al-stack > .feat ul li{
  opacity:0;transform:translateY(10px);
  transition:opacity .45s var(--al-ease), transform .55s var(--al-ease);
  transition-delay:calc(300ms + var(--i,0) * 80ms);
}
.al-stack > .feat.al-in ul li{opacity:1;transform:none;}

/* ============================================================
 * 3b. Card layout: copy left, illustration right
 * ========================================================== */
.al-stack > .feat.al-has-vec{
  display:grid;
  grid-template-columns:minmax(0,1.04fr) minmax(0,.96fr);
  gap:46px;
  align-items:center;
}
.al-card-text{min-width:0;}
.al-card-vec{min-width:0;display:flex;align-items:center;justify-content:center;}
.al-card-vec svg{width:100%;height:auto;max-height:290px;overflow:visible;}

/* supporting lines, divided like the reference cards */
.al-points{list-style:none;margin:18px 0 0;padding:0;}
.al-points .al-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);
}
.al-points .al-point::before{
  content:"";position:absolute;left:3px;top:19px;
  width:8px;height:8px;border-radius:50%;
  background:var(--grad,linear-gradient(135deg,#701893,#1308AD));
}
.al-stack > .feat .al-points .al-point{
  opacity:0;transform:translateY(12px);
  transition:opacity .5s var(--al-ease), transform .6s var(--al-ease);
  transition-delay:calc(420ms + var(--i,0) * 95ms);
}
.al-stack > .feat.al-in .al-points .al-point{opacity:1;transform:none;}

/* ============================================================
 * 3c. illustration animations — all keyed off .al-in on the card
 * ========================================================== */

/* strokes draw themselves (lengths measured in script) */
.al-card-vec [data-al-draw]{
  stroke-dashoffset:var(--len,0);
  transition:stroke-dashoffset 1.3s var(--al-ease);
  transition-delay:var(--dd,0ms);
}
.al-in .al-card-vec [data-al-draw]{stroke-dashoffset:0;}

/* elements scale in, staggered by --p */
.al-card-vec .al-pop{
  opacity:0;transform:scale(.68);
  transform-box:fill-box;transform-origin:50% 50%;
  transition:opacity .5s var(--al-ease), transform .62s var(--al-back);
  transition-delay:calc(260ms + var(--p,0) * 100ms);
}
.al-in .al-card-vec .al-pop{opacity:1;transform:none;}

/* bars grow up from their baseline */
.al-card-vec .al-bar{
  transform:scaleY(0);
  transform-box:fill-box;transform-origin:50% 100%;
  transition:transform .8s var(--al-ease);
  transition-delay:calc(320ms + var(--p,0) * 95ms);
}
.al-in .al-card-vec .al-bar{transform:none;}

/* data travelling the connector paths */
.al-card-vec .al-flow{opacity:0;transition:opacity .5s ease .7s;}
.al-in .al-card-vec .al-flow{opacity:1;}

/* ambient loops — parked until the card lands, so nothing burns
   frames while it is still off screen */
.al-card-vec .al-float,
.al-card-vec .al-ring,
.al-card-vec .al-spin{animation-play-state:paused;}
.al-in .al-card-vec .al-float,
.al-in .al-card-vec .al-ring,
.al-in .al-card-vec .al-spin{animation-play-state:running;}

.al-card-vec .al-float{
  animation:alFloat 4.4s ease-in-out infinite;
  transform-box:fill-box;transform-origin:50% 50%;
}
@keyframes alFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}

.al-card-vec .al-ring{
  fill:none;
  animation:alRing 3s ease-out infinite;
  transform-box:fill-box;transform-origin:50% 50%;
}
@keyframes alRing{0%{transform:scale(.72);opacity:.85}100%{transform:scale(1.5);opacity:0}}

.al-card-vec .al-spin{
  transform-box:view-box;
  animation:alSpin 24s linear infinite;
}
@keyframes alSpin{to{transform:rotate(360deg)}}

/* ============================================================
 * 4. Page-wide entrances (outside the deck)
 * ========================================================== */
.al-anim .reveal{opacity:1;transform:none;transition:none;}

.al-anim .al-pill{
  opacity:0;transform:translateY(12px) scale(.9);
  clip-path:inset(0 42% 0 42% round 999px);
  transition:opacity .55s var(--al-ease,ease), transform .7s var(--al-back,ease), clip-path .7s var(--al-ease,ease);
  transition-delay:var(--d,0ms);
}
.al-anim .al-pill.al-in{opacity:1;transform:none;clip-path:inset(0 0 0 0 round 999px);}

/* heading words hinge up out of a clip mask */
.al-w{
  display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-bottom:.2em;margin-bottom:-.2em;
  perspective:680px;
}
.al-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(--al-ease,ease), opacity .62s var(--al-ease,ease), filter .62s var(--al-ease,ease);
  transition-delay:var(--d,0ms);
}
.al-split.al-in .al-w > i{transform:none;opacity:1;filter:blur(0);}

.al-anim .al-fade{
  opacity:0;transform:translateY(18px);
  transition:opacity .85s var(--al-ease,ease), transform .85s var(--al-ease,ease);
  transition-delay:var(--d,0ms);
}
.al-anim .al-fade.al-in{opacity:1;transform:none;}

/* plain cards outside the deck hinge up from their bottom edge */
.al-anim .al-card{
  opacity:0;
  transform:perspective(1300px) rotateX(11deg) translateY(50px) scale(.955);
  transform-origin:50% 100%;
  transition:opacity .8s var(--al-ease,ease), transform 1.05s var(--al-ease,ease);
  transition-delay:var(--d,0ms);
}
.al-anim .al-card.al-in{opacity:1;transform:none;}

/* ============================================================
 * 5. Smaller screens — the deck still stacks.
 *
 *    This unstacked into a plain column at first, on the assumption
 *    that a sticky deck needs vertical room a phone frame does not
 *    have. It does have the room; the cards just have to be built
 *    for the frame. The deck is the whole point of the section, and
 *    dropping it on the device most people read the page on threw
 *    it away exactly where it mattered.
 *
 *    What a phone changes is the measurements, not the mechanism:
 *    one column, a shorter pin offset measured off the mobile
 *    header, a smaller gap so a card is not held for half a screen
 *    of scrolling, and a card that has to fit the viewport once
 *    pinned - which is why the illustration goes under the copy
 *    here and away entirely below 575.
 * ========================================================== */
@media (max-width:991px){
  .al-stacked{
    --al-gap:11vh;
    --al-min:0;        /* a phone card is already taller than any floor */
    --al-tail:50vh;
  }
  .al-stack > .feat{padding:26px 24px;}
  .al-stack > .feat .num{top:20px;right:22px;font-size:32px;}
  .al-stage{padding-bottom:76px;}
  .al-stage .section-head{margin-bottom:30px;}
  /* copy first, illustration beneath it */
  .al-stack > .feat.al-has-vec{grid-template-columns:1fr;gap:20px;}
  .al-card-vec{order:2;}
  .al-card-vec svg{max-height:170px;}
}
/* A pinned card has to fit between the header and the bottom of the
   screen, or its last lines sit below the fold for the whole time it
   is held there - and unlike a card that merely scrolls past, you
   cannot scroll down to them. So on a phone the card is trimmed to
   the frame: the illustration goes, the chrome tightens, and the
   supporting lines this layer injects go too. The page's own copy -
   the tag, the heading, the bullets and the product link - is
   untouched and complete; what is dropped is what this layer added
   on top of it, which is the right thing to lose when the frame runs
   out of room. Measured against the tallest card in the deck. */
@media (max-width:575px){
  .al-stacked{--al-gap:9vh;--al-tail:44vh;}
  .al-stack > .feat{padding:18px 18px 20px;}
  .al-stack > .feat .num{top:14px;right:16px;font-size:26px;}
  .al-stack > .feat .feat-ico{width:34px;height:34px;}
  .al-stack > .feat .feat-ico svg{width:17px;height:17px;}
  .al-stack > .feat .tag{margin-bottom:6px;}
  .al-stack > .feat h3{font-size:18px;line-height:1.3;margin-bottom:8px;}
  .al-stack > .feat p{font-size:13.5px;line-height:1.55;margin-bottom:8px;}
  .al-stack > .feat ul:not(.al-points){margin-bottom:8px;}
  .al-stack > .feat ul:not(.al-points) li{font-size:13.5px;line-height:1.5;margin-bottom:5px;}
  /* The illustration stays. It is the thing that makes a card a card
     rather than a block of text, and hiding it to buy height was the
     wrong saving - the supporting lines this layer injects are the
     ones to drop, because the page's own copy already says what they
     restate. The vector keeps its own animation; it is only capped,
     so a pinned card still fits between the header and the fold. */
  .al-points{display:none;}
  .al-stack > .feat.al-has-vec{gap:14px;}
  /* Capped against the frame as well as in pixels. A phone reports
     innerHeight already shortened by the browser's own chrome, and
     that chrome is not a fixed amount - so the illustration gives
     back height on a short frame instead of pushing the bottom of a
     pinned card past the fold. */
  .al-card-vec svg{max-height:124px;max-height:min(124px, 16vh);}
}

/* The one case where the deck genuinely cannot work: a frame too
   short to hold a whole card. A card pinned taller than the viewport
   is worse than no deck at all - the part below the fold cannot be
   scrolled to while it is held there. So rather than trimming the
   card until nothing is left of it, short frames get the plain
   column, where every card is full height and everything in it can
   be reached. That is a phone in landscape, and the smallest phones
   in portrait. Height, not width, because height is the thing
   actually in short supply. */
@media (max-height:600px){
  .al-stack.bento{display:grid;grid-template-columns:1fr;gap:24px;}
  .al-stack > .feat{position:relative;min-height:0;margin-bottom:0;}
  .al-stack-tail{display:none;}
}

/* ============================================================
 * 6. Reduced motion — the script does not stack at all in this
 *    case, but keep the guard so nothing animates if it ever does.
 * ========================================================== */
@media (prefers-reduced-motion:reduce){
  .al-vortex{display:none;}
  .al-stack > .feat{position:relative;min-height:0;margin-bottom:26px;}
  .al-stack-tail{display:none;}
  .al-stack > .feat .feat-ico,
  .al-stack > .feat h3,
  .al-stack > .feat .tag,
  .al-stack > .feat .num,
  .al-stack > .feat > p,
  .al-stack > .feat ul li,
  .al-stack > .feat .al-points .al-point,
  .al-card-vec .al-pop,.al-card-vec .al-flow,
  .al-anim .al-pill,.al-anim .al-fade,.al-anim .al-card{
    opacity:1 !important;transform:none !important;
    filter:none !important;clip-path:none !important;transition:none !important;
  }
  .al-w > i{transform:none !important;opacity:1 !important;filter:none !important;transition:none !important;}
  .al-card-vec .al-bar{transform:none !important;transition:none !important;}
  .al-card-vec [data-al-draw]{stroke-dashoffset:0 !important;transition:none !important;}
  .al-card-vec .al-float,.al-card-vec .al-ring,.al-card-vec .al-spin{animation:none !important;}
}
@media print{
  .al-vortex{display:none !important;}
}

/* ============================================================
 * 7. Support for lusion-motion.js
 *
 * That script is shared with aboutus-lusion.html, 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;}
}

/* ============================================================
 * 0c. Hero band - the gradient treatment from the influencer page
 *
 * The page ships this hero as dark copy on white with the scene
 * boxed inside an opaque purple card. Here the whole band becomes
 * the brand gradient - slowly drifting, as on influencers-
 * application-lusion - the copy flips to white, and the card
 * dissolves so the isometric scene floats on the band itself.
 *
 * Nothing is added or removed from the markup; every rule below
 * only restates a colour, so the content is untouched.
 * ========================================================== */

.hero{
  color:#fff;
  background:linear-gradient(120deg,#2b00ba,#430171,#701893,#1308AD,#2b00ba);
  background-size:300% 300%;
  animation:alHeroGrad 16s ease-in-out infinite;
}
@keyframes alHeroGrad{
  0%{background-position:0% 50%;}
  50%{background-position:100% 50%;}
  100%{background-position:0% 50%;}
}
/* the page's own light-ground wash, restated for a dark one */
.hero::before{
  background:
    radial-gradient(680px 420px at 82% 6%, rgba(255,255,255,.10), transparent 60%),
    radial-gradient(620px 520px at 4% 92%, rgba(19,8,173,.32), transparent 60%);
}

/* ---------- the copy column ---------- */
.hero .eyebrow{background:rgba(255,255,255,.14);color:#fff;}
.hero .eyebrow .dot{background:#fff;}
.hero h1{color:#fff;}
/* .hl is a gradient clipped to the text - invisible on the gradient
   itself, so it goes back to a flat tint */
.hero h1 .hl{
  background:none;
  color:#c9a7ff;
  -webkit-text-fill-color:#c9a7ff;
}
.hero p.lede{color:#DAD3F2;}

.hero .hero-ctas .btn-primary{
  background:#fff;
  color:#393939;
  box-shadow:0 12px 28px rgba(16,4,50,.26);
}
.hero .hero-ctas .btn-primary:hover{
  filter:none;
  background:#fff;
  box-shadow:0 16px 34px rgba(16,4,50,.34);
}
.hero .hero-ctas .btn-ghost{border-color:rgba(255,255,255,.4);}

/* the trust line reads as bare grey text on white; on the band it
   becomes the same frosted chip row the influencer hero uses */
.hero .hero-trust{color:#E7ECF5;}
.hero .hero-trust .pill{
  color:#E7ECF5;
  background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.16);
  padding:8px 15px;
  border-radius:999px;
}
.hero .hero-trust svg{color:#9be6d8;}

/* ---------- the scene column ---------- */
/* the card frame disappears so the scene sits on the band, with a
   soft glow behind it in place of the old panel */
.hero .hero-card{
  background:transparent;
  border:0;
  box-shadow:none;
  padding:0;
}
/* Dropping the card's padding lets the scene run the full width of
   the column, which is what we want everywhere it fits. On a phone
   the page's own hero card is already a little wider than the
   viewport, so without this the scene would be clipped at both ends -
   the inset puts it back exactly where the untouched page draws it. */
@media (max-width:767px){
  .hero .hero-card{padding:0 26px;}
}
.hero .hero-card::before{
  content:"";
  position:absolute;
  left:50%;top:50%;
  width:78%;height:66%;
  transform:translate(-50%,-50%);
  border-radius:50%;
  z-index:0;
  pointer-events:none;
  background:radial-gradient(circle, rgba(201,167,255,.40), transparent 68%);
  filter:blur(26px);
  animation:alHeroGlow 6s ease-in-out infinite;
}
@keyframes alHeroGlow{
  0%,100%{opacity:.7;}
  50%{opacity:1;}
}
.hero .hero-card > *{position:relative;z-index:1;}

.hero .hc-top{margin-bottom:10px;}
.hero .hc-badge{color:rgba(255,255,255,.76);}
.hero .hc-live{color:rgba(255,255,255,.88);}

.hero .hc-stat{
  background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.16);
  -webkit-backdrop-filter:blur(8px);
          backdrop-filter:blur(8px);
}
.hero .hc-stat span{color:#DAD3F2;}

@media (prefers-reduced-motion:reduce){
  .hero,.hero .hero-card::before{animation:none;}
}

/* ---------- the band's own breathing room ----------
 * The page gives this hero 132px/60px; the influencer band it is now
 * matching uses 140px/90px, and with the gradient running edge to edge
 * the shallow bottom reads as the copy sitting on the seam. Matched to
 * the influencer page. The <=991 top stays at the page's own 44px,
 * which is set against this header's mobile height, not the desktop one.
 */
.hero{padding:140px 0 90px;}
@media (max-width:991px){
  .hero{padding:44px 0 72px;}
}
