/* ==========================================================================
   showcase.css — Venue marquee
   --------------------------------------------------------------------------
   Depends on css/variables.css for design tokens (--brand, --card, --muted,
   --text, --ring, radii, spacing, easings). No hard-coded palette values, so
   both themes (:root dark / :root.light) are covered by the token swap alone.

   Scope:
     `.marquee` — an infinitely auto-scrolling strip of venue names.
     TEXT PILLS, not logos: real conference logos are trademarked and would
     mean shipping third-party image assets, which the "self-hosted only" rule
     and licence hygiene both rule out. Text also stays crisp at any zoom / DPR
     and inherits the theme for free.

   DOM contract:
     div.marquee[aria-hidden]
       └ div.marquee-track
           └ span.marquee-item  ×N, THE LIST REPEATED TWICE

   The marquee container is `aria-hidden` because it is purely decorative:
   every venue in the strip is already named in the publications list, so the
   duplicated pills would only add noise for screen-reader users. It also
   contains no focusable elements, so nothing is trapped behind the hidden
   subtree.

   MOTION
   --------------------------------------------------------------------------
   Only `transform` is animated (compositor-friendly, no layout or paint per
   frame), and the strip collapses to a static state under
   `prefers-reduced-motion: reduce` (see the block at the end).

   CONTRAST (Req 9.5)
   --------------------------------------------------------------------------
   `.marquee-item` text is --text on --card (dark 7.5:1), and the strip is
   decorative/aria-hidden regardless.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Venue marquee
   --------------------------------------------------------------------------
   Geometry note (the -50% trick): the item list is duplicated, so the track
   is exactly two copies wide. Sliding it by -50% therefore lands copy #2
   precisely where copy #1 started, and the loop restart is invisible.

   The spacing between pills MUST come from a per-item `margin-inline-end`
   rather than `gap` on the track. With `gap`, a doubled list of N items has
   2N-1 gaps, so half the track width is NOT half the item list and the wrap
   would visibly jump by one gap. With a trailing margin every item has the
   same outer width, the track is 2N equal cells wide, and -50% is exact.
   -------------------------------------------------------------------------- */

.marquee {
  --marquee-duration: 36s;
  --marquee-gap: var(--space-2);

  position: relative;
  overflow: hidden;           /* the clipping viewport for the track */
  padding-block: var(--space-1);
  /* Both edges fade to transparent so pills enter and leave softly instead
     of being sliced by a hard border. */
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    black 12%,
    black 88%,
    transparent
  );
  mask-image: linear-gradient(
    90deg,
    transparent,
    black 12%,
    black 88%,
    transparent
  );
}

.marquee-track {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  /* Size to content, not to the clipping parent, so the second copy really
     does sit off-screen to the right. */
  width: max-content;
  animation: marquee-scroll var(--marquee-duration) linear infinite;
  will-change: transform;
}

.marquee-item {
  flex: 0 0 auto;
  margin-inline-end: var(--marquee-gap);   /* see geometry note above */
  padding: 0.5rem var(--space-2);
  border: 1px solid var(--ring);
  border-radius: var(--radius-pill);
  background: var(--card);
  font-family: var(--font-sans);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: var(--text);
}

@keyframes marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* Pause on hover so a name can be read without chasing it. */
.marquee:hover .marquee-track {
  animation-play-state: paused;
}

/* --------------------------------------------------------------------------
   Reduced motion
   --------------------------------------------------------------------------
   The marquee stops entirely and rests at translateX(0) — the start of the
   first copy — so the strip reads as a normal left-aligned row of pills
   rather than freezing mid-wrap with a half-clipped name. The edge mask is
   narrowed to the trailing edge only, since with no motion the leading pills
   are permanent content and must not sit under a fade.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .marquee {
    -webkit-mask-image: linear-gradient(90deg, black 88%, transparent);
    mask-image: linear-gradient(90deg, black 88%, transparent);
  }

  .marquee-track,
  .marquee:hover .marquee-track {
    animation: none;
    transform: translateX(0);
    will-change: auto;
  }
}
