/* Campaign journey — the four benefit cards read as one path, not four boxes.
   Loaded after rewards-figma-tuning.css, which sizes the same .reward-benefit
   elements for a three-column grid; the overrides here widen it to four and
   add the connecting rail, the step numbers and the destination treatment. */

.reward-journey {
    --journey-line: #bfd9ff;
    --journey-ink: #0c2340;
    --journey-blue: #0049fe;
    --journey-orange: #ef6b3b;
    margin: 0 auto 76px;
}

/* ---- Section heading ------------------------------------------------- */

.reward-journey__head {
    margin: 0 0 26px;
    text-align: center;
}

.reward-journey__title {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 18px;
    margin: 0;
    color: var(--journey-ink);
    font-size: clamp(1.5rem, 2.5vw, 2.15rem);
    font-weight: 500;
}

.reward-journey__title::before,
.reward-journey__title::after {
    content: "";
    width: 56px;
    height: 1px;
    background: #ef8b66;
}

.reward-journey__copy {
    max-width: 720px;
    margin: 10px auto 0;
    color: #65768a;
    font-size: clamp(.92rem, 1.15vw, 1.05rem);
    line-height: 1.7;
}

/* ---- The track ------------------------------------------------------- */

/* rewards-figma-tuning.css sizes .reward-benefits for the old three-card row
   and only inside a min-width:1025px block, so both the column count and the
   margin are restated here for every width. */
.reward-journey__track,
.rewards-page .reward-journey__track {
    position: relative;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The card geometry comes from the tuning sheet, but its typography rules
   target the h2 this section no longer uses: the h2 is now the section
   heading, and each stop carries an h3 under it. */
.reward-journey__stop h3 {
    margin: 0;
    color: var(--journey-ink);
    font-size: clamp(1.05rem, 1.3vw, 1.28rem);
    font-weight: 500;
    line-height: 1.25;
}

.reward-journey__stop p {
    margin: 0;
    color: var(--journey-ink);
    font-size: clamp(.84rem, 1vw, .93rem);
    font-weight: 400;
    line-height: 1.45;
}

/* The tuning sheet spaces the copy block at a flat 12px gap, which was right
   for a title and a line of text. With a step number above and a CTA below,
   the rhythm is tighter and set here.

   It also hard-codes `text-align: right`, correct while this section was
   Arabic-only but wrong in English — hence `start`, and hence the
   .rewards-page prefix needed to outweigh that rule. */
.reward-journey__stop > div,
.reward-journey__link > div,
.rewards-page .reward-journey__stop > div,
.rewards-page .reward-journey__link > div {
    display: flex;
    flex: 1;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
    min-width: 0;
    text-align: start;
}

/* The rail is the whole idea: one continuous line through every stop, so the
   four cards read as a single path rather than four separate vendors. It is
   painted behind the cards and grows from the start edge, which in Arabic is
   the right — the direction the request actually travels. */
.reward-journey__rail {
    position: absolute;
    z-index: 0;
    inset-inline: 8%;
    /* Sits on the icon row rather than the card midpoint, so the segments
       visible between cards line up with the icons they connect. */
    top: 50%;
    height: 2px;
    margin-top: -1px;
    overflow: hidden;
    border-radius: 2px;
    background: linear-gradient(90deg, rgba(191, 217, 255, 0) 0%, var(--journey-line) 10%, var(--journey-line) 90%, rgba(191, 217, 255, 0) 100%);
    pointer-events: none;
}

/* Drawn complete by default and only pulled back to zero once the script is
   present, so a failed script leaves a finished rail rather than an empty one. */
.reward-journey__rail i {
    display: block;
    width: 100%;
    height: 100%;
    background: linear-gradient(90deg, var(--journey-blue), var(--journey-orange));
    transform-origin: right center;
    transition: transform 1.5s cubic-bezier(.22, .61, .36, 1);
}

.js-journey .reward-journey:not(.is-revealed) .reward-journey__rail i { transform: scaleX(0); }

.reward-journey.is-ltr .reward-journey__rail i { transform-origin: left center; }

.reward-journey.is-revealed .reward-journey__rail i { transform: scaleX(1); }

/* ---- Stops ----------------------------------------------------------- */

/* .reward-benefit already carries the card geometry from the Figma tuning
   sheet. Only the path-specific behaviour is declared here. */
.reward-journey__stop {
    position: relative;
    z-index: 1;
    transition: transform .35s cubic-bezier(.22, .61, .36, 1), box-shadow .35s ease, border-color .35s ease;
}

/* Each stop wakes as the rail reaches it. --stop-index is set per card in the
   view so the stagger follows the path instead of the DOM order alone.

   The hidden start state is gated on .js-journey, which the script sets on
   <html> before observing. Without JS — blocked, failed, or an engine where
   the observer never fires — no rule ever hides the stops, so the section
   degrades to the finished layout instead of disappearing. */
.js-journey .reward-journey:not(.is-revealed) .reward-journey__stop {
    opacity: 0;
    transform: translateX(18px);
}

.js-journey .reward-journey.is-ltr:not(.is-revealed) .reward-journey__stop { transform: translateX(-18px); }

.reward-journey.is-revealed .reward-journey__stop {
    animation: reward-journey-stop-in .55s cubic-bezier(.22, .61, .36, 1) both;
    animation-delay: calc(var(--stop-index, 0) * .16s + .1s);
}

@keyframes reward-journey-stop-in {
    from { opacity: 0; transform: translateX(18px); }
    to { opacity: 1; transform: translateX(0); }
}

.reward-journey.is-ltr.is-revealed .reward-journey__stop {
    animation-name: reward-journey-stop-in-ltr;
}

@keyframes reward-journey-stop-in-ltr {
    from { opacity: 0; transform: translateX(-18px); }
    to { opacity: 1; transform: translateX(0); }
}

/* ---- Step number ----------------------------------------------------- */

/* The number rides on the same line as the title — a stop label, not a
   floating badge above the copy. */
.reward-journey__heading {
    display: flex;
    align-items: center;
    gap: 9px;
}

.reward-journey__step {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 21px;
    height: 21px;
    border: 1px solid rgba(0, 73, 254, .3);
    border-radius: 50%;
    background: #fff;
    color: var(--journey-blue);
    font-size: .7rem;
    font-weight: 600;
    line-height: 1;
    transition: background .3s ease, color .3s ease, border-color .3s ease;
}

/* ---- Icon ------------------------------------------------------------ */

/* The tuning sheet only gives the icon its white disc and orange halo above
   1025px; below that the base sheet leaves a flat 42px chip with no glow, so
   the stations stop reading as stations exactly where the rail is dropped and
   they carry the path alone. The treatment is restated here for every width. */
.reward-journey__stop .reward-benefit__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 50px;
    width: 50px;
    min-width: 50px;
    height: 50px;
    min-height: 50px;
    padding: 12px;
    border: .5px solid var(--journey-orange);
    border-radius: 44px;
    background: #fff;
    box-shadow: 0 0 9px rgba(239, 107, 59, .6);
    transition: transform .4s cubic-bezier(.22, .61, .36, 1), box-shadow .4s ease;
}

