/* Home page (src/pages.js home()) — sections not reused elsewhere live here
   instead of the shared style.css. */

/* ===========================================================================
   SCROLL REVEAL — shared by the sections below
   Gated on html.js (set by assets/js/main.js) so that with JavaScript off
   nothing is ever hidden. main.js adds .is-revealed as each element scrolls in.
   =========================================================================== */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 0.7s cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1),
    filter 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  filter: none;
}

/* Artwork gets its own entrance: it settles up out of a slight scale-down
   instead of sliding, which reads as the screenshot coming into focus rather
   than a block of copy arriving. Slower than the text, so the image is still
   resolving as the words around it land. */
.js [data-reveal='image'] {
  transform: translateY(26px) scale(0.965);
  filter: saturate(0.75);
  transition-duration: 0.95s;
}

/* Rails and lists stagger, so a section assembles itself rather than snapping. */
.js [data-reveal]:nth-child(2) {
  transition-delay: 0.07s;
}
.js [data-reveal]:nth-child(3) {
  transition-delay: 0.14s;
}
.js [data-reveal]:nth-child(4) {
  transition-delay: 0.21s;
}
.js [data-reveal]:nth-child(5) {
  transition-delay: 0.28s;
}

@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js [data-reveal='image'] {
    opacity: 1;
    transform: none;
    filter: none;
    transition: none;
  }
}

/* ===========================================================================
   HERO SECTION — src/components/hero.js
   =========================================================================== */

/* Full-bleed: the section spans the viewport and sits flush under the header,
   so the navy runs unbroken from the navbar into the hero. Only the *contents*
   are constrained — to the same rail the navbar uses, which is what lines the
   headline up with the brand above it. */
.hero-section {
  padding: 0;
}

.hero-card {
  position: relative;
  overflow: hidden;
  width: 100%;
  background: linear-gradient(
    180deg,
    var(--primary-950) 0%,
    var(--color-primary) 55%,
    var(--color-neutral) 100%
  );
}

/* The animated telemetry mesh — assets/js/hero-shader.js.
   Sized entirely here: the canvas cannot carry an inline style attribute
   (style-src is 'self' and build.mjs fails the build on one), and the script
   reads these dimensions back to size its drawing buffer.

   If WebGL is unavailable the canvas simply paints nothing and the card's own
   gradient underneath is what shows, so the hero never looks broken. */
.hero-shader {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  mix-blend-mode: screen;
  pointer-events: none;
}

.hero-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  /* Real bottom padding, not the 0 the old layout used. The badge overhangs
     the window by 0.75rem and the window's drop shadow reaches ~90px further,
     and .hero-card clips with overflow: hidden — so with no padding here both
     were being sliced off at the section boundary. */
  padding: clamp(2.5rem, 6vw, 4.5rem) var(--content-pad) clamp(3.5rem, 7vw, 6rem);
  text-align: center;
}

/* --- Headline block -------------------------------------------------------- */

.hero-lead {
  max-width: 62rem;
  margin-inline: auto;
}

.hero-title {
  margin: 0 0 1.1rem;
  font-family: var(--font-headline);
  font-size: clamp(2rem, 5.2vw, 3.8rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--text-on-dark);
  text-wrap: balance;
}
.hero-title-accent {
  color: var(--accent);
}
/* A brighter blue than --action-blue, which is tuned for a solid button and
   goes muddy as large display type on navy. Local to the hero on purpose. */
.hero-title-alt {
  color: #3b82f6;
}

.hero-lede {
  max-width: 60ch;
  margin: 0 auto 2rem;
  color: var(--text-on-dark-muted);
  font-size: clamp(0.98rem, 1.3vw, 1.08rem);
  line-height: 1.7;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem;
  margin: 0 0 clamp(2rem, 4vw, 3rem);
}

.btn-hero {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 52px;
  padding: 0 1.5rem;
  border: 1px solid transparent;
  border-radius: 10px;
  font-size: 0.95rem;
  font-weight: 600;
  text-decoration: none;
  transition:
    transform 0.2s ease,
    box-shadow 0.2s ease,
    background-color 0.2s ease,
    border-color 0.2s ease;
}
.btn-hero-icon {
  flex: none;
}

/* Same cyan as the navbar CTA — one accent, used once per surface. */
.btn-hero--primary {
  background: linear-gradient(
    135deg,
    var(--tertiary-400) 0%,
    var(--accent) 45%,
    var(--accent-strong) 100%
  );
  color: var(--on-accent);
  box-shadow: 0 0 26px rgb(var(--color-tertiary-rgb) / 0.4);
}
.btn-hero--primary:hover,
.btn-hero--primary:focus-visible {
  transform: translateY(-1px);
  box-shadow: 0 0 34px rgb(var(--color-tertiary-rgb) / 0.55);
}

.btn-hero--ghost {
  background: rgb(var(--color-secondary-rgb) / 0.05);
  border-color: var(--border-on-dark-strong);
  color: var(--text-on-dark);
}
.btn-hero--ghost:hover,
.btn-hero--ghost:focus-visible {
  background: rgb(var(--color-secondary-rgb) / 0.1);
  border-color: rgb(var(--color-tertiary-rgb) / 0.4);
  color: var(--text-on-dark);
}

/* --- Stage: telemetry strip, window, badge --------------------------------- */

.hero-stage {
  position: relative;
  max-width: 68rem;
  margin-inline: auto;
}

