/* ==========================================================================
   Arc carousel 1.0 — a picture carousel laid out on a giant wheel
   --------------------------------------------------------------------------
   Plain CSS. No framework, no build step, no external request.

   The component enhances a native radio group. Every card is the <label> of an
   <input type="radio">, so before the script runs — or if it never runs — the
   wheel still turns: clicking a card selects it, the arrow keys walk through
   the group, and the whole layout follows because one single custom property,
   --wcar-index, drives the geometry. The script only adds what CSS cannot do
   on its own: dragging, the wheel of the mouse, and the two arrow buttons.

   --wcar-index is registered with @property, so it interpolates. Transitioning
   that ONE number rotates the wheel, rescales the front card, fades the others
   and reorders the stack — all in step, because they are all derived from it.

   PROPORTIONS
   Every metric is expressed in em and derives from --wcar-font-size, the body
   copy of the component (15 px on the reference). The ratios come from the
   published original, measured in the browser at five widths — see README.md,
   "Provenance" and the table of ratios:

     body copy        1                (the reference unit)
     title            2.6667 em        Lora, 1.2 line height
     card width       clamp(9.6267em, 18.24cqw, 14.1867em)
     card height      1.25 x its width (portrait)
     card radius      1.2 em
     arc radius       clamp(14.6667em, 72cqw, 48em)
     arc top padding  17.0667 em       (from the top edge to the top of the arc)
     active card      x 1.2, lifted 1.2 em; the others x 0.86 at 0.66 opacity
     text block       52 em wide at most, 0.8667 em between its lines
     dots             0.4 em, 1.2 em once active, 0.5334 em apart

   So changing --wcar-font-size rescales the whole component — drawing
   included, not only the text — and nothing else needs to be touched. The two
   clamp() bounds are em, the middle term is cqw: the arc keeps following the
   width of its container, exactly like the original.

   Order of this file:
     1. Face declarations
     2. Registered properties
     3. Design tokens
     4. Scene and halo
     5. Index: which card is at the top
     6. Placement: angle, distance, falloff
     7. Cards
     8. Caption: headline, arrows, body copy, call to action
     9. Dots
    10. Probe
    11. Narrow containers
    12. Fallbacks: reduced motion, forced colours, no :has()

   Naming follows BEM: .arc-carousel, .arc-carousel__part,
   .arc-carousel--variant.
   ========================================================================== */

/* ==========================================================================
   1. Face declarations
   --------------------------------------------------------------------------
   Three files, all local, latin subset only — enough for French and English.
   Inter carries the body copy and the button, Lora the titles. Both are under
   the SIL Open Font License; see README.md, "Credits".
   ========================================================================== */

