/* ──────────────────────────────────────────────────────────────────────
 * UNIVERSAL CAROUSEL — single source of truth (react-slick backed)
 *
 * Used by `<UniversalCarousel/>` (src/components/elements/renderers/
 * UniversalCarousel.tsx). Every carousel widget on the platform
 * (availability-table, compound-section card carousels, image-carousel,
 * content-slider, logo-slider, etc.) renders via this single component
 * and consumes the same CSS. New carousel widgets must NOT hand-roll
 * track/slide/nav markup — call the component instead and theme it via
 * the CSS vars below.
 *
 * Slick base CSS (.slick-slider, .slick-list, .slick-track, .slick-slide)
 * is loaded by globals.css. This file only adds platform-level theming
 * and the mobile-snap contract.
 *
 * DOM (slick-rendered):
 *   .uc                    — wrapper from UniversalCarousel
 *     .slick-slider        — slick container
 *       .slick-list        — overflow viewport
 *         .slick-track     — flex track
 *           .slick-slide   — one slide (we add `.uc-slide`)
 *             > children
 *       .slick-prev / .slick-next  — arrow buttons (we add `.uc-nav`)
 *       .slick-dots        — dot indicator list (we add `.uc-dots`)
 *
 * CSS-var contract (set on `.uc` or any ancestor):
 *   --uc-cpv                 — desktop cards-per-view (default 3)
 *   --uc-gap                 — desktop inter-card gap (default 24px)
 *   --uc-arrow-size          — diameter of nav arrow (default 44px)
 *   --uc-arrow-radius        — border-radius of nav arrow (default 50%)
 *   --uc-arrow-bg            — bg color (default --site-accent)
 *   --uc-arrow-color         — icon color (default --site-accent-fg)
 *   --uc-arrow-shadow        — drop shadow (default subtle)
 * Legacy --carousel-arrow-* / --carousel-dot-* tokens (emitted by
 * buildCarouselStyleVars) are honored as fallbacks.
 *
 * Hover-shell contract (per slot — emitted by UniversalCarousel.tsx):
 *   [data-card-hover-shell]  — DOM attribute carried by every .uc-slide.
 *                              Marks the slot as the stable hover anchor
 *                              for descendant cards. See "Card hover shell
 *                              — framework contract" block below.
 *   --uc-slot-hovered        — 0 when the slot is not hovered, 1 when it
 *                              is. Descendant card CSS reads this var to
 *                              drive shake-free :hover lifts.
 *
 * Mobile contract (≤768px):
 *   - slick collapses to 1 slide per view (configured in JS responsive[])
 *   - inter-card gap = 0 (slick uses negative-margin track; padding zeroed)
 *   - arrows shrink + tuck inside frame
 * ────────────────────────────────────────────────────────────────────── */

/* ── Wrapper ─────────────────────────────────────────────────────────── */
.uc {
  position: relative;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
}
.uc .slick-slider {
  /* slick adds touch-action: pan-y; keep but make sure it inherits width. */
  width: 100%;
  max-width: 100%;
  min-width: 0;
}
.uc .slick-list {
  /* Card drop shadows are allowed to bleed past the .slick-list edges
   * generously — the off-screen-slide leak that would normally constrain
   * the clip margin is solved structurally by the
   * `.uc:not(.uc--marquee):not(.uc--fade) .slick-slide:not(.slick-active)
   *  { visibility: hidden }` rule below. Non-active slides take layout
   * space (so the track's translate3d math is unaffected) but paint
   * nothing — clip margin can be as large as needed without revealing
   * neighbor content.
   *
   * IMPORTANT: use the `overflow-clip-margin` SHORTHAND, not the
   * `overflow-clip-margin-block` / `-inline` logical-axis longhands.
   * The logical-axis longhands are CSS Overflow L4 and are not yet
   * implemented in Chromium (computed value comes back as "" — they're
   * silently ignored). The shorthand applies the same value to all
   * four physical sides which is exactly what we want here. */
  overflow: clip;
  overflow-clip-margin: 200px;
}
.uc .slick-track {
  display: flex;
  align-items: stretch;
  /* slick sets margin-left:0 and uses translate3d for positioning — leave
   * default, just ensure children stretch and lay out cleanly. */
}

