/**
 * @file
 * Feature carousel styles.
 *
 * Values from Figma 1142:42926 and are exact, replacing an earlier pass measured
 * from a PNG export. The layout is not centred: the section is padded 240px on the
 * left and the row runs to the right viewport edge, so the track bleeds off screen
 * as in the comp.
 *
 * The background is a flat grey shared with the tabbed content panel, from
 * --ln-color-surface-gray in css/tokens.css. It was the design's own gradient at
 * an exported 144.95deg; see the note on that token for why both sections went
 * flat. Before that it was a stand-in reusing the tabbed content panel's colours,
 * because the comp's original ground — a darker olive fade under a swirl texture
 * — could not be reproduced in CSS.
 */

.ln-carousel {
  --ln-carousel-padding-block: 80px;
  --ln-carousel-padding-inline: clamp(1.25rem, 12.5vw, 240px);

  /* Left column: 510px of content plus a 64px gutter before the track. */
  --ln-carousel-copy-width: 510px;
  --ln-carousel-copy-gutter: 64px;

  --ln-carousel-fg: #1c1c1c;
  --ln-carousel-heading-fg: #171717;
  --ln-carousel-accent: #cf0000;

  /* Shared with the tabs panel, so the two sections cannot drift apart. */
  --ln-carousel-surface: var(--ln-color-surface-gray, #ededed);

  --ln-carousel-card-width: 320px;
  --ln-carousel-card-height: 405px;
  --ln-carousel-card-gap: 16px;
  --ln-carousel-card-radius: 16px;

  /* Asymmetric: the comp holds a consistent 72px above the icon and lets the
     copy run as far down the card as it needs. See .ln-carousel__card. */
  --ln-carousel-card-padding-start: 72px;
  --ln-carousel-card-padding-end: 32px;
  --ln-carousel-card-padding-inline: 32px;

  --ln-carousel-card-shadow: 0 6px 6px rgb(99 102 106 / 28%);

  /* Room inside the scroll container for the shadow, from the comp's "Carousel
     Shadow" frame. Must live on the track, not the viewport — see the note there. */
  --ln-carousel-shadow-room-block: 32px;
  --ln-carousel-shadow-room-inline: 24px;

  /* Left edge shadow, so the cards read as passing under the copy column.
     Opacity is driven from the scroll position by carousel.js. */
  --ln-carousel-edge-shadow-width: 48px;
  --ln-carousel-edge-shadow-color: 99 102 106;
  --ln-carousel-edge-shadow-strength: 18%;
  --ln-carousel-edge-shadow-opacity: 0;

  /**
   * Vertical envelope for that shadow: strongest across the middle of the
   * component and fading to nothing at the top and bottom, as the comp shows.
   *
   * Held in a custom property because it is needed twice, once prefixed. Black
   * is arbitrary — a gradient mask reads alpha only, so the stops are the shape
   * and the colour never renders.
   *
   * 55% at the quarter points rather than the 50% a straight ramp would give,
   * which bulges the envelope out into a curve instead of a hard triangle.
   */
  --ln-carousel-edge-shadow-envelope: linear-gradient(
    180deg,
    rgb(0 0 0 / 0%) 0%,
    rgb(0 0 0 / 55%) 22%,
    rgb(0 0 0 / 100%) 50%,
    rgb(0 0 0 / 55%) 78%,
    rgb(0 0 0 / 0%) 100%
  );

  --ln-carousel-track-bg: #ffffff;
  --ln-carousel-button-size: 40px;
  --ln-carousel-button-gap: 32px;

  /**
   * Pills on this surface are white, per the design. The pill's own default is
   * #ececec, which against this background sits within a level or two of
   * invisible.
   */
  --ln-pill-bg: #ffffff;

  --ln-carousel-font: Outfit, sans-serif;

  position: relative;
  box-sizing: border-box;
  color: var(--ln-carousel-fg);
  font-family: var(--ln-carousel-font);
}

/* Background variants. */
.ln-carousel--bg-gray {
  background-color: var(--ln-carousel-surface);
}

.ln-carousel--bg-none {
  background-image: none;
}

.ln-carousel *,
.ln-carousel *::before,
.ln-carousel *::after {
  box-sizing: inherit;
}

/**
 * .ln-carousel__pin is a plain wrapper now.
 *
 * It was a sticky, viewport-tall box back when vertical page scroll drove the
 * track and the section needed a runway to be scrolled through. The carousel
 * advances on its own clock instead, so the section is its natural height and
 * this element only groups the content. Kept rather than removed from the markup
 * because nothing is gained by churning the template.
 */

/**
 * Padded on the left only. In the comp the row is 1680px starting after a 240px
 * left inset, which at 1920 runs exactly to the right edge — the cards are meant
 * to bleed off screen, so there is no right padding and no centring.
 */
.ln-carousel__inner {
  display: flex;
  flex-direction: column;
  inline-size: 100%;
  padding-block: var(--ln-carousel-padding-block);
  padding-inline-start: var(--ln-carousel-padding-inline);
}

/* Spans both columns, above the row. */
.ln-carousel__heading :is(h2, h3, p) {
  margin: 0;
  color: var(--ln-carousel-heading-fg);
  font-size: 48px;
  font-weight: 500;
  line-height: 1.3;
}

/**
 * Grid, not flex, because the media is placed differently at each breakpoint.
 *
 * Desktop wants it beneath the copy in the left column; a phone wants it beneath
 * the card track. Those are two-dimensional placements of the same three boxes,
 * which is what grid-template-areas is for. As flex it was impossible without
 * moving the element in the DOM: the media sat inside .ln-carousel__copy, so it
 * was a *grandchild* of this row and `order` — which only reorders siblings
 * within one container — could never move it past the track.
 *
 * The viewport spans both rows so the track keeps its full height while the copy
 * and the media stack beside it. align-items: start matches the flex-start the
 * flex version used.
 *
 * minmax(0, 1fr) rather than 1fr on the track column: a 1fr track floors at
 * min-content, and the track's min-content is a card, so the column could not
 * shrink below ~320px and would push the grid wider than its container.
 *
 * The gutter between the two columns is column-gap, not padding on the copy.
 * It used to be both at once — the column was `copy-width + gutter` wide and
 * .ln-carousel__copy reserved the gutter again with padding-inline-end — which
 * worked only because the copy was the column's sole occupant. The media is now
 * a second item in that column, and it had no such padding, so it ran the full
 * width and met the card track. A gap between columns belongs to the grid, where
 * everything placed in the column gets it; the geometry is identical either way,
 * 510px of content and 64px of clearance.
 */
.ln-carousel__row {
  display: grid;
  grid-template-columns: var(--ln-carousel-copy-width) minmax(0, 1fr);
  grid-template-areas:
    "copy  viewport"
    "media viewport";
  column-gap: var(--ln-carousel-copy-gutter);
  align-items: start;
  min-inline-size: 0;
}

.ln-carousel__copy {
  grid-area: copy;
}

.ln-carousel__media {
  grid-area: media;
}

.ln-carousel__viewport {
  grid-area: viewport;
}

/**
 * Left column.
 *
 * display: flex here makes this a flex *container* for the pill and copy inside
 * it. Its own width comes from the row's grid-template-columns — the
 * `flex: 0 0 calc(copy-width + gutter)` that used to sit here is ignored on a
 * grid item, so it has gone rather than staying as a second, silent claim on the
 * same measurement.
 */
.ln-carousel__copy {
  display: flex;
  flex-direction: column;
  gap: 32px;
  padding-block-start: 32px;
  font-size: 20px;
  font-weight: 600;
  line-height: 1.3;
}

/**
 * Collapse the first and last elements' own spacing, so the 32px above is the
 * whole gap.
 *
 * Descendant selectors, not `>`. This was `> :first-child` and matched Drupal's
 * field wrapper div rather than the element inside it, so the first element's own
 * 1rem top margin survived and the gap above the copy rendered 48px against the
 * 32px this file asks for. Same trap as the comparison table's group description,
 * which is why that one uses descendants too.
 *
 * Margin only. An earlier version also zeroed padding-block, on the mistaken
 * belief that Cohesion sets padding on p as well as margin. It does not — the
 * paragraph base style sets margin: 1rem 0 and no padding at all. The 12px being
 * removed was the *pill's* own padding, which is what gives it its shape, and the
 * first element in this field is usually the pill. So the rule was flattening the
 * one thing it had no business touching.
 *
 * Specificity is easy to get wrong here, and I did: `:first-child` is a
 * pseudo-*class*, so this selector is (0,2,0) — a tie with .ln-pill.ln-pill in
 * css/editor-styles.css, decided by source order, not the clear loss to it that
 * the old comment claimed. Zeroing margin is safe under that tie because the pill
 * declares no block margin of its own. Zeroing padding was not.
 */
.ln-carousel__copy :first-child {
  margin-block-start: 0;
}

.ln-carousel__copy :last-child {
  margin-block-end: 0;
}

/**
 * The supporting media below the copy — a video or a still image.
 *
 * No --ln-video-ratio: nothing is known yet about the dimensions the designer
 * will deliver for this column, and a wrong reserved ratio letterboxes. Falling
 * back to the file's intrinsic ratio is correct at the cost of one reflow when
 * metadata arrives. Set the token here once there is an asset to measure.
 *
 * The wrapper is what video.js binds hover to, since .ln-video takes no pointer
 * events. It sits at the video's own size, so hovering the clip is the trigger
 * and hovering the copy above it is not.
 */
.ln-carousel__media {
  display: block;
  inline-size: 100%;

  /**
   * Space above the media, at every width.
   *
   * A margin on the item rather than a row-gap on the grid, because the two
   * layouts want the gap in different places and row-gap cannot tell them apart.
   * On desktop the rows are copy / media with the track spanning both, so a
   * row-gap would land correctly — but on a phone the rows are copy / track /
   * media, and the same row-gap would also push the track away from the copy,
   * where the 32px of shadow room above the cards is already doing that job.
   *
   * 32px because that is what the media used to inherit: it lived inside
   * .ln-carousel__copy, whose `gap: 32px` separated it from the body copy.
   * Promoting it to its own grid row dropped that, so this is as much a
   * restoration on desktop as it is a fix for the phone, where it had come to
   * rest directly against the arrows.
   */
  margin-block-start: 32px;
}

/**
 * Keep a still image inside the wrapper.
 *
 * There was no rule here because this slot only ever held the video component,
 * which sizes itself. An image arrives at its intrinsic width and overflows the
 * column, which is what "breaking out of the container" is.
 *
 * A descendant selector, not a child one: the image path renders
 * content.field_media through the media formatter, so there are Drupal field and
 * media wrapper divs between this element and the img.
 *
 * inline-size: 100% rather than max-inline-size, so a still fills the column the
 * way the video did — the two are interchangeable in this slot and should look
 * it. The cost is that an image supplied smaller than the column upscales, so
 * these want exporting at the column's 2x width, same as the clips.
 *
 * block-size: auto rather than the height: 100% that also appears to work. It
 * only appears to because this wrapper has no definite height, so 100% resolves
 * to auto anyway. The comment above anticipates giving it a reserved aspect
 * ratio once the designer settles the dimensions — and on that day height: 100%
 * would start stretching every image to fill it, which is a distortion nobody
 * would connect back to this line.
 */
.ln-carousel__media img {
  display: block;
  inline-size: 100%;
  block-size: auto;
}

/**
 * Right column. Takes the remaining width and runs to the viewport edge, so the
 * track is clipped mid-card exactly as the comp shows.
 *
 * No padding of its own. The shadow room has to sit on the track instead — the
 * track is the scroll container and clips its own children, so anything spent
 * out here is on the wrong side of the clip. The 32px above the controls is the
 * track's own padding-block-end.
 */
/**
 * The track column.
 *
 * display: flex stacks the track and the controls row inside it. There is no
 * `flex` shorthand any more, and its absence is worth a note: `flex: 1 1 0` used
 * to be here to claim the spare width, and when the row flipped to a column at
 * 64rem that same declaration became "basis 0, grow into the spare *height*" —
 * which a content-sized row has none of, so the viewport computed to zero height
 * and clipped the entire track away behind its own overflow: hidden. As a grid
 * item it is sized by the template instead, at both breakpoints, so that failure
 * cannot recur.
 */
.ln-carousel__viewport {
  position: relative;
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
  overflow: hidden;
}

/**
 * The left edge shadow. Sells the idea that the cards pass beneath the copy
 * column rather than simply being cut off at it.
 *
 * A pseudo-element on the viewport, not on the track: the track is the scroll
 * container, so anything positioned inside it would scroll away with the cards.
 * Here it stays put and the cards move under it.
 *
 * Hidden at rest — nothing is behind the column yet, so a shadow would be
 * describing an occlusion that is not happening. carousel.js raises the opacity
 * as the first card passes under, reaching full once that card is out of sight.
 *
 * "At rest" is now only the opening hold. Once the marquee is running a card is
 * always leaving, so the shadow is on for the rest of the visit — which is why
 * carousel.js ramps it off cumulative travel rather than off scrollLeft, a value
 * that no longer starts at zero or increases monotonically.
 *
 * pointer-events: none so it never swallows a click on the controls row beneath.
 *
 * Two falloffs, kept separate so either can be tuned without disturbing the
 * other: the background is the horizontal profile, dark at the edge and clear by
 * 48px, and the mask is the vertical envelope that concentrates it in the middle
 * of the component. Multiplying them gives the radial spill the comp shows —
 * closer to light wrapping round a soft edge than to a uniform band.
 *
 * Doing it as one radial-gradient was the alternative and would be a line
 * shorter, but an ellipse anchored to the edge pinches to a point at the top and
 * bottom, and the horizontal reach would then be governed by the vertical radius.
 * Two axes, two declarations.
 *
 * Without mask support the horizontal gradient still renders, just as an even
 * band — the effect degrades rather than disappearing.
 *
 * The 90deg is physical, so this would need flipping for an RTL language. None of
 * the site's locales are RTL today; if one is added, mirror it under :dir(rtl).
 */
.ln-carousel__viewport::before {
  content: '';
  position: absolute;
  z-index: 1;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: var(--ln-carousel-edge-shadow-width);
  background-image: linear-gradient(
    90deg,
    rgb(var(--ln-carousel-edge-shadow-color) / var(--ln-carousel-edge-shadow-strength)) 0%,
    rgb(var(--ln-carousel-edge-shadow-color) / calc(var(--ln-carousel-edge-shadow-strength) * 0.36)) 40%,
    rgb(var(--ln-carousel-edge-shadow-color) / 0%) 100%
  );
  -webkit-mask-image: var(--ln-carousel-edge-shadow-envelope);
  mask-image: var(--ln-carousel-edge-shadow-envelope);
  opacity: var(--ln-carousel-edge-shadow-opacity);
  pointer-events: none;

  /**
   * No transition. The opacity is recomputed every frame from the track
   * position, so easing it would leave the shadow trailing the cards it is meant
   * to be occluding.
   */
  transition: none;
}

/**
 * A real scroll container, not a transformed strip. That keeps swiping, scroll
 * snapping and focus-follows-scroll working; carousel.js only sets scrollLeft.
 *
 * scrollbar-width: none hides the horizontal bar, which would otherwise sit under
 * the cards and twitch as the track drifts. The track is still scrollable by
 * every other means — drag, swipe, trackpad, arrows.
 *
 * The padding is what stops the card shadows being clipped, and it belongs here
 * rather than on the viewport. overflow-x: auto forces overflow-y to compute to
 * auto as well, so this element clips its children on all four sides at its own
 * padding box — a shadow needs room inside that box to survive. Padding on an
 * ancestor cannot help.
 *
 * It does not throw the scroll maths off: clientWidth counts both paddings and
 * scrollWidth counts the end one, so scrollLeft still runs 0 to the last card,
 * and each end of the scroll leaves the shadow its room.
 */
.ln-carousel__track {
  display: flex;
  gap: var(--ln-carousel-card-gap);
  padding-block: var(--ln-carousel-shadow-room-block);
  padding-inline: var(--ln-carousel-shadow-room-inline);
  overflow-x: auto;
  /* Insets the snapport to match the padding. Without it the snap positions are
     measured from the border box, so snapping the first card flush would scroll
     the left inset away and clip the shadow it exists to protect. */
  scroll-padding-inline: var(--ln-carousel-shadow-room-inline);

  /**
   * No snapping, and no smooth scroll-behavior. Both are load-bearing.
   *
   * carousel.js assigns scrollLeft a continuous value every frame. Mandatory
   * snapping pulls each of those to the nearest card, so the cards jumped between
   * positions instead of drifting. A smooth scroll-behavior animates every one of
   * those assignments, which leaves the track lagging its own clock.
   *
   * Both matter more now than they did. The marquee corrects scrollLeft by a
   * whole set width when it crosses a boundary, and that correction has to land
   * on the exact pixel to be invisible — anything that animates or rounds it
   * turns the seam into a visible slide.
   *
   * The arrows still glide, because they pass behavior: 'smooth' to scrollTo()
   * explicitly and an option beats the stylesheet.
   */
  scroll-snap-type: none;
  scroll-behavior: auto;
  scrollbar-width: none;
  overscroll-behavior-x: contain;

  /* Grab affordance for the mouse drag. Touch keeps native scrolling. */
  cursor: grab;
}

/**
 * user-select while dragging: without it a throw across the cards selects their
 * text, which then fights the next drag and leaves a highlight behind.
 */
.ln-carousel.is-dragging .ln-carousel__track {
  cursor: grabbing;
  user-select: none;
}

.ln-carousel__track::-webkit-scrollbar {
  display: none;
}

/**
 * Cards. Drupal's field wrappers are stripped by
 * field--field-cards.html.twig, so each card is a direct flex child here.
 *
 * Height comes from the 405px minimum, not from padding. The padding is
 * deliberately asymmetric — 72px above the icon, 32px below the copy — because
 * the comp holds the icons on a common line while the copy runs to whatever
 * depth it needs. Matching 72px at the bottom, as an earlier pass did, added
 * 40px of height no card in the comp has.
 *
 * min-block-size rather than block-size: the track stretches every card to the
 * tallest, so they stay a uniform 405px, but a card whose copy genuinely does
 * not fit grows instead of spilling out. That matters here — the Spanish and
 * French translations of the same card run appreciably longer than the English.
 *
 * justify-content is start so the extra height from stretching falls at the
 * bottom, which is what makes the copy sit at different depths per card.
 */
.ln-carousel__card {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  justify-content: flex-start;
  gap: 32px;
  inline-size: var(--ln-carousel-card-width);
  min-block-size: var(--ln-carousel-card-height);
  padding-block: var(--ln-carousel-card-padding-start) var(--ln-carousel-card-padding-end);
  padding-inline: var(--ln-carousel-card-padding-inline);
  border-radius: var(--ln-carousel-card-radius);
  /**
   * Two layers, straight from the comp: a low-opacity metallic sheen raking
   * across an opaque white base. The sheen is what gives the cards their brushed
   * look; a plain white fill reads noticeably flatter.
   */
  background-image:
    linear-gradient(
      223.269deg,
      rgb(229 229 232 / 30%) 2.124%,
      rgb(199 199 204 / 30%) 22.914%,
      rgb(255 255 255 / 30%) 45.437%,
      rgb(184 184 189 / 30%) 67.254%,
      rgb(241 241 241 / 30%) 79.151%,
      rgb(173 173 178 / 30%) 98.027%
    ),
    linear-gradient(90deg, #ffffff 0%, #ffffff 100%);
  box-shadow: var(--ln-carousel-card-shadow);
  scroll-snap-align: start;
}

/* Title and body sit 16px apart, inside the card's own 32px rhythm. */
.ln-carousel__card-text {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/**
 * Sized by height, not width: each glyph has its own aspect ratio in the comp
 * (64-89px wide) but they all stand 80px tall, so height is the shared measure.
 */
.ln-carousel__card-icon img {
  display: block;
  inline-size: auto;
  block-size: 80px;
}

.ln-carousel__card-title {
  margin: 0;
  font-size: 24px;
  font-weight: 500;
  line-height: 1.2;
}

.ln-carousel__card-body {
  margin: 0;
  font-size: 18px;
  font-weight: 300;
  line-height: 1.3;
}

.ln-carousel__card-body > :first-child {
  margin-top: 0;
}

.ln-carousel__card-body > :last-child {
  margin-bottom: 0;
}

/**
 * Progress bar and arrows. 40px tall row, space-between, with a 64px inset on the
 * right so the arrows sit inside the bleed rather than off screen.
 */
/**
 * The controls row, now holding only the arrows.
 *
 * space-between and a gap were both here to keep the progress bar off the left
 * arrow. With the bar gone there is one child, so the arrows are pushed to the
 * end instead — which is where the comp puts them, and where space-between left
 * them once the bar hit its width cap.
 *
 * The start padding stays. It matched the track's own inset so the bar began
 * level with the first card's left edge; it now simply keeps the row's box
 * consistent with the track above it, which matters because both sit inside the
 * same column and any difference reads as a misalignment.
 */
.ln-carousel__controls {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  block-size: 40px;
  padding-inline-start: var(--ln-carousel-shadow-room-inline);
  padding-inline-end: var(--ln-carousel-copy-gutter);
}

.ln-carousel__buttons {
  display: flex;
  flex: 0 0 auto;
  gap: var(--ln-carousel-button-gap);
}

/**
 * Repeated class to outrank Site Studio's global button styles, which otherwise
 * apply a brand-red hover fill. Same technique as the comparison table toggle.
 */
.ln-carousel__button.ln-carousel__button {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--ln-carousel-button-size);
  block-size: var(--ln-carousel-button-size);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ln-carousel-track-bg);
  color: var(--ln-carousel-fg);
  cursor: pointer;
}

.ln-carousel__button.ln-carousel__button:hover,
.ln-carousel__button.ln-carousel__button:focus {
  background: var(--ln-carousel-track-bg);
  color: var(--ln-carousel-accent);
}

.ln-carousel__button:focus-visible {
  outline: 2px solid var(--ln-carousel-fg);
  outline-offset: 2px;
}

/* The shared chevron points down; rotate it for left and right. */
.ln-carousel__button--prev svg {
  transform: rotate(90deg);
}

.ln-carousel__button--next svg {
  transform: rotate(-90deg);
}

/**
 * One column below the pinning breakpoint. The track keeps snapping and the
 * arrows keep working, so the component degrades to an ordinary swipe carousel —
 * which is also what reduced-motion and coarse-pointer visitors get at any width.
 */
@media (max-width: 64rem) {
  .ln-carousel {
    --ln-carousel-padding-block: 56px;
    --ln-carousel-card-width: 280px;
    --ln-carousel-card-padding-start: 40px;
    --ln-carousel-card-padding-end: 24px;
    --ln-carousel-copy-gutter: 0px;

    /* No bleed in one column, so the track and controls sit flush with the copy
       above them. The block inset stays — the shadow still needs it. */
    --ln-carousel-shadow-room-inline: 0px;

    /* Nothing to pass under here: the copy sits above the track, not beside it.
       Zeroed via the width because carousel.js sets the opacity inline, which
       would outrank any override of it from this stylesheet. */
    --ln-carousel-edge-shadow-width: 0px;
  }

  .ln-carousel__heading :is(h2, h3, p) {
    font-size: clamp(2rem, 6vw, 48px);
  }

  /**
   * One column, with the media last.
   *
   * The whole point of the grid above: the same three boxes, restacked. The media
   * moves from beneath the copy to beneath the track by naming the areas in a
   * different order, which is not something `order` could have done — it sat
   * inside .ln-carousel__copy and so was never a sibling of the track.
   *
   * The reading order in the DOM stays copy, media, track. Only the visual order
   * diverges here, and only for a supporting asset, so nothing meaningful is lost
   * — the field is labelled "Supporting image or video" and the clip is
   * decorative. It would matter if the media ever held a link.
   */
  .ln-carousel__row {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "copy"
      "viewport"
      "media";
  }

  .ln-carousel__copy {
    max-inline-size: var(--ln-carousel-copy-width);
  }

}

/**
 * Phone. Measured from the designer's 401px comp.
 *
 * Card geometry came out of an edge-detection pass on the card row: the visible
 * card runs 42 to 322 and the next starts at 346, so 280px wide with a **24px
 * gap** rather than desktop's 16. The 280px was already right; the gap was not.
 *
 * The track goes full-bleed and the copy does not. In the comp a card is clipped
 * at each edge of the frame, which is what tells the reader there is more to
 * scroll — the strongest affordance available now that the progress bar is gone.
 * The negative margin breaks the track out of the section's gutter while the
 * matching padding keeps the first card aligned to that gutter, so the row reads
 * as starting with the copy above it rather than at the screen edge.
 *
 * Copy centres here and is left-aligned on desktop. That cannot come from the
 * content, because it is one rich-text field serving both, so the stylesheet
 * decides. The pill needs its own margin: it is display:block with
 * width:fit-content, and text-align on an ancestor does not move a block box.
 *
 * 47.99rem is the page's single breakpoint — see the note in css/layout.css. The
 * 64rem block above is separate and stays: it drops the two columns early
 * because 510px of copy beside a track does not fit at 1024px, so between 48 and
 * 64rem the component is one column without the phone treatment.
 */
@media (max-width: 47.99rem) {
  .ln-carousel {
    --ln-carousel-padding-block: 32px;
    --ln-carousel-padding-inline: 16px;
    --ln-carousel-card-gap: 24px;
  }

  /**
   * Both sides, where every wider width pads the start only.
   *
   * On desktop the track deliberately bleeds off the right edge, so the inner
   * has no end padding for it to escape. Here the bleed is symmetrical and comes
   * from the track's own negative margin instead, which means the inner can pad
   * both sides and the heading, copy and arrows all sit on the same 16px gutter.
   */
  .ln-carousel__inner {
    padding-inline: var(--ln-carousel-padding-inline);
  }

  .ln-carousel__heading,
  .ln-carousel__copy {
    text-align: center;
  }

  .ln-carousel__copy .ln-pill {
    margin-inline: auto;
  }

  .ln-carousel__track {
    margin-inline: calc(-1 * var(--ln-carousel-padding-inline));
    padding-inline: var(--ln-carousel-padding-inline);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ln-carousel__track {
    transition: none;
    scroll-behavior: auto;
  }
}