/* The base sheet flips the icon to the start edge with order:-1, which the
   journey does not need: the icon is already first in the source. */
.reward-journey__stop .reward-benefit__icon { order: 0; }

@media (max-width: 640px) {
    .reward-journey__stop .reward-benefit__icon {
        flex-basis: 44px;
        width: 44px;
        min-width: 44px;
        height: 44px;
        min-height: 44px;
        padding: 10px;
    }
}

/* The image icons were sized by the tuning sheet's `.reward-benefit__icon img`
   rule, which an inline <svg> never matches — so the glyphs get the same box
   explicitly instead of collapsing to their intrinsic size. */
.reward-journey__stop .reward-benefit__icon svg {
    width: 100%;
    height: 100%;
    color: #0a395c;
    overflow: visible;
}

/* ---- Proof scenes ----------------------------------------------------- */

/* Each stop shows the evidence for its own claim on hover: real catalog
   rewards fan out of stop 1, quantity chips rise on stop 2, a delivery route
   draws on stop 3, sparks trail the rocket on stop 4.

   The layer is painted inside the card, clipped to it, and never takes the
   pointer — it sits under the content so it can never intercept a click on
   the destination link or cover the copy. */
.reward-journey__stop { overflow: hidden; }

.reward-journey__scene {
    position: absolute;
    z-index: 0;
    inset: 0;
    overflow: hidden;
    border-radius: inherit;
    pointer-events: none;
}

/* The card's own children need to sit above the scene. The anchor on stop 4
   is positioned for the same reason. */
.reward-journey__stop > .reward-benefit__icon,
.reward-journey__stop > div,
.reward-journey__link {
    position: relative;
    z-index: 1;
}

/* THE CARD MAKES ROOM FOR ITS OWN EVIDENCE.

   The copy fills the card at rest — there is no spare room a scene could be
   tucked into, and painting one underneath just puts prize photos behind
   Arabic text. So the description steps aside on hover and the scene takes
   the space it leaves: the card stops telling and starts showing.

   The title stays. It is what the visitor is scanning for, and losing it
   mid-hover would make the row feel unstable. */
.reward-journey__stop p {
    transition: opacity .3s ease, transform .35s cubic-bezier(.22, .61, .36, 1);
}

/* The wash of colour behind every scene. It is the first thing to move, so
   the card registers as awake before the eye has resolved what changed. */
.reward-journey__glow {
    position: absolute;
    inset-inline-start: 8px;
    top: 50%;
    width: 150px;
    height: 150px;
    margin-top: -75px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(239, 107, 59, .16), rgba(239, 107, 59, 0) 68%);
    opacity: 0;
    transform: scale(.5);
    transition: transform .6s cubic-bezier(.22, .61, .36, 1), opacity .45s ease;
}