.hero-telemetry {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin: 0 0 0.85rem;
}
.hero-tele {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.8rem;
  border-radius: 999px;
  background: rgb(var(--color-primary-rgb) / 0.6);
  border: 1px solid var(--border-on-dark);
  color: var(--text-on-dark-muted);
  font-family: var(--font-label);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.hero-tele-value {
  color: var(--accent);
}
.hero-tele-dot {
  width: 0.42rem;
  height: 0.42rem;
  flex: none;
  border-radius: 50%;
  background: var(--accent);
}
.hero-tele-dot--live {
  background: #10b981;
  animation: hero-live 2.4s ease-in-out infinite;
}
@keyframes hero-live {
  50% {
    opacity: 0.25;
  }
}

/* The window, tilted just enough to read as a screen in space rather than a
   flat pasted image. transform-style is left alone: only the wrapper rotates,
   so the screenshot inside stays crisp. */
.hero-window {
  position: relative;
  margin: 0;
  border-radius: 12px;
  overflow: hidden;
  background: var(--primary-950);
  border: 1px solid rgb(var(--color-tertiary-rgb) / 0.25);
  box-shadow:
    0 0 0 1px rgb(var(--color-tertiary-rgb) / 0.12),
    0 40px 80px -30px rgb(0 0 0 / 0.85);
  transform: perspective(2200px) rotateY(-3.5deg) rotateZ(-0.7deg);
  transform-origin: 50% 50%;
}

.hero-window-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.9rem;
  background: rgb(var(--color-neutral-rgb) / 0.9);
  border-bottom: 1px solid var(--border-on-dark);
  font-family: var(--font-label);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
}

/* Three window controls drawn as one element, so the bar needs no extra
   markup for pure decoration. */
.hero-window-dots {
  flex: none;
  width: 2.6rem;
  height: 0.6rem;
  background-image:
    radial-gradient(circle 0.3rem at 0.3rem 50%, #ff5f57 98%, transparent),
    radial-gradient(circle 0.3rem at 1.3rem 50%, #febc2e 98%, transparent),
    radial-gradient(circle 0.3rem at 2.3rem 50%, #28c840 98%, transparent);
}

.hero-window-url {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text-on-dark-subtle);
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hero-window-status {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  flex: none;
  color: var(--text-on-dark-muted);
  text-transform: uppercase;
  white-space: nowrap;
}

.hero-window img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--color-neutral);
}

/* Rides across the window's lower-left corner. */
.hero-badge {
  position: absolute;
  left: clamp(0.5rem, 3vw, 2.5rem);
  bottom: clamp(-0.75rem, -1vw, -0.5rem);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  padding: 0.45rem 0.9rem;
  border-radius: 8px;
  background: rgb(var(--color-primary-rgb) / 0.92);
  border: 1px solid rgb(var(--color-tertiary-rgb) / 0.3);
  color: var(--text-on-dark-muted);
  font-family: var(--font-label);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}
.hero-badge-count {
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
  background: rgb(16 185 129 / 0.16);
  color: #10b981;
}

/* ===========================================================================
   RESPONSIVE
   =========================================================================== */

@media (max-width: 900px) {
  /* Flat below this width: the tilt costs horizontal room the screenshot
     needs, and the perspective reads as a mistake on a narrow screen. */
  .hero-window {
    transform: none;
  }
  .hero-telemetry {
    justify-content: center;
  }
}

@media (max-width: 640px) {
  .hero-inner {
    padding: clamp(2rem, 8vw, 2.75rem) var(--content-pad) clamp(2.5rem, 8vw, 3.5rem);
  }
  /* Quieter on a phone, where the copy sits directly over the mesh rather
     than beside it. */
  .hero-shader {
    opacity: 0.6;
  }
  .hero-actions {
    flex-direction: column;
    align-items: stretch;
  }
  .btn-hero {
    width: 100%;
  }
  .hero-tele {
    font-size: 0.62rem;
    padding: 0.3rem 0.65rem;
    white-space: normal;
  }
  /* Back into the flow: overlapping the corner leaves it half off a narrow
     screen, and it would cover the screenshot it is meant to annotate. */
  .hero-badge {
    position: static;
    margin: 0.85rem auto 0;
    white-space: normal;
    text-align: center;
  }
  .hero-window-url {
    display: none;
  }
}

@media (max-width: 420px) {
  .hero-window {
    border-radius: 10px;
  }
  .hero-window-status {
    font-size: 0.6rem;
  }
}

/* Short landscape phones — the headline alone would fill the viewport. */
@media (max-height: 520px) and (orientation: landscape) {
  .hero-inner {
    padding-top: clamp(1.5rem, 5vh, 2.5rem);
  }
  .hero-lede {
    margin-bottom: 1.25rem;
  }
}

@media (min-width: 1600px) {
  .hero-lead {
    max-width: 68rem;
  }
  .hero-stage {
    max-width: 74rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-tele-dot--live {
    animation: none;
  }
}

/* Lit seam at the top of a band. On a dark page the one-step tonal change
   between surfaces is too subtle to mark a boundary by itself, so each of
   these carries a thin line of light the way the footer does. */
.platform-section::before,
.flow-section::before,
.aio-section::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent,
    rgb(var(--color-tertiary-rgb) / 0.22) 30%,
    rgb(var(--color-secondary-rgb) / 0.1) 60%,
    transparent
  );
  pointer-events: none;
  z-index: 2;
}

/* ===========================================================================
   COMPLIANCE SECTION — src/components/compliance.js
   =========================================================================== */