/* ── Slide gutter via padding (engine has no native inter-slide gap) ─── */
.uc .slick-slide {
  height: auto;
  /* Engine-agnostic slide sizing: each slide is exactly 1/--uc-cpv of the
   * viewport. Embla (current engine) requires per-slide flex-basis in CSS;
   * the previous react-slick engine set it inline at mount. The flex-basis
   * value drives the cards-per-view math; padding-inline below paints the
   * visual gap between cards. */
  flex: 0 0 calc(100% / var(--uc-cpv, 1));
  min-width: 0;
  /* Pad each slide horizontally by half the desired gap. The container is
   * flush; padding inside each slide creates the visual gap between cards. */
  padding-inline: calc(var(--uc-gap, 24px) / 2);
  padding-block: 16px;
  box-sizing: border-box;
}
.uc .slick-slide > div {
  height: 100%;
}
.uc-slide {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  height: 100%;
  min-width: 0;
  width: 100%;
}
.uc-slide > * {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
}
/* slideAspectRatio — when set, every .uc-slide enforces a uniform aspect.
 * `free` (default) leaves --uc-slide-aspect unset and slides size to content. */
.uc[style*="--uc-slide-aspect"] .uc-slide {
  aspect-ratio: var(--uc-slide-aspect);
}
/* imageFit — applies to every <img>/<video> inside a slide. Default 'cover'. */
.uc-slide img,
.uc-slide video {
  object-fit: var(--uc-image-fit, cover);
}

/* ── Card hover shell — framework contract ─────────────────────────────
 *
 * Cards rendered inside a UniversalCarousel slot would shake on hover if
 * the lift transform were applied to the card itself: cursor at the
 * bottom edge → card lifts away → mouseleave fires → card drops →
 * mouseenter → loop. The slot ([data-card-hover-shell]) carries 16px of
 * block padding (see .uc .slick-slide above), so anchoring :hover on the
 * slot keeps the cursor inside the hover zone while the card translates
 * up.
 *
 * Cards opt in by being a descendant. The card's own CSS still owns the
 * lift declarations — this rule only re-broadcasts the slot's :hover
 * state via the shared --uc-slot-hovered flag, which card rules can
 * read instead of (or in addition to) the card's own :hover.
 * ────────────────────────────────────────────────────────────────────── */
[data-card-hover-shell] { --uc-slot-hovered: 0; }
[data-card-hover-shell]:hover { --uc-slot-hovered: 1; }

/* ── Off-screen slide hiding (shadow-leak fix) ───────────────────────────
 * Hides slides that are not currently in-viewport so the .slick-list can
 * use a large overflow-clip-margin (above) without revealing neighbor
 * cards. The slot still occupies layout (visibility: hidden, not display:
 * none), so the track's translate3d math and Embla's scroll-snap stay
 * exactly the same — only paint is suppressed.
 *
 * Embla's ClassNames plugin (UniversalCarousel.tsx, `inView: 'slick-active'`)
 * adds `.slick-active` the moment a slide enters the viewport and removes
 * it the moment the slide leaves, so entering slides paint smoothly with
 * the animation and exiting slides remain painted until they're fully
 * off-screen. No engine timing flicker.
 *
 * Excluded: marquee (every slide must paint as the track scrolls
 * continuously) and fade (slides are stacked and the inactive ones
 * still need to paint at opacity 0 during the cross-fade transition).
 * ────────────────────────────────────────────────────────────────────── */
.uc:not(.uc--marquee):not(.uc--fade) .slick-slide:not(.slick-active) {
  visibility: hidden;
}

/* Ensure track edge-to-edge alignment (cancel slide padding on outer edges
 * so the first/last card aligns with the section gutter). Use negative
 * margin on the track equal to half the gap. */
.uc .slick-list {
  margin-inline: calc(var(--uc-gap, 24px) / -2);
}

