/* =============================================================
   TransRisk v3.3 — modules-parallax.css

   The six product modules on the home page, as a scroll-driven rail
   of alternating rows on the navy band rather than a 3x2 card grid.

   Two things carry the section:

     1. The band itself is navy, with the dot grid and glow orbs the
        hero and the closing CTA already use. The module diagrams are
        light artwork, so on this ground they read as lit panels —
        .tr-shot--on-dark exists in shots.css for exactly that reason.

     2. As a row scrolls up, its diagram wipes in from the outer edge
        and its copy lags behind the scroll, then settles. That is
        driven from /js/modules-parallax.js, which writes --p and --pc
        onto each row.

   None of the motion is in the resting state. Everything below that
   moves is scoped to .modules-rail.is-live, a class only the script
   adds, so a static export with the script blocked still renders all
   six rows complete. Companion behaviour: /js/modules-parallax.js.
============================================================= */

/* ── Band ──────────────────────────────────────────────────── */

.modules-section {
  position: relative;
  overflow: hidden;
  background: var(--color-navy);
}

.modules-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.modules-tex {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
  background-size: 28px 28px;
}

.modules-glow {
  position: absolute;
  width: 560px;
  height: 560px;
  border-radius: 50%;
  filter: blur(120px);
  opacity: 0.16;
}

.modules-glow--a {
  background: var(--color-green);
  top: -200px;
  left: -160px;
}

.modules-glow--b {
  background: #1a4fa8;
  bottom: -240px;
  right: -180px;
}

/* Everything real sits above the texture. */
.modules-section > .container {
  position: relative;
  z-index: 1;
}

/* ── Header ────────────────────────────────────────────────── */

.modules-header {
  text-align: center;
  max-width: 820px;
  margin: 0 auto 20px;
}

.modules-subtitle {
  margin: 14px auto 0;
  text-align: center;
}

/* ── Rail ──────────────────────────────────────────────────── */

.modules-rail {
  display: flex;
  flex-direction: column;
}

/* --p is the raw scroll progress through the row, --pc the same
   progress rescaled so the wipe completes early. Both default to 1:
   the resting state is the finished state, so nothing depends on the
   script having run. */
.mod-row {
  --p: 1;
  --pc: 1;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  align-items: center;
  gap: clamp(40px, 6vw, 88px);
  padding: clamp(52px, 7vh, 84px) 0;
  min-height: 62vh;
}

/* A hairline between rows, so six of them read as a sequence rather
   than a drift. Not on the first — the header is already above it. */