/* Full-bleed dark band, continuing straight out of the hero — same navy at the
   seam, so the two read as one surface rather than two stacked cards. */
.compliance-section {
  position: relative;
  overflow: hidden;
  padding: var(--section-y) 0;
  background:
    radial-gradient(120% 70% at 50% 0%, rgb(var(--color-tertiary-rgb) / 0.12), transparent 60%),
    linear-gradient(
      180deg,
      var(--color-neutral) 0%,
      rgb(var(--color-primary-rgb) / 0.55) 40%,
      rgb(var(--color-primary-rgb) / 0.85) 100%
    ),
    url('/assets/img/compliance-image.png');
  background-size: cover, cover, cover;
  background-position:
    center,
    center,
    center bottom;
  background-repeat: no-repeat, no-repeat, no-repeat;
}

/* Dissolve into the light band below instead of cutting to it. */
.compliance-section::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  /* Kept inside the section's own bottom padding, so it never washes out the
     ground behind the last row of cards. */
  height: clamp(48px, 6vw, 96px);
  background: linear-gradient(180deg, transparent, var(--surface-page));
  pointer-events: none;
}

.compliance-panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--content-pad);
}

.compliance-head {
  position: relative;
  z-index: 1;
  max-width: 34rem;
  margin: 0 auto clamp(2.5rem, 5vw, 3.5rem);
  text-align: center;
}
.compliance-eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
  margin: 0 0 1rem;
  color: var(--accent);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
}
.compliance-eyebrow::before,
.compliance-eyebrow::after {
  content: '';
  width: 2rem;
  height: 1px;
  background: rgb(var(--color-tertiary-rgb) / 0.4);
}
.compliance-head h2 {
  color: var(--text-on-dark);
  margin-bottom: 0.75rem;
}
.compliance-head h2 span {
  color: var(--accent);
}
.compliance-head p {
  color: var(--text-on-dark-muted);
  margin-bottom: 0;
}

.compliance-diagram {
  position: relative;
  z-index: 1;
}

/* Positioned so the connection network can be laid over the whole row; the
   rails and the shield are lifted above it so the cables run behind them.

   --compliance-card-gap is the space between two cards. It lives here rather
   than on the rail because the stacked layout needs it too: below 980px the
   row becomes one column, and this element's own gap is then what falls
   between the last card of the left rail and the first of the right. */
.compliance-top {
  --compliance-card-gap: clamp(0.85rem, 2vw, 1.25rem);

  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(1.5rem, 5vw, 4rem);
}

.compliance-rail {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  max-width: 300px;
  gap: var(--compliance-card-gap);
}

.compliance-shield {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  width: clamp(150px, 18vw, 240px);
}

/* Arrival glow. Runs on the same 3.2s period as the cables, so the shield
   swells just as the pulses land on it. Deliberately faint — the shield is the
   focal point because it is lit, not because it flashes. */
.compliance-shield::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 155%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(var(--color-tertiary-rgb) / 0.2), transparent 62%);
  transform: translate(-50%, -50%);
  opacity: 0;
  pointer-events: none;
  animation: compliance-shield-pulse 3.2s ease-in-out infinite;
}

.compliance-shield img {
  /* Above ::before, which is absolutely positioned and would otherwise paint
     over the artwork. */
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 0 40px rgb(var(--color-tertiary-rgb) / 0.35));
  animation: shield-float 7s ease-in-out infinite;
}

@keyframes compliance-shield-pulse {
  0%,
  50% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.92);
  }
  78% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1.04);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(1.14);
  }
}

@keyframes shield-float {
  0%,
  100% {
    transform: translateY(-6px);
    filter: drop-shadow(0 0 34px rgb(var(--color-tertiary-rgb) / 0.3));
  }
  50% {
    transform: translateY(6px);
    filter: drop-shadow(0 0 52px rgb(var(--color-tertiary-rgb) / 0.45));
  }
}
@media (prefers-reduced-motion: reduce) {
  .compliance-shield img {
    animation: none;
  }
}

.compliance-item {
  display: flex;
  align-items: center;
}
.compliance-rail--left .compliance-item {
  flex-direction: row-reverse;
}

/* --- Connection network — src/components/compliance.js CONNECTIONS ---------
   One SVG stretched over the row, behind the cards and the shield. It is
   decorative, so it is aria-hidden and takes no pointer events.

   preserveAspectRatio="none" lets the viewBox act as a percentage grid: the
   anchor points stay on the cards at any width, and the only cost is that the
   curves flatten on a wide row — which is what a long cable run should do
   anyway. Stroke weight is held constant with vector-effect, so the flattening
   never thins or thickens the line.
   --------------------------------------------------------------------------- */