/* ── Navigation arrows ───────────────────────────────────────────────── */
.uc .uc-nav,
.uc .slick-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: var(--uc-arrow-size, 44px);
  height: var(--uc-arrow-size, 44px);
  border-radius: var(--uc-arrow-radius, 50%);
  border: none;
  /* Fall through to the legacy --carousel-arrow-* tokens emitted by
   * buildCarouselStyleVars so existing widget themes restyle the
   * universal carousel without per-renderer overrides. */
  background: var(--uc-arrow-bg, var(--carousel-arrow-bg, var(--site-accent, var(--site-primary))));
  color: var(--uc-arrow-color, var(--carousel-arrow-color, var(--site-accent-fg, var(--site-primary-fg, currentColor))));
  /* !important on display+align+justify because vendored slick-carousel.css
     declares `.slick-prev, .slick-next { display: block }` and ships in
     a way that beats this rule on cascade order on prod (the inner SVG
     icon renders flush-left at x=0 in the 44px button instead of centered
     at x=13). */
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  cursor: pointer;
  box-shadow: var(--uc-arrow-shadow, var(--carousel-arrow-shadow, 0 4px 16px rgba(0, 0, 0, 0.18)));
  transition: transform 160ms ease, filter 160ms ease, background-color 160ms ease, color 160ms ease, box-shadow 160ms ease;
  /* slick adds a font-size: 0 hack to hide its default chevron content; we
   * paint our own SVG icon child so reset font + line-height. */
  font-size: 0;
  line-height: 0;
  padding: 0;
}
.uc .slick-prev,
.uc .uc-nav--prev { left: 8px; }
.uc .slick-next,
.uc .uc-nav--next { right: 8px; }
/* slick's default ::before pseudo-element renders an arrow glyph — we
 * supply our own <CarouselArrowIcon/> child, so suppress slick's. */
.uc .slick-arrow::before {
  content: none !important;
}
.uc .slick-arrow.slick-disabled {
  opacity: 0.35;
  pointer-events: none;
}
.uc .uc-nav:hover,
.uc .slick-arrow:hover {
  filter: var(--uc-arrow-hover-filter, var(--carousel-arrow-hover-filter, brightness(1.12)));
  background: var(--uc-arrow-hover-bg, var(--carousel-arrow-hover-bg, var(--uc-arrow-bg, var(--carousel-arrow-bg, var(--site-accent, var(--site-primary))))));
  color: var(--uc-arrow-hover-color, var(--carousel-arrow-hover-color, var(--uc-arrow-color, var(--carousel-arrow-color, currentColor))));
  transform: translateY(-50%) scale(var(--uc-arrow-hover-scale, var(--carousel-arrow-hover-scale, 1.06)));
}
.uc .uc-nav:focus-visible,
.uc .slick-arrow:focus-visible {
  outline: 2px solid var(--site-accent, currentColor);
  outline-offset: 3px;
  box-shadow:
    var(--uc-arrow-shadow, var(--carousel-arrow-shadow, 0 4px 16px rgba(0, 0, 0, 0.18))),
    0 0 0 4px color-mix(in srgb, var(--site-accent, currentColor) 22%, transparent);
}
.uc .uc-nav--primary {
  background: var(--site-btn-primary-bg, var(--site-primary, currentColor));
  color: var(--site-btn-primary-text, var(--site-primary-fg, currentColor));
  border: 1px solid var(--site-btn-primary-bg, var(--site-primary, currentColor));
}
.uc .uc-nav--primary:hover {
  background: var(--site-btn-primary-hover-bg, var(--site-primary, currentColor));
  color: var(--site-btn-primary-hover-text, var(--site-primary-fg, currentColor));
  border-color: var(--site-btn-primary-hover-bg, var(--site-primary, currentColor));
  filter: none;
}
.uc .uc-nav--secondary {
  background: var(--site-btn-outline-bg, color-mix(in srgb, currentColor 10%, transparent));
  backdrop-filter: blur(10px) saturate(1.4);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
  color: var(--site-btn-outline-text, var(--site-primary, currentColor));
  border: 1px solid var(--site-btn-outline-border, color-mix(in srgb, currentColor 25%, transparent));
  box-shadow: none;
}
.uc .uc-nav--secondary:hover {
  background: var(--site-btn-outline-hover-bg, color-mix(in srgb, currentColor 18%, transparent));
  color: var(--site-btn-outline-hover-text, var(--site-primary-fg, currentColor));
  border-color: var(--site-btn-outline-border, color-mix(in srgb, currentColor 40%, transparent));
  filter: none;
}

