.herobuilder-carousel .hb-stage {
    width: 100%;
    overflow: hidden;
    /* Own stacking context so the layers' z-indexes stay contained and can't paint over
       the Bootstrap carousel controls/indicators (which live in the carousel context). */
    position: relative;
    z-index: 0;
}

/* Keep the carousel controls and indicators above the slide layers. */
.herobuilder-carousel .carousel-control-prev,
.herobuilder-carousel .carousel-control-next,
.herobuilder-carousel .carousel-indicators {
    z-index: 5;
}

/* Positioning + geometry come from the per-slide scoped CSS. */
.hb-layer {
    position: absolute;
}

.hb-layer .hb-layer-img,
.hb-layer.hb-layer-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: fill;
}

/* Text layers: fill their geometry box, vertically centred; box-sizing keeps the
   readability scrim padding inside the placed box.

   `line-height` is reset here on purpose: `.herobuilder-carousel .carousel-item`
   below sets `line-height: 0` to kill the inline-image baseline gap under the
   image layer, and that value is inherited. Without this reset every text layer
   that has no explicit `lh-*` class collapses — all wrapped lines land on the
   same baseline and the text renders as an unreadable overlay of itself.
   Bootstrap's `lh-*` utilities ship with !important, so they still win. */
.hb-layer-text {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    justify-content: center;
    line-height: normal;
}

/* Button layers fill their placed box; the label is centred and btn classes style it. */
.hb-layer-button {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    text-decoration: none;
}

.herobuilder-carousel .carousel-item {
    /* Ensure the slide fills the stage without extra whitespace. */
    line-height: 0;
}

/* ---------------------------------------------------------------------------
   Bootstrap 5 carousel fallback.

   The CE emits Bootstrap carousel markup, but a site theme may compile only a
   subset of Bootstrap's components (a theme that curates its own SCSS component
   list may leave `bootstrap/carousel` out, e.g. when its legacy hero slider used
   a different library). Without the component CSS every slide stays
   `display: block` and the slides stack vertically instead of sliding.

   These rules mirror Bootstrap's own carousel component, scoped to
   `.herobuilder-carousel` so they only ever affect this CE. On a theme that
   *does* ship the component they resolve to the same values, just at a higher
   specificity — so keeping them is harmless either way.
   --------------------------------------------------------------------------- */
.herobuilder-carousel {
    position: relative;
}

.herobuilder-carousel.pointer-event {
    touch-action: pan-y;
}

.herobuilder-carousel .carousel-inner {
    position: relative;
    width: 100%;
    overflow: hidden;
}

.herobuilder-carousel .carousel-inner::after {
    display: block;
    clear: both;
    content: "";
}

.herobuilder-carousel .carousel-item {
    position: relative;
    display: none;
    float: left;
    width: 100%;
    margin-right: -100%;
    backface-visibility: hidden;
    transition: transform 0.6s ease-in-out;
}

.herobuilder-carousel .carousel-item.active,
.herobuilder-carousel .carousel-item-next,
.herobuilder-carousel .carousel-item-prev {
    display: block;
}

.herobuilder-carousel .carousel-item-next:not(.carousel-item-start),
.herobuilder-carousel .active.carousel-item-end {
    transform: translateX(100%);
}

.herobuilder-carousel .carousel-item-prev:not(.carousel-item-end),
.herobuilder-carousel .active.carousel-item-start {
    transform: translateX(-100%);
}

/* Cross-fade instead of sliding (slider_effect = fade). */
.herobuilder-carousel.carousel-fade .carousel-item {
    opacity: 0;
    transition-property: opacity;
    transform: none;
}

.herobuilder-carousel.carousel-fade .carousel-item.active,
.herobuilder-carousel.carousel-fade .carousel-item-next.carousel-item-start,
.herobuilder-carousel.carousel-fade .carousel-item-prev.carousel-item-end {
    z-index: 1;
    opacity: 1;
}

.herobuilder-carousel.carousel-fade .active.carousel-item-start,
.herobuilder-carousel.carousel-fade .active.carousel-item-end {
    z-index: 0;
    opacity: 0;
    transition: opacity 0s 0.6s;
}