.compliance-network {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

/* The cable itself: always present, low and cool, so the row still reads as a
   connected network when no pulse happens to be passing. */
.compliance-connection-path {
  fill: none;
  stroke: rgb(var(--color-tertiary-rgb) / 0.26);
  stroke-width: 1.25;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* The travelling pulse.

   Each path carries pathLength="100", so one dash pattern serves all eight
   cables regardless of their real length: 3 units lit in a 50-unit period puts
   two pulses on every cable, evenly spaced. */
.compliance-data-pulse {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 3 47;
  vector-effect: non-scaling-stroke;
  animation: compliance-flow 3.2s linear infinite;
}

/* A wider, fainter copy under the bright one. This is the glow — a second
   stroke costs nothing, where an SVG filter or a drop-shadow on an element
   that repaints every frame would. */
.compliance-data-pulse--glow {
  stroke: rgb(var(--color-tertiary-rgb) / 0.3);
  stroke-width: 7;
}

/* Lowering the offset slides the dash pattern forward along the path, and every
   path is authored card -> shield, so the pulses always travel inward. One
   period is exactly the dash pattern (3 + 47), so the loop is seamless. */
@keyframes compliance-flow {
  from {
    stroke-dashoffset: 50;
  }
  to {
    stroke-dashoffset: 0;
  }
}

/* Negative delays so the cables are already mid-flight on the first frame,
   rather than firing in unison and then drifting apart. */
.compliance-connection:nth-child(1) .compliance-data-pulse {
  animation-delay: -0.1s;
}
.compliance-connection:nth-child(2) .compliance-data-pulse {
  animation-delay: -0.5s;
}
.compliance-connection:nth-child(3) .compliance-data-pulse {
  animation-delay: -0.9s;
}
.compliance-connection:nth-child(4) .compliance-data-pulse {
  animation-delay: -1.3s;
}
.compliance-connection:nth-child(5) .compliance-data-pulse {
  animation-delay: -0.3s;
}
.compliance-connection:nth-child(6) .compliance-data-pulse {
  animation-delay: -0.7s;
}
.compliance-connection:nth-child(7) .compliance-data-pulse {
  animation-delay: -1.1s;
}
.compliance-connection:nth-child(8) .compliance-data-pulse {
  animation-delay: -1.5s;
}

@media (prefers-reduced-motion: reduce) {
  /* Static cables stay; only the motion goes. */
  .compliance-data-pulse {
    animation: none;
    display: none;
  }
  .compliance-shield::before {
    animation: none;
    opacity: 0;
  }
}

.compliance-card {
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 78px;
  padding: 0.8rem 0.95rem;
  background: rgb(var(--color-secondary-rgb) / 0.05);
  border: 1px solid var(--border-on-dark);
  border-radius: var(--radius);
  transition:
    border-color 0.2s,
    background-color 0.2s,
    transform 0.2s;
}
.compliance-item:hover .compliance-card {
  border-color: rgb(var(--color-tertiary-rgb) / 0.45);
  background: rgb(var(--color-tertiary-rgb) / 0.08);
  transform: translateY(-2px);
}

.compliance-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: linear-gradient(
    160deg,
    rgb(var(--color-tertiary-rgb) / 0.22),
    rgb(var(--color-tertiary-rgb) / 0.1)
  );
  border: 1px solid rgb(var(--color-tertiary-rgb) / 0.3);
  color: var(--accent);
}
.compliance-icon svg {
  width: 18px;
  height: 18px;
}

.compliance-card h3 {
  color: var(--text-on-dark);
  font-size: 0.93rem;
  margin: 0 0 0.2rem;
}
.compliance-card p {
  color: var(--text-on-dark-subtle);
  font-size: 0.81rem;
  line-height: 1.4;
  margin: 0;
}

.compliance-bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1.5rem, 4vw, 3rem);
  margin-top: clamp(2rem, 4vw, 3rem);
}
.compliance-bottom .compliance-item {
  flex-direction: column;
  width: min(100%, 260px);
}
.compliance-bottom .compliance-card {
  flex-direction: column;
  align-items: center;
  text-align: center;
}

@media (max-width: 980px) {
  /* Stacked, this element's gap is no longer rail-to-shield — it is the space
     between the last card of one rail and the first of the next. Matching the
     card gap is what keeps all eight evenly spaced. */
  .compliance-top {
    flex-direction: column;
    gap: var(--compliance-card-gap);
  }
  /* The shield's breathing room now has to come from its own margin, since the
     gap above shrank to the card spacing. */
  .compliance-shield {
    order: -1;
    margin-bottom: 2.25rem;
  }
  .compliance-rail {
    max-width: none;
    width: 100%;
  }
  .compliance-item,
  .compliance-rail--left .compliance-item,
  .compliance-bottom .compliance-item {
    flex-direction: row;
  }
  /* The row stacks into a single column here, so the cables no longer join
     anything — they would cut across the cards. Drop the whole network rather
     than leave connections pointing at nothing. */
  .compliance-network {
    display: none;
  }
  .compliance-bottom .compliance-card {
    flex-direction: row;
    align-items: flex-start;
    text-align: left;
  }
}

@media (max-width: 640px) {
  /* One value, so the rail gap and the rail-to-rail gap tighten together. */
  .compliance-top {
    --compliance-card-gap: 0.7rem;
  }
  .compliance-bottom {
    gap: 0.7rem;
  }
  .compliance-bottom .compliance-item {
    width: 100%;
  }
}

/* ===========================================================================
   ALL-IN-ONE SECTION — src/components/all-in-one.js
   Light card (unlike the two dark sections above) with a vertical timeline of
   feature steps on the left and the product art on the right.
   =========================================================================== */

/* First of three light bands. They share a background family and differ only in
   tint, so the eye reads one continuous light region with three topics in it
   rather than three cards — the washes are what mark the boundaries. */
.aio-section {
  position: relative;
  padding: var(--section-y) 0 var(--section-y-tight);
  background:
    radial-gradient(70% 55% at 12% 0%, rgb(var(--color-tertiary-rgb) / 0.09), transparent 62%),
    radial-gradient(60% 55% at 100% 100%, rgb(var(--color-primary-rgb) / 0.05), transparent 58%),
    /* resolves into the white band below, so the two light sections meet
       without a visible step */
    linear-gradient(
        180deg,
        var(--surface-page) 0%,
        var(--surface-page) 72%,
        var(--surface-raised) 100%
      );
}