.reward-journey__stop--select .reward-journey__glow,
.reward-journey__stop--supply .reward-journey__glow {
    background: radial-gradient(circle, rgba(0, 73, 254, .13), rgba(0, 73, 254, 0) 68%);
}

/* 1 — Real rewards. The chips start stacked behind the icon disc and fan out
   across the card, so the claim "we help you choose" is answered with what is
   actually in the catalog right now rather than with stock art. */
.reward-journey__chip {
    position: absolute;
    top: 56%;
    inset-inline-start: 86px;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    margin-top: -19px;
    padding: 5px;
    border: 1px solid #ffd9c9;
    border-radius: 10px;
    background: #fff;
    box-shadow: 0 6px 14px rgba(12, 35, 64, .12);
    opacity: 0;
    /* Every chip begins hidden under the icon; hover deals them outward. */
    transform: translateX(0) scale(.6) rotate(0deg);
    transition: transform .5s cubic-bezier(.22, .61, .36, 1), opacity .35s ease;
}

.reward-journey__chip img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* 2 — Quantity, not price. Sourcing a hundred units is the doubt this stop
   has to answer, and the store never shows a number before the team has
   reviewed the request — so these are counts, never currency. */
.reward-journey__count {
    position: absolute;
    inset-inline-start: 104px;
    padding: 3px 10px;
    border: 1px solid rgba(0, 73, 254, .22);
    border-radius: 999px;
    background: #fff;
    color: var(--journey-blue);
    font-size: .72rem;
    font-weight: 700;
    line-height: 1.4;
    white-space: nowrap;
    opacity: 0;
    box-shadow: 0 4px 12px rgba(12, 35, 64, .1);
    transform: translateY(10px);
    transition: transform .45s cubic-bezier(.22, .61, .36, 1), opacity .35s ease;
}

.reward-journey__count--1 { top: 34%; inset-inline-start: 100px; }
.reward-journey__count--2 { top: 34%; inset-inline-start: 158px; }

/* 3 — The route. Warehouse to winner is the part of delivery nobody pictures
   until they are shown it; the dash offset animates the line into being. */
.reward-journey__route {
    position: absolute;
    inset-inline-start: 96px;
    top: 58%;
    width: 116px;
    height: 34px;
    margin-top: -17px;
    color: var(--journey-orange);
    opacity: 0;
    transition: opacity .35s ease;
}

.reward-journey__route svg { width: 100%; height: 100%; }

.reward-journey__route-line {
    stroke-dashoffset: 60;
    transition: stroke-dashoffset .9s cubic-bezier(.22, .61, .36, 1);
}

.reward-journey__route-pin {
    opacity: 0;
    transition: opacity .3s ease .15s;
}

/* 4 — Sparks trailing the rocket. Smallest of the four scenes on purpose:
   the destination already carries the orange treatment and the CTA, and a
   busy scene there would compete with the thing being clicked. */
.reward-journey__spark {
    position: absolute;
    inset-inline-start: 40px;
    top: 50%;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--journey-orange);
    opacity: 0;
    transition: transform .55s cubic-bezier(.22, .61, .36, 1), opacity .4s ease;
}

.reward-journey__spark--1 { margin-top: -14px; }
.reward-journey__spark--2 { margin-top: -4px; width: 3px; height: 3px; }
.reward-journey__spark--3 { margin-top: 6px; width: 5px; height: 5px; }
.reward-journey__spark--4 { margin-top: 15px; width: 3px; height: 3px; }
.reward-journey__spark--5 { margin-top: -22px; width: 3px; height: 3px; }

/* Rings pushing out from the launch point. The destination is the one stop
   allowed to be loud — it is the only one asking for a click. */
.reward-journey__ring {
    position: absolute;
    inset-inline-start: 18px;
    top: 50%;
    width: 54px;
    height: 54px;
    margin-top: -27px;
    border: 2px solid var(--journey-orange);
    border-radius: 50%;
    opacity: 0;
    transform: scale(.5);
}

/* Twinkles for stop 1 — the small lift of picking something good. Drawn as
   four-point stars rather than dots so they read as sparkle, not dust. */
.reward-journey__twinkle {
    position: absolute;
    width: 10px;
    height: 10px;
    background: var(--journey-orange);
    clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
    opacity: 0;
    transform: scale(0) rotate(0deg);
    transition: transform .45s cubic-bezier(.22, .61, .36, 1), opacity .3s ease;
}

.reward-journey__twinkle--1 { inset-inline-start: 96px; top: 24%; }
.reward-journey__twinkle--2 { inset-inline-start: 150px; top: 66%; width: 7px; height: 7px; }
.reward-journey__twinkle--3 { inset-inline-start: 206px; top: 32%; width: 8px; height: 8px; }