@font-face {
  font-family: "Arc carousel Inter";
  src: url("inter-500-latin.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Arc carousel Inter";
  src: url("inter-600-latin.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Arc carousel Lora";
  src: url("lora-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   2. Registered properties
   --------------------------------------------------------------------------
   --wcar-index is the position of the wheel, counted in cards: 0 puts the
   first card at the top, 4.5 stops halfway between the fifth and the sixth.
   It has to be registered, otherwise the browser treats it as a string and
   the transition jumps instead of turning.

   Everything else is derived from it at use time, so registering this one
   number is enough to animate the whole wheel.
   ========================================================================== */

@property --wcar-index {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

/* ==========================================================================
   3. Design tokens
   ========================================================================== */

.arc-carousel {
  /* — Type ------------------------------------------------------------ */
  --wcar-font-size: 15px;
  --wcar-font-body: "Arc carousel Inter", ui-sans-serif, system-ui, sans-serif;
  --wcar-font-title: "Arc carousel Lora", ui-serif, Georgia, serif;
  --wcar-title-size: 2.6667em;
  --wcar-title-weight: 400;
  --wcar-title-leading: 1.2;
  --wcar-title-tracking: -0.01em;
  --wcar-body-weight: 500;
  --wcar-body-leading: 1.3;
  --wcar-body-tracking: -0.01em;

  /* — Colours --------------------------------------------------------- */
  --wcar-bg: #ffffff;
  --wcar-title-color: #000000;
  /* The original ships #cccccc here: 1.6:1 against white, unreadable. The
     value below keeps the same quiet grey at 5.4:1. Put #cccccc back to get
     the original exactly. */
  --wcar-body-color: #6a6a6a;
  --wcar-cta-bg: #000000;
  --wcar-cta-color: #ffffff;
  --wcar-card-bg: #f5f5f5;
  --wcar-focus-color: #000000;
  --wcar-dot-color: 0 0 0;
  --wcar-dot-alpha: 0.18;
  --wcar-dot-alpha-on: 0.55;

  /* The original writes an invalid box-shadow — "0px 10px 30px undefinedpx
     rgba(0,0,0,0.12)" — so no shadow is painted at all. Set this to `none` to
     reproduce that. */
  --wcar-card-shadow: 0 0.6667em 2em rgb(0 0 0 / 0.12);
  --wcar-card-veil: linear-gradient(
    to top,
    rgb(0 0 0 / 0.28) 0%,
    rgb(0 0 0 / 0.12) 40%,
    rgb(0 0 0 / 0) 70%
  );
  --wcar-halo: radial-gradient(
    60em 33.3334em at 50% 0%,
    rgb(0 0 0 / 0.06),
    rgb(0 0 0 / 0) 60%
  );

  /* — The wheel ------------------------------------------------------- */
  /* Angles are plain numbers, turned into degrees only where they rotate
     something: a number divides and compares, an angle does not. */
  --wcar-span: 245; /* degrees covered by the whole set of cards */
  --wcar-spacing: -3.5; /* degrees added between two neighbours */
  --wcar-tilt: 0; /* degrees the whole arc is rolled by */
  --wcar-radius: clamp(14.6667em, 72cqw, 48em);
  --wcar-arc-top: 17.0667em;
  --wcar-card-width: clamp(9.6267em, 18.24cqw, 14.1867em);
  --wcar-card-ratio: 1.25; /* portrait: height = ratio x width */
  --wcar-card-radius: 1.2em;

  /* — What being at the top does to a card ---------------------------- */
  --wcar-scale-on: 1.2;
  --wcar-scale-off: 0.86;
  --wcar-opacity-off: 0.66;
  --wcar-lift: 1.2em;
  /* Half-widths of the three falloffs, in degrees: past that angle a card is
     fully "away". They differ on purpose — the lift dies out before the
     scaling, which dies out before the fading. */
  --wcar-falloff-scale: 60;
  --wcar-falloff-opacity: 80;
  --wcar-falloff-lift: 55;

  /* — The text block -------------------------------------------------- */
  --wcar-content-max: 52em;
  --wcar-content-lift: 3.2em;
  --wcar-content-offset: -9.6em;
  --wcar-content-bump: 0em; /* narrow containers push the block down */
  --wcar-content-pad: clamp(1.0667em, 6cqw, 3.2em);
  --wcar-gap: 0.8667em;
  --wcar-headline-gap: 0.8em;
  --wcar-arrow-size: 2.8em;
  --wcar-arrow-icon: 1.7334em;
  --wcar-arrow-shrink: 0;
  /* The button sets a font-size of its own, and an em inside a custom property
     is resolved by whoever reads it — written in em, this padding would come
     out 7 % short. Anything a smaller or larger box consumes is therefore
     spelled out against the module. */
  --wcar-cta-pad: calc(0.8 * var(--wcar-font-size)) calc(1.0667 * var(--wcar-font-size));
  --wcar-cta-gap: calc(0.5334 * var(--wcar-font-size));
  --wcar-focus-width: calc(0.1334 * var(--wcar-font-size));
  --wcar-focus-offset: calc(0.1334 * var(--wcar-font-size));

  /* — Dots ------------------------------------------------------------ */
  --wcar-dot-size: 0.4em;
  --wcar-dot-size-on: 1.2em;
  --wcar-dot-gap: 0.5334em;
  --wcar-dots-bottom: 1.2em;
  --wcar-dots-opacity: 0.7;

  /* — Motion ---------------------------------------------------------- */
  /* The original animates the rotation with a spring (stiffness 430, damping
     52, mass 1). Its damping ratio is 1.25, so it never overshoots: the curve
     below is that spring, sampled every 20 ms over the 500 ms Motion actually
     runs it. Both values are knobs — no need to open the script to retune the
     movement. */
  --wcar-duration: 500ms;
  --wcar-ease: linear(
    0, 0.06222, 0.18389, 0.31376, 0.43282, 0.53552, 0.6216, 0.69273, 0.75108,
    0.79876, 0.83764, 0.86932, 0.8951, 0.91609, 0.93317, 0.94706, 0.95837,
    0.96756, 0.97505, 0.98113, 0.98609, 0.99012, 0.9934, 0.99606, 0.99823, 1
  );
  /* How long the wheel waits, after the last notch of the mouse wheel, before
     it settles on a card. Read by the script off the probe. */
  --wcar-wheel-settle: 140ms;
  --wcar-fade-duration: 220ms;
  --wcar-fade-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --wcar-dot-duration: 180ms;

  /* — Grip ------------------------------------------------------------ */
  /* The wheel is grabbable everywhere, so it says so. `pointer` restores the
     original, which only showed a hand over the cards — and only ever dragged
     from the background. */
  --wcar-cursor: grab;
  --wcar-cursor-held: grabbing;
  /* How far the pointer travels before a press stops being a click. */
  --wcar-drag-threshold: 5px;

  /* — Frame ----------------------------------------------------------- */
  --wcar-height: 100svh;
}

/* ==========================================================================
   4. Scene and halo
   ========================================================================== */

/* The component brings its own box model: it must not depend on a reset that
   the host page may or may not have. */
.arc-carousel,
.arc-carousel *,
.arc-carousel *::before,
.arc-carousel *::after {
  box-sizing: border-box;
}

.arc-carousel {
  position: relative;
  width: 100%;
  height: var(--wcar-height);
  /* clip rather than hidden: half the wheel is outside the frame by design,
     and `hidden` keeps a scrollable box around it — one that the browser
     would happily scroll to reveal a card that has just taken focus, dragging
     the whole layout sideways. `clip` cannot scroll at all. */
  overflow: hidden;
  overflow: clip;
  background: var(--wcar-bg);
  font-family: var(--wcar-font-body);
  font-size: var(--wcar-font-size);
  /* The arc reads the width of the component, and the text block reads its
     height, so the component has to be a size container. */
  container: arc-carousel / size;
  touch-action: pan-y;
}

/* One layer holding everything, so that a single :has() on it can hand the
   selected index to the cards, to the caption and to the dots at once. */
.arc-carousel__stage {
  position: absolute;
  inset: 0;
  cursor: var(--wcar-cursor);
  transition: --wcar-index var(--wcar-duration) var(--wcar-ease);
}

/* While a finger or the mouse is holding the wheel, the position is set frame
   by frame: any transition here would lag one behind. */
.arc-carousel[data-wcar-dragging] .arc-carousel__stage {
  transition: none;
}

/* And the whole component follows the hand: the cursor closes, and nothing
   gets selected on the way. */
.arc-carousel[data-wcar-dragging],
.arc-carousel[data-wcar-dragging] .arc-carousel__stage,
.arc-carousel[data-wcar-dragging] .arc-carousel__card {
  cursor: var(--wcar-cursor-held);
  user-select: none;
}

.arc-carousel__halo {
  position: absolute;
  inset: 0;
  background-image: var(--wcar-halo);
  pointer-events: none;
}

.arc-carousel__track {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* ==========================================================================
   5. Index: which card is at the top
   --------------------------------------------------------------------------
   Two things are read straight from the markup, so that dropping a card in or
   out needs no other edit and no script at all:

     --wcar-count  how many cards there are — the last rule that matches wins,
                   so the highest reachable :nth-child() gives the count;
     --wcar-index  which one is selected.

   Twelve rules each: that is the ceiling of the original component, and a
   wheel is unreadable long before that.
   ========================================================================== */

.arc-carousel__stage {
  --wcar-count: 1;
}

.arc-carousel__stage:has(.arc-carousel__item:nth-child(2)) { --wcar-count: 2; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(3)) { --wcar-count: 3; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(4)) { --wcar-count: 4; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(5)) { --wcar-count: 5; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(6)) { --wcar-count: 6; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(7)) { --wcar-count: 7; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(8)) { --wcar-count: 8; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(9)) { --wcar-count: 9; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(10)) { --wcar-count: 10; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(11)) { --wcar-count: 11; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(12)) { --wcar-count: 12; }

.arc-carousel__stage:has(.arc-carousel__item:nth-child(1) .arc-carousel__radio:checked) { --wcar-index: 0; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(2) .arc-carousel__radio:checked) { --wcar-index: 1; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(3) .arc-carousel__radio:checked) { --wcar-index: 2; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(4) .arc-carousel__radio:checked) { --wcar-index: 3; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(5) .arc-carousel__radio:checked) { --wcar-index: 4; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(6) .arc-carousel__radio:checked) { --wcar-index: 5; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(7) .arc-carousel__radio:checked) { --wcar-index: 6; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(8) .arc-carousel__radio:checked) { --wcar-index: 7; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(9) .arc-carousel__radio:checked) { --wcar-index: 8; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(10) .arc-carousel__radio:checked) { --wcar-index: 9; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(11) .arc-carousel__radio:checked) { --wcar-index: 10; }
.arc-carousel__stage:has(.arc-carousel__item:nth-child(12) .arc-carousel__radio:checked) { --wcar-index: 11; }

/* Rank of each card and of each dot. Same twelve ranks, so the two lists are
   declared together. */
.arc-carousel__item:nth-child(1), .arc-carousel__dot:nth-child(1) { --wcar-i: 0; }
.arc-carousel__item:nth-child(2), .arc-carousel__dot:nth-child(2) { --wcar-i: 1; }
.arc-carousel__item:nth-child(3), .arc-carousel__dot:nth-child(3) { --wcar-i: 2; }
.arc-carousel__item:nth-child(4), .arc-carousel__dot:nth-child(4) { --wcar-i: 3; }
.arc-carousel__item:nth-child(5), .arc-carousel__dot:nth-child(5) { --wcar-i: 4; }
.arc-carousel__item:nth-child(6), .arc-carousel__dot:nth-child(6) { --wcar-i: 5; }
.arc-carousel__item:nth-child(7), .arc-carousel__dot:nth-child(7) { --wcar-i: 6; }
.arc-carousel__item:nth-child(8), .arc-carousel__dot:nth-child(8) { --wcar-i: 7; }
.arc-carousel__item:nth-child(9), .arc-carousel__dot:nth-child(9) { --wcar-i: 8; }
.arc-carousel__item:nth-child(10), .arc-carousel__dot:nth-child(10) { --wcar-i: 9; }
.arc-carousel__item:nth-child(11), .arc-carousel__dot:nth-child(11) { --wcar-i: 10; }
.arc-carousel__item:nth-child(12), .arc-carousel__dot:nth-child(12) { --wcar-i: 11; }

/* ==========================================================================
   6. Placement: angle, distance, falloff
   --------------------------------------------------------------------------
   Cards sit at a regular pitch along the arc. The card whose rank equals
   --wcar-index is at the top; the others are --wcar-offset degrees away from
   it, positive to the right.

   Three quantities fade with that distance, each with its own reach:

       falloff(d, reach) = (1 - min(d / reach, 1))^3

   an ease-out cubic read backwards. It is 1 at the top and reaches exactly 0
   at `reach`, which is what keeps the far cards perfectly still while the
   front one moves.
   ========================================================================== */

.arc-carousel__item {
  --wcar-step: calc(var(--wcar-span) / max(1, var(--wcar-count) - 1) + var(--wcar-spacing));
  --wcar-offset: calc((var(--wcar-i) - var(--wcar-index)) * var(--wcar-step));
  --wcar-distance: max(var(--wcar-offset), -1 * var(--wcar-offset));

  --wcar-u-scale: calc(1 - clamp(0, var(--wcar-distance) / var(--wcar-falloff-scale), 1));
  --wcar-u-opacity: calc(1 - clamp(0, var(--wcar-distance) / var(--wcar-falloff-opacity), 1));
  --wcar-u-lift: calc(1 - clamp(0, var(--wcar-distance) / var(--wcar-falloff-lift), 1));

  --wcar-f-scale: calc(var(--wcar-u-scale) * var(--wcar-u-scale) * var(--wcar-u-scale));
  --wcar-f-opacity: calc(var(--wcar-u-opacity) * var(--wcar-u-opacity) * var(--wcar-u-opacity));
  --wcar-f-lift: calc(var(--wcar-u-lift) * var(--wcar-u-lift) * var(--wcar-u-lift));

  position: absolute;
  inset: 0;
  /* The layer is only a frame of reference: it must catch nothing, or the
     topmost card would swallow every drag. */
  pointer-events: none;
}

/* ==========================================================================
   7. Cards
   --------------------------------------------------------------------------
   A card is the <label> of a radio button, so selecting one needs no script.

   It is placed at the centre of the arc and then pushed out along its own
   radius. Written in that order — lift, then turn, then push, then scale —
   the lift stays vertical on screen (it is applied before the rotation) and
   the scaling happens around the middle of the card, exactly like the
   original, which sets translate, scale and rotate as three separate motion
   values.
   ========================================================================== */

.arc-carousel__card {
  position: absolute;
  left: 50%;
  top: calc(var(--wcar-arc-top) + var(--wcar-radius));
  width: var(--wcar-card-width);
  height: calc(var(--wcar-card-width) * var(--wcar-card-ratio));
  margin-left: calc(var(--wcar-card-width) / -2);
  margin-top: calc(var(--wcar-card-width) * var(--wcar-card-ratio) / -2);
  border-radius: var(--wcar-card-radius);
  background: var(--wcar-card-bg);
  box-shadow: var(--wcar-card-shadow);
  overflow: hidden;
  cursor: var(--wcar-cursor);
  pointer-events: auto;
  transform-origin: 50% 50%;
  transform:
    translateY(calc(-1 * var(--wcar-lift) * var(--wcar-f-lift)))
    rotate(calc((var(--wcar-offset) + var(--wcar-tilt)) * 1deg))
    translateY(calc(-1 * var(--wcar-radius)))
    scale(calc(var(--wcar-scale-off) + (var(--wcar-scale-on) - var(--wcar-scale-off)) * var(--wcar-f-scale)));
  opacity: calc(var(--wcar-opacity-off) + (1 - var(--wcar-opacity-off)) * var(--wcar-f-opacity));
  z-index: calc(10 + 1000 * var(--wcar-f-opacity));
  -webkit-tap-highlight-color: transparent;
}

.arc-carousel__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* A dragged image is a drag of the browser's own, not ours. */
  -webkit-user-drag: none;
  user-select: none;
}

.arc-carousel__veil {
  position: absolute;
  inset: 0;
  background-image: var(--wcar-card-veil);
  pointer-events: none;
}

/* The title of the card names the radio button for a screen reader; on screen
   it is the caption underneath that says it.

   The status line is the other half of that deal: turning the wheel with the
   arrow buttons, the mouse wheel or a drag changes the selection without
   moving the focus, so nothing would be announced. The script writes the new
   title here. Without the script it stays empty and inert. */
.arc-carousel__name,
.arc-carousel__status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Hidden, but not display:none — a control that is not laid out cannot take
   focus, and the group would lose its keyboard support. */
.arc-carousel__radio {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  opacity: 0;
  appearance: none;
  pointer-events: none;
}

.arc-carousel__card:has(.arc-carousel__radio:focus-visible) {
  outline: var(--wcar-focus-width) solid var(--wcar-focus-color);
  outline-offset: var(--wcar-focus-offset);
}

/* ==========================================================================
   8. Caption: headline, arrows, body copy, call to action
   --------------------------------------------------------------------------
   Each card carries its own caption; only the selected one is laid out. That
   is what makes the text follow the wheel without a script — and it also
   keeps the eight other calls to action out of the tab order, since
   display:none removes them from the document altogether.

   The vertical position is the formula of the original: the block sits just
   under the shoulder of the arc, but never below 60 % of the height.
   ========================================================================== */

.arc-carousel__caption {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(
    max(
      var(--wcar-arc-top) + 0.58 * var(--wcar-radius),
      min(
        var(--wcar-arc-top) + 2 * var(--wcar-radius) - 0.35 * var(--wcar-card-width) *
          var(--wcar-card-ratio),
        0.6 * 100cqh
      )
    ) - var(--wcar-content-lift) + var(--wcar-content-offset) + var(--wcar-content-bump)
  );
  padding-inline: var(--wcar-content-pad);
  z-index: 1100;
  /* The block spans the full width, and it sits over the cards. Left as a
     catcher — which is what the original does — it swallows every click aimed
     at a card passing behind it, and every grab started there. Only what
     actually carries something answers. */
  pointer-events: none;
}

.arc-carousel__item:not(:has(.arc-carousel__radio:checked)) .arc-carousel__caption {
  display: none;
}

.arc-carousel__panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--wcar-gap);
  max-width: var(--wcar-content-max);
  margin: 0 auto;
  text-align: center;
  animation: arc-carousel-enter var(--wcar-fade-duration) var(--wcar-fade-ease) backwards;
}

/* Only the starting state is described: the arrival is left to the rules
   above, so the animation never overwrites a value they set. */
@keyframes arc-carousel-enter {
  from {
    opacity: 0;
    transform: translateY(0.6667em);
  }
}

.arc-carousel__headline,
.arc-carousel__text,
.arc-carousel__cta {
  pointer-events: auto;
}

.arc-carousel__headline {
  display: flex;
  align-items: center;
  gap: var(--wcar-headline-gap);
}

.arc-carousel__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* The original lets the two arrows be squeezed by a long title: below 480 px
     they lose a quarter of their width, and the title takes the room. Set
     --wcar-arrow-shrink to 1 to get that back. */
  flex: 0 var(--wcar-arrow-shrink) auto;
  width: var(--wcar-arrow-size);
  height: var(--wcar-arrow-size);
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--wcar-title-color);
  font: inherit;
  cursor: pointer;
}

.arc-carousel__arrow:disabled {
  cursor: default;
  opacity: 0.35;
}

.arc-carousel__arrow:focus-visible {
  outline: var(--wcar-focus-width) solid var(--wcar-focus-color);
  outline-offset: var(--wcar-focus-offset);
}

.arc-carousel__arrow svg {
  display: block;
  width: var(--wcar-arrow-icon);
  height: var(--wcar-arrow-icon);
}

/* Without a script the two arrows have nothing to act on: the selected card is
   held by the radio group, and CSS cannot ask for "the next one". They are
   hidden until the script announces itself. */
.arc-carousel:not([data-wcar-ready]) .arc-carousel__arrow {
  display: none;
}

.arc-carousel__title {
  margin: 0;
  font-family: var(--wcar-font-title);
  font-size: var(--wcar-title-size);
  font-weight: var(--wcar-title-weight);
  line-height: var(--wcar-title-leading);
  letter-spacing: var(--wcar-title-tracking);
  color: var(--wcar-title-color);
}

.arc-carousel__text {
  margin: 0;
  font-size: 1em;
  font-weight: var(--wcar-body-weight);
  line-height: var(--wcar-body-leading);
  letter-spacing: var(--wcar-body-tracking);
  color: var(--wcar-body-color);
}

.arc-carousel__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--wcar-cta-gap);
  padding: var(--wcar-cta-pad);
  border-radius: 999px;
  background: var(--wcar-cta-bg);
  color: var(--wcar-cta-color);
  font-family: var(--wcar-font-body);
  font-size: 0.9334em;
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--wcar-body-tracking);
  text-decoration: none;
}

