/* ============================================================
   v3-wall.css — Red Banana v3 "THE OBJECT"
   WALL AND LIST LANE. Branch rb-bg/v3-object.
   Contract: RB-V3-DIRECTION-CONTRACT.md §7 ("WALL AND LIST LANE:
   assets/js/v3-wall.js, assets/css/v3-wall.css"). Creative direction:
   rb-v3/SIGNATURE-MOMENTS.md Moment 4 (numbers wall) and Moment 6
   (capabilities list), read against Bob's 17:43 IST rulings in
   RB-V3-DIRECTION-CONTRACT.md §8 (A2 vermilion, A4 archive figure
   dropped, A5 FAQ).

   Loads AFTER v3.css (index.html <head> hand-off point, already
   stubbed as a commented <link> at the exact spot for this lane) so
   every rule below wins per-property against v3.css with no
   !important. This file styles ONLY the elements v3-wall.js injects
   (.wall-strike, .wall-marquee*, .cap-rule) plus the small per-tile
   layout override the five-tile figure count needs — it does not
   restate any rule v3.css already owns (colours, base grid, base
   .cap-item states) unless overriding a specific property.

   VERMILION: zero uses of --red in this file. Moment 6's "live
   capability row's .num colour" — my one budgeted use of the four
   site-wide permitted uses of --red — is already implemented in
   v3.css line ~183 (`.cap-item.is-live .num, .cap-item:hover .num,
   .cap-item:focus-within .num { color: var(--red); }`, committed by
   the integrator before this lane started). This lane's job for that
   rule is only to make `.is-live` reflect hover, focus-visible AND
   the scroll driver (v3-wall.js) — the colour itself needs no line
   here. See the report for confirmation this was checked, not
   assumed.
   ============================================================ */

/* ---------- Moment 4: numbers wall ---------- */

/* Five real tiles as committed (index.html: 6 kiosk apps, 2 languages,
   51 quiz questions, 3,000+ checks in test, Opened / 14 August 2026 —
   the archive figure is correctly absent per A4). v3.css's own
   .wall-grid is a fixed repeat(3, 1fr)/repeat(2, 1fr) grid authored
   for an assumed six tiles; v3-wall.js counts the REAL tiles at
   runtime and adds a `wall-grid--N` class (N = actual count) so this
   file lays out whatever is actually in the DOM rather than assuming
   six. Five-across reads cleanly at desktop widths for five tiles
   without the awkward 3+2 split the untouched three-column grid would
   otherwise give it. */
#numbers-wall .wall-grid.wall-grid--5 {
  grid-template-columns: repeat(5, 1fr);
  position: relative;
  z-index: 1;
}
#numbers-wall .wall-grid.wall-grid--4 { grid-template-columns: repeat(4, 1fr); position: relative; z-index: 1; }
#numbers-wall .wall-grid.wall-grid--6 { grid-template-columns: repeat(3, 1fr); position: relative; z-index: 1; }
@media (max-width: 760px) {
  #numbers-wall .wall-grid.wall-grid--5,
  #numbers-wall .wall-grid.wall-grid--4,
  #numbers-wall .wall-grid.wall-grid--6 {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Stacking context: #numbers-wall is already position:relative via
   v3.css's .v3-section rule. .inner needs to sit above the injected
   strike/marquee decoration; v3.css does not set a z-index on .inner
   so this is a genuinely new property, not an override. */
#numbers-wall .inner { position: relative; z-index: 1; }

/* Six striking "tube" columns, injected by v3-wall.js, aria-hidden,
   spanning the full section behind the content. transform-origin
   bottom so scaleY(0 -> 1) reads as rising, not falling. Filled
   fractionally brighter than the section's own light ground so the
   "circuit powering up" is visible even though (see the report) the
   base ground here is already a static light class rather than a
   scroll-driven dark-to-light transition — the strike is additive
   light on top of light, not light replacing dark. */
#numbers-wall .wall-strike-layer {
  position: absolute;
  inset: 0;
  display: flex;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
#numbers-wall .wall-strike {
  flex: 1 1 0;
  height: 100%;
  transform: scaleY(0);
  transform-origin: bottom;
  background: #f4f5f5; /* a hair brighter than --ink (#E1E5E5), the section's own ground */
  will-change: transform, filter;
}
#numbers-wall .wall-strike + .wall-strike { margin-left: 1px; }

