/* ============================================================
 * rtl-lusion.css — animation layer for
 * retailer-app-lusion.html
 *
 *   1. the hero scene is rebuilt as an isometric glass composition:
 *      the retailer tapping Order Now at the counter, cart parcels
 *      streaming out of the phone with a live offer attached, and
 *      the DMS / SFA / BI cards pulsing as each one lands
 *   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 (rt- 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, 9.6s, shared by every part so the beat lines up:
 *
 *   0.0-1.4s   the tap — the avatar's arm reaches, Order Now flashes
 *   1.4-2.6s   the live offer slides onto the cart
 *   1.0-9.6s   parcels stream out continuously along the route
 *   each parcel's arrival pulses DMS, then SFA, then BI
 *
 * Everything is driven off --rth-cyc, so retiming the whole scene is
 * one number. Each element's own delay is a fraction of it.
 *
 * The parcels themselves run on SMIL animateMotion rather than CSS,
 * because they follow a curved route; their 3.2s period is deliberately
 * independent of the cycle, so the stream never visibly loops in step
 * with the tap.
 * ========================================================== */

.rtl-scene{--rth-cyc:9.6s;}

/* The rebuilt scene carries a counter, a phone and three backend cards
   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. */
.rtl-scene{width:min(520px,100%);}
.rtl-stage{height:auto;min-height:360px;padding:16px 0;}
@media (max-width:900px){.rtl-stage{min-height:300px;}}
@media (max-width:480px){.rtl-stage{min-height:240px;}}

/* ---------- glass panels ---------- */
.rtl-scene .rth-glass{
  fill:rgba(255,255,255,.10);
  stroke:rgba(255,255,255,.26);
  stroke-width:1.4;
}

/* ---------- the phone, breathing on the spot ---------- */
.rtl-scene .rth-phone{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:rthFloat 6s ease-in-out infinite;
}
@keyframes rthFloat{
  0%,100%{transform:translateY(0);}
  50%{transform:translateY(-7px);}
}

/* ---------- 1. the tap ----------
   The arm reaches on the beat, the button flashes under it, and a
   ring expands from the contact point. */
.rtl-scene .rth-arm{
  transform-box:fill-box;transform-origin:0% 0%;
  animation:rthArm var(--rth-cyc) ease-in-out infinite;
}
@keyframes rthArm{
  0%{transform:rotate(0deg);}
  8%{transform:rotate(-7deg);}
  16%,22%{transform:rotate(-13deg);}
  34%,100%{transform:rotate(0deg);}
}
.rtl-scene .rth-cta{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:rthCta var(--rth-cyc) ease-out infinite;
}
@keyframes rthCta{
  0%,14%{transform:scale(1);filter:brightness(1);}
  18%{transform:scale(.96);filter:brightness(1.45);}
  26%,100%{transform:scale(1);filter:brightness(1);}
}
.rtl-scene .rth-tap{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:rthTap var(--rth-cyc) ease-out infinite;
}
@keyframes rthTap{
  0%,15%{transform:scale(.3);opacity:0;}
  19%{opacity:.85;}
  32%,100%{transform:scale(1.9);opacity:0;}
}

/* ---------- 2. the live offer landing on the cart ---------- */
.rtl-scene .rth-offer{
  transform-box:fill-box;transform-origin:50% 50%;
  animation:rthOffer var(--rth-cyc) cubic-bezier(.34,1.32,.44,1) infinite;
}
@keyframes rthOffer{
  0%,18%{opacity:0;transform:translateX(-18px) scale(.9);}
  26%,88%{opacity:1;transform:translateX(0) scale(1);}
  96%,100%{opacity:0;transform:translateX(6px) scale(.96);}
}

/* ---------- 3. the route the parcels take ---------- */
.rtl-scene .rth-route{animation:rthRouteDash 1.4s linear infinite;}
@keyframes rthRouteDash{to{stroke-dashoffset:-14;}}

/* The parcels are moved by SMIL; this only fades each one in as it
   leaves the phone and out again as it reaches the cards, so neither
   end of the route pops. */
.rtl-scene .rth-parcel{animation:rthParcel 3.2s linear infinite;}
.rtl-scene .rth-parcel.p2{animation-delay:-2.4s;}
.rtl-scene .rth-parcel.p3{animation-delay:-1.6s;}
.rtl-scene .rth-parcel.p4{animation-delay:-0.8s;}
@keyframes rthParcel{
  0%{opacity:0;}
  12%,78%{opacity:1;}
  100%{opacity:0;}
}

/* ---------- 4. each system pulsing as the data lands ----------
   The three fire in sequence, a third of a parcel-period apart, so the
   order reads DMS -> SFA -> BI rather than all three at once. */
