/* ════════════════════════════════════════════════════════════════════════
 * dp-attraction-wall.css — the counter-scrolling wall of attraction art.
 *
 * Markup and the reasoning behind the row maths: views/partials/
 * attraction-wall.ejs. Where the field sits and how far it bleeds is the
 * PAGE's business, not this file's — see `body .atw` in
 * views/download.ejs. (That rule is deliberately NOT bare `.atw`: this
 * file's own `.atw { inset: 0 }` is linked after that page's inline
 * <style>, so at equal specificity it would win and the wall would stop
 * breaking out of the page's column.) This file owns look and motion only, the same split
 * dp-floaters.css had.
 * ════════════════════════════════════════════════════════════════════ */

.atw {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: var(--atw-rowgap, 14px);
  overflow: hidden;
  /* Scenery, not a control surface. See the note in
     views/partials/attraction-wall.ejs — a full-screen moving layer of
     link targets underneath the download button was a trap. */
  pointer-events: none;

  /* The rows would otherwise stop dead against the top and bottom of the
     field, which draws a hard horizontal edge across the page and makes
     the wall look like a panel someone dropped in. Fading them out means
     it reads as something the hero is sitting in front of. */
  /* Percentages again, but harmless ones: this is a soft edge, and 5%
     of a short field and 5% of a tall one both read as "the rows fade
     out here". At 9% it ate most of the top row once the phone layout
     started packing eight rows in. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 5%, #000 95%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 5%, #000 95%, transparent 100%);
}

/* The legibility scrim used to live here, as a radial gradient on
   .atw::after sized in PERCENTAGES OF THE FIELD. That was a bug waiting
   for a tall window: at 1440x900 "46% x 44%" is a modest blob around the
   copy, and at 577x1027 it is an ellipse 531 wide by 834 tall over a
   field 577 by 947 — white paint over almost the whole wall. Whole rows
   went blank, and tiles crossing the gradient's falloff faded in and out
   as they scrolled, which read as the rows glitching.

   The wash belongs to the COPY, whose size barely changes with the
   viewport, not to the field, whose size changes enormously. It is now a
   fixed-size halo on the hero — see `body .hero::before` in
   views/download.ejs. It is the PAGE's own gradient in whichever theme
   is rendering (--dl-halo), and the two themes need different STOPS as
   well as a different colour: the near-opaque centre that reads as the
   wall thinning out on white reads as a black oval painted over the
   artwork on dark. */

.atw-row {
  position: relative;
  flex: 1 1 0;          /* equal shares of the field, so equal tile sizes */
  min-height: 0;        /* or a flex row refuses to shrink below its content */
  overflow: hidden;
}

.atw-track {
  display: flex;
  height: 100%;
  width: max-content;
  animation: atwRoll var(--atw-dur, 80s) linear infinite;
}
.atw-row--rev .atw-track { animation-direction: reverse; }

@keyframes atwRoll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* TILES ARE TRANSPARENT (v2, Aug 2026). They used to be flattened onto
   white in lib/wallTiles.js, which on a dark page drew the wall as a grid
   of opaque white squares. The plate never was a rule in this file — the
   `no card, no fill, no border` note below has always been true and was
   simply being contradicted by the image itself. */
.atw-tile {
  display: block;
  flex: 0 0 auto;
  height: 100%;
  aspect-ratio: 1 / 1;
  /* margin, NOT the track's flex gap — see the loop note in the partial.
     A gap puts an odd number of gaps in an even number of copies and the
     -50% wrap lands half a gap out. */
  margin-right: var(--atw-gap, 14px);
  border-radius: 18%;
  overflow: hidden;
  /* No card, no fill, no border. The renditions are the pipeline's
     transparent preview art flattened onto white (lib/wallTiles.js), so
     on this page the tile's box is invisible and what drifts past is the
     ATTRACTION, cut out and floating. Give it a background and you get
     216 faint grey squares instead, and the page stops being white. The
     radius and the clip stay for the handful of previews that are opaque
     edge to edge. */
  /* --atw-dim is set per tile from its measured ink — see atwDim() in
     views/partials/attraction-wall.ejs. The scale is the global dial on
     top of it, so a breakpoint can back the whole wall off without
     undoing the per-tile evening-out. */
  opacity: calc(var(--atw-dim, .42) * var(--atw-dim-scale, 1));
}
.atw-tile img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Lazy tiles keep their square (the span's aspect-ratio) so the
   2-copy -50% loop does not hitch when src is still data-src.
   Hide the src-less img so browsers do not paint a broken-image icon
   in the hole; the tile box itself is the placeholder. */
.atw-tile img:not([src]) {
  visibility: hidden;
}

/* Rows 6-8 exist for the phone, where the field is tall and narrow and
   five rows would mean under three enormous tiles across. See ATW_ROWS
   in views/partials/attraction-wall.ejs. */
@media (min-width: 701px) {
  .atw-row:nth-child(n + 6) { display: none; }
}

/* The copy takes up far more of a phone screen, so the wall backs off a
   little further behind it. */
@media (max-width: 700px) {
  .atw { --atw-dim-scale: .8; --atw-gap: 9px; --atw-rowgap: 9px; }
}

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