/* Beat 05 — Movement */

.beat-movement { height: 300vh; }

.beat-movement__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--c-aperture);
}

.movement__wall {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  gap: 0;
  overflow: hidden;
}

/* Horizontal and continuous. Two identical passes per row and a -50% translate, so the
   wrap has no seam; alternating rows reverse, so the wall never reads as one object. */
.wall__row {
  display: flex;
  gap: 0;
  width: max-content;
  will-change: transform;
  animation: wall-x var(--dur, 160s) linear infinite;
}

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

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

/* At rest: a white or gold mark, faded, on the aperture's own black. Hovering brings it up
   and drops a Portalith-shaped chip in behind it — inset from the cell, so the wall reads
   as marks with air around them rather than as a solid ribbon. */
.wall__cell {
  flex: 0 0 22vw;
  position: relative;
  display: grid;
  place-items: center;
  padding: 2.2vw 1.6vw;
}

/* The chip. Same radius as every other rectangle on the page — it is a Portalith. */
.wall__cell::before {
  content: "";
  position: absolute;
  inset: 2.2vw 1.6vw;
  border-radius: var(--portalith-radius);
  background-color: var(--chip, var(--c-portalith));
  opacity: 0;
  transition: opacity 0.35s var(--ease-out);
}

.wall__cell:hover::before,
.wall__cell:focus-within::before { opacity: 1; }

/* Drawn as a mask, not an <img>: the supplied files are white pixels, and a mask is the
   only way to give them a colour of their own. --src and --mark are written by wall.js. */
.wall__mark {
  position: relative;   /* above the chip */
  z-index: 1;
  width: 68%;
  height: 56%;
  background-color: var(--mark, #fff);
  -webkit-mask: var(--src) center / contain no-repeat;
  mask: var(--src) center / contain no-repeat;
  /* Faded rather than blurred: at rest the roster is present but unclaimed, and hovering
     is what brings one forward. A heavy blur made the wall read as broken rather than as
     waiting. */
  opacity: 0.32;
  transition: opacity 0.35s var(--ease-out), background-color 0.35s var(--ease-out);
}

.wall__cell:hover .wall__mark,
.wall__cell:focus-within .wall__mark { opacity: 1; }

/* Motion off: the wall stops and every mark is in focus — nothing may depend on a hover
   the visitor cannot or will not perform. */
.movement__wall.is-static .wall__row { animation: none; transform: none; }
.movement__wall.is-static .wall__mark { opacity: 1; }
.movement__wall.is-static .wall__cell::before { opacity: 1; }

/* The plaque. Gold at every client, always — only the sector tag carries the medium. */
.movement__plaque {
  position: absolute;
  z-index: 20;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(60vw, 940px);
  padding: 2.25rem;
  display: grid;
  /* Four columns and one row: name, sector, year, arrow — then a reserved slot the
     monogram sits in. The monogram is positioned absolutely, so it is not a grid item and
     claims no track of its own; without that last column auto-placement walks the metadata
     straight into the strip it occupies and SPIRITS lands across the fg's crossbar. The
     column is what keeps them apart, so do not drop it when adding a field here. */
  grid-template-columns: 1fr auto auto auto 6.5rem;
  gap: 0 1.25rem;
  align-items: center;
  background: var(--c-portalith);
  color: var(--c-ink);
  border-radius: var(--portalith-radius);
  overflow: hidden;
}

/* Debossed, not printed: the monogram is a shadow in the plaque's own surface. */
.plaque__monogram {
  position: absolute;
  right: 2.25rem;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--f-display);
  font-size: 6rem;
  line-height: 1;
  color: transparent;
  text-shadow:
    0 1px 0 rgb(255 255 255 / 0.35),
    0 -1px 1px rgb(0 0 0 / 0.22);
  pointer-events: none;
  user-select: none;
}

.plaque__client {
  grid-column: 1;
  grid-row: 1;
  font-family: var(--f-display);
  font-size: clamp(2rem, 4vw, 3.25rem);
  line-height: 1;
}

/* Sector and year ride one baseline as a single metadata pair, divided by a hairline. */
.plaque__sector, .plaque__year {
  grid-row: 1;
  align-self: center;
  font-size: var(--t-nav);
  letter-spacing: var(--tracking-nav);
  text-transform: uppercase;
}
.plaque__sector { grid-column: 2; }
.plaque__year {
  grid-column: 3;
  padding-left: 1.25rem;
  border-left: 1px solid rgb(17 17 17 / 0.28);
}

/* The arrow rides the metadata baseline rather than the corner. It has to: on a plaque this
   height a corner arrow lands on the monogram's f ascender. */
.plaque__arrow { grid-column: 4; grid-row: 1; align-self: center; font-size: 1rem; }

.movement__plaque.is-swapping .plaque__client { animation: plaque-swap 0.45s var(--ease-out) both; }

/* Reduced motion has no scrub, so the runway would become N viewport-heights of an
   unchanging frame. Collapse it and let the stage flow normally.

   Every child of .beat-movement__stage stays absolutely positioned and contributes no
   height, so the collapse target must be a fixed viewport height rather than auto — auto
   flattens the stage to whatever padding is left over. */
:root[data-motion="reduced"] .beat-movement { height: 100vh; }
:root[data-motion="reduced"] .beat-movement__stage {
  position: relative;
  height: 100vh;
}

@keyframes plaque-swap {
  from { opacity: 0; transform: translateY(0.4em); }
  to   { opacity: 1; transform: translateY(0); }
}
