/*
Carousel

<div class="carousel" role="region" aria-roledescription="carousel" data-orientation>
  <button class="carousel-rotation">                 autoplay only; first tab stop (APG)
  <div class="carousel-viewport">                    the viewport: clips
    <div class="carousel-container" aria-live>      the track: a flex row
      <div class="carousel-item" role="group" aria-roledescription="slide">
  <button class="carousel-previous" data-carousel-prev>
  <button class="carousel-next" data-carousel-next>
  <div class="carousel-dots" role="group">          dots only
    <button class="carousel-dot" data-state>

Slides size with flex-basis (class on CarouselItem, or --carousel-item-size)
and space with --carousel-gap. The engine moves the track with transform,
so nothing around the carousel ever moves.
*/

@layer components {

.carousel {
  position:  relative;
}

.carousel-viewport {
  overflow: hidden;
  border-radius: inherit;
}

.carousel-container {
  display:             flex;
  margin-inline-start: calc(-1 * var(--carousel-gap));
  touch-action:        pan-y pinch-zoom;
  backface-visibility: hidden;
}

.carousel[data-orientation="vertical"] .carousel-container {
  flex-direction:      column;
  height:              100%;
  margin-inline-start: 0;
  margin-top:          calc(-1 * var(--carousel-gap));
  touch-action:        pan-x pinch-zoom;
}

.carousel-item {
  flex:                 0 0 var(--carousel-item-size, 100%);
  min-width:            0;
  min-height:           0;
  padding-inline-start: var(--carousel-gap);
  transform:            translate3d(0, 0, 0);
}

.carousel[data-orientation="vertical"] .carousel-item {
  padding-inline-start: 0;
  padding-top:          var(--carousel-gap);
}

/* PREVIOUS / NEXT -------------------------------------------------------
   Outside the track by --space-3 whatever the button's size: the inset puts
   the button's inner edge there and translate moves it out by its own size. */

.carousel > .carousel-previous.button,
.carousel > .carousel-next.button {
  position:      absolute;
  border-radius: var(--radius-pill);
  top:           50%;
}

.carousel > .carousel-previous.button {
  inset-inline-start: calc(-1 * var(--space-3));
  translate:          -100% -50%;
}

.carousel > .carousel-next.button {
  inset-inline-end: calc(-1 * var(--space-3));
  translate:        100% -50%;
}

.carousel:dir(rtl) > .carousel-previous.button {
  translate: 100% -50%;
}

.carousel:dir(rtl) > .carousel-next.button {
  translate: -100% -50%;
}

.carousel[data-orientation="vertical"] > .carousel-previous.button,
.carousel[data-orientation="vertical"] > .carousel-next.button {
  inset-inline-start: 50%;
  inset-inline-end:   auto;
}

.carousel[data-orientation="vertical"] > .carousel-previous.button {
  top:       calc(-1 * var(--space-3));
  translate: -50% -100%;
}

.carousel[data-orientation="vertical"] > .carousel-next.button {
  top:       auto;
  bottom:    calc(-1 * var(--space-3));
  translate: -50% 100%;
}

.carousel[data-orientation="vertical"]:dir(rtl) > .carousel-previous.button {
  translate: 50% -100%;
}

.carousel[data-orientation="vertical"]:dir(rtl) > .carousel-next.button {
  translate: 50% 100%;
}

.carousel[data-orientation="vertical"] > .carousel-previous .icon,
.carousel[data-orientation="vertical"] > .carousel-next .icon {
  rotate: 90deg;
}

/* :dir() follows the nearest dir, so dir="ltr" inside an rtl page stays ltr. */
.carousel:dir(rtl) .carousel-previous .icon,
.carousel:dir(rtl) .carousel-next .icon {
  scale: -1 1;
}

.carousel-previous.button:disabled,
.carousel-next.button:disabled,
.carousel-previous.button[aria-disabled="true"],
.carousel-next.button[aria-disabled="true"] {
  opacity: var(--opacity-disabled);
}

/* Phone: outside the track there is no room; sit over its edges. */
@media (max-width: 40rem) {
  .carousel[data-orientation="horizontal"] > .carousel-previous.button {
    inset-inline-start: var(--space-2);
  }

  .carousel[data-orientation="horizontal"] > .carousel-next.button {
    inset-inline-end: var(--space-2);
  }

  .carousel[data-orientation="horizontal"] > .carousel-previous.button,
  .carousel[data-orientation="horizontal"] > .carousel-next.button {
    translate:  0 -50%;
    background: var(--bg-elevated);
  }
}

/* Rotation Control */

.carousel > .carousel-rotation.button {
  position:           absolute;
  top:                var(--space-2);
  inset-inline-start: var(--space-2);
  z-index:            1;
  border-radius:      var(--radius-pill);
}

/* Play and pause share one cell; only the current one shows. */
.carousel-swap {
  display: inline-grid;
}

.carousel-swap > * {
  grid-area: 1 / 1;
  display:   inline-grid;
}

.carousel-swap[data-state="off"] > .swap-on,
.carousel-swap[data-state="on"] > .swap-off {
  visibility: hidden;
}

/* Pickers */

.carousel-dots {
  display:         flex;
  justify-content: center;
  flex-wrap:       wrap;
  padding-top:     var(--space-2);
}

.carousel-dot {
  display:       inline-grid;
  place-items:   center;
  width:         var(--control-height-sm);
  height:        var(--control-height-sm);
  padding:       0;
  border:        0;
  background:    none;
  border-radius: var(--radius-pill);
  cursor:        pointer;
}

.carousel-dot::before {
  content:       "";
  width:         var(--space-2);
  height:        var(--space-2);
  border-radius: var(--radius-pill);
  background:    var(--rule-strong);
  transition:    background-color var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out);
}

.carousel-dot:hover::before {
  background: var(--ink-dim);
}

.carousel-dot[data-state="active"]::before {
  background: var(--accent);
  transform:  scale(1.25);
}

.carousel-dot[aria-disabled="true"] {
  cursor: default;
}

.carousel-dot:focus-visible {
  outline:    none;
  box-shadow: var(--focus-ring);
}

/* AUTO HEIGHT plugin: slides keep their own height and the track takes the
   selected one's. */

.carousel-container[data-auto-height] {
  align-items: flex-start;
  transition:  height var(--duration-normal) var(--ease-out);
}

}
