/* Hero slider — peek carousel used for the home page hero.

   Authoring: add, remove or comment out .hero-slide blocks in the markup.
   The dots, ARIA labelling and infinite looping are all generated by
   scripts/hero-slider.js from whatever slides are present, so the counts can
   never fall out of sync the way the old dot markup could. */

.hero-slider {
    /* Share of the viewport width taken by the centred slide. The remainder is
       split between the two peeking neighbours either side. */
    --hero-slide-fraction: 0.78;
    --hero-slide-gap: 8px;
    --hero-slide-radius: 16px;
    /* Vertical breathing room inside the viewport so the slide shadows are not
       sliced off by the edge-fade mask, which clips to the border box.
       A CSS box-shadow blurs with a Gaussian of sigma = blur / 2, so its
       visible tail reaches roughly (offset + blur) — not (offset + blur / 2).
       Size the bottom against the largest shadow below: the hover state at
       0 22px 48px needs ~70px. The top only needs (blur - offset). */
    --hero-shadow-room-top: 46px;
    --hero-shadow-room-bottom: 74px;
    /* Width of the soft fade at the left and right edges. */
    --hero-edge-fade: 44px;
    --hero-arrow-size: 46px;
    --hero-chevron-size: 24px;
    /* Where the arrow sits across the neighbour gutter: 0 is hard against the
       screen edge, 0.5 is the middle of the gutter. Lower to move it out. */
    --hero-arrow-gutter-position: 0.18;
    /* Floor on how close an arrow's centre may sit to the screen edge. Measured
       from the chevron, not the button box: the box is an invisible hit area,
       so letting it overhang the edge slightly costs nothing, whereas sizing
       this against the box would hold the visible chevron well short. */
    --hero-arrow-inset: calc(var(--hero-chevron-size) / 2 + 10px);
    --hero-accent: #3077E1;

    position: relative;
    /* Full bleed to the screen edges, capped on desktop. The cap is set by the
       artwork: the source images are 2208px wide, so a centred slide beyond
       roughly 1170 CSS px starts upscaling on a 2x display. */
    width: 100%;
    max-width: 1500px;
    margin: 0 auto;
    font-family: 'Catamaran', sans-serif;
    outline: none;
}

/* Wraps the artwork and the arrows only, so the arrows centre on the slide
   rather than on the slide plus the dot row beneath it. */
.hero-slider-stage {
    position: relative;
}

/* Height is derived from the centred slide's 16:9 artwork:
   16 / (9 * 0.78) = 2.279. Keep this in step with --hero-slide-fraction.
   box-sizing is pinned so the ratio always applies to the content box and the
   shadow padding sits outside it, whatever the page sets globally. */
.hero-slider-viewport {
    position: relative;
    box-sizing: content-box;
    aspect-ratio: 2.279;
    padding: var(--hero-shadow-room-top) 0 var(--hero-shadow-room-bottom);
    /* Soft edges rather than a hard clip: the neighbours fade out towards the
       screen edge instead of being sliced. Also hides the off-screen slides. */
    -webkit-mask-image: linear-gradient(
        to right,
        transparent 0,
        #000 var(--hero-edge-fade),
        #000 calc(100% - var(--hero-edge-fade)),
        transparent 100%
    );
    mask-image: linear-gradient(
        to right,
        transparent 0,
        #000 var(--hero-edge-fade),
        #000 calc(100% - var(--hero-edge-fade)),
        transparent 100%
    );
    cursor: grab;
    touch-action: pan-y;
    user-select: none;
    -webkit-user-select: none;
}

.hero-slider.is-dragging .hero-slider-viewport {
    cursor: grabbing;
}

.hero-slide {
    position: absolute;
    /* Offset past the shadow padding: absolute children are placed against the
       padding box, so top: 0 would sit above the content box. */
    top: var(--hero-shadow-room-top);
    left: 50%;
    width: calc(var(--hero-slide-fraction) * 100%);
    aspect-ratio: 16 / 9;
    opacity: var(--slide-opacity, 0);
    pointer-events: none;
    transform:
        translate3d(calc(-50% + var(--slide-x, 0px)), 0, 0)
        scale(var(--slide-scale, 0.92));
    transition:
        transform 620ms cubic-bezier(0.22, 1, 0.36, 1),
        opacity 380ms ease;
    will-change: transform;
}

.hero-slide.is-visible {
    pointer-events: auto;
}

/* While the user is driving the position directly, JavaScript sets the
   transform every frame — CSS easing on top of that would lag behind. */
.hero-slider.is-dragging .hero-slide,
.hero-slider.is-scrolling .hero-slide,
.hero-slider.is-animating .hero-slide {
    transition: opacity 200ms ease;
}