.aio-panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--content-pad);
}

.aio-head {
  position: relative;
  z-index: 1;
  max-width: 42rem;
  margin: 0 auto clamp(2.5rem, 5vw, 3.5rem);
  text-align: center;
}

/* The label wraps to two lines on a phone, so it needs its own leading and
   enough room under it to clear the heading. The margin scales with the
   viewport because the heading it has to sit clear of does too. */
.aio-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  max-width: 100%;
  margin: 0 0 clamp(1.5rem, 4vw, 1.9rem);
  padding: 0.55rem 1.05rem;
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid var(--line);
  color: var(--navy);
  font-size: 0.76rem;
  font-weight: 700;
  line-height: 1.45;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  box-shadow: var(--shadow-sm);
}
.aio-eyebrow svg {
  color: var(--accent-on-light);
  flex-shrink: 0;
}

.aio-head h2 {
  margin-bottom: 0.75rem;
}
.aio-head h2 span {
  color: var(--accent-on-light);
}
.aio-head p {
  color: var(--muted);
  margin-bottom: 0;
  font-size: 1.02rem;
}

.aio-body {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 3.5rem);
}

/* Capped and centred in its column: left to fill a 1600px rail the step cards
   stretch to ~780px each and the text strands along the left edge. */
.aio-body {
  justify-items: center;
}

.aio-timeline {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  width: 100%;
  max-width: 640px;
}
.aio-timeline::before {
  content: '';
  position: absolute;
  right: 23px;
  top: 30px;
  bottom: 30px;
  width: 2px;
  background: var(--line);
}

.aio-step {
  position: relative;
  display: flex;
  align-items: center;
}

.aio-dot {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  width: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.aio-dot::before {
  content: '';
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--neutral-600);
  transition:
    border-color 0.2s,
    background-color 0.2s,
    box-shadow 0.2s;
}
.aio-step:hover .aio-dot::before {
  border-color: var(--accent-on-light);
  background: var(--accent-on-light);
  box-shadow: 0 0 0 4px rgb(var(--color-tertiary-rgb) / 0.18);
}

.aio-card {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1rem 1.15rem;
  box-shadow: var(--shadow-sm);
  transition:
    border-color 0.2s,
    box-shadow 0.2s,
    transform 0.2s,
    background-color 0.2s;
}
.aio-card:hover,
.aio-card:focus-visible {
  border-color: var(--accent-on-light);
  background: var(--surface-sunken);
  box-shadow: 0 14px 28px rgb(var(--color-tertiary-rgb) / 0.18);
  transform: translateX(6px);
}

.aio-icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(
    160deg,
    rgb(var(--color-tertiary-rgb) / 0.18),
    rgb(var(--color-tertiary-rgb) / 0.04)
  );
  border: 1px solid rgb(var(--color-tertiary-rgb) / 0.25);
  color: var(--accent-on-light);
  transition: transform 0.2s;
}
.aio-card:hover .aio-icon {
  transform: scale(1.08) rotate(-4deg);
}
.aio-icon svg {
  width: 20px;
  height: 20px;
}

.aio-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.aio-card-title {
  font-weight: 700;
  font-size: 1rem;
  color: var(--ink);
}
.aio-card-blurb {
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.4;
}

.aio-chevron {
  flex-shrink: 0;
  color: var(--muted);
  transition:
    transform 0.2s,
    color 0.2s;
}
.aio-card:hover .aio-chevron {
  transform: translateX(4px);
  color: var(--accent-on-light);
}

.aio-art {
  display: flex;
  align-items: center;
  justify-content: center;
}
.aio-art img {
  width: 100%;
  max-width: var(--art-max);
  height: auto;
  display: block;
}

@media (max-width: 980px) {
  .aio-body {
    grid-template-columns: 1fr;
  }
  .aio-art {
    order: -1;
    margin-bottom: 1rem;
  }
}

@media (max-width: 640px) {
  .aio-card {
    padding: 0.9rem 1rem;
    gap: 0.65rem;
  }
  .aio-icon {
    width: 38px;
    height: 38px;
  }
  .aio-icon svg {
    width: 18px;
    height: 18px;
  }
  .aio-card-title {
    font-size: 0.93rem;
  }
  .aio-card-blurb {
    font-size: 0.81rem;
  }
  .aio-dot {
    width: 34px;
  }
  .aio-timeline::before {
    right: 17px;
  }
  .aio-chevron {
    display: none;
  }
}

/* ===========================================================================
   PLATFORM SECTION — src/components/platform.js
   White bordered panel: pitch copy and a checklist on the left, product
   screenshot on the right.
   =========================================================================== */

/* Second light band — plain white, so it reads as a step forward from the
   tinted section above without needing a border to say so. */
.platform-section {
  position: relative;
  padding: var(--section-y-tight) 0;
  background: var(--surface-raised);
}

.platform-panel {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--content-pad);
}

.platform-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 3.5rem);
}

.platform-eyebrow {
  margin: 0 0 1rem;
  color: var(--accent-on-light);
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
}

.platform-content h2 {
  margin-bottom: 0.9rem;
  font-size: clamp(1.65rem, 2.9vw, 2.2rem);
  line-height: 1.18;
}

.platform-lede {
  max-width: 44ch;
  margin-bottom: 1.6rem;
  color: var(--body);
  font-size: 0.97rem;
}