.mod-row + .mod-row {
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

/* Even rows put the diagram on the left. Only the placement swaps; the
   DOM keeps title-before-image on every row, so the reading order and
   the tab order stay the same all the way down.

   The track widths are mirrored along with it. Moving the two children
   across a fixed 5fr/7fr grid would hand the wide track to the copy and
   squeeze the diagram into the narrow one on every other row — the
   diagram is the wide column throughout. */
.mod-row:nth-child(even) {
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
}

.mod-row:nth-child(even) > .mod-row-copy { grid-column: 2; grid-row: 1; }
.mod-row:nth-child(even) > .mod-row-shot { grid-column: 1; grid-row: 1; }

/* ── Copy column ───────────────────────────────────────────── */

.mod-row-step {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(74, 222, 128, 0.9);
  margin-bottom: 14px;
}

.mod-row-title {
  font-size: clamp(23px, 2.5vw, 33px);
  font-weight: 700;
  color: var(--color-white);
  line-height: 1.2;
  letter-spacing: -0.022em;
  margin: 0;
}

.mod-row-body {
  margin: 18px 0 0;
  font-size: clamp(14.5px, 1.2vw, 16px);
  line-height: 1.78;
  color: rgba(255, 255, 255, 0.68);
  max-width: 46ch;
}

/* Underlined text link rather than the old card's bare arrow disc.
   The visible text stays short and identical down all six rows — the
   module's name is three lines above it, and repeating it here read as
   a stutter. The name lives in aria-label instead, which is how the six
   deep-dive links on /product/ handle the same problem. */
.mod-row-go {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 26px;
  padding-bottom: 5px;
  font-size: 14px;
  font-weight: 600;
  color: var(--color-white);
  text-decoration: none;
  /* Short enough to fit the narrowest column; nowrap so a squeezed
     width breaks the row rather than dropping the arrow onto its own
     line. .btn-primary carries the same guard. */
  white-space: nowrap;
  border-bottom: 1px solid rgba(255, 255, 255, 0.22);
  transition: color var(--transition), border-color var(--transition);
}

.mod-row-go svg {
  flex-shrink: 0;
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.mod-row-go:hover {
  color: #4ade80;
  border-color: rgba(74, 222, 128, 0.55);
}

.mod-row-go:hover svg {
  transform: translateX(4px);
}

.mod-row-go:focus-visible {
  outline: 2px solid var(--color-green-light);
  outline-offset: 5px;
  border-radius: 2px;
}

/* ── Diagram column ────────────────────────────────────────── */

.mod-row-shot {
  margin: 0;
}

/* Qualified by .mod-row so these outrank shots.css's own `.tr-shot img`
   on specificity rather than on which stylesheet the page happens to
   load second. The figure keeps its lightbox; only the treatment
   changes, because a light diagram on navy needs the darker shadow and
   the pale edge that .tr-shot--on-dark exists to give it. */
.mod-row .mod-row-shot img {
  width: 100%;
  height: auto;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-lg);
  background: var(--color-white);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
}

/* shots.css lifts a zoomable figure and swaps in --shadow-lg on hover.
   Keep the lift, keep the shadow: --shadow-lg is tuned for a light
   ground and reads on this navy as the shadow being switched off. */
.mod-row .mod-row-shot[data-lightbox]:hover img,
.mod-row .mod-row-shot[data-lightbox]:focus-visible img {
  box-shadow: 0 36px 90px rgba(0, 0, 0, 0.5);
}

/* The row's own h3 already names the module. */
.mod-row .mod-row-shot figcaption {
  display: none;
}

/* ── Scroll-driven state ───────────────────────────────────────
   Only under .is-live, which /js/modules-parallax.js adds. Without
   the script — or under reduced-motion, where the script returns
   before adding it — every row stays exactly as declared above. */

.modules-rail.is-live .mod-row-copy {
  transform: translateY(calc((1 - var(--p)) * -40px));
}

.modules-rail.is-live .mod-row-shot {
  opacity: var(--pc);
  clip-path: inset(0 calc((1 - var(--pc)) * 100%) 0 0);
}

/* Wipe from whichever edge the diagram sits against, so it opens
   away from the copy rather than towards it. */
.modules-rail.is-live .mod-row:nth-child(even) .mod-row-shot {
  clip-path: inset(0 0 0 calc((1 - var(--pc)) * 100%));
}

/* clip-path cuts at the border box, which would shear the drop
   shadow off a finished row. The script marks a row .is-open once
   the wipe has run out, and the clip comes off. */
.modules-rail.is-live .mod-row.is-open .mod-row-shot {
  clip-path: none;
}

/* ── Responsive ────────────────────────────────────────────── */

@media (max-width: 900px) {
  .mod-row,
  .mod-row:nth-child(even) {
    grid-template-columns: 1fr;
    gap: 26px;
    padding: 40px 0;
    min-height: 0;
  }

  /* Stacked, every row reads copy-then-diagram; the alternation only
     means anything when there are two columns to alternate between. */
  .mod-row:nth-child(even) > .mod-row-copy,
  .mod-row:nth-child(even) > .mod-row-shot {
    grid-column: 1;
    grid-row: auto;
  }

  .mod-row-body {
    max-width: none;
  }

  .modules-rail.is-live .mod-row:nth-child(even) .mod-row-shot {
    clip-path: inset(0 calc((1 - var(--pc)) * 100%) 0 0);
  }
}

@media (max-width: 560px) {
  .mod-row-go {
    margin-top: 22px;
  }
}

/* ── Reduced motion ────────────────────────────────────────────
   The script bails out before going live, so these rules should
   never be needed. They are here so that a row cannot be left
   half-wiped if it ever does. */
@media (prefers-reduced-motion: reduce) {
  .modules-rail.is-live .mod-row-copy {
    transform: none;
  }

  .modules-rail.is-live .mod-row-shot,
  .modules-rail.is-live .mod-row:nth-child(even) .mod-row-shot {
    opacity: 1;
    clip-path: none;
  }
}