.rtl-scene .rth-sys-pulse{
  transform-box:fill-box;transform-origin:50% 50%;
  opacity:0;
  animation:rthSysPulse 3.2s ease-out infinite;
}
.rtl-scene .rth-sys.s2 .rth-sys-pulse{animation-delay:-2.85s;}
.rtl-scene .rth-sys.s3 .rth-sys-pulse{animation-delay:-2.5s;}
@keyframes rthSysPulse{
  0%,72%{opacity:0;transform:scale(1);}
  78%{opacity:.9;transform:scale(1.04);}
  92%,100%{opacity:0;transform:scale(1.1);}
}

@media (prefers-reduced-motion:reduce){
  .rtl-scene .rth-phone,.rtl-scene .rth-arm,.rtl-scene .rth-cta,
  .rtl-scene .rth-tap,.rtl-scene .rth-offer,.rtl-scene .rth-route,
  .rtl-scene .rth-parcel,.rtl-scene .rth-sys-pulse{
    animation:none !important;transform:none !important;
  }
  /* the finished state: offer applied, nothing mid-flight */
  .rtl-scene .rth-offer{opacity:1 !important;}
  .rtl-scene .rth-tap,.rtl-scene .rth-parcel,
  .rtl-scene .rth-sys-pulse{opacity:0 !important;}
}

.rt-stacked{
  --rt-top: 104px;      /* where every card pins, clearing the header */
  --rt-gap: 15vh;       /* scroll distance between one pin and the next */
  --rt-min: 52vh;       /* card height — no dead frame under a pinned card */
  --rt-tail: 22vh;      /* the LAST card's stick room, plus the surplus
                           that keeps the FIRST pinned until it arrives */
  --rt-ease: cubic-bezier(.22,.8,.3,1);
  --rt-back: cubic-bezier(.34,1.32,.44,1);
}

/* ============================================================
 * 3. The sticky deck (USP grid)
 * ========================================================== */

/* ---------- vortex backdrop ----------
 * The same swirl the van-sales and integration pages run behind their
 * decks. 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. */
.rt-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. */
.rt-vortex{
  position:sticky;
  top:0;
  height:100vh;
  margin-bottom:-100vh;
  z-index:0;
  pointer-events:none;
  opacity:0;
  transition:opacity 1.3s var(--rt-ease,ease);
}
.rt-stage.rt-on-stage .rt-vortex{opacity:1;}
.rt-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. */
.rt-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%);
}
.rt-stage > .container{position:relative;z-index:2;}

@media (prefers-reduced-motion:reduce){.rt-vortex{display:none;}}

.rt-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. */
.rt-stack-tail{
  display:block;
  height:var(--rt-tail,22vh);
  pointer-events:none;
}

.rt-stack > .feat{
  position:sticky;
  top:var(--rt-top,104px);
  margin-bottom:var(--rt-gap,15vh);
  min-height:var(--rt-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);
}
.rt-stack > .feat:hover{transform:none;border-color:#E2D7F2;}
.rt-stack > .feat.rt-last{margin-bottom:0;}
.rt-stack > .feat.span2,
.rt-stack > .feat.span3,
.rt-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. */
.rt-stage .section-head{
  margin-bottom:26px;
  opacity:1;
  transform:none;
  transition:none;
}

/* ---------- card layout: copy left, illustration right ---------- */
.rt-stack > .feat.rt-has-vec{
  display:grid;
  grid-template-columns:minmax(0,1.04fr) minmax(0,.96fr);
  gap:46px;
  align-items:center;
}
.rt-card-text{min-width:0;}
.rt-card-vec{min-width:0;display:flex;align-items:center;justify-content:center;}
.rt-card-vec svg{width:100%;height:auto;max-height:290px;overflow:visible;}

.rt-points{list-style:none;margin:18px 0 0;padding:0;}
.rt-points .rt-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);
}
.rt-points .rt-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 ---------- */
.rt-stack .rt-noanim,
.rt-stack .rt-noanim *{transition:none !important;animation:none !important;}

.rt-stack > .feat .feat-ico{
  opacity:0;transform:scale(.66) rotate(-10deg);
  transition:opacity .5s var(--rt-ease), transform .62s var(--rt-back);
  transition-delay:60ms;
}
.rt-stack > .feat.rt-in .feat-ico{opacity:1;transform:none;}

.rt-stack > .feat h3{
  opacity:0;transform:translateY(16px);clip-path:inset(0 0 100% 0);
  transition:opacity .55s var(--rt-ease), transform .7s var(--rt-ease), clip-path .7s var(--rt-ease);
  transition-delay:150ms;
}
.rt-stack > .feat.rt-in h3{opacity:1;transform:none;clip-path:inset(0 0 0 0);}