/* ── Dots ────────────────────────────────────────────────────────────── */
.uc .slick-dots,
.uc .uc-dots {
  display: flex !important;
  justify-content: center;
  align-items: center;
  gap: var(--carousel-dot-gap, 8px);
  list-style: none;
  margin: 16px 0 0 0;
  padding: 0;
  position: static;
  bottom: auto;
  width: 100%;
}
.uc .slick-dots li,
.uc .uc-dots li {
  width: auto;
  height: auto;
  margin: 0;
  padding: 0;
}
.uc .slick-dots li button,
.uc .uc-dots li button.uc-dot {
  width: var(--carousel-dot-size, 10px);
  height: var(--carousel-dot-size, 10px);
  border-radius: 999px;
  border: none;
  padding: 0;
  background: var(--carousel-dot-color, color-mix(in srgb, currentColor 35%, transparent));
  cursor: pointer;
  transition: width 160ms ease, background-color 160ms ease, transform 160ms ease;
}
.uc .slick-dots li button::before,
.uc .uc-dots li button::before {
  content: none !important;
}
.uc .slick-dots li.slick-active button,
.uc .uc-dots li.slick-active button.uc-dot {
  width: var(--carousel-dot-active-width, var(--carousel-dot-size, 10px));
  background: var(--carousel-dot-active-color, var(--site-accent, currentColor));
}

/* ── Marquee mode (logo-slider) ──────────────────────────────────────── */
.uc--marquee .slick-list {
  overflow: hidden;
}
.uc--marquee .slick-track {
  /* No transition flicker between loops — handled by slick + linear ease. */
  display: flex;
}
.uc--marquee .slick-slide {
  /* Tighter padding for marquees — logos sit closer together. */
  padding-block: 8px;
  /* Marquee slides take their natural width (logo) instead of 1/cpv of the
   * viewport — overrides the universal flex-basis contract above so the
   * AutoScroll engine has a meaningfully-wider track than the viewport. */
  flex: 0 0 auto;
}

/* ── Mobile snap contract ────────────────────────────────────────────── *
 * At ≤768px every paged carousel collapses to exactly one card per frame,
 * no neighbour peek. The JS engine (UniversalCarousel) sets --uc-cpv via
 * matchMedia after hydration, but the CSS layer below pins the slide width
 * to 100% IMMEDIATELY at this breakpoint so the SSR / pre-hydration paint
 * does not flash a desktop-cpv layout to the user. Without this rule, slow
 * phones briefly show 2–3 squished cards before matchMedia resolves; users
 * have screenshots of the broken state.
 * ──────────────────────────────────────────────────────────────────── */
@container site style(--site-bp: mobile) {
  .uc--paged .slick-slide {
    /* Force 1 card per frame regardless of --uc-cpv (which the JS sets to 1
     * post-hydration anyway — this is the SSR safety net). Marquee + vertical
     * variants keep their natural / column flex via the !important overrides
     * elsewhere. */
    flex: 0 0 100% !important;
  }
  .uc .slick-slide {
    padding-inline: 0 !important;
  }
  .uc .slick-list {
    margin-inline: 0 !important;
    /* Mobile shows 1 card per view with zero slide-padding, so neighbor
     * cards sit right at the boundary. Drop the desktop bleed back to a
     * tight value just for shadow softness — keep it small so the next
     * page's card content doesn't peek during a swipe. */
    overflow-clip-margin: 8px !important;
  }
  .uc .uc-nav,
  .uc .slick-arrow {
    /* WCAG 2.5.5 / Apple HIG floor — 44x44. Smaller arrows are
       hard to hit on touch. */
    width: 44px;
    height: 44px;
  }
  .uc .slick-prev,
  .uc .uc-nav--prev { left: 4px; }
  .uc .slick-next,
  .uc .uc-nav--next { right: 4px; }
}
@media (max-width: 768px) {
  .uc--paged .slick-slide {
    /* Force 1 card per frame regardless of --uc-cpv (which the JS sets to 1
     * post-hydration anyway — this is the SSR safety net). Marquee + vertical
     * variants keep their natural / column flex via the !important overrides
     * elsewhere. */
    flex: 0 0 100% !important;
  }
  .uc .slick-slide {
    padding-inline: 0 !important;
  }
  .uc .slick-list {
    margin-inline: 0 !important;
    /* Mobile shows 1 card per view with zero slide-padding, so neighbor
     * cards sit right at the boundary. Drop the desktop bleed back to a
     * tight value just for shadow softness — keep it small so the next
     * page's card content doesn't peek during a swipe. */
    overflow-clip-margin: 8px !important;
  }
  .uc .uc-nav,
  .uc .slick-arrow {
    /* WCAG 2.5.5 / Apple HIG floor — 44x44. Smaller arrows are
       hard to hit on touch. */
    width: 44px;
    height: 44px;
  }
  .uc .slick-prev,
  .uc .uc-nav--prev { left: 4px; }
  .uc .slick-next,
  .uc .uc-nav--next { right: 4px; }
}