.arc-carousel__cta:focus-visible {
  outline: var(--wcar-focus-width) solid var(--wcar-focus-color);
  outline-offset: var(--wcar-focus-offset);
}

/* ==========================================================================
   9. Dots
   --------------------------------------------------------------------------
   Decoration, and nothing else: the state they show is already carried by the
   radio group, which a screen reader reads properly. They are hidden from the
   accessibility tree so as not to say the same thing twice.

   The width follows --wcar-index continuously, so a dot grows while the wheel
   is being dragged instead of snapping once it lands.
   ========================================================================== */

.arc-carousel__dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--wcar-dots-bottom);
  display: flex;
  justify-content: center;
  gap: var(--wcar-dot-gap);
  opacity: var(--wcar-dots-opacity);
  pointer-events: none;
  z-index: 1200;
}

.arc-carousel__dot {
  --wcar-dot-distance: max(
    var(--wcar-i) - var(--wcar-index),
    var(--wcar-index) - var(--wcar-i)
  );
  --wcar-dot-on: clamp(0, 1 - var(--wcar-dot-distance), 1);

  width: calc(
    var(--wcar-dot-size) + (var(--wcar-dot-size-on) - var(--wcar-dot-size)) * var(--wcar-dot-on)
  );
  height: var(--wcar-dot-size);
  border-radius: 999px;
  background: rgb(
    var(--wcar-dot-color) /
      calc(
        var(--wcar-dot-alpha) + (var(--wcar-dot-alpha-on) - var(--wcar-dot-alpha)) *
          var(--wcar-dot-on)
      )
  );
  transition: width var(--wcar-dot-duration) ease;
}

