/* --cslr-* custom properties are the theming surface (the --ss-*
   convention from split-section). Defaults reproduce the bodysoul look;
   themes override the properties, not the rules. --cslr-accent falls back
   through bodysoul's action token so that site needs no theme change. */
.slider-container {
  /* Palette Kit first, then the theme token, then the literal: with the
     plugin absent --pal-action is undefined and the chain below is what
     rendered before it existed. --cslr-control-color deliberately does NOT
     read a role - it is a near-black chrome ink, and every palette so far
     maps `ink` to a mid warm-grey, which would grey the arrows out. */
  --cslr-accent-default: var(--pal-action, var(--bodysoul-action-book, #1E7A6B));
  --cslr-control-color: #3b3b3b;
  --cslr-fade: 600ms;
  --cslr-image-max-height: 650px;
  --cslr-overlay-type-size: 4.76837rem;
  --cslr-controls-offset: 14px;
}

/* Flush slides (1.6.0): while the block runs as a carousel each slide already
   fills the width, so a slide's block's own top/bottom padding — typically
   set for the stacked layout above the activation breakpoint — reads as a
   gap over the image. With the option on the container publishes
   --sx-host-pad-top/-bottom: 0px, a HOST token the split-section blocks read
   ahead of their own padding value (the contract is theirs:
   split-section/AGENTS.md "Host padding token"). The generated inert CSS
   (content-slider.php) sets both back to `initial` above the breakpoint —
   the guaranteed-invalid value, so var() falls through to the block's own
   padding there. Cooperation, not a forced override: a block that does not
   read the token keeps its padding. */
.slider-container.is-flush-slides {
  --sx-host-pad-top: 0px;
  --sx-host-pad-bottom: 0px;
}

/* Optional intro (heading/paragraph/buttons) representing the group,
   rendered as a sibling before .slider-container rather than nested inside
   it — deliberately isolated from the carousel's own box/positioning
   context so every existing slider's arrows/dots/playpause need zero
   changes, at the cost of the intro not automatically inheriting the
   slider's own alignment (e.g. full-bleed). */
.slider-intro {
  margin-bottom: var(--cslr-intro-gap, 1.5rem);
}

.slider-arrows .arrow {
  align-items: center;
  background-color: transparent;
  border: none;
  cursor: pointer;
  display: flex;
  height: 1.7em;
  justify-content: center;
  padding: 0;
  position: absolute;
  top: 42.5%;
  transform: translateY(-50%);
  width: 1.7em;
  z-index: 2;
}

.slider-arrows .arrow {
  color: var(--cslr-control-color);
}

.slider-arrows .arrow svg {
  fill: none;
  height: 4.8em;
  width: auto;
}

.slider-arrows .arrow:focus-visible {
  outline: 2px solid var(--cslr-accent, var(--cslr-accent-default));
  outline-offset: 4px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: no-preference) {
  .arrow svg {
    transition: transform 150ms ease;
  }
  .arrow-next:hover svg {
    transform: scaleX(1) translateX(2px);
  }
  .arrow-prev:hover svg {
    /* translate happens on the flipped axis, so this nudges left */
    transform: scaleX(-1) translateX(2px);
  }
}

.slider-arrows {
  position: absolute;
  top: 50%;
  width: 100%;
}

.arrow-prev {
  left: 1em;
}

.arrow-prev svg {
  transform: scaleX(-1);
}

.arrow-next {
  right: 1em;
}

.arrow-next svg {
  transform: scaleX(1);
}

.slider-container {
  overflow: hidden;
  position: relative;
}

/* No floor unless one is asked for (1.8.0): the slider is as tall as its
   slides. The block's "Minimum height" setting writes these two properties
   inline (render.php); a theme may set them too. Phones fall back to the
   desktop value, so one setting covers both unless the phone one is given.
   Until 1.8.0 the fallbacks were 22vw / 73.54vw — a hero floor every slider
   carried, which left a band of empty space under a short content panel. */
.slider-container {
  min-height: var(--cslr-min-height-mobile, var(--cslr-min-height, 0px));
}

@media (min-width: 834px) {
  .slider-container {
    min-height: var(--cslr-min-height, 0px);
  }
}

/* All slides share one grid cell: the container takes the tallest slide's
   height (no page jump between slides) and inactive slides sit stacked
   underneath, hidden. Shorter slides centre in the shared cell.
   Direct-child selectors on purpose: only the slider's own slides stack —
   a nested block that happens to emit a slide-item class must not be
   swallowed by these rules. */
.slider-container > .slider-wrapper {
  display: grid;
  width: 100%;
}

/* Each of the three nested grids is ONE column of minmax(0, 1fr) (1.8.1):
   an implicit column is sized from its content and never narrower than it,
   so a slide holding something that reports a wide intrinsic size — an
   inline-size container, a long unbroken URL, a table — pushed the slide
   wider than the slider (bodysoul's gift voucher strip: a 2004px slide in a
   1638px slider). A single full-width track changes nothing for content
   that fits. */
.slider-container > .slider-wrapper,
.slider-container > .slider-wrapper > .slide-item,
.slider-container .slider-wrapper .slide-item .slide-content {
  grid-template-columns: minmax(0, 1fr);
}

.slider-container > .slider-wrapper > .slide-item {
  position: relative;
  grid-area: 1 / 1;
  display: grid;
  align-content: center;
  visibility: hidden;
  opacity: 0;
}

.slider-container > .slider-wrapper > .slide-item.active {
  visibility: visible;
  opacity: 1;
  z-index: 1;
}

/* Crossfade: the outgoing slide keeps its visibility until its fade ends. */
@media (prefers-reduced-motion: no-preference) {
  .slider-container > .slider-wrapper > .slide-item {
    transition: opacity var(--cslr-fade, 600ms) ease, visibility 0s linear var(--cslr-fade, 600ms);
  }
  .slider-container > .slider-wrapper > .slide-item.active {
    transition: opacity var(--cslr-fade, 600ms) ease;
  }
}

/* ---- Height modes -------------------------------------------------------
   Everything above is the `tallest` mode: one shared grid cell, so the row is
   sized by the tallest slide and nothing below the slider ever moves.

   `smooth` and `instant` take the ACTIVE slide's height instead. Both work
   the same way and need no measuring: the inactive slides come out of flow,
   leaving the active one — still in flow — to size the wrapper by itself.
   That keeps the crossfade (they stay stacked and fade exactly as before)
   and it stays correct with JavaScript off.

   `smooth` differs only in animating the change, which auto heights cannot
   do, so view-module.js puts an explicit pixel height on the wrapper. Until
   that script runs, `smooth` behaves as `instant` rather than breaking.

   --cslr-min-height[-mobile], when set, applies in every mode: it is a
   deliberate floor, not part of the tallest-slide behaviour. */

.slider-container[data-height-mode='smooth'] > .slider-wrapper,
.slider-container[data-height-mode='instant'] > .slider-wrapper {
  display: block;
  position: relative;
}

.slider-container[data-height-mode='smooth'] > .slider-wrapper > .slide-item,
.slider-container[data-height-mode='instant'] > .slider-wrapper > .slide-item {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}

.slider-container[data-height-mode='smooth'] > .slider-wrapper > .slide-item.active,
.slider-container[data-height-mode='instant'] > .slider-wrapper > .slide-item.active {
  position: relative;
}

@media (prefers-reduced-motion: no-preference) {
  .slider-container[data-height-mode='smooth'] > .slider-wrapper {
    transition: height var(--cslr-height-fade, 400ms) ease;
  }
}

.slider-container .slider-wrapper .slide-item a {
  text-decoration: none;
}

.slider-container .slider-wrapper .slide-item .slide-content {
  display: grid;
}

.slider-container .slider-wrapper .slide-item .slide-content picture {
  grid-row: -1/3;
  grid-column: -1/1;
}

.slider-container .slider-wrapper .slide-item .slide-content picture img {
  /* block, not inline (1.7.1): an inline image sits on the text baseline and
     the line box keeps descender room under it (~9px at a 19px/1.5 body),
     which the picture, and so the slide, carried as a bare strip below the
     photo. There is no text on this line to align with. */
  display: block;
  width: 100%;
  /* cover (1.8.2): once max-height clamps, `fill` kept the full width and
     squashed the photo (measured 1.15 -> 1.28 at 834px, 4.22 -> 5.85 at
     3800px); cover trims it top and bottom instead. height:auto because the
     width/height attributes would otherwise set a fixed px height. */
  height: auto;
  max-height: var(--cslr-image-max-height, 650px);
  object-fit: cover;
  object-position: var(--cslr-pos-xl, 50% 50%);
}

/* Focal point per width band (1.9.0). The queries MUST stay identical to the
   <source> media in blocks/slide/render.php: render.php resolves which slot's
   image each band shows and publishes that slot's point under the band name. */
@media (max-width: 2560px) {
  .slider-container .slider-wrapper .slide-item .slide-content picture img {
    object-position: var(--cslr-pos-lg, 50% 50%);
  }
}

@media (max-width: 1024px) {
  .slider-container .slider-wrapper .slide-item .slide-content picture img {
    object-position: var(--cslr-pos-md, 50% 50%);
  }
}

@media (max-width: 834px) {
  .slider-container .slider-wrapper .slide-item .slide-content picture img {
    object-position: var(--cslr-pos-sm, 50% 50%);
  }
}

.slider-container .slider-wrapper .slide-item .slide-content-inner {
  align-self: stretch;
  justify-self: stretch;
  display: grid;
  grid-row: 2/4;
  grid-column: -1/1;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  align-items: center;
  justify-content: center;
  font-size: var(--cslr-overlay-type-size, 4.76837rem);
}

/* The overlay type size is for text written straight into a hero slide.
   A layout block hosted in the slide (Split Section, Section) brings its
   own typography and must see the page's size, exactly as a panel slide
   does — otherwise anything inside it without a size of its own (the
   theme's buttons inherit) renders at display scale. `inherit` reaches
   past the overlay rule to .slide-content, which never sets a size.
   A Jump Links outline is the same case (1.9.1): it sizes everything in
   em, so inside a hero its four links came out at 47.7px.
   Browsers without :has() keep the old behaviour; nothing breaks. */
.slider-container .slider-wrapper .slide-item .slide-content-inner:has(> .slide-content-blocks > .wp-block-aurora-arcade-split-section),
.slider-container .slider-wrapper .slide-item .slide-content-inner:has(> .slide-content-blocks > .wp-block-aurora-arcade-section),
.slider-container .slider-wrapper .slide-item .slide-content-inner:has(> .slide-content-blocks > .wp-block-aurora-arcade-jump-links) {
  font-size: inherit;
}

/* A hosted Jump Links outline also needs a column of definite width
   (1.9.1): its centred-block mode puts inline-size containment on its
   PARENT (jump-links' own trade-off, documented in its style.css), and a
   box under containment contributes nothing to an intrinsic track — so in
   the centre style's `auto` column, and the single implicit column below
   834px, the whole content column collapsed to 0 and the H1 beside the
   outline went with it (measured on bodysoul's Spray Tans page). The
   outline centres itself in a wide column; the H1 that the hugging column
   used to centre by geometry is centred by text-align instead. */
@media (max-width: 833px) {
  /* The centre style's `grid-column-start: 2` holds at every width, so
     below 834px the div sat in an implicit second column; span it. */
  .slider-container .slider-wrapper .slide-item .slide-content-inner:has(> .slide-content-blocks > .wp-block-aurora-arcade-jump-links) {
    grid-template-columns: minmax(0, 1fr);
  }

  .slider-container .slider-wrapper .slide-item .slide-content-inner:has(> .slide-content-blocks > .wp-block-aurora-arcade-jump-links) > .slide-content-blocks {
    grid-column: 1 / -1;
  }
}

.slider-container .slider-wrapper .slide-item .slide-content-inner:has(> .slide-content-blocks > .wp-block-aurora-arcade-jump-links) > .slide-content-blocks {
  min-width: 0;
}

.slider-container .slider-wrapper .slide-item.is-style-align-center .slide-content-inner:has(> .slide-content-blocks > .wp-block-aurora-arcade-jump-links) > .slide-content-blocks {
  text-align: center;
}

@media (min-width: 834px) {
  .slider-container .slider-wrapper .slide-item.is-style-align-center .slide-content-inner:has(> .slide-content-blocks > .wp-block-aurora-arcade-jump-links) {
    grid-template-columns: 60px minmax(0, 1fr) 60px;
  }
}

.slider-container .slider-wrapper .slide-item .slide-content-inner > div {
  padding: 1.6rem;
  overflow: hidden;
}

.slider-container .slider-wrapper .slide-item .slide-content-inner > div h1 {
  margin: 0;
}

.slider-container .slider-wrapper .slide-item .slide-content-inner > div p {
  margin-top: 0;
  max-width: 100%;
}

@media (min-width: 834px) {
  .slider-container .slider-wrapper .slide-item .slide-content-inner > div {
    padding: 0;
  }
}

@media (min-width: 834px) {
  .slider-container .slider-wrapper .slide-item .slide-content-inner {
    grid-row: -1/3;
  }
}

@media (min-width: 834px) {
  .slider-container .slider-wrapper .slide-item.is-style-align-left .slide-content-inner {
    grid-template-columns: 60px calc(60% - 60px) calc(40% - 60px) 60px;
  }
}

.slider-container .slider-wrapper .slide-item.is-style-align-left .slide-content-inner > div {
  grid-column-start: 2;
}

@media (min-width: 834px) {
  .slider-container .slider-wrapper .slide-item.is-style-align-center .slide-content-inner {
    grid-template-columns: 60px auto 60px;
  }
}

.slider-container .slider-wrapper .slide-item.is-style-align-center .slide-content-inner > div {
  grid-column-start: 2;
}

@media (min-width: 834px) {
  .slider-container .slider-wrapper .slide-item.is-style-align-right .slide-content-inner {
    grid-template-columns: 60px calc(40% - 60px) calc(60% - 60px) 60px;
  }
}

.slider-container .slider-wrapper .slide-item.is-style-align-right .slide-content-inner > div {
  grid-column-start: 3;
}

/* ---- Content panel layout ----------------------------------------------
   A slide with no hero image: the overlay grid, its huge display type and
   its overflow clipping all step aside, and the inner blocks own the full
   width (Split Section is the intended tenant). */

.slider-container .slider-wrapper .slide-item--panel .slide-content {
  display: block;
}

.slider-container .slider-wrapper .slide-item--panel .slide-content-inner {
  display: block;
  height: auto;
  font-size: inherit;
}

.slider-container .slider-wrapper .slide-item--panel .slide-content-inner > div {
  padding: 0;
  overflow: visible;
}

/* ---- Slide navigation dots ---------------------------------------------
   Unlabelled: classic round dots. When any slide sets a label the whole
   bar switches to labelled pills (.slider-dots--labeled). */

.slider-dots {
  position: absolute;
  left: 50%;
  bottom: var(--cslr-controls-offset, 14px);
  transform: translateX(-50%);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  z-index: 2;
  max-width: calc(100% - 96px);
}

.slider-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1px solid var(--cslr-control-color);
  background: transparent;
  cursor: pointer;
  padding: 0;
}

.slider-dot.active {
  background: var(--cslr-accent, var(--cslr-accent-default));
  border-color: var(--cslr-accent, var(--cslr-accent-default));
}

.slider-dot:focus-visible {
  outline: 2px solid var(--cslr-accent, var(--cslr-accent-default));
  outline-offset: 3px;
}

.slider-dots--labeled .slider-dot {
  width: auto;
  height: auto;
  border-radius: 999px;
  padding: 0.3em 0.9em;
  font-size: 0.8125rem;
  line-height: 1.4;
  background: rgba(255, 255, 255, 0.85);
  border-color: rgba(0, 0, 0, 0.2);
  color: var(--cslr-control-color);
}

.slider-dots--labeled .slider-dot.active {
  background: var(--cslr-accent, var(--cslr-accent-default));
  border-color: var(--cslr-accent, var(--cslr-accent-default));
  color: #fff;
}

/* ---- Pause/play control ------------------------------------------------ */

.slider-playpause {
  position: absolute;
  right: 12px;
  bottom: var(--cslr-controls-offset, 14px);
  z-index: 2;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.2);
  background: rgba(255, 255, 255, 0.85);
  color: var(--cslr-control-color);
  cursor: pointer;
  padding: 0;
}

.slider-playpause svg {
  width: 12px;
  height: 12px;
  fill: currentColor;
}

.slider-playpause .cslr-icon-play {
  display: none;
}

.slider-playpause.is-stopped .cslr-icon-play {
  display: block;
}

.slider-playpause.is-stopped .cslr-icon-pause {
  display: none;
}

.slider-playpause:focus-visible {
  outline: 2px solid var(--cslr-accent, var(--cslr-accent-default));
  outline-offset: 3px;
}

/* ---- Dark mode -------------------------------------------------------
   The only dark rules in this plugin, and they exist solely to let a
   palette carry a dark ramp: --pal-action-dark is emitted as its own
   property, so an unmapped dark role is UNDEFINED and the chain below
   collapses to the same value the light rule resolves to. Both selectors
   are needed - the estate flips dark by OS preference AND by an explicit
   data-theme attribute, and the attribute must be able to force light. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .slider-container {
    --cslr-accent-default: var(--pal-action-dark, var(--pal-action, var(--bodysoul-action-book, #1E7A6B)));
  }
}

:root[data-theme="dark"] .slider-container {
  --cslr-accent-default: var(--pal-action-dark, var(--pal-action, var(--bodysoul-action-book, #1E7A6B)));
}