/* Three drifting marquee columns behind the tiles: real figures only,
   copied at runtime from the DOM (never composed), mono face, low
   opacity. Drift is pure CSS (@keyframes translateY, applied by
   v3-wall.js as an inline animation-duration computed once at init,
   not per frame). The column BULGE (scaleX) is a separate transform
   on the outer column element, written by v3-wall.js's damped rAF
   loop — kept on a different element than the drift's translateY so
   the two motions never fight over the same `transform` shorthand. */
#numbers-wall .wall-marquee-layer {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: space-between;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
#numbers-wall .wall-marquee-col {
  width: 31%;
  height: 140%;
  top: -20%;
  position: relative;
  transform: scaleX(1);
  will-change: transform;
}
#numbers-wall .wall-marquee-track {
  font-family: var(--font-mono, monospace);
  font-size: clamp(1.1rem, 3vw, 1.9rem);
  line-height: 1.6;
  letter-spacing: 0.02em;
  color: var(--grey-6);
  opacity: 0.10;
  white-space: pre-line;
  text-align: center;
  will-change: transform;
}

/* Tiles sit above both decoration layers automatically via
   z-index: 1 on .inner above; no additional z-index needed on
   .wall-tile itself. */

/* Figures arrive via a mask reveal (clip-path inset, bottom-up —
   "printed onto the wall"), the one divergence from the site's
   default blur/yPercent reveal primitive that this moment is allowed.
   Rest state below is the pre-animation state v3-wall.js animates
   FROM; under reduced motion or no-JS, v3-wall.js never adds this
   class at all, so this rule never applies and the figure is at its
   plain, fully-visible default (v3.css's own .wall-figure rule). */
#numbers-wall .wall-figure.wall-figure--masked {
  clip-path: inset(0 0 100% 0);
}
#numbers-wall .wall-figure.wall-figure--revealed {
  clip-path: inset(0 0 0% 0);
}

/* ROUND 2 FIX (Bob's defect report): the previous rule here gated the
   tiles' colour on the `.wall-lit` class (added by v3-wall.js only
   once scroll progress through the strike animation reaches 0.62),
   defaulting to --grey-4 (#525252) at rest and only reaching full
   dark ink once that threshold was crossed. Confirmed by Playwright
   (getComputedStyle sampled mid-scroll, section visible, class not
   yet applied): the REST state really did render `rgb(82, 82, 82)` —
   a mid-grey, not the dark ink these are meant to read as — for the
   entire period between the section entering the viewport and the
   strike animation finishing. That is the defect: these are static
   DATA tiles (6 kiosk apps, 2 languages, 51 quiz questions, 3,000+
   checks in test, Opened/14 August 2026), not part of the "lights
   coming up" decoration, and they must never depend on a
   scroll-linked animation settling to be legible — exactly the kind
   of thing a stalled reveal (a known separate bug elsewhere in the
   reveal system) would leave permanently dim.

   Fix: figures and labels are unconditionally coloured, independent
   of `.wall-lit`. `.wall-lit` still gets toggled by v3-wall.js (kept
   for the strike-column flash it does nothing else with — grepped,
   confirmed no other consumer) but no longer drives tile text colour.

   Figure: #0E0E10 per Bob's exact spec, full display weight — this
   is a literal hex, not var(--ground) (#080808), because Bob's spec
   named this exact value and it is close but not identical to the
   token. Measured contrast against the section's actual rendered
   background (rgb(225, 229, 229), confirmed via computed style, not
   assumed from the --ink token) = 15.19:1.

   Label: dark grey #46484B (not var(--grey-4), which at 6.15:1 was
   adequate alone but v3.css's own `.wall-label { opacity: 0.7 }`
   composites any color down — grey-4 at 0.7 opacity over this
   background lands under 4.5:1 in the pre-lit path that used to
   exist). This rule also resets opacity to 1 so the AA figure below
   is what actually renders, not a blend. Measured contrast (opacity
   1, against the same rendered background) = 7.23:1. */