.hero-slide-link {
    display: block;
    width: 100%;
    height: 100%;
    text-decoration: none;
    border-radius: var(--hero-slide-radius);
    outline: none;
    /* Stops the browser dragging the link's URL instead of swiping the slider. */
    -webkit-user-drag: none;
}

.hero-slide img {
    display: block;
    width: 100%;
    height: 100%;
    max-width: none;
    object-fit: cover;
    border-radius: var(--hero-slide-radius);
    background: #f2f4f7;
    box-shadow:
        0 8px 20px rgba(24, 31, 42, 0.14),
        0 2px 6px rgba(24, 31, 42, 0.10),
        0 0 0 1px rgba(18, 24, 33, 0.06);
    /* The link owns the pointer target; this also stops the browser's native
       image drag from hijacking a swipe. */
    pointer-events: none;
    -webkit-user-drag: none;
    user-select: none;
    transition: box-shadow 320ms ease;
}

/* Kept within --hero-shadow-room-bottom so the mask never clips it. */
.hero-slide.is-active img {
    box-shadow:
        0 20px 44px rgba(24, 31, 42, 0.22),
        0 6px 14px rgba(24, 31, 42, 0.13),
        0 0 0 1px rgba(18, 24, 33, 0.07);
}

.hero-slider:not(.is-dragging) .hero-slide.is-active .hero-slide-link:hover img {
    box-shadow:
        0 22px 48px rgba(24, 31, 42, 0.26),
        0 8px 18px rgba(24, 31, 42, 0.15),
        0 0 0 1px rgba(18, 24, 33, 0.07);
}

.hero-slide-link:focus-visible img {
    box-shadow:
        0 0 0 4px rgba(48, 119, 225, 0.45),
        0 20px 44px rgba(24, 31, 42, 0.22);
}

/* Arrows — bare chevrons, no container, matching the app icon carousel further
   down the page. They sit over the peeking neighbour they move to rather than
   over the current slide: the horizontal placement is the midpoint of the
   neighbour gutter, (100% - slide width) / 2, halved again.
   The button keeps its full size as an invisible hit area for touch, even
   though only the chevron is drawn. */
.hero-slider-arrow {
    --arrow-shift: -50%;

    position: absolute;
    z-index: 120;
    /* The viewport's shadow padding is deliberately uneven, so its midpoint is
       lower than the slide's. Lift the arrows back onto the slide's centre. */
    top: calc(
        50% - (var(--hero-shadow-room-bottom) - var(--hero-shadow-room-top)) / 2
    );
    display: grid;
    width: var(--hero-arrow-size);
    height: var(--hero-arrow-size);
    padding: 0;
    border: 0;
    border-radius: 10px;
    background: transparent;
    /* Matched to .app-carousel-arrow in app-icon-carousel.css so both
       carousels on the page use the same chevron grey. */
    color: #a5a9b0;
    box-shadow: none;
    cursor: pointer;
    place-items: center;
    transform: translate(var(--arrow-shift), -50%);
    opacity: 0;
    transition:
        opacity 260ms ease,
        color 200ms ease,
        transform 200ms ease;
}

.hero-slider.is-ready .hero-slider-arrow {
    opacity: 1;
}

.hero-slider-arrow svg {
    display: block;
    width: var(--hero-chevron-size);
    height: var(--hero-chevron-size);
    overflow: visible;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.3;
    stroke-linecap: round;
    stroke-linejoin: round;
    /* Soft light halo so the bare chevron keeps its edge over darker or busy
       artwork, where a plain grey stroke would otherwise disappear. */
    filter: drop-shadow(0 1px 3px rgba(255, 255, 255, 0.95));
}

.hero-slider-arrow:hover {
    color: #70757d;
    transform: translate(var(--arrow-shift), -50%) scale(1.16);
}

.hero-slider-arrow:active {
    transform: translate(var(--arrow-shift), -50%) scale(1.04);
}

.hero-slider-arrow:focus-visible {
    outline: 2px solid rgba(48, 119, 225, 0.6);
    outline-offset: 2px;
}

.hero-slider-arrow-previous {
    left: max(
        var(--hero-arrow-inset),
        calc(
            (100% - var(--hero-slide-fraction) * 100%) / 2
            * var(--hero-arrow-gutter-position)
        )
    );
}

.hero-slider-arrow-next {
    --arrow-shift: 50%;

    right: max(
        var(--hero-arrow-inset),
        calc(
            (100% - var(--hero-slide-fraction) * 100%) / 2
            * var(--hero-arrow-gutter-position)
        )
    );
}