.platform-points {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
.platform-points li {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  color: var(--ink);
  font-size: 0.97rem;
  font-weight: 600;
}
.platform-points svg {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  margin-top: 0.1rem;
  color: var(--accent-on-light);
}

.platform-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.9rem 1.75rem;
  border-radius: 6px;
  background: var(--action-on-light);
  color: var(--text-on-dark);
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  box-shadow: 0 10px 22px rgb(var(--color-primary-rgb) / 0.22);
  transition:
    background-color 0.2s,
    transform 0.2s,
    box-shadow 0.2s;
}
.platform-cta:hover,
.platform-cta:focus-visible {
  background: var(--action-on-light-hover);
  color: var(--text-on-dark);
  transform: translateY(-1px);
  box-shadow: 0 14px 28px rgb(var(--color-primary-rgb) / 0.3);
}
.platform-cta svg {
  width: 34px;
  height: 12px;
  transition: transform 0.2s;
}
.platform-cta:hover svg {
  transform: translateX(4px);
}

.platform-visual {
  display: flex;
  justify-content: center;
}
.platform-visual img {
  display: block;
  width: 100%;
  max-width: calc(var(--art-max) + 80px);
  height: auto;
  border-radius: 8px;
  background: var(--color-primary);
}

@media (max-width: 980px) {
  .platform-body {
    grid-template-columns: 1fr;
  }
  .platform-lede {
    max-width: none;
  }
}

@media (max-width: 640px) {
  .platform-points li {
    font-size: 0.95rem;
  }
  .platform-cta {
    width: 100%;
    justify-content: center;
  }
}

/* ===========================================================================
   HOW IT WORKS SECTION — src/components/how-it-works.js
   Five steps joined by dotted connectors. A "current" runs Connect -> Improve
   on a 3s loop: each connector wipes blue, and each node pulses as the current
   reaches it. It runs on a timer, independent of the pointer.

   Geometry note: connectors are pseudo-elements on the step they run *into*,
   positioned against the previous node using the known column gap and node
   size, so the same two rules serve both the 5-across row and the mobile
   snake. ::before is the dotted base, ::after is the travelling current.
   =========================================================================== */

/* Last light band, fading back down toward the dark closer. */
.flow-section {
  position: relative;
  padding: var(--section-y-tight) 0 var(--section-y);
  background: linear-gradient(180deg, var(--surface-raised) 0%, var(--surface-page) 100%);
}

.flow-panel {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--content-pad);
}

.flow-head {
  text-align: center;
  margin-bottom: clamp(2.25rem, 4.5vw, 3.25rem);
}
.flow-eyebrow {
  margin: 0 0 0.85rem;
  color: var(--accent-on-light);
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.flow-head h2 {
  margin: 0;
  font-size: clamp(1.6rem, 3vw, 2.25rem);
  line-height: 1.2;
}

.flow-steps {
  --flow-node: 76px;
  --flow-gap: clamp(1rem, 2.5vw, 2rem);
  --flow-stalk: 6px;

  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  column-gap: var(--flow-gap);
  row-gap: 2.75rem;
}

.flow-step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* --- Node ------------------------------------------------------------------ */

.flow-node {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--flow-node);
  height: var(--flow-node);
  border-radius: 50%;
  background: var(--paper);
  border: 1px solid var(--line);
  color: var(--muted);
  box-shadow: 0 6px 16px rgb(0 0 0 / 0.35);
  animation: flow-node-pulse 3s ease-in-out infinite;
}
.flow-node svg {
  width: 28px;
  height: 28px;
}

/* color is inherited by the icon through currentColor, so one animation
   lights the ring and the glyph together. */
@keyframes flow-node-pulse {
  0%,
  20%,
  100% {
    color: var(--muted);
    border-color: var(--line);
    box-shadow: 0 6px 16px rgb(0 0 0 / 0.35);
    transform: translateY(0) scale(1);
  }
  7% {
    color: var(--accent-on-light);
    border-color: rgb(var(--color-tertiary-rgb) / 0.6);
    box-shadow:
      0 6px 18px rgb(0 0 0 / 0.35),
      0 0 0 6px rgb(var(--color-tertiary-rgb) / 0.14);
    transform: translateY(-4px) scale(1.06);
  }
}

.flow-label {
  margin: 1.1rem 0 0.5rem;
  font-size: 1rem;
  font-weight: 700;
  color: var(--ink);
}
.flow-num {
  color: var(--accent-on-light);
}

.flow-blurb {
  margin: 0;
  max-width: 22ch;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
}

/* --- Connectors ------------------------------------------------------------ */

.flow-step + .flow-step::before,
.flow-step + .flow-step::after {
  content: '';
  position: absolute;
  top: calc(var(--flow-node) / 2 - 1px);
  height: 2px;
  /* from the previous node's right edge to this node's left edge */
  left: calc(-50% - var(--flow-gap) + var(--flow-node) / 2 + var(--flow-stalk));
  right: calc(50% + var(--flow-node) / 2 + var(--flow-stalk));
}

.flow-step + .flow-step::before {
  background: repeating-linear-gradient(to right, var(--neutral-700) 0 3px, transparent 3px 9px);
}

.flow-step + .flow-step::after {
  background: linear-gradient(
    to right,
    rgb(var(--color-tertiary-rgb) / 0.4),
    var(--accent-on-light)
  );
  transform-origin: left center;
  transform: scaleX(0);
  opacity: 0;
  animation: flow-wipe-x 3s linear infinite;
}