/* Legacy non-slick carousels still in the codebase (native scroll-snap
 * viewports for feature-cards / testimonials) keep their mobile rules. */
@container site style(--site-bp: mobile) {
  .el-feature-cards__viewport,
  .el-testimonials__viewport {
    --fcpv: 1;
    --tcpv: 1;
    gap: 0 !important;
    padding-inline: 0 !important;
    scroll-padding-inline: 0 !important;
    /* Use the shorthand — `overflow-clip-margin-inline` is silently
     * ignored by Chromium (CSS Overflow L4 logical-axis longhands
     * aren't implemented). */
    overflow-clip-margin: 0 !important;
    scroll-snap-type: x mandatory !important;
  }
  .el-feature-cards__viewport > .el-feature-cards__card,
  .el-feature-cards__viewport > a.el-feature-cards__card,
  .el-testimonials__viewport > .el-testimonials__card {
    flex-basis: 100% !important;
  }
}
@media (max-width: 768px) {
  .el-feature-cards__viewport,
  .el-testimonials__viewport {
    --fcpv: 1;
    --tcpv: 1;
    gap: 0 !important;
    padding-inline: 0 !important;
    scroll-padding-inline: 0 !important;
    /* Use the shorthand — `overflow-clip-margin-inline` is silently
     * ignored by Chromium (CSS Overflow L4 logical-axis longhands
     * aren't implemented). */
    overflow-clip-margin: 0 !important;
    scroll-snap-type: x mandatory !important;
  }
  .el-feature-cards__viewport > .el-feature-cards__card,
  .el-feature-cards__viewport > a.el-feature-cards__card,
  .el-testimonials__viewport > .el-testimonials__card {
    flex-basis: 100% !important;
  }
}

/* ──────────────────────────────────────────────────────────────────────
 * UNIVERSAL CARD EQUAL-HEIGHT CONTRACT
 *
 * Every card-bearing parent (grids + carousel viewports) shares a single
 * equal-height rule so cards in the same row line up at every breakpoint.
 * Two pieces:
 *   1. Parent: grid containers use `grid-auto-rows: 1fr` + `align-items:
 *      stretch`; carousel viewports use `align-items: stretch` directly.
 *   2. Card: every direct child is `display: flex; flex-direction: column;
 *      height: 100%; min-width: 0` so the card fills its slot.
 * ─────────────────────────────────────────────────────────────────────── */
.el-avail-table__grid,
.el-avail-table__fp-grid,
.el-feature-cards__grid,
.el-pricing-card__grid,
.el-rating__grid,
.el-services__grid,
.el-stats__grid,
.el-team__grid,
.el-testimonials__grid {
  display: grid;
  grid-auto-rows: 1fr;
  align-items: stretch;
  justify-items: stretch;
}

.uc .slick-track,
.el-feature-cards__viewport,
.el-testimonials__viewport {
  align-items: stretch;
}