/* The original only ever draws nine dots, whatever the number of cards: past
   the ninth, nothing shows the selection any more. Add data-dots-limit to get
   that back. */
.arc-carousel[data-dots-limit] .arc-carousel__dot:nth-child(n + 10) {
  display: none;
}

/* ==========================================================================
   10. Probe
   --------------------------------------------------------------------------
   getComputedStyle() hands back "calc(245 / 9 + -3.5)" for a custom property,
   not the number. The script needs the real pitch to turn a drag of so many
   pixels into so many cards, so the value is carried by the width of an
   element that takes no room and is never painted — a width is always
   resolved.

   The probe carries three readings at once: the pitch on its width, the drag
   threshold on its height, and the settling delay of the mouse wheel on its
   transition-duration.
   ========================================================================== */

.arc-carousel__probe {
  position: absolute;
  left: 0;
  top: 0;
  width: calc(
    (var(--wcar-span) / max(1, var(--wcar-count) - 1) + var(--wcar-spacing)) * 1px
  );
  height: var(--wcar-drag-threshold);
  visibility: hidden;
  pointer-events: none;
  /* Second reading carried by the probe: a duration is always resolved on
     transition-duration, never on the custom property itself. */
  transition-property: opacity;
  transition-duration: var(--wcar-wheel-settle);
}