#numbers-wall .wall-figure { color: #0E0E10; }
#numbers-wall .wall-label { color: #46484B; opacity: 1; }

/* ---------- Moment 6: capabilities list ---------- */

#capabilities .cap-list { position: relative; }

/* A11Y FIX defect 4 (RB-V3-QA-A11Y.md DEFECT 4, "serious"): the audit
   found v3.css's global `a:focus-visible { outline: 2px solid
   var(--ink); outline-offset: 3px; }` computed-present on these links
   (getComputedStyle correctly reports outline-style/width/color) but
   confirmed by screenshot that it does not paint here specifically --
   ruled out ancestor clipping and z-index overlap by inspecting the
   whole chain, root cause not fully diagnosed. `.cap-item a` is a
   `display: grid` box (v3.css); box-shadow does not share whatever
   Chromium outline-paint quirk is in play here, so it replaces outline
   as the focus indicator on THIS component only (every other link and
   button on the site keeps the outline, which the audit screenshotted
   working correctly everywhere else). `inset` keeps the ring inside the
   anchor's own box so it can't be clipped or covered by the next
   .cap-item's border/background in the list, and its --ink colour
   against --ground (15.77:1) or the :focus-within --grey-1 hover fill
   (still >8:1) both clear WCAG 1.4.11's 3:1 floor by a wide margin --
   measured, see qa/a11y-fix-*.png before/after. The .num vermilion
   already fires on :focus-within (v3.css line ~994, unchanged); this
   adds the same colour explicitly on :focus-visible too, per the
   brief's "plus the vermilion index colour on :focus-visible". */
#capabilities .cap-item a:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--ink);
}
#capabilities .cap-item a:focus-visible .num {
  color: var(--red);
}

/* The single physical rule that slides between the six rows. Colour
   is --grey-3 per SIGNATURE-MOMENTS.md ("1px, --grey-3") — not
   vermilion; the .num colour change on the live row is v3.css's own
   rule, untouched here. */
#capabilities .cap-rule {
  position: absolute;
  top: 0;
  left: 0;
  height: 1px;
  background: var(--grey-3);
  pointer-events: none;
  will-change: transform, width;
}

/* Phone <=640px: the sliding rule reads as noise at 64px row spacing
   on a 390px screen (SIGNATURE-MOMENTS.md, stated explicitly as a
   deliberate divergence, not a defect). Replaced by a 2px left
   border on the live row. Not vermilion — var(--ink), matching the
   live row's own text colour so the indicator reads as "this text is
   lit," not as a second, uncoordinated accent colour. */
@media (max-width: 640px) {
  #capabilities .cap-rule { display: none; }
  #capabilities .cap-item { border-left: 2px solid transparent; transition: border-color 0.001ms; }
  #capabilities .cap-item.is-live { border-left-color: var(--ink); }
  html.js:not(.reduced-motion) #capabilities .cap-item { transition: border-color 0.28s ease; }
}

/* Reduced motion: the rule still exists and still jumps to the live
   row (SIGNATURE-MOMENTS.md: "The rule jumps to position with
   duration 0"), it simply never tweens — v3-wall.js drives it with a
   zero-duration quickTo under this condition, so no CSS transition
   override is needed here beyond v3.css's own global
   `* { transition-duration: 0.001ms !important }` reduced-motion
   rule, which already covers the hover-state colour/x-translate
   transitions this file does not restate. */