.el-avail-table__grid > *,
.el-avail-table__fp-grid > *,
.el-feature-cards__grid > *,
.el-pricing-card__grid > *,
.el-rating__grid > *,
.el-services__grid > *,
.el-stats__grid > *,
.el-team__grid > *,
.el-testimonials__grid > *,
.uc .slick-slide > div,
.el-feature-cards__viewport > .el-feature-cards__card,
.el-testimonials__viewport > .el-testimonials__card {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-width: 0;
  width: 100%;
}

@container site style(--site-bp: mobile) {
  .el-avail-table__grid,
  .el-avail-table__fp-grid,
  .el-feature-cards__grid,
  .el-pricing-card__grid,
  .el-rating__grid,
  .el-services__grid,
  .el-stats__grid,
  .el-team__grid,
  .el-testimonials__grid {
    grid-auto-rows: 1fr;
    align-items: stretch;
  }
}
@media (max-width: 768px) {
  .el-avail-table__grid,
  .el-avail-table__fp-grid,
  .el-feature-cards__grid,
  .el-pricing-card__grid,
  .el-rating__grid,
  .el-services__grid,
  .el-stats__grid,
  .el-team__grid,
  .el-testimonials__grid {
    grid-auto-rows: 1fr;
    align-items: stretch;
  }
}

/* ── Pause/Play button ─────────────────────────────────────────────────── *
 * Bottom-right corner toggle. Non-decorative — only renders when autoplay
 * is on. Theme follows --carousel-arrow-* tokens for visual cohesion.
 * ──────────────────────────────────────────────────────────────────────── */
.uc-pauseplay {
  position: absolute;
  bottom: 16px;
  right: 16px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.55);
  color: white;
  cursor: pointer;
  z-index: 3;
  padding: 0;
  transition: background-color 160ms ease, transform 160ms ease, border-color 160ms ease;
}
.uc-pauseplay:hover {
  background: rgba(0, 0, 0, 0.75);
  transform: scale(1.05);
  border-color: color-mix(in srgb, currentColor 45%, transparent);
}
.uc-pauseplay:focus-visible {
  outline: 2px solid color-mix(in srgb, currentColor 80%, white 20%);
  outline-offset: 3px;
}
.uc-pauseplay svg {
  width: 14px;
  height: 14px;
}

/* ── Progress bar ──────────────────────────────────────────────────────── *
 * Thin bar at the bottom of the carousel. Width animates 0%→100% over the
 * autoplay interval (read from --uc-interval CSS var). React resets the
 * animation on each slide change via key={currentSlide}.
 * ──────────────────────────────────────────────────────────────────────── */
.uc-progress {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: rgba(255, 255, 255, 0.15);
  z-index: 3;
  overflow: hidden;
  pointer-events: none;
}
.uc-progress__bar {
  height: 100%;
  width: 0%;
  background: var(--carousel-dot-active-color, var(--site-accent, currentColor));
  animation: uc-progress-fill var(--uc-interval, 5000ms) linear forwards;
}
@keyframes uc-progress-fill {
  from { width: 0%; }
  to   { width: 100%; }
}

/* ── Slide counter ─────────────────────────────────────────────────────── *
 * "{n} / {total}" pill. Position controlled via modifier classes.
 * ──────────────────────────────────────────────────────────────────────── */
.uc-counter {
  position: absolute;
  padding: 6px 12px;
  background: rgba(0, 0, 0, 0.55);
  color: white;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.02em;
  z-index: 3;
  pointer-events: none;
  white-space: nowrap;
}
.uc-counter--bottom-right { bottom: 16px; right: 16px; }
.uc-counter--bottom-left  { bottom: 16px; left: 16px; }
.uc-counter--top-right    { top: 16px; right: 16px; }
.uc-counter--top-left     { top: 16px; left: 16px; }

/* ── Dot shapes ────────────────────────────────────────────────────────── *
 * Modifier class on .uc-dots controls the shape of every dot button. The
 * default 'circle' shape is already set by the generic .uc-dots rule above.
 * ──────────────────────────────────────────────────────────────────────── */