/* ==========================================================================
   11. Narrow containers
   --------------------------------------------------------------------------
   Three settings only: the arc opens less, it takes more of the width, and
   the cards take a larger share of it. Same breakpoints as the original, but
   read on the container rather than on the window — the component keeps its
   proportions inside a half-width column.
   ========================================================================== */

@container arc-carousel (max-width: 768px) {
  .arc-carousel__stage {
    --wcar-span: 205;
    --wcar-radius: clamp(14.6667em, 78cqw, 48em);
    --wcar-card-width: clamp(9.1201em, 25.84cqw, 13.1734em);
  }
}

@container arc-carousel (max-width: 480px) {
  .arc-carousel__stage {
    --wcar-span: 155;
    --wcar-radius: clamp(14.6667em, 88cqw, 48em);
    --wcar-card-width: clamp(8.1067em, 39.52cqw, 12.16em);
    --wcar-content-bump: 6.4em;
    --wcar-dots-bottom: 5.3334em;
  }
}

/* ==========================================================================
   12. Fallbacks
   ========================================================================== */

/* A delay is movement spread over time, so it goes too. What is a picture and
   not a movement — the halo, the veil, the arc itself — stays. */
@media (prefers-reduced-motion: reduce) {
  .arc-carousel__stage,
  .arc-carousel__dot {
    transition-duration: 1ms;
    transition-delay: 0ms;
  }

  .arc-carousel__panel {
    animation: none;
  }
}