/* Crates for stop 2 — volume shown as volume. They stack up from the base
   line, each a beat after the last. */
.reward-journey__crate {
    position: absolute;
    bottom: 16px;
    width: 18px;
    border: 1.5px solid rgba(0, 73, 254, .5);
    border-radius: 3px;
    background: linear-gradient(180deg, rgba(0, 73, 254, .16), rgba(0, 73, 254, .06));
    opacity: 0;
    transform: translateY(14px);
    transition: transform .45s cubic-bezier(.22, .61, .36, 1), opacity .3s ease;
}

.reward-journey__crate--1 { inset-inline-start: 104px; height: 14px; }
.reward-journey__crate--2 { inset-inline-start: 124px; height: 23px; }
.reward-journey__crate--3 { inset-inline-start: 144px; height: 32px; }

/* The parcel that rides the delivery route. offset-path follows the same
   curve the line draws; browsers without it simply never move the parcel,
   which is why it also starts invisible. */
.reward-journey__parcel {
    offset-path: path("M8 30C28 30 34 10 60 10s32 20 52 20");
    offset-distance: 0%;
    offset-rotate: 0deg;
    opacity: 0;
    transition: opacity .3s ease;
}

/* ---- Glyph choreography ---------------------------------------------- */

/* Each stop acts out what it means rather than sharing one generic lift:
   the gift opens, the carton turns, the truck drives, the rocket climbs.
   All four are transforms on grouped paths — no layout is touched, so the
   whole set stays on the compositor.

   Origins are percentages of each group's own box rather than viewBox units,
   so they hold at the 50px desktop disc and the 44px mobile one alike. */
.reward-journey__glyph-lid,
.reward-journey__glyph-bow,
.reward-journey__glyph-box,
.reward-journey__glyph-truck,
.reward-journey__glyph-wheel,
.reward-journey__glyph-rocket,
.reward-journey__glyph-flame {
    transition: transform .55s cubic-bezier(.22, .61, .36, 1), opacity .3s ease;
}

/* 1 — Selection: the lid lifts and the bow pulls up with it. A prize being
   opened, not a box being displayed. */
.reward-journey__glyph-lid { transform-origin: 50% 40%; }
.reward-journey__glyph-bow { transform-origin: 50% 30%; }

/* 2 — Supply: the carton turns on its vertical axis. The flat outline only
   implies depth; the turn shows it. */
.reward-journey__glyph--supply { perspective: 90px; }
.reward-journey__glyph-box {
    transform-origin: 50% 50%;
    transform-style: preserve-3d;
}

/* 3 — Delivery: the body pulls away and the hubs turn inside their tyres.
   Only the spoke rotates — turning the whole wheel outline made it read as
   a wheel coming off rather than a wheel rolling. */
.reward-journey__glyph-truck { transform-origin: 50% 60%; }

.reward-journey__glyph-spoke {
    opacity: .4;
    transition: transform .6s cubic-bezier(.3, .7, .4, 1), opacity .3s ease;
}

.reward-journey__glyph-wheel--rear .reward-journey__glyph-spoke { transform-origin: 31.25% 75%; }
.reward-journey__glyph-wheel--front .reward-journey__glyph-spoke { transform-origin: 75% 75%; }

/* 4 — Launch: the rocket climbs along its own diagonal and the exhaust
   flares behind it. The only glyph that leaves its frame, for the only stop
   that leads somewhere. */
.reward-journey__glyph-rocket { transform-origin: 56% 56%; }
.reward-journey__glyph-flame { transform-origin: 40% 80%; }

/* ---- Destination (stop 4) -------------------------------------------- */

/* The only clickable stop, so it is the only one that carries the orange CTA
   colour — hover weight tracks what actually does something. */
.reward-journey__stop--launch {
    border-color: var(--journey-orange) !important;
    box-shadow: 0 0 3px rgba(239, 107, 59, .18) !important;
}

/* The anchor takes over the card's own flex row, so it restates the gap the
   tuning sheet sets on .reward-benefit — `inherit` would read the <li>'s
   computed gap, which is not what a flex child inherits. */
.reward-journey__link {
    display: flex;
    align-items: center;
    gap: 20px;
    width: 100%;
    color: inherit;
    text-decoration: none;
}

@media (max-width: 1024px) {
    .reward-journey__link { gap: 15px; }
}

.reward-journey__stop--launch .reward-benefit__icon {
    border-color: var(--journey-orange);
    box-shadow: 0 0 9px rgba(239, 107, 59, .6);
}

.reward-journey__stop--launch .reward-benefit__icon svg { color: var(--journey-orange); }

.reward-journey__stop--launch .reward-journey__step {
    border-color: var(--journey-orange);
    background: var(--journey-orange);
    color: #fff;
}

.reward-journey__cta {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    margin-top: 2px;
    color: var(--journey-orange);
    font-size: .88rem;
    font-weight: 600;
}