@keyframes flow-wipe-x {
  0% {
    transform: scaleX(0);
    opacity: 1;
  }
  20% {
    transform: scaleX(1);
    opacity: 1;
  }
  38% {
    transform: scaleX(1);
    opacity: 0;
  }
  38.01%,
  100% {
    transform: scaleX(0);
    opacity: 0;
  }
}

@keyframes flow-wipe-y {
  0% {
    transform: scaleY(0);
    opacity: 1;
  }
  20% {
    transform: scaleY(1);
    opacity: 1;
  }
  38% {
    transform: scaleY(1);
    opacity: 0;
  }
  38.01%,
  100% {
    transform: scaleY(0);
    opacity: 0;
  }
}

/* The current reaches node k at k x 0.6s within the 3s loop. Each connector
   starts one segment earlier, so it finishes wiping exactly as the node it
   feeds lights up. */
.flow-step:nth-child(1) .flow-node {
  animation-delay: 0s;
}
.flow-step:nth-child(2) .flow-node {
  animation-delay: 0.6s;
}
.flow-step:nth-child(3) .flow-node {
  animation-delay: 1.2s;
}
.flow-step:nth-child(4) .flow-node {
  animation-delay: 1.8s;
}
.flow-step:nth-child(5) .flow-node {
  animation-delay: 2.4s;
}

.flow-step:nth-child(2)::after {
  animation-delay: 0s;
}
.flow-step:nth-child(3)::after {
  animation-delay: 0.6s;
}
.flow-step:nth-child(4)::after {
  animation-delay: 1.2s;
}
.flow-step:nth-child(5)::after {
  animation-delay: 1.8s;
}

/* --- Mobile snake ----------------------------------------------------------
   Two columns walked in an S: 1 -> 2 down to 3 -> 4 down to 5. Horizontal
   connectors mirror on the right-to-left leg; vertical ones sit in the row
   gap directly above their node. */

@media (max-width: 900px) {
  .flow-steps {
    --flow-node: 62px;
    --flow-gap: clamp(1.25rem, 6vw, 2.5rem);
    --flow-row: 3rem;

    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: var(--flow-row);
  }

  .flow-step:nth-child(1) {
    grid-column: 1;
    grid-row: 1;
  }
  .flow-step:nth-child(2) {
    grid-column: 2;
    grid-row: 1;
  }
  .flow-step:nth-child(3) {
    grid-column: 2;
    grid-row: 2;
  }
  .flow-step:nth-child(4) {
    grid-column: 1;
    grid-row: 2;
  }
  .flow-step:nth-child(5) {
    grid-column: 1;
    grid-row: 3;
  }

  /* right-to-left leg: 3 -> 4, drawn on 4's right */
  .flow-step:nth-child(4)::before,
  .flow-step:nth-child(4)::after {
    left: calc(50% + var(--flow-node) / 2 + var(--flow-stalk));
    right: calc(-50% - var(--flow-gap) + var(--flow-node) / 2 + var(--flow-stalk));
  }
  .flow-step:nth-child(4)::before {
    background: repeating-linear-gradient(to left, var(--neutral-700) 0 3px, transparent 3px 9px);
  }
  .flow-step:nth-child(4)::after {
    background: linear-gradient(
      to left,
      rgb(var(--color-tertiary-rgb) / 0.4),
      var(--accent-on-light)
    );
    transform-origin: right center;
  }

  /* downward legs: 2 -> 3 and 4 -> 5, drawn in the row gap above the node */
  /* Grid items stretch, so the step box starts at the row boundary and its
     node sits flush with the top: the gap above is exactly --flow-row. */
  .flow-step:nth-child(3)::before,
  .flow-step:nth-child(3)::after,
  .flow-step:nth-child(5)::before,
  .flow-step:nth-child(5)::after {
    top: calc(0px - var(--flow-row));
    bottom: auto;
    left: calc(50% - 1px);
    right: auto;
    width: 2px;
    height: calc(var(--flow-row) - var(--flow-stalk));
  }
  .flow-step:nth-child(3)::before,
  .flow-step:nth-child(5)::before {
    background: repeating-linear-gradient(to bottom, var(--neutral-700) 0 3px, transparent 3px 9px);
  }
  .flow-step:nth-child(3)::after,
  .flow-step:nth-child(5)::after {
    background: linear-gradient(
      to bottom,
      rgb(var(--color-tertiary-rgb) / 0.4),
      var(--accent-on-light)
    );
    transform-origin: center top;
    transform: scaleY(0);
    animation-name: flow-wipe-y;
  }

  .flow-node svg {
    width: 24px;
    height: 24px;
  }
  .flow-label {
    margin-top: 0.9rem;
    font-size: 0.94rem;
  }
  .flow-blurb {
    font-size: 0.84rem;
  }
}

