/* ==========================================================================
   MARQUEE — a seamless scrolling rail
   R9k. Built for the Hero's partner strip at R7m; promoted to a component
   when §8 needed the same rail inside its box. Two copies of a
   seamless-loop calculation is two places to get it wrong.

   THE FADE IS THE COMPONENT. Without it a marquee has two hard edges where
   items appear and vanish out of nothing, and those edges are the thing that
   makes a strip look cheap. Masked, the row reads as a longer set passing
   behind the frame. The stops are 8% / 92% — the same values the Hero's card
   slider uses, so a page carrying both has one dissolve distance.

   The mask fades to TRANSPARENT, not to a colour, so the rail dissolves into
   whatever is behind it. That is what lets the same component sit on the page
   ground in the Hero and inside a #171717 box in §8 with no variant.

   THE LOOP, AND WHY THE TRANSLATE IS NOT A ROUND -50%.

   Two identical groups sit in one flex track with ONE gap between them, so
   the track's width is (2 x group) + gap. To land group two exactly where
   group one began, the track must travel (group + gap) — which is half its
   own width PLUS half a gap, not half its width. Hence:

       translateX(calc(-50% - var(--marquee-gap) / 2))

   The gap is a local custom property precisely so the track's `gap` and the
   keyframe's correction can never drift apart. Change it in one place.

   An earlier version put a trailing `padding-inline-end` on each group and
   translated a clean -50%. The arithmetic was right and it still failed:
   reset.css carries `ul[role="list"] { padding: 0 }`, specificity (0,1,1)
   against a single class's (0,1,0). The reset won, the trailing gap never
   existed, and the two groups butted together into one double-width plate at
   the seam. Putting the gap on the TRACK — a plain div, and a property no
   reset touches — removes the dependency rather than out-specifying it.
   ========================================================================== */

.marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}

.marquee__track {
  --marquee-gap: var(--space-2xl);
  display: flex;
  gap: var(--marquee-gap);
  inline-size: max-content;
}

.marquee__group {
  display: flex;
  align-items: center;
  gap: var(--marquee-gap);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The plate holds the mass a real logo occupies. Height is on the spacing
   scale; width is derived from it (3x) rather than picked, so the plate stays
   in the system if the scale ever moves. */
.marquee__logo {
  flex: none;
  inline-size: calc(var(--space-3xl) * 3);
  block-size: var(--space-3xl);
}

/* R13e — REAL LOGOS. The <li> stays the box and the image sits inside it, so
   the plate's dimensions keep governing the loop arithmetic no matter what
   the files measure.

   ⚠ object-fit: contain, NEVER cover. Everywhere else on this page a photo is
   cropped to fill its box; a LOGO that is cropped is a damaged trademark. The
   plate is 3:1 and the supplied files are 2.89:1, so contain leaves a hair of
   space at the sides and nothing is lost.

   block-size: 100% for the reason it is needed on every other <img> here —
   `height="268"` is a presentational hint and wins wherever no CSS sets a
   height, which would make each plate 268px tall inside a 64px row. */
.marquee__logo img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  /* §6c — partner logos render grayscale at rest and return to colour one at
     a time. The rail already pauses on hover and on focus, so the logo a
     reader stops on is the one that colours. Colour is a treatment and never
     a meaning here, so nothing is lost where hover does not exist. */
  filter: grayscale(1);
  transition: filter var(--duration-base) var(--ease-standard);
}

.marquee__logo:hover img,
.marquee__logo:focus-within img { filter: none; }

@media (prefers-reduced-motion: reduce) {
  .marquee__logo img { transition: none; }
}

/* MOTION IS OPT-IN, NOT OPT-OUT. Under reduced motion the animation never
   exists, so there is nothing to switch off — and that matters here, because
   a stopped marquee would leave the second group parked off-screen. The
   fallback below turns the rail into an ordinary wrapping row instead, where
   every plate is visible. Nothing becomes invisible when motion is off (§18). */
@media (prefers-reduced-motion: no-preference) {
  .marquee__track { animation: marquee-scroll var(--duration-marquee) linear infinite; }

  /* R11c — THE ONE MODIFIER. `animation-direction: reverse` runs the same
     keyframe backwards, which works here only because the two groups are
     identical: the track starts parked at (-50% - gap/2) and walks to 0, so
     the seam lands in exactly the same place going right as going left. A
     negative-duration or a second keyframe would both be ways of writing this
     that can drift from the original. This cannot — there is one keyframe. */
  .marquee__track--reverse { animation-direction: reverse; }

  /* Pause on hover AND on keyboard focus. The plates are inert today, but the
     moment they carry links this is the only thing standing between the page
     and a moving target. */
  .marquee:hover .marquee__track,
  .marquee:focus-within .marquee__track { animation-play-state: paused; }
}

@media (prefers-reduced-motion: reduce) {
  .marquee {
    -webkit-mask-image: none;
            mask-image: none;
  }
  .marquee__track { flex-wrap: wrap; inline-size: auto; }
  .marquee__group { flex-wrap: wrap; }
  .marquee__group[aria-hidden="true"] { display: none; }
}

/* The -50% is deliberately NOT the whole story — see the note above. Half the
   track plus half a gap is the only distance that lands group two on group
   one's starting position. */
@keyframes marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-50% - var(--marquee-gap) / 2), 0, 0); }
}