/* An arrow pointing the way the reader is already travelling: left in Arabic,
   right in English. Drawn left-facing and mirrored for LTR. */
.reward-journey__cta i {
    display: block;
    width: 13px;
    height: 8px;
    background: currentColor;
    clip-path: polygon(38% 0, 0 50%, 38% 100%, 38% 68%, 100% 68%, 100% 32%, 38% 32%);
    transition: transform .3s cubic-bezier(.22, .61, .36, 1);
}

.reward-journey.is-ltr .reward-journey__cta i { transform: scaleX(-1); }

/* ---- Hover ----------------------------------------------------------- */

/* The card itself only lifts. The meaning is carried by the glyph, which
   performs its own stop — so the four cards do not share one generic
   flourish. `:focus-within` is paired with `:hover` throughout so the
   destination behaves the same for a keyboard.

   Card lift and glow are the same for stops 1-3; the destination lifts
   further and glows orange, because it is the one that leads somewhere. */
@media (hover: hover) {
    .reward-journey__stop:hover {
        transform: translateY(-3px);
        border-color: rgba(0, 73, 254, .55);
        box-shadow: 0 8px 22px rgba(12, 35, 64, .09);
    }

    /* The disc grows a little under every glyph, which reads as the station
       coming forward on the path. */
    .reward-journey__stop:hover .reward-benefit__icon { transform: scale(1.07); }

    /* 1 — Selection: the lid rises off the box and the bow lifts with it,
       a shade further, so the ribbon looks pulled rather than translated. */
    .reward-journey__stop--select:hover .reward-journey__glyph-lid {
        transform: translateY(-2.4px);
    }

    .reward-journey__stop--select:hover .reward-journey__glyph-bow {
        transform: translateY(-3.4px) scale(1.06);
    }

    /* The copy steps aside so the evidence has somewhere to land. Stops 1-3
       only: the destination keeps its text, because its copy carries the CTA
       and a card you are about to click should not rearrange itself. */
    .reward-journey__stop--select:hover p,
    .reward-journey__stop--supply:hover p,
    .reward-journey__stop--deliver:hover p {
        opacity: 0;
        transform: translateY(6px);
    }

    /* …and the real rewards are dealt out of the box it just opened. They
       travel along the reading direction, each a beat behind the last, so it
       reads as one hand of cards rather than three things appearing at once. */
    .reward-journey__stop--select:hover .reward-journey__chip {
        opacity: 1;
    }

    .reward-journey__stop--select:hover .reward-journey__chip--1 {
        transform: translateX(-6px) scale(1) rotate(-7deg);
        transition-delay: .04s;
    }

    .reward-journey__stop--select:hover .reward-journey__chip--2 {
        transform: translateX(-46px) scale(1) rotate(3deg);
        transition-delay: .1s;
    }

    .reward-journey__stop--select:hover .reward-journey__chip--3 {
        transform: translateX(-86px) scale(1) rotate(10deg);
        transition-delay: .16s;
    }

    /* The fan follows the text direction, so in English it deals rightward. */
    .reward-journey.is-ltr .reward-journey__stop--select:hover .reward-journey__chip--1 { transform: translateX(6px) scale(1) rotate(7deg); }
    .reward-journey.is-ltr .reward-journey__stop--select:hover .reward-journey__chip--2 { transform: translateX(46px) scale(1) rotate(-3deg); }
    .reward-journey.is-ltr .reward-journey__stop--select:hover .reward-journey__chip--3 { transform: translateX(86px) scale(1) rotate(-10deg); }

    /* The wash arrives first on every stop. */
    .reward-journey__stop:hover .reward-journey__glow,
    .reward-journey__stop--launch:focus-within .reward-journey__glow {
        opacity: 1;
        transform: scale(1);
    }

    /* The sparkles pop in after the chips have started moving, then keep a
       slow shimmer for as long as the pointer stays — the card does not
       freeze once its entrance is over. */
    .reward-journey__stop--select:hover .reward-journey__twinkle {
        opacity: 1;
        animation: reward-journey-twinkle-in .5s cubic-bezier(.22,.61,.36,1) both;
    }

    .reward-journey__stop--select:hover .reward-journey__twinkle--1 { animation-delay: .22s; }
    .reward-journey__stop--select:hover .reward-journey__twinkle--2 { animation-delay: .5s; }
    .reward-journey__stop--select:hover .reward-journey__twinkle--3 { animation-delay: .78s; }

    /* 2 — Supply: the quantity chips rise as the carton turns. */
    .reward-journey__stop--supply:hover .reward-journey__count {
        opacity: 1;
        transform: translateY(0);
    }

    .reward-journey__stop--supply:hover .reward-journey__count--1 { transition-delay: .06s; }
    .reward-journey__stop--supply:hover .reward-journey__count--2 { transition-delay: .16s; }

    /* …and the crates stack up under them, tallest last. */
    .reward-journey__stop--supply:hover .reward-journey__crate {
        opacity: 1;
        transform: translateY(0);
    }

    .reward-journey__stop--supply:hover .reward-journey__crate--1 { transition-delay: .1s; }
    .reward-journey__stop--supply:hover .reward-journey__crate--2 { transition-delay: .2s; }
    .reward-journey__stop--supply:hover .reward-journey__crate--3 { transition-delay: .3s; }

    /* 3 — Delivery: the route draws itself from warehouse to winner, both
       pins land, and then a parcel runs the route on a loop. The loop is the
       point — delivery is a thing that keeps happening, not a single event. */
    .reward-journey__stop--deliver:hover .reward-journey__route { opacity: .9; }

    .reward-journey__stop--deliver:hover .reward-journey__route-line { stroke-dashoffset: 0; }

    .reward-journey__stop--deliver:hover .reward-journey__route-pin { opacity: 1; }

    .reward-journey__stop--deliver:hover .reward-journey__parcel {
        opacity: 1;
        animation: reward-journey-parcel 1.9s cubic-bezier(.4, 0, .5, 1) .35s infinite;
    }

    /* 4 — Launch: sparks trail away behind the climbing rocket. */
    .reward-journey__stop--launch:hover .reward-journey__spark,
    .reward-journey__stop--launch:focus-within .reward-journey__spark {
        opacity: .7;
        transform: translate(-26px, 16px);
    }

    .reward-journey.is-ltr .reward-journey__stop--launch:hover .reward-journey__spark,
    .reward-journey.is-ltr .reward-journey__stop--launch:focus-within .reward-journey__spark {
        transform: translate(26px, 16px);
    }

    .reward-journey__stop--launch:hover .reward-journey__spark--2,
    .reward-journey__stop--launch:focus-within .reward-journey__spark--2 { transition-delay: .07s; }
    .reward-journey__stop--launch:hover .reward-journey__spark--3,
    .reward-journey__stop--launch:focus-within .reward-journey__spark--3 { transition-delay: .13s; }
    .reward-journey__stop--launch:hover .reward-journey__spark--4,
    .reward-journey__stop--launch:focus-within .reward-journey__spark--4 { transition-delay: .19s; }
    .reward-journey__stop--launch:hover .reward-journey__spark--5,
    .reward-journey__stop--launch:focus-within .reward-journey__spark--5 { transition-delay: .25s; }

    /* The rings keep pulsing outward while the pointer stays, so the
       destination is the one card that is still doing something a second
       after you arrive on it. */
    .reward-journey__stop--launch:hover .reward-journey__ring,
    .reward-journey__stop--launch:focus-within .reward-journey__ring {
        animation: reward-journey-ring 1.8s cubic-bezier(.2, .6, .4, 1) infinite;
    }

    .reward-journey__stop--launch:hover .reward-journey__ring--2,
    .reward-journey__stop--launch:focus-within .reward-journey__ring--2 { animation-delay: .9s; }

    /* The glyph keeps a slow hover-bob under the same rule, so the rocket is
       not frozen mid-climb for as long as the pointer rests. */
    .reward-journey__stop--launch:hover .reward-journey__glyph-rocket,
    .reward-journey__stop--launch:focus-within .reward-journey__glyph-rocket {
        animation: reward-journey-rocket-bob 1.6s ease-in-out .55s infinite;
    }

    .reward-journey__stop--launch:hover .reward-journey__glyph-flame,
    .reward-journey__stop--launch:focus-within .reward-journey__glyph-flame {
        animation: reward-journey-flame .42s ease-in-out .55s infinite alternate;
    }

    /* Stop 2's carton keeps turning back and forth rather than stopping at
       28deg, which reads as inspection rather than a single flip. */
    .reward-journey__stop--supply:hover .reward-journey__glyph-box {
        animation: reward-journey-box-turn .9s cubic-bezier(.22,.61,.36,1) both;
    }

    /* Stop 3's wheels keep rolling for as long as the truck is "moving". */
    .reward-journey__stop--deliver:hover .reward-journey__glyph-spoke {
        animation: reward-journey-roll 1.1s linear .6s infinite;
    }

    .reward-journey.is-ltr .reward-journey__stop--deliver:hover .reward-journey__glyph-spoke {
        animation-name: reward-journey-roll-ltr;
    }
}

