/* ==========================================================================
   COMPONENT: Carousel — hand-built. No Swiper.
   CSS scroll-snap does the transport, so it swipes and keyboard-scrolls with
   zero JS. carousel.js adds ARIA, buttons, and dot sync as enhancement.
   ========================================================================== */

.c-carousel { display: grid; gap: var(--sp-5); }

.c-carousel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: var(--sp-4);
}

.c-carousel__viewport {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  /* Full-bleed track that still aligns to the content edge. */
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
  padding-block-end: var(--sp-2);
  overscroll-behavior-x: contain;
}

.c-carousel__viewport::-webkit-scrollbar { display: none; }

@media (prefers-reduced-motion: reduce) {
  .c-carousel__viewport { scroll-behavior: auto; }
}

.c-carousel__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(min(84vw, 22rem), 1fr);
  gap: var(--gap-col);
  align-items: stretch;
}

@media (min-width: 768px)  { .c-carousel__track { grid-auto-columns: minmax(20rem, 1fr); } }

/* A definite third, not minmax(0, a third). With 0 as the floor the five columns
   were free to shrink until they all fitted — at 1440px that produced five 249px
   cards, no overflow, and therefore a permanently disabled Next button and a
   carousel that did not carousel. A fixed track width overflows on purpose:
   three cards visible, the rest reachable. */
@media (min-width: 1180px) {
  .c-carousel__track { grid-auto-columns: calc((100% - var(--gap-col) * 2) / 3); }
}

.c-carousel__slide {
  scroll-snap-align: start;
  scroll-snap-stop: always;
  display: grid;
  min-width: 0;
}

/* --------------------------------------------------------------------------
   CONTROLS
   -------------------------------------------------------------------------- */

/* The controls overlay the slides rather than sitting in the head. In the head
   they were a row of two arrows above the track — on a phone, where the head is
   a column, that row read as furniture belonging to nothing, and it pushed the
   first card down by 62px. On the images they are where a thumb already is.

   --carousel-media-h is published by carousel.js from the first slide's media
   box, so the arrows land on the centre of the photograph at any card width. The
   50% fallback keeps them sane before the script runs and on any carousel whose
   slides have no media at all. */
/* min-width: 0 is load-bearing, not defensive. .c-carousel is a grid, so the
   stage is a grid item with min-width: auto — and its own min-content is the
   track's max-content, because the scroll container between them no longer sits
   directly in the grid. Without this the stage measured 1639px inside a 343px
   column and the whole document scrolled sideways. */
.c-carousel__stage {
  position: relative;
  min-width: 0;
}

.c-carousel__controls {
  position: absolute;
  inset-block-start: calc(var(--carousel-media-h, 50%) / 2);
  inset-inline: var(--sp-3);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  transform: translateY(-50%);
  /* The layer spans the track, so it must not intercept swipes — only the two
     buttons take pointer events. */
  pointer-events: none;
}

.c-carousel__controls > * { pointer-events: auto; }

.c-carousel__btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  /* Opaque white, not a hairline ring: over a photograph a transparent button
     with a --c-line-strong border is invisible against half the frames it can
     land on. */
  background-color: var(--c-white);
  border: 1px solid var(--c-line);
  border-radius: var(--r-full);
  color: var(--c-ink);
  box-shadow: var(--shadow-2);
  transition:
    background-color var(--d-fast) var(--e-out),
    color var(--d-fast) var(--e-out),
    transform var(--d-fast) var(--e-out),
    opacity var(--d-fast) var(--e-out);
}

@media (hover: hover) {
  .c-carousel__btn:hover:not(:disabled) {
    background-color: var(--c-ink);
    color: var(--c-text-inv);
    transform: scale(1.08);
  }
}

/* At the ends the button fades out of the way of the photograph instead of
   sitting on it as a grey disc. Still in the layout, still announced disabled. */
.c-carousel__btn:disabled {
  opacity: 0;
  pointer-events: none;
  cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
  .c-carousel__btn { transition: none; }
  .c-carousel__btn:hover:not(:disabled) { transform: none; }
}
.c-carousel__btn svg { width: 18px; height: 18px; }

.c-carousel__dots {
  display: flex;
  gap: var(--sp-2);
  align-items: center;
}

.c-carousel__dot {
  width: 8px;
  height: 8px;
  border-radius: var(--r-full);
  background-color: var(--c-line-strong);
  transition: background-color var(--d-fast) var(--e-out), width var(--d-base) var(--e-out);
}

.c-carousel__dot[aria-selected="true"] {
  width: 26px;
  background-color: var(--c-ink);
}

/* Dots are a real tablist; the hit area must still be 44px. */
.c-carousel__dot-hit {
  display: grid;
  place-items: center;
  width: 28px;
  height: 44px;
}

/* On an ink ground the button keeps its white fill — it is over a photograph
   either way — and only the hover inverts, so the ladder still goes somewhere. */
.is-inverted .c-carousel__btn:hover:not(:disabled) { background-color: var(--c-ink); color: var(--c-text-inv); }
.is-inverted .c-carousel__dot { background-color: rgb(255 255 255 / 0.3); }
.is-inverted .c-carousel__dot[aria-selected="true"] { background-color: var(--c-white); }