.rt-stack > .feat .tag{
  opacity:0;clip-path:inset(0 100% 0 0 round 999px);
  transition:opacity .35s var(--rt-ease), clip-path .65s var(--rt-ease);
  transition-delay:320ms;
}
.rt-stack > .feat.rt-in .tag{opacity:1;clip-path:inset(0 0 0 0 round 999px);}

.rt-stack > .feat > p{
  opacity:0;transform:translateY(10px);
  transition:opacity .5s var(--rt-ease), transform .6s var(--rt-ease);
  transition-delay:260ms;
}
.rt-stack > .feat.rt-in > p{opacity:1;transform:none;}

.rt-stack > .feat .rt-points .rt-point{
  opacity:0;transform:translateY(12px);
  transition:opacity .5s var(--rt-ease), transform .6s var(--rt-ease);
  transition-delay:calc(420ms + var(--i,0) * 95ms);
}
.rt-stack > .feat.rt-in .rt-points .rt-point{opacity:1;transform:none;}

/* ---------- illustration animations ---------- */
.rt-card-vec [data-rt-draw]{
  stroke-dashoffset:var(--len,0);
  transition:stroke-dashoffset 1.3s var(--rt-ease);
  transition-delay:var(--dd,0ms);
}
.rt-in .rt-card-vec [data-rt-draw]{stroke-dashoffset:0;}

.rt-card-vec .rt-pop{
  opacity:0;transform:scale(.68);
  transform-box:fill-box;transform-origin:50% 50%;
  transition:opacity .5s var(--rt-ease), transform .62s var(--rt-back);
  transition-delay:calc(260ms + var(--p,0) * 100ms);
}
.rt-in .rt-card-vec .rt-pop{opacity:1;transform:none;}

.rt-card-vec .rt-bar{
  transform:scaleY(0);
  transform-box:fill-box;transform-origin:50% 100%;
  transition:transform .8s var(--rt-ease);
  transition-delay:calc(320ms + var(--p,0) * 95ms);
}
.rt-in .rt-card-vec .rt-bar{transform:none;}

.rt-card-vec .rt-flow{opacity:0;transition:opacity .5s ease .7s;}
.rt-in .rt-card-vec .rt-flow{opacity:1;}

.rt-card-vec .rt-float,
.rt-card-vec .rt-ring,
.rt-card-vec .rt-spin{animation-play-state:paused;}
.rt-in .rt-card-vec .rt-float,
.rt-in .rt-card-vec .rt-ring,
.rt-in .rt-card-vec .rt-spin{animation-play-state:running;}

.rt-card-vec .rt-float{
  animation:rtFloat 4.4s ease-in-out infinite;
  transform-box:fill-box;transform-origin:50% 50%;
}
@keyframes rtFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}

.rt-card-vec .rt-ring{
  fill:none;animation:rtRing 3s ease-out infinite;
  transform-box:fill-box;transform-origin:50% 50%;
}

.rt-card-vec .rt-spin{
  transform-box:view-box;animation:rtSpin 24s linear infinite;
}
@keyframes rtSpin{to{transform:rotate(360deg)}}

/* the scan bar sweeping the QR on the verification card */
.rt-card-vec .rt-scanbar{
  animation:rtScanbar 2.8s ease-in-out infinite;
}
@keyframes rtScanbar{
  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){
  .rt-stack.bento{display:grid;grid-template-columns:1fr;gap:26px;}
  .rt-stack > .feat{position:relative;min-height:0;margin-bottom:0;padding:28px 26px;}
  .rt-stack > .feat.rt-last{margin-bottom:0;}
  .rt-stack-tail{display:none;}
  .rt-stack > .feat.rt-has-vec{grid-template-columns:1fr;gap:24px;}
  .rt-card-vec{order:2;}
  .rt-card-vec svg{max-height:210px;}
  .rt-stage .section-head{margin-bottom:34px;}
}
@media (max-width:575px){
  .rt-stack > .feat{padding:24px 22px;}
  .rt-points .rt-point{font-size:13.5px;padding:9px 0 9px 22px;}
  .rt-points .rt-point::before{top:16px;width:7px;height:7px;}
  .rt-card-vec{display:none;}   /* copy wins the space on a phone */
}

/* ============================================================
 * 5. Reduced motion
 * ========================================================== */