.herobuilder-carousel .carousel-control-prev,
.herobuilder-carousel .carousel-control-next {
    position: absolute;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 15%;
    padding: 0;
    color: #fff;
    text-align: center;
    background: none;
    border: 0;
    opacity: 0.5;
    transition: opacity 0.15s ease;
}

.herobuilder-carousel .carousel-control-prev:hover,
.herobuilder-carousel .carousel-control-prev:focus,
.herobuilder-carousel .carousel-control-next:hover,
.herobuilder-carousel .carousel-control-next:focus {
    color: #fff;
    text-decoration: none;
    outline: 0;
    opacity: 0.9;
}

.herobuilder-carousel .carousel-control-prev {
    left: 0;
}

.herobuilder-carousel .carousel-control-next {
    right: 0;
}

.herobuilder-carousel .carousel-control-prev-icon,
.herobuilder-carousel .carousel-control-next-icon {
    display: inline-block;
    width: 2rem;
    height: 2rem;
    background-repeat: no-repeat;
    background-position: 50%;
    background-size: 100% 100%;
}

.herobuilder-carousel .carousel-control-prev-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e");
}

.herobuilder-carousel .carousel-control-next-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
}

.herobuilder-carousel .carousel-indicators {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    display: flex;
    justify-content: center;
    padding: 0;
    margin-right: 15%;
    margin-bottom: 1rem;
    margin-left: 15%;
    list-style: none;
}

.herobuilder-carousel .carousel-indicators [data-bs-target] {
    box-sizing: content-box;
    flex: 0 1 auto;
    width: 30px;
    height: 3px;
    padding: 0;
    margin-right: 3px;
    margin-left: 3px;
    text-indent: -999px;
    cursor: pointer;
    background-color: #fff;
    background-clip: padding-box;
    border: 0;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
    opacity: 0.5;
    transition: opacity 0.6s ease;
}

.herobuilder-carousel .carousel-indicators .active {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .herobuilder-carousel .carousel-item,
    .herobuilder-carousel .carousel-control-prev,
    .herobuilder-carousel .carousel-control-next,
    .herobuilder-carousel .carousel-indicators [data-bs-target] {
        transition: none;
    }
}

/* ---------------------------------------------------------------------------
   Transition: "layers" (slider_effect = layers).

   The slide itself cross-fades (Bootstrap's .carousel-fade), which is what carries the
   background image: the incoming background is already visible while the outgoing one
   fades, so the stage is never empty. Every other layer is animated on its own —
   fading out front-most first, and building back up rearmost-first on the incoming
   slide, staggered by depth.

   Only `opacity` is animated on purpose. The generated per-slide CSS owns `transform`
   on .hb-layer (layer rotation) and on .hb-layer-img (flip), so a transform here would
   silently drop those.

   --hb-depth (0 = rearmost) and --hb-depth-rev (0 = front-most) come from the
   composition's z-order; the rearmost layer carries .hb-layer-bg and is exempt.
   --------------------------------------------------------------------------- */
.herobuilder-carousel.hb-fx-layers .carousel-item .hb-layer:not(.hb-layer-bg) {
    opacity: 0;
    transition: opacity 260ms ease;
}

/* Resting and incoming slide: rearmost layer first, so the composition builds up in depth
   order. The incoming item only gains .active once Bootstrap's 600ms item fade is done,
   which is exactly when the new background has arrived. */
.herobuilder-carousel.hb-fx-layers .carousel-item.active .hb-layer:not(.hb-layer-bg) {
    opacity: 1;
    transition-delay: calc(var(--hb-depth, 1) * 70ms);
}

/* Outgoing slide: front-most layer first and quicker than the background cross-fade, so the
   composition comes apart before the background underneath it changes. */
.herobuilder-carousel.hb-fx-layers .carousel-item.active.carousel-item-start .hb-layer:not(.hb-layer-bg),
.herobuilder-carousel.hb-fx-layers .carousel-item.active.carousel-item-end .hb-layer:not(.hb-layer-bg) {
    opacity: 0;
    transition-duration: 180ms;
    transition-delay: calc(var(--hb-depth-rev, 0) * 70ms);
}