@media (forced-colors: active) {
  .arc-carousel {
    --wcar-card-shadow: none;
  }

  .arc-carousel__card {
    border: 1px solid CanvasText;
    /* The veil would paint a black block over a forced-colours image. */
    opacity: 1;
  }

  .arc-carousel__veil,
  .arc-carousel__halo {
    display: none;
  }

  .arc-carousel__cta {
    border: 1px solid ButtonText;
  }

  .arc-carousel__dot {
    forced-color-adjust: none;
    background: CanvasText;
  }

  .arc-carousel__card:has(.arc-carousel__radio:focus-visible),
  .arc-carousel__arrow:focus-visible,
  .arc-carousel__cta:focus-visible {
    outline-color: Highlight;
  }
}

/* Without :has() the wheel cannot know which card is selected, so it would
   pile every card on top of the first one. Better to fall back to a plain
   readable column: the pictures, their titles, their links. */
@supports not selector(:has(*)) {
  .arc-carousel {
    height: auto;
    container-type: normal;
  }

  .arc-carousel__stage {
    position: static;
  }

  .arc-carousel__track {
    position: static;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16em), 1fr));
    gap: 2em;
    padding: 2em;
  }

  .arc-carousel__item {
    position: static;
    pointer-events: auto;
  }

  .arc-carousel__card {
    position: static;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / var(--wcar-card-ratio);
    margin: 0;
    transform: none;
    opacity: 1;
  }

  .arc-carousel__caption {
    position: static;
    padding: 1em 0 0;
  }

  .arc-carousel__panel {
    animation: none;
  }

  .arc-carousel__dots,
  .arc-carousel__halo {
    display: none;
  }
}