@media (max-width: 400px) {
  .flow-blurb {
    font-size: 0.8rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .flow-node {
    animation: none;
  }
  .flow-step + .flow-step::after {
    animation: none;
    opacity: 0;
  }
}

/* ===========================================================================
   HOME CTA — src/components/cta.js
   The closing band. It has no bottom padding and square bottom corners so it
   meets the footer with no seam; the large top-left radius is the only
   rounded corner, matching the design.
   =========================================================================== */

/* The panel is the band: it sits on the content rail with the page showing to
   its left, right and top, and runs off the bottom into the full-width footer.
   The one large top-left corner is the only radius — the bottom is square so
   there is no seam where the footer starts. */
.home-cta {
  padding: var(--section-y-tight) 0 0;
  background: var(--surface-page);
}

.home-cta-panel {
  position: relative;
  overflow: hidden;
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(1.75rem, 4vw, 3.5rem);
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding: clamp(2.5rem, 4.5vw, 4.25rem) clamp(1.75rem, 3.5vw, 3.5rem);
  border-radius: clamp(2rem, 4vw, 3.75rem) 0 0 0;
  background:
    radial-gradient(70% 120% at 85% 50%, rgb(var(--color-tertiary-rgb) / 0.14), transparent 60%),
    linear-gradient(180deg, var(--neutral-800) 0%, var(--color-neutral) 100%);
  /* Lifted a step above the page ground and edged in light, so the one large
     corner still reads now that the ground behind it is dark too. */
  box-shadow:
    inset 1px 1px 0 rgb(var(--color-secondary-rgb) / 0.07),
    0 -18px 40px -24px rgb(0 0 0 / 0.8);
}

/* Particle wash, reusing the compliance texture. */
.home-cta-panel::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('/assets/img/compliance-image.png');
  background-size: cover;
  background-position: center;
  opacity: 0.5;
  mix-blend-mode: screen;
  pointer-events: none;
}

.home-cta-copy,
.home-cta-actions {
  position: relative;
  z-index: 1;
}

.home-cta-copy h2 {
  margin: 0 0 1.1rem;
  color: var(--text-on-dark);
  font-size: clamp(1.5rem, 2.9vw, 2.35rem);
  line-height: 1.22;
  max-width: 20ch;
}
.home-cta-copy p {
  margin: 0;
  max-width: 44ch;
  color: var(--text-on-dark-muted);
  font-size: 1rem;
}

/* Capped and pinned to the right of its column. Stretching to fill the column
   gave a button the width of half the screen on a large monitor — a call to
   action reads as one when it looks clickable, not when it is huge. */
.home-cta-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2.25rem;
  width: 100%;
  max-width: 21rem;
  margin-left: auto;
}

/* Solid blue rectangle: square-cornered on purpose, so it reads as the one
   hard-edged element against the rounded panel. */
.home-cta-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 1.3rem 1.75rem;
  border-radius: 3px;
  background: var(--action-blue);
  color: var(--text-on-dark);
  font-size: 1.02rem;
  font-weight: 700;
  text-decoration: none;
  transition:
    background-color 0.2s,
    transform 0.2s,
    box-shadow 0.2s;
}
.home-cta-btn:hover,
.home-cta-btn:focus-visible {
  background: var(--action-blue-hover);
  color: var(--text-on-dark);
  transform: translateY(-2px);
  box-shadow: 0 18px 36px rgb(var(--color-primary-rgb) / 0.55);
}

/* Centred under the button, as a plain link — no box competing with it. */
.home-cta-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
  color: var(--text-on-dark);
  font-size: 1.02rem;
  font-weight: 600;
  text-decoration: none;
  transition: color 0.2s;
}
.home-cta-link:hover,
.home-cta-link:focus-visible {
  color: var(--accent);
}

.home-cta-btn svg,
.home-cta-link svg {
  width: 34px;
  height: 12px;
  flex-shrink: 0;
  transition: transform 0.2s;
}
.home-cta-btn:hover svg,
.home-cta-link:hover svg {
  transform: translateX(4px);
}

@media (max-width: 860px) {
  .home-cta-panel {
    grid-template-columns: minmax(0, 1fr);
    border-radius: clamp(1.5rem, 6vw, 2.5rem) 0 0 0;
  }
  .home-cta-copy h2 {
    max-width: none;
  }
  .home-cta-actions {
    align-items: stretch;
    max-width: none;
    margin-left: 0;
  }
  .home-cta-btn,
  .home-cta-link {
    width: 100%;
  }
}

@media (max-width: 480px) {
  .home-cta-panel {
    padding: 1.75rem 1.15rem 2rem;
  }
  .home-cta-btn {
    padding: 0.95rem 1.25rem;
    font-size: 0.95rem;
  }
  .home-cta-btn svg,
  .home-cta-link svg {
    width: 24px;
  }
}

/* ===========================================================================
   LARGE SCREENS — 1600px and up
   The rail widens in style.css; these are the per-section adjustments that
   keep each band's proportions instead of just letting everything stretch.
   =========================================================================== */

@media (min-width: 1600px) {
  /* The hero has its own wide-screen rules alongside the rest of its block. */

  /* Compliance — the rails grow with the diagram so the shield stays the
     centre of gravity rather than a speck between two narrow columns. */
  .compliance-rail {
    max-width: 380px;
  }
  .compliance-shield {
    width: clamp(220px, 15vw, 300px);
  }
  .compliance-head {
    max-width: 40rem;
  }

  /* All-in-one / platform — headings and copy scale with the band. */
  .aio-head {
    max-width: 48rem;
  }
  .aio-head p {
    font-size: 1.08rem;
  }
  .aio-timeline {
    max-width: 680px;
  }

  .platform-lede {
    max-width: 48ch;
    font-size: 1.04rem;
  }

  /* How it works — five nodes across a 1440px rail get lost at 76px. */
  .flow-steps {
    --flow-node: 88px;
  }
  .flow-node svg {
    width: 32px;
    height: 32px;
  }
  .flow-label {
    font-size: 1.06rem;
  }
  .flow-blurb {
    max-width: 24ch;
    font-size: 0.95rem;
  }

  /* CTA — the copy column has room for a longer measure. */
  .home-cta-copy p {
    font-size: 1.04rem;
  }
  .home-cta-actions {
    max-width: 24rem;
  }
}