/* Dots — the active one stretches into a pill that fills with the accent
   colour to show how long is left before the slider advances. */
.hero-slider-dots {
    display: flex;
    gap: 7px;
    justify-content: center;
    align-items: center;
    min-height: 10px;
    /* Negative because the extra shadow room below the slide is padding inside
       the viewport. This pulls the dots back to the same visual gap they had
       before that room was widened. */
    margin-top: -22px;
    margin-bottom: 46px;
    opacity: 0;
    transition: opacity 260ms ease;
}

.hero-slider.is-ready .hero-slider-dots {
    opacity: 1;
}

.hero-slider-dot {
    position: relative;
    width: 9px;
    height: 9px;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: #d5d9df;
    cursor: pointer;
    overflow: hidden;
    transition:
        width 380ms cubic-bezier(0.22, 1, 0.36, 1),
        background-color 260ms ease;
}

.hero-slider-dot:hover {
    background: #b9bfc8;
}

.hero-slider-dot.is-active {
    width: 34px;
    background: #d5d9df;
}

.hero-slider-dot:focus-visible {
    outline: 2px solid rgba(48, 119, 225, 0.6);
    outline-offset: 3px;
}

.hero-slider-dot-progress {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border-radius: 999px;
    background: var(--hero-accent);
    transform: scaleX(var(--dot-progress, 0));
    transform-origin: left center;
}

/* Screen-reader announcement of the current slide, updated only when the
   visitor navigates so auto-advance does not chatter. */
.hero-slider-status {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    -webkit-clip-path: inset(50%);
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Before the script runs, show the first slide so the hero is never blank. */
.hero-slider:not(.is-ready) .hero-slide:first-child {
    --slide-opacity: 1;
    --slide-scale: 1;
}

@media (max-width: 900px) {
    .hero-slider {
        --hero-slide-fraction: 0.80;
        --hero-slide-gap: 6px;
        --hero-slide-radius: 14px;
        /* Bottom clears the 0 17px 36px hover shadow below. */
        --hero-shadow-room-top: 34px;
        --hero-shadow-room-bottom: 58px;
        --hero-edge-fade: 24px;
        /* Only the chevron is drawn, so this is a pure hit area — kept at the
           44px touch-target minimum without affecting how it looks. */
        --hero-arrow-size: 44px;
        --hero-chevron-size: 21px;
    }

    /* 16 / (9 * 0.80) = 2.222 */
    .hero-slider-viewport {
        aspect-ratio: 2.222;
    }

    .hero-slide.is-active img {
        box-shadow:
            0 15px 32px rgba(24, 31, 42, 0.20),
            0 5px 12px rgba(24, 31, 42, 0.12),
            0 0 0 1px rgba(18, 24, 33, 0.07);
    }

    /* Scaled down with the resting shadow so it still fits the shadow room. */
    .hero-slider:not(.is-dragging) .hero-slide.is-active .hero-slide-link:hover img {
        box-shadow:
            0 17px 36px rgba(24, 31, 42, 0.24),
            0 6px 14px rgba(24, 31, 42, 0.14),
            0 0 0 1px rgba(18, 24, 33, 0.07);
    }


    .hero-slider-dots {
        margin-top: -18px;
        margin-bottom: 40px;
    }
}

@media (max-width: 540px) {
    .hero-slider {
        --hero-slide-gap: 4px;
        --hero-slide-radius: 12px;
        /* Bottom clears the 0 12px 26px hover shadow below. */
        --hero-shadow-room-top: 26px;
        --hero-shadow-room-bottom: 42px;
        --hero-edge-fade: 14px;
        --hero-arrow-size: 34px;
        --hero-chevron-size: 18px;
    }

    .hero-slide.is-active img {
        box-shadow:
            0 11px 24px rgba(24, 31, 42, 0.20),
            0 4px 9px rgba(24, 31, 42, 0.12),
            0 0 0 1px rgba(18, 24, 33, 0.07);
    }

    .hero-slider:not(.is-dragging) .hero-slide.is-active .hero-slide-link:hover img {
        box-shadow:
            0 12px 26px rgba(24, 31, 42, 0.24),
            0 5px 11px rgba(24, 31, 42, 0.14),
            0 0 0 1px rgba(18, 24, 33, 0.07);
    }

    .hero-slider-arrow svg {
        stroke-width: 2.4;
    }

    .hero-slider-dots {
        margin-top: -14px;
        margin-bottom: 32px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .hero-slide,
    .hero-slide img,
    .hero-slider-arrow,
    .hero-slider-dot {
        transition-duration: 0.01ms;
    }
}