/* ---- Looping keyframes ------------------------------------------------ */

/* These run only while a card is hovered (declared inside the hover block
   above), so nothing animates on an idle page. */

@keyframes reward-journey-twinkle-in {
    from { opacity: 0; transform: scale(.4) rotate(-30deg); }
    to { opacity: .9; transform: scale(1) rotate(0deg); }
}

@keyframes reward-journey-parcel {
    0% { offset-distance: 0%; opacity: 0; }
    12% { opacity: 1; }
    88% { opacity: 1; }
    100% { offset-distance: 100%; opacity: 0; }
}

@keyframes reward-journey-ring {
    0% { opacity: 0; transform: scale(.45); }
    18% { opacity: .75; }
    100% { opacity: 0; transform: scale(2.1); }
}

@keyframes reward-journey-rocket-bob {
    0%, 100% { transform: translate(2.4px, -2.4px); }
    50% { transform: translate(3.4px, -4px); }
}

@keyframes reward-journey-flame {
    from { transform: translate(-1.6px, 1.6px) scale(1.05); opacity: .4; }
    to { transform: translate(-2.2px, 2.2px) scale(1.3); opacity: .7; }
}

@keyframes reward-journey-box-turn {
    from { transform: rotateY(0) translateZ(0); }
    to { transform: rotateY(26deg) translateZ(2px); }
}