/* Reduced motion: keep every layer up, no staggering — the slide change itself stays a plain
   cross-fade. Repeating the outgoing selector here keeps it from winning on specificity. */
@media (prefers-reduced-motion: reduce) {
    .herobuilder-carousel.hb-fx-layers .carousel-item .hb-layer:not(.hb-layer-bg),
    .herobuilder-carousel.hb-fx-layers .carousel-item.active.carousel-item-start .hb-layer:not(.hb-layer-bg),
    .herobuilder-carousel.hb-fx-layers .carousel-item.active.carousel-item-end .hb-layer:not(.hb-layer-bg) {
        opacity: 1;
        transition: none;
    }
}

/* ---------------------------------------------------------------------------
   Transition: "parallax" (slider_effect = parallax).

   Same choreography as "layers", but the elements also drift horizontally, further the
   further forward they sit — so the slide comes apart and reassembles with depth. The
   background layer never moves: it only cross-fades with the slide, which keeps the
   stage covered at all times.

   Movement uses the individual `translate` property, not `transform`: the generated
   per-slide CSS already puts `transform:rotate()` on .hb-layer, and individual transform
   properties compose (translate → rotate → scale) instead of replacing it.

   The offset is a viewport-relative length, not a percentage: `translate` percentages
   resolve against the element's own box, and layer boxes here range from a few percent of
   the stage to over 200% of it (corner clusters), which would scramble the depth order.
   Override --hb-parallax-step per site to dial the travel up or down.
   --------------------------------------------------------------------------- */
.herobuilder-carousel.hb-fx-parallax .carousel-item .hb-layer:not(.hb-layer-bg) {
    --hb-parallax-step: clamp(8px, 1.8vw, 34px);
    --hb-off: calc(var(--hb-depth, 0) * var(--hb-parallax-step));
    opacity: 0;
    translate: var(--hb-off) 0;
    transition: opacity 300ms ease, translate 380ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Backward navigation: the incoming slide waits on the other side, so the travel direction
   always matches the direction the user asked for. */
.herobuilder-carousel.hb-fx-parallax .carousel-item.carousel-item-prev .hb-layer:not(.hb-layer-bg) {
    translate: calc(-1 * var(--hb-off)) 0;
}

/* Resting and incoming slide: settle into place, rearmost layer first. */
.herobuilder-carousel.hb-fx-parallax .carousel-item.active .hb-layer:not(.hb-layer-bg) {
    opacity: 1;
    translate: 0 0;
    transition-delay: calc(var(--hb-depth, 1) * 70ms);
}

/* Outgoing slide, forward: drift on to the left, front-most layer leaving first. */
.herobuilder-carousel.hb-fx-parallax .carousel-item.active.carousel-item-start .hb-layer:not(.hb-layer-bg) {
    opacity: 0;
    translate: calc(-1 * var(--hb-off)) 0;
    transition-duration: 260ms;
    transition-delay: calc(var(--hb-depth-rev, 0) * 70ms);
}

/* Outgoing slide, backward: same, mirrored. */
.herobuilder-carousel.hb-fx-parallax .carousel-item.active.carousel-item-end .hb-layer:not(.hb-layer-bg) {
    opacity: 0;
    translate: var(--hb-off) 0;
    transition-duration: 260ms;
    transition-delay: calc(var(--hb-depth-rev, 0) * 70ms);
}

@media (prefers-reduced-motion: reduce) {
    .herobuilder-carousel.hb-fx-parallax .carousel-item .hb-layer:not(.hb-layer-bg),
    .herobuilder-carousel.hb-fx-parallax .carousel-item.carousel-item-prev .hb-layer:not(.hb-layer-bg),
    .herobuilder-carousel.hb-fx-parallax .carousel-item.active.carousel-item-start .hb-layer:not(.hb-layer-bg),
    .herobuilder-carousel.hb-fx-parallax .carousel-item.active.carousel-item-end .hb-layer:not(.hb-layer-bg) {
        opacity: 1;
        translate: 0 0;
        transition: none;
    }
}