@media (prefers-reduced-motion:reduce){
  .rt-stack > .feat{position:relative;min-height:0;margin-bottom:26px;}
  .rt-stack-tail{display:none;}
  .rt-stack > .feat .feat-ico,
  .rt-stack > .feat h3,
  .rt-stack > .feat .tag,
  .rt-stack > .feat > p,
  .rt-stack > .feat .rt-points .rt-point,
  .rt-card-vec .rt-pop,.rt-card-vec .rt-flow{
    opacity:1 !important;transform:none !important;
    clip-path:none !important;transition:none !important;
  }
  .rt-card-vec .rt-bar{transform:none !important;transition:none !important;}
  .rt-card-vec [data-rt-draw]{stroke-dashoffset:0 !important;transition:none !important;}
  .rt-card-vec .rt-float,.rt-card-vec .rt-ring,.rt-card-vec .rt-spin,
  .rt-card-vec .rt-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. */
.rt-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. */
.rt-flow-sec .flow-visual::before,
.rt-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;
}
.rt-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%);
}
.rt-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. */
.rt-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 */
.rt-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);
}

.rt-flow-sec .flow-visual .fv-txt{color:#fff;}
.rt-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. */
.rt-flow-sec .flow-visual .fv-bar{background:rgba(255,255,255,.18);}
.rt-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 .rt-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. */
.rt-mods{
  --rtm-ease:cubic-bezier(.22,.8,.3,1);
  --rtm-pop:cubic-bezier(.34,1.32,.44,1);
}

/* rewinding must not play the entrance backwards */
.rt-mods .rt-noanim,
.rt-mods .rt-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 */
.rt-mods .mod-card{position:relative;overflow:hidden;}

/* --- card: hinges up from its bottom edge in perspective --- */
.rt-mods .rt-mcard{
  opacity:0;
  transform:perspective(1300px) rotateX(11deg) translateY(50px) scale(.955);
  transform-origin:50% 100%;
  transition:opacity .8s var(--rtm-ease), transform 1.05s var(--rtm-ease);
  transition-delay:var(--d,0ms);
  will-change:opacity,transform;
}
.rt-mods .rt-mcard.rt-min{opacity:1;transform:none;}

/* --- sheen sweeping across as the card lands --- */
.rt-mods .rt-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;
}
.rt-mods .rt-mcard.rt-min::before{
  animation:rtSheen 1.15s var(--rtm-ease) forwards;
  animation-delay:calc(var(--d,0ms) + 260ms);
}
@keyframes rtSheen{
  0%  {transform:translateX(-130%);opacity:0;}
  28% {opacity:1;}
  100%{transform:translateX(130%);opacity:0;}
}

/* --- icon: pops in --- */
.rt-mods .rt-mico{
  opacity:0;transform:scale(.42) rotate(-24deg);
  transition:opacity .5s var(--rtm-ease), transform .75s var(--rtm-pop);
  transition-delay:var(--d,0ms);
}
.rt-mods .rt-mico.rt-min{opacity:1;transform:none;}

/* --- badge: wipes in from the left without distorting its text --- */
.rt-mods .rt-mtag{
  opacity:0;clip-path:inset(0 100% 0 0 round 999px);
  transition:opacity .35s var(--rtm-ease), clip-path .7s var(--rtm-ease);
  transition-delay:var(--d,0ms);
}
.rt-mods .rt-mtag.rt-min{opacity:1;clip-path:inset(0 0 0 0 round 999px);}

/* --- the ghost index, dropping in out of focus --- */
.rt-mods .rt-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;
}
.rt-mods .rt-mnum{
  opacity:0;transform:translateY(-16px) scale(1.35);filter:blur(7px);
  transition:opacity .75s var(--rtm-ease), transform .9s var(--rtm-ease),
             filter .75s var(--rtm-ease);
  transition-delay:var(--d,0ms);
}
.rt-mods .rt-mnum.rt-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. --- */
.rt-mods .rt-w{
  display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-bottom:.2em;margin-bottom:-.2em;
  perspective:680px;
}
.rt-mods .rt-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(--rtm-ease),
             opacity .62s var(--rtm-ease),
             filter .62s var(--rtm-ease);
  transition-delay:var(--d,0ms);
  will-change:transform,opacity,filter;
}
.rt-mods .rt-split.rt-min .rt-w > i{transform:none;opacity:1;filter:blur(0);}

/* --- bullets: follow the heading, one after another --- */
.rt-mods .rt-mli{
  opacity:0;transform:translateY(10px);
  transition:opacity .5s var(--rtm-ease), transform .6s var(--rtm-ease);
  transition-delay:var(--d,0ms);
}
.rt-mods .rt-mli.rt-min{opacity:1;transform:none;}

@media (prefers-reduced-motion:reduce){
  .rt-mods .rt-mcard,.rt-mods .rt-mico,.rt-mods .rt-mtag,
  .rt-mods .rt-mnum,.rt-mods .rt-mli,.rt-mods .rt-w > i{
    opacity:1 !important;transform:none !important;filter:none !important;
    clip-path:none !important;transition:none !important;
  }
  .rt-mods .rt-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;}
}
