/* Homepage gallery marquee: rows of design tiles drifting sideways. CSS
   owns the motion (GPU transform only, no layout work); the marquee
   Stimulus controller just toggles .is-running while the section is on
   screen so hidden tabs and scrolled-past sections cost nothing.

   Loop mechanics: each track holds the same tile set twice; the second
   set is inert. Every set carries padding-right equal to the tile gap,
   so one set plus its padding is exactly half the track width and the
   translateX(-50%) loop point is seamless. */

.marquee-rows {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-4);
}

/* Stillness controls above the strip: hover and focus already ease the
   rows to a stop; the toggle is the same mechanism for touch (WCAG
   2.2.2), and the skip link spares keyboard users 510 tab stops. */
.marquee-controls {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-3);
  margin-top: calc(-1 * var(--space-5));
}

.marquee-toggle {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  padding: 0.45em 1.1em;
  cursor: pointer;
}

.marquee-toggle:hover {
  color: var(--ink);
  border-color: var(--ink);
}

/* Visually hidden until keyboard focus lands on it. */
.marquee-skip {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.marquee-skip:focus-visible {
  position: static;
  width: auto;
  height: auto;
  clip-path: none;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  border-radius: var(--radius-pill);
  padding: 0.45em 1.1em;
  text-decoration: none;
}

.marquee {
  --marquee-gap: var(--space-4);
  overflow: hidden;
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee-scroll 90s linear infinite;
  animation-play-state: paused;
  /* Keep the strip on its own compositor layer across play-state flips:
     without this the hover-pause re-snapshots the layer and hitches. */
  will-change: transform;
}

.is-running .marquee-track {
  animation-play-state: running;
}

/* Hover/focus pause is playbackRate-driven in the marquee controller:
   animation-play-state flips snap visibly in WebKit. */

.marquee-reverse {
  animation-direction: reverse;
}

.marquee-set {
  display: flex;
  gap: var(--marquee-gap);
  padding-right: var(--marquee-gap);
}

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

.marquee-tile {
  display: block;
  position: relative;
  /* Late-decoding images may repaint only their own tile, never the
     strip: kills the first-visit decode jank on cold edge caches. */
  contain: content;
  flex: none;
  width: 16rem;
  border: var(--border-hard);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--paper-card);
}

.marquee-tile img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* Hover affordance is border + label tint, never a transform: scaling an
   image inside a clipped tile on the animated strip re-rasterizes mid-
   drift and reads as jank (owner-reported 2026-07-08). */
.marquee-tile:hover,
.marquee-tile:focus-visible {
  border-color: var(--accent);
}

.marquee-tile:hover span,
.marquee-tile:focus-visible span {
  background: var(--accent);
}

.marquee-tile span {
  position: absolute;
  left: var(--space-2);
  bottom: var(--space-2);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: rgba(16, 16, 16, 0.82);
  color: var(--paper);
  padding: 2px 8px;
  border-radius: var(--radius-sm);
}

.marquee-section .gallery-more {
  margin-top: var(--space-6);
}

@media (max-width: 719px) {
  .marquee-tile {
    width: 11rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
  }

  /* The strip becomes a plain swipeable row instead of a moving one. */
  .marquee {
    overflow-x: auto;
  }

  /* Static strip: nothing to pause. */
  .marquee-toggle {
    display: none;
  }
}