.uc-dots--dash li button.uc-dot {
  width: 24px;
  height: 4px;
  border-radius: 2px;
}
.uc-dots--dash li.slick-active button.uc-dot {
  width: 32px;
}
.uc-dots--square li button.uc-dot {
  border-radius: 2px;
}
.uc-dots--number li button.uc-dot {
  width: auto;
  min-width: 24px;
  padding: 0 8px;
  height: 24px;
  border-radius: 12px;
  font-size: 12px;
  font-weight: 600;
  line-height: 22px;
  color: var(--carousel-dot-color, color-mix(in srgb, currentColor 65%, transparent));
  background: transparent;
  border: 1px solid var(--carousel-dot-color, color-mix(in srgb, currentColor 35%, transparent));
}
.uc-dots--number li.slick-active button.uc-dot {
  width: auto;
  background: var(--carousel-dot-active-color, var(--site-accent, currentColor));
  color: var(--site-accent-fg, var(--site-primary-fg, white));
  border-color: var(--carousel-dot-active-color, var(--site-accent, currentColor));
}

/* ── Thumbnail strip ───────────────────────────────────────────────────── *
 * Grid of small thumbnail buttons rendered below the carousel. Clicks call
 * slickGoTo(i). Active thumb gets full opacity + accent border.
 * ──────────────────────────────────────────────────────────────────────── */
.uc-thumbnails {
  display: flex;
  gap: 8px;
  justify-content: center;
  padding: 16px 0 0;
  flex-wrap: wrap;
}
.uc-thumb {
  width: 60px;
  height: 40px;
  border-radius: 4px;
  overflow: hidden;
  opacity: 0.5;
  transition: opacity 160ms ease, border-color 160ms ease, transform 160ms ease;
  cursor: pointer;
  border: 2px solid transparent;
  background: rgba(255, 255, 255, 0.05);
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.uc-thumb:hover {
  opacity: 0.85;
}
.uc-thumb:focus-visible {
  outline: 2px solid color-mix(in srgb, currentColor 80%, white 20%);
  outline-offset: 2px;
}
.uc-thumb--active {
  opacity: 1;
  border-color: var(--site-accent, currentColor);
}
.uc-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.uc-thumb__placeholder {
  font-size: 12px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.7);
}

/* ── Vertical orientation ──────────────────────────────────────────────── *
 * Slick handles most internals via vertical:true; we re-orient the arrows
 * so they sit top/bottom instead of left/right, and zero the negative
 * track margin which was tuned for horizontal layouts.
 * ──────────────────────────────────────────────────────────────────────── */
.uc--vertical .slick-list {
  margin-inline: 0;
}
.uc--vertical .slick-track {
  /* Embla in axis: 'y' mode requires the container to be a column flex.
   * react-slick produced this implicitly; we set it explicitly. */
  flex-direction: column;
}
.uc--vertical .slick-slide {
  padding-inline: 0;
  padding-block: calc(var(--uc-gap, 24px) / 2);
  /* In vertical mode the size axis flips: each slide is 1/cpv of the
   * container HEIGHT, not width. Use auto so the slide takes its natural
   * content height — the container scrolls on the y-axis. */
  flex: 0 0 auto;
  width: 100%;
}
.uc--vertical .slick-prev,
.uc--vertical .uc-nav--prev {
  top: 8px;
  left: 50%;
  bottom: auto;
  right: auto;
  transform: translate(-50%, 0) rotate(90deg);
}
.uc--vertical .slick-next,
.uc--vertical .uc-nav--next {
  bottom: 8px;
  top: auto;
  left: 50%;
  right: auto;
  transform: translate(-50%, 0) rotate(90deg);
}
.uc--vertical .uc-nav:hover,
.uc--vertical .slick-arrow:hover {
  transform: translate(-50%, 0) rotate(90deg) scale(var(--uc-arrow-hover-scale, 1.06));
}

/* ── RTL ───────────────────────────────────────────────────────────────── *
 * Slick handles direction via rtl:true. We just need to mirror the arrow
 * icon glyph orientation when rtl is active so prev/next arrows still
 * point in the visually-correct direction.
 * ──────────────────────────────────────────────────────────────────────── */
.uc--rtl .uc-nav svg,
.uc--rtl .slick-arrow svg {
  transform: scaleX(-1);
}