@keyframes reward-journey-roll {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

@keyframes reward-journey-roll-ltr {
    from { transform: rotate(0deg); }
    to { transform: rotate(-360deg); }
}

/* Re-opened so the rules that follow stay inside the hover guard. */
@media (hover: hover) {

    /* The carton's turn and the wheels' roll are the looping keyframes
       declared above — a static transform here would be a later declaration
       and would win over them, so neither is restated.

       3 — Delivery: the truck body pulls away, and keeps that offset while
       the wheels roll under it. */
    .reward-journey__stop--deliver:hover .reward-journey__glyph-truck {
        transform: translateX(2.6px);
    }

    .reward-journey.is-ltr .reward-journey__stop--deliver:hover .reward-journey__glyph-truck {
        transform: translateX(-2.6px);
    }

    /* The hubs keep rolling under the looping keyframe declared above; only
       the darkening is set here, because a transform at this point in the
       cascade would beat the animation. */
    .reward-journey__stop--deliver:hover .reward-journey__glyph-spoke {
        opacity: .85;
    }

    /* 4 — Launch: the rocket climbs its own diagonal and the exhaust flares
       behind it. Held slightly longer than the others so it reads as a
       departure rather than a twitch. */
    .reward-journey__stop--launch:hover,
    .reward-journey__stop--launch:focus-within {
        transform: translateY(-5px);
        box-shadow: 0 12px 28px rgba(239, 107, 59, .22) !important;
    }

    .reward-journey__stop--launch:hover .reward-benefit__icon,
    .reward-journey__stop--launch:focus-within .reward-benefit__icon {
        box-shadow: 0 0 16px rgba(239, 107, 59, .75);
    }

    /* The rocket's climb and the flame's flare are the looping keyframes
       above; both start from the pose that used to be set statically here,
       so restating it would only override the loop. */

    .reward-journey.is-ltr .reward-journey__stop--launch:hover .reward-journey__cta i,
    .reward-journey.is-ltr .reward-journey__stop--launch:focus-within .reward-journey__cta i { transform: scaleX(-1) translateX(4px); }
    .reward-journey.is-rtl .reward-journey__stop--launch:hover .reward-journey__cta i,
    .reward-journey.is-rtl .reward-journey__stop--launch:focus-within .reward-journey__cta i { transform: translateX(-4px); }
}

.reward-journey__link:focus-visible {
    outline: 2px solid var(--journey-orange);
    outline-offset: 4px;
    border-radius: 6px;
}

/* ---- Responsive ------------------------------------------------------ */

/* The base sheet collapses .reward-benefits to a single column at 900px and
   the tuning sheet only knows about three columns above 1025px, so each step
   down is restated here with the .reward-journey__track class to stay ahead
   of both on specificity as well as source order. */
@media (max-width: 1200px) {
    .reward-journey__track,
    .rewards-page .reward-journey__track { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    /* Two rows of two: a single horizontal line no longer describes the path,
       and a rail that stops halfway reads as a broken one. */
    .reward-journey__rail { display: none; }
}

@media (max-width: 640px) {
    /* On a phone the four stops are already a long vertical read.  The
       generic portal spacing made the hand-off to the prize catalogue feel
       like an empty, unrelated section. Keep the hand-off deliberate, but
       close enough that the catalogue is visibly the next step. */
    .rewards-page .reward-journey { margin-bottom: 28px; }

    .rewards-page .reward-journey__head { margin-bottom: 18px; }

    .reward-journey__track,
    .rewards-page .reward-journey__track { grid-template-columns: 1fr; gap: 12px; }

    /* Collections follows the journey directly in the document. Explicitly
       reset its block-start margin so no global section rule can reopen a
       large blank gap between the final action and the catalogue heading. */
    .rewards-page .reward-journey + .rewards-choice-section { margin-top: 0; }

    .rewards-page .reward-journey + .rewards-choice-section .section-head {
        margin-bottom: 18px;
    }

    .reward-journey__title { gap: 10px; }
    .reward-journey__title::before,
    .reward-journey__title::after { width: 28px; }
}

/* ---- Reduced motion --------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .reward-journey__rail i { transition: none; transform: scaleX(1); }

    .reward-journey:not(.is-revealed) .reward-journey__stop,
    .reward-journey.is-ltr:not(.is-revealed) .reward-journey__stop {
        opacity: 1;
        transform: none;
    }

    .reward-journey.is-revealed .reward-journey__stop { animation: none; }

    .reward-journey__stop,
    .reward-journey__stop .reward-benefit__icon,
    .reward-journey__cta i,
    .reward-journey__glyph-lid,
    .reward-journey__glyph-bow,
    .reward-journey__glyph-box,
    .reward-journey__glyph-truck,
    .reward-journey__glyph-spoke,
    .reward-journey__glyph-rocket,
    .reward-journey__glyph-flame,
    .reward-journey__chip,
    .reward-journey__count,
    .reward-journey__route,
    .reward-journey__route-line,
    .reward-journey__route-pin,
    .reward-journey__spark { transition: none; }
}

/* Reduced motion keeps the colour and shadow feedback — hover still has to
   say which card is under the cursor — and drops only the movement. */
@media (prefers-reduced-motion: reduce) and (hover: hover) {
    .reward-journey__stop:hover,
    .reward-journey__stop--launch:hover,
    .reward-journey__stop--launch:focus-within { transform: none; }

    .reward-journey__stop:hover .reward-benefit__icon { transform: none; }

    .reward-journey__stop--select:hover .reward-journey__glyph-lid,
    .reward-journey__stop--select:hover .reward-journey__glyph-bow,
    .reward-journey__stop--supply:hover .reward-journey__glyph-box,
    .reward-journey__stop--deliver:hover .reward-journey__glyph-truck,
    .reward-journey__stop--deliver:hover .reward-journey__glyph-spoke,
    .reward-journey.is-ltr .reward-journey__stop--deliver:hover .reward-journey__glyph-truck,
    .reward-journey.is-ltr .reward-journey__stop--deliver:hover .reward-journey__glyph-spoke,
    .reward-journey__stop--launch:hover .reward-journey__glyph-rocket,
    .reward-journey__stop--launch:focus-within .reward-journey__glyph-rocket,
    .reward-journey__stop--launch:hover .reward-journey__glyph-flame,
    .reward-journey__stop--launch:focus-within .reward-journey__glyph-flame { transform: none; }

    /* The proof still appears — it is information, not decoration — it simply
       appears in place instead of travelling there. The chips keep a small
       fanned offset so three of them are not stacked into one. */
    /* Every loop is silenced; the evidence still appears, in place. */
    .reward-journey__stop:hover .reward-journey__twinkle,
    .reward-journey__stop:hover .reward-journey__parcel,
    .reward-journey__stop:hover .reward-journey__ring,
    .reward-journey__stop--launch:focus-within .reward-journey__ring,
    .reward-journey__stop:hover .reward-journey__glyph-rocket,
    .reward-journey__stop--launch:focus-within .reward-journey__glyph-rocket,
    .reward-journey__stop:hover .reward-journey__glyph-flame,
    .reward-journey__stop--launch:focus-within .reward-journey__glyph-flame,
    .reward-journey__stop:hover .reward-journey__glyph-box,
    .reward-journey__stop:hover .reward-journey__glyph-spoke {
        animation: none;
    }

    /* The rings and the travelling parcel are pure motion with nothing to
       say once still, so they stay hidden rather than sitting as artefacts. */
    .reward-journey__stop:hover .reward-journey__ring,
    .reward-journey__stop--launch:focus-within .reward-journey__ring,
    .reward-journey__stop:hover .reward-journey__parcel { opacity: 0; }

    .reward-journey__stop:hover .reward-journey__twinkle,
    .reward-journey__stop:hover .reward-journey__crate,
    .reward-journey__stop:hover .reward-journey__glow {
        opacity: 1;
        transform: none;
    }

    .reward-journey__stop--select:hover .reward-journey__chip--1 { transform: translateX(-6px); }
    .reward-journey__stop--select:hover .reward-journey__chip--2 { transform: translateX(-46px); }
    .reward-journey__stop--select:hover .reward-journey__chip--3 { transform: translateX(-86px); }
    .reward-journey.is-ltr .reward-journey__stop--select:hover .reward-journey__chip--1 { transform: translateX(6px); }
    .reward-journey.is-ltr .reward-journey__stop--select:hover .reward-journey__chip--2 { transform: translateX(46px); }
    .reward-journey.is-ltr .reward-journey__stop--select:hover .reward-journey__chip--3 { transform: translateX(86px); }

    .reward-journey__stop--supply:hover .reward-journey__count { transform: none; }

    .reward-journey__stop--launch:hover .reward-journey__spark,
    .reward-journey__stop--launch:focus-within .reward-journey__spark,
    .reward-journey.is-ltr .reward-journey__stop--launch:hover .reward-journey__spark,
    .reward-journey.is-ltr .reward-journey__stop--launch:focus-within .reward-journey__spark { transform: none; }
}
