/* Unified banner system - every banner on the site (homepage hero, mid-page
   video banners, product page banners) is built by AZBannerRenderer from
   Admin > Banners data into this one set of classes; nothing here is specific
   to any one banner or page. Imported by styles.css for the live storefront,
   and loaded directly by the admin banner editor so its live preview renders
   with the exact same rules a visitor would see. */
.banner-slot {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  overflow: hidden;
  isolation: isolate;
  /* Fallback covers sites (Khalis Herb's Suxnix rebuild) that never define
     --pine - without it this background silently fell through to white,
     showing as a white strip top/bottom on any "contain"-fit banner whose
     image doesn't fill the fixed frame. Sites that do define --pine (AZ
     Herbal Care) are unaffected, since the fallback only applies when the
     variable is genuinely missing. */
  background: var(--pine, #142013);
  touch-action: pan-y;
  /* Lets the height rules below reference this box's own rendered width
     instead of the whole browser window - on the live site the box IS the
     full window width so this changes nothing, but inside the admin editor's
     narrower preview panel it stops the frame from being computed as if it
     were full-page-wide, which was cropping images far more than intended. */
  container-type: inline-size;
}

.banner-slot[data-banner-frame="natural"] {
  line-height: 0;
  background: none;
}

.banner-slides {
  position: relative;
}

/* The height lives here rather than on .banner-slot itself - a container can't
   use its own container-query units to size itself (that's circular and the
   browser ignores it), so .banner-slot is the query container and this child
   is what's actually sized off its width. */
.banner-slot[data-banner-frame="fixed-tall"] .banner-slides {
  height: 43.58vw; /* fallback for browsers without container query units */
  height: 43.58cqw;
  max-height: 828px;
  min-height: 320px;
}

.banner-slot[data-banner-frame="fixed-short"] .banner-slides {
  height: 22vw; height: clamp(140px, 22vw, 380px);
  height: 22cqw; height: clamp(140px, 22cqw, 380px);
}

/* Natural-frame banners (no fixed height) stack in normal flow, so hiding an
   inactive slide really does mean display:none - there's no absolute
   positioning/opacity system for them to crossfade or slide with. This must
   NOT apply to fixed-* frame banners below: display can't be transitioned,
   so if this generic rule also matched them, an outgoing slide would vanish
   from the render tree the instant .is-active is removed, cutting off the
   opacity/transform transition before the browser ever got to animate it -
   this was a real bug (confirmed via zero transitionend events ever firing)
   that silently broke BOTH the fade and slide transitions below. */
.banner-slot[data-banner-frame="natural"] .banner-slide {
  display: none;
}

.banner-slot[data-banner-frame="natural"] .banner-slide.is-active {
  display: block;
}

.banner-slot[data-banner-frame^="fixed"] .banner-slide {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0; inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity var(--banner-transition-duration, 0.7s) ease;
}

.banner-slot[data-banner-frame^="fixed"] .banner-slide.is-active {
  display: block;
  opacity: 1;
}

/* Slide transition variant - set by AZBannerRenderer's initSlot() via
   [data-banner-transition="slide"] on .banner-slot when the admin picks
   "Slide" instead of "Fade" for this banner location. All slides always stay
   in the DOM (they're position:absolute already, from the rule above), so
   the outgoing and incoming slide can sit side by side mid-transition - the
   idle/rest position for every non-active slide is off-screen to the right;
   .is-prev (added by show() in banner-renderer.js, briefly, while moving
   forward) parks the just-left slide off-screen to the left instead, so it
   animates out to the left while the incoming one slides in from the right.
   Going backward is the mirror image, handled in JS by momentarily jumping
   the incoming slide to the left with .is-preset-left (transition disabled)
   before letting it animate back to center like any other .is-active slide -
   see the comment above show() in banner-renderer.js for the full reasoning. */
.banner-slot[data-banner-frame^="fixed"][data-banner-transition="slide"] .banner-slide {
  opacity: 1;
  transform: translateX(100%);
  transition: transform var(--banner-transition-duration, 0.7s) ease;
}

.banner-slot[data-banner-frame^="fixed"][data-banner-transition="slide"] .banner-slide.is-active {
  transform: translateX(0);
}

.banner-slot[data-banner-frame^="fixed"][data-banner-transition="slide"] .banner-slide.is-prev {
  transform: translateX(-100%);
}

.banner-slot[data-banner-frame^="fixed"][data-banner-transition="slide"] .banner-slide.is-preset-left {
  transition: none;
  transform: translateX(-100%);
}

.banner-media {
  display: block;
  width: 100%;
  height: auto;
  -webkit-user-drag: none;
  user-select: none;
}

/* Absolutely positioned with inset:0 (rather than width/height:100%) so the
   media always exactly fills .banner-slides' box - width/height percentages
   round independently and can leave a sub-pixel gap at the bottom edge that
   exposes .banner-slot's dark background as a thin grey line. */
.banner-slot[data-banner-frame^="fixed"] .banner-media {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0; inset: 0;
  width: 100%;
  height: 100%;
}

.banner-click-wrap {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0; inset: 0;
  z-index: 1;
}

.banner-cta {
  position: absolute;
  z-index: 2;
}

.banner-copy {
  position: absolute;
  z-index: 2;
  max-width: min(520px, 90%);
  padding: 4vw; padding: clamp(20px, 4vw, 40px);
}

/* Position (left/top/transform) is set inline per-banner by buildSlide() in
   banner-renderer.js - a free-form (x%, y%) center point dragged into place
   in the admin editor, replacing the old fixed 9-position preset classes
   that used to live here. */

.banner-copy-align-left { text-align: left; }
.banner-copy-align-center { text-align: center; }
.banner-copy-align-right { text-align: right; }

.banner-heading {
  margin: 0;
  color: currentColor;
  font-family: "Inter", system-ui, sans-serif;
  font-weight: 700;
  /* --banner-heading-max is an admin-chosen ceiling (default 3.6rem) - it only
     raises how large the heading can get on wide screens, it never stops the
     vw-based term from scaling it down on narrow ones. */
  font-size: 4vw; font-size: clamp(2rem, 4vw, var(--banner-heading-max, 3.6rem));
  letter-spacing: -0.03em;
  line-height: 1.05;
}

.banner-subheading,
.banner-description {
  margin: 10px 0 0;
  color: currentColor;
  font-size: 1.2vw; font-size: clamp(0.9rem, 1.2vw, 1.05rem);
  font-weight: 600;
}

.banner-description {
  font-weight: 400;
  opacity: 0.92;
}

.banner-button {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 46px;
  padding: 0 24px;
  color: #fff;
  background: var(--pine, #242424);
  border: 1px solid var(--pine, #242424);
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 900;
  letter-spacing: 0.1em;
  text-decoration: none;
  text-transform: uppercase;
  transition: color 180ms ease, background 180ms ease, transform 180ms ease;
}

.banner-button:hover,
.banner-button:focus-visible {
  color: var(--pine, #242424);
  background: var(--gold-light, #86c94f);
  border-color: var(--gold-light, #86c94f);
  transform: translateY(-2px);
}

/* A dedicated strip below the banner image (not an overlay on top of it) -
   sits in normal flow right after .banner-slides, so it reads as its own
   "slide bar" rather than competing with whatever photo is showing. */
.banner-dots {
  position: static;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px 0;
  background: var(--pine, #0d3323);
}

.banner-dot {
  width: 9px;
  height: 9px;
  padding: 0;
  background: rgba(255, 255, 255, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 999px;
  cursor: pointer;
  transition: width 0.2s ease, background 0.2s ease;
}

.banner-dot.is-active {
  width: 24px;
  background: var(--gold, #519f10);
  border-color: var(--gold, #519f10);
}

.banner-arrow {
  position: absolute;
  z-index: 3;
  top: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  transform: translateY(-50%);
  color: #fff;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 50%;
  cursor: pointer;
  transition: background 180ms ease, transform 180ms ease, border-color 180ms ease;
}

.banner-arrow:hover,
.banner-arrow:focus-visible {
  background: rgba(0, 0, 0, 0.6);
  border-color: #fff;
  transform: translateY(-50%) scale(1.06);
}

.banner-arrow svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

.banner-arrow-prev { left: 16px; }
.banner-arrow-next { right: 16px; }

@media (max-width: 560px) {
  .banner-arrow { width: 36px; height: 36px; }
  .banner-arrow svg { width: 18px; height: 18px; }
}

@keyframes banner-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes banner-slide-in {
  from { opacity: 0; transform: translateX(-24px); }
  to { opacity: 1; transform: translateX(0); }
}

@keyframes banner-zoom-in {
  from { opacity: 0; transform: scale(0.92); }
  to { opacity: 1; transform: scale(1); }
}

.banner-slide.is-active .banner-anim-media-fade { animation: banner-fade-in 0.8s ease both; }
.banner-slide.is-active .banner-anim-media-slide { animation: banner-slide-in 0.8s cubic-bezier(0.2, 0.75, 0.25, 1) both; }
.banner-slide.is-active .banner-anim-media-zoom { animation: banner-zoom-in 0.8s cubic-bezier(0.2, 0.75, 0.25, 1) both; }
.banner-slide.is-active .banner-anim-text-fade { animation: banner-fade-in 0.6s ease both; animation-delay: 0.15s; }
.banner-slide.is-active .banner-anim-text-slide { animation: banner-slide-in 0.6s cubic-bezier(0.2, 0.75, 0.25, 1) both; animation-delay: 0.15s; }
.banner-slide.is-active .banner-anim-text-zoom { animation: banner-zoom-in 0.6s cubic-bezier(0.2, 0.75, 0.25, 1) both; animation-delay: 0.15s; }
.banner-slide.is-active .banner-anim-button-fade { animation: banner-fade-in 0.5s ease both; animation-delay: 0.35s; }
.banner-slide.is-active .banner-anim-button-slide { animation: banner-slide-in 0.5s cubic-bezier(0.2, 0.75, 0.25, 1) both; animation-delay: 0.35s; }
.banner-slide.is-active .banner-anim-button-zoom { animation: banner-zoom-in 0.5s cubic-bezier(0.2, 0.75, 0.25, 1) both; animation-delay: 0.35s; }

@media (max-width: 980px) {
  .banner-copy {
    max-width: min(78vw, 480px);
  }

  /* A much taller crop than desktop (was 111.1vw) cut off more than half of any
     wide banner photo regardless of focal point - most uploaded banners (device
     photos, social-style graphics) are landscape, so this keeps enough width
     visible for admin-uploaded images to still show their content on phones. */
  .banner-slot[data-banner-frame="fixed-tall"] .banner-slides {
    height: 70vw;
    height: 70cqw;
    max-height: none;
    min-height: 280px;
  }
}

@media (max-width: 560px) {
  .banner-heading {
    font-size: 8vw; font-size: clamp(1.7rem, 8vw, 2.4rem);
  }

  .banner-slot[data-banner-frame="fixed-tall"] .banner-slides {
    min-height: 260px;
  }

  .banner-dots {
    bottom: 12px;
    gap: 7px;
  }

  .banner-dot {
    width: 8px;
    height: 8px;
  }

  .banner-dot.is-active {
    width: 22px;
  }

  .banner-copy {
    max-width: min(86vw, 340px);
    padding: 18px;
  }

  .banner-button {
    min-height: 42px;
    margin-top: 14px;
    padding: 0 20px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .banner-slide,
  .banner-anim-media-fade, .banner-anim-media-slide, .banner-anim-media-zoom,
  .banner-anim-text-fade, .banner-anim-text-slide, .banner-anim-text-zoom,
  .banner-anim-button-fade, .banner-anim-button-slide, .banner-anim-button-zoom {
    animation: none;
    transition: none;
  }
}

/* Placement banners land between two sections that weren't designed with a
   banner gap between them, so they carry their own vertical rhythm - the
   same clamp() range used site-wide for section padding - rather than
   depending on whatever their new neighbours happen to have. Scoped to
   [data-banner-dynamic] (set only by script.js's dynamic-placement insertion)
   so the pre-existing hand-placed banner slots are untouched. */
.banner-slot[data-banner-dynamic] {
  margin-top: 6vw; margin-top: clamp(40px, 6vw, 72px);
  margin-bottom: 6vw; margin-bottom: clamp(40px, 6vw, 72px);
}

/* Product pages are the one exception to the vertical rhythm above: banners
   there (hand-placed or Custom Placement) should butt up directly against
   whatever's next to them, with zero gap - current banners and any future
   ones alike. This clears the NEXT section's own top margin whenever it
   follows any banner, and the rule below removes a dynamic placement's own
   top/bottom margin entirely in this context - together they cover a
   banner in either position, next to any section.
   display: flow-root matters here as much as margin-top: 0 - without it, a
   section with no top padding/border of its own (e.g. .details-dossier)
   still shows a gap, because its first child's top margin (e.g.
   .product-tabs picks up its own margin-top on narrower breakpoints)
   collapses straight through the section's top edge per normal CSS margin-
   collapsing rules. flow-root opens a new block formatting context so that
   can never happen.
   Deliberately an explicit list, NOT ".banner-slot + *" - .product-view is
   a display:grid two-column layout (gallery | buy box), and a wildcard
   selector here previously forced display:flow-root onto it whenever a
   banner landed immediately before it (anchor "hero", position "before"),
   silently collapsing that grid to a single column and making the product
   image render far larger than intended. Only list section classes here
   that are plain display:block with no layout mode of their own to lose;
   a brand-new anchor's section must be added to this list explicitly
   rather than assumed to be flow-root-safe. */
.details-page .banner-slot + .details-dossier,
.details-page .banner-slot + .product-reviews-section,
.details-page .banner-slot + .recommended-products-section {
  margin-top: 0;
  display: flow-root;
}

.details-page .banner-slot[data-banner-dynamic] {
  margin-top: 0;
  margin-bottom: 0;
}

/* Stacked display: every banner shown one under the other, full width. */
.banner-stack {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.banner-stack > .banner-slide {
  position: relative;
  width: 100%;
}
