/* motion.css: the shared motion system of the public site (docs/MOTION.md). Platform layer, tokens only.
   Everything here is progressive: without JavaScript, with prefers-reduced-motion or in print the page
   is static and complete. The <html> classes come from an inline script in <head> (before first paint)
   and from motion.js:
     .motion         JS on and motion allowed (every effect below is scoped to it)
     .motion-native  CSS scroll-driven animations supported (animation-timeline)
     .motion-ready   motion.js attached its observers (hidden start states only exist with it)
   Only transform, opacity and clip-path are animated. */

:root {
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --dur-reveal: 720ms;
  --dur-intro: 900ms;
  --reveal-y: 24px;
  --stagger: 70ms;
  --parallax-amp: 5%;
  --parallax-scale: 1.12;
}
@media (max-width: 767.98px) {
  :root { --reveal-y: 16px; --parallax-amp: 2.5%; --parallax-scale: 1.06; --dur-reveal: 600ms; }
}

/* Scroll progress: --p goes from 0 to 1 while an element crosses the viewport (see docs/MOTION.md §6).
   Default 1 = final state, so a page without the timeline or without motion.js looks finished. */
@property --p {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}
@keyframes m-progress { from { --p: 0; } to { --p: 1; } }

html.motion.motion-native :is([data-progress], [data-parallax]) {
  animation: m-progress linear both;
  animation-timeline: view();
  animation-range: cover var(--p-start, 0%) cover var(--p-end, 100%);
}
html.motion.motion-native [data-progress="enter"] { animation-range: entry 0% entry 100%; }
html.motion.motion-native [data-progress="contain"] { animation-range: contain 0% contain 100%; }
html.motion.motion-native [data-progress="exit"] { animation-range: exit 0% exit 100%; }
html.motion.motion-native [data-progress="top"] { animation-timeline: scroll(root block); animation-range: 0px 100vh; }
html.motion.motion-native [data-progress="page"] { animation-timeline: scroll(root block); animation-range: normal; }

/* ---------- Effect helpers (read --p) ---------- */
html.motion:is(.motion-native, .motion-ready) .fx-fill-x { transform-origin: 0 50%; transform: scaleX(var(--p)); }
html.motion:is(.motion-native, .motion-ready) .fx-fill-y { transform-origin: 50% 100%; transform: scaleY(var(--p)); }

/* Parallax-lite for photos: the image is scaled up a little so the drift never shows an edge. */
[data-parallax] { overflow: hidden; }
html.motion:is(.motion-native, .motion-ready) :is([data-parallax] > img, [data-parallax] > picture > img, .fx-parallax) {
  transform: translate3d(0, calc((var(--p) - .5) * 2 * var(--parallax-amp)), 0) scale(var(--parallax-scale));
}

/* ---------- Reveal on enter (time based, triggered once by motion.js) ---------- */
html.motion.motion-ready [data-reveal]:not(.is-in),
html.motion.motion-ready [data-reveal-stagger]:not(.is-in) > * {
  opacity: 0;
  transform: translate3d(0, var(--reveal-y), 0);
}
html.motion.motion-ready [data-reveal="fade"]:not(.is-in) { transform: none; }
html.motion.motion-ready [data-reveal="scale"]:not(.is-in) { transform: scale(.96); }
html.motion.motion-ready [data-reveal="left"]:not(.is-in) { transform: translate3d(calc(var(--reveal-y) * -1), 0, 0); }
html.motion.motion-ready [data-reveal="right"]:not(.is-in) { transform: translate3d(var(--reveal-y), 0, 0); }
html.motion.motion-ready [data-reveal="clip"]:not(.is-in) { opacity: 1; transform: none; clip-path: inset(0 0 100% 0 round var(--r-lg)); }
html.motion.motion-ready [data-reveal].is-revealing,
html.motion.motion-ready [data-reveal-stagger].is-revealing > * {
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out),
    clip-path calc(var(--dur-reveal) * 1.3) var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger) + var(--reveal-delay, 0ms));
}
html.motion.motion-ready [data-reveal="clip"].is-in { clip-path: inset(0 0 0 0 round var(--r-lg)); }

/* ---------- Page load entrance (hero only, CSS keyframes, no JS needed) ---------- */
@keyframes m-intro-rise {
  from { opacity: 0; transform: translate3d(0, 28px, 0); }
  to { opacity: 1; transform: none; }
}
@keyframes m-intro-clip {
  from { clip-path: inset(7% 5% 7% 5% round var(--r-xl)); transform: scale(1.06); }
  to { clip-path: inset(0 0 0 0 round var(--r-xl)); transform: none; }
}
@keyframes m-intro-fade { from { opacity: 0; } to { opacity: 1; } }
html.motion [data-intro] {
  animation: m-intro-rise var(--dur-intro) var(--ease-out) both;
  animation-delay: calc(var(--intro-i, 0) * 90ms + 80ms);
}
html.motion [data-intro="clip"] { animation-name: m-intro-clip; animation-duration: 1200ms; animation-delay: 0ms; }
html.motion [data-intro="fade"] { animation-name: m-intro-fade; }
@media (max-width: 767.98px) {
  @keyframes m-intro-clip-sm { from { clip-path: inset(0 0 12% 0); } to { clip-path: inset(0 0 0 0); } }
  html.motion [data-intro="clip"] { animation-name: m-intro-clip-sm; animation-duration: 900ms; }
}

/* ---------- Auto motion of shared components (docs/MOTION.md §16) ---------- */
/* Stripe meter: wipes in from the left the first time it is seen. */
html.motion.motion-ready .meter:not(.is-in) { clip-path: inset(0 100% 0 0); }
html.motion.motion-ready .meter.is-revealing { transition: clip-path 1100ms var(--ease-out) 120ms; }
html.motion.motion-ready .meter.is-in { clip-path: inset(0 0 0 0); }
/* Bar chart (.bars > .bar-row > .bar-track > .bar): bars grow from the axis, one after another. */
html.motion.motion-ready .bars:not(.is-in) .bar { transform: scaleX(0); }
html.motion.motion-ready .bars .bar { transform-origin: 0 50%; }
html.motion.motion-ready .bars.is-revealing .bar { transition: transform 900ms var(--ease-out); }
html.motion.motion-ready .bars.is-revealing .bar-row:nth-child(2) .bar { transition-delay: 90ms; }
html.motion.motion-ready .bars.is-revealing .bar-row:nth-child(3) .bar { transition-delay: 180ms; }
html.motion.motion-ready .bars.is-revealing .bar-row:nth-child(4) .bar { transition-delay: 270ms; }
html.motion.motion-ready .bars.is-revealing .bar-row:nth-child(n+5) .bar { transition-delay: 360ms; }

/* ---------- Counters and rolling digits (motion.js builds the markup) ---------- */
.count-live { display: inline-block; font-variant-numeric: tabular-nums lining-nums; }
.roll-host { position: relative; display: inline-block; }
.roll-host.is-rolling { color: transparent; }
.roll-host .roll {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-start;
  color: var(--roll-color, currentColor);
  pointer-events: none;
}
.roll-sep { white-space: pre; }
.roll-col { display: block; height: 1lh; overflow: hidden; }
@supports not (height: 1lh) { .roll-col { height: 1em; } }
.roll-strip {
  display: flex;
  flex-direction: column;
  transform: translate3d(0, 0, 0);
  transition: transform 1400ms var(--ease-out);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.roll-strip > span { display: block; height: 1lh; }
@supports not (height: 1lh) { .roll-strip > span { height: 1em; } }
.roll-host.is-rolled .roll-strip { transform: translate3d(0, calc(var(--d) * -1lh), 0); }
@supports not (height: 1lh) { .roll-host.is-rolled .roll-strip { transform: translate3d(0, calc(var(--d) * -1em), 0); } }

/* ---------- Stripe progress (logo bar rhythm, bar : gap = 13 : 5 ≈ 2.6 : 1) ---------- */
.stripe-progress {
  --sp-bar: var(--ink);
  --sp-track: var(--line);
  position: relative;
  display: block;
  height: 6px;
  border-radius: 1px;
  background: linear-gradient(90deg, var(--sp-track) 13px, transparent 13px) 0 0 / 18px 100% repeat-x;
}
.stripe-progress > span {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--sp-bar) 13px, transparent 13px) 0 0 / 18px 100% repeat-x;
}
html.motion:is(.motion-native, .motion-ready) .stripe-progress > span { clip-path: inset(0 calc((1 - var(--p)) * 100%) 0 0); }
.stripe-progress--band { --sp-bar: var(--on-band); --sp-track: var(--on-band-line); }
.stripe-progress--accent { --sp-bar: var(--accent); }

/* Stepped stripe: N parts, done parts filled, the active part in the accent colour. */
.stripe-steps { display: grid; grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); gap: 5px; height: 6px; }
.stripe-steps > span { display: block; border-radius: 1px; background: var(--line); transition: background-color var(--dur-2) var(--ease); }
.stripe-steps > span.is-done { background: var(--ink); }
.stripe-steps > span.is-active { background: var(--accent); }
:is(.section--navy, .on-band) .stripe-steps > span { background: var(--on-band-line); }
:is(.section--navy, .on-band) .stripe-steps > span.is-done { background: var(--on-band); }
:is(.section--navy, .on-band) .stripe-steps > span.is-active { background: var(--accent); }

/* ---------- Horizontal rail (scroll snap, no autoplay) ---------- */
.rail { --rail-w: min(84vw, 420px); position: relative; display: flex; flex-direction: column; gap: var(--sp-4); min-width: 0; }
.rail-track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--rail-w);
  gap: var(--grid-gap);
  margin: 0 calc(var(--gutter) * -1);
  padding: 4px var(--gutter) var(--sp-2);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter);
  scrollbar-width: none;
  list-style: none;
}
.rail-track::-webkit-scrollbar { display: none; }
.rail-track > * { scroll-snap-align: start; min-width: 0; }
.rail-track:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.rail-nav { display: flex; gap: var(--sp-2); align-self: flex-end; }
.rail-btn {
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  border: 1.5px solid currentColor;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--ink);
  transition: background-color var(--dur-1) var(--ease), opacity var(--dur-1) var(--ease);
}
.rail-btn:hover { background: var(--bg-alt); }
.rail-btn:disabled { opacity: .35; cursor: default; background: transparent; }
:is(.section--navy, .on-band) .rail-btn { color: var(--on-band); }
:is(.section--navy, .on-band) .rail-btn:hover { background: var(--band-raised); }
.rail.is-static .rail-nav, .rail.is-static .rail-progress { display: none; }
.rail-progress { position: relative; height: 3px; background: var(--line); border-radius: 2px; overflow: hidden; }
/* Thumb: as wide as the visible share of the rail, moved along by the scroll share (--p, set by motion.js). */
.rail-progress > span { position: absolute; inset: 0; background: var(--ink); transform-origin: 0 50%; transform: translateX(calc(var(--rail-p, 0) * (1 - var(--rail-view, 1)) * 100%)) scaleX(var(--rail-view, 1)); }
:is(.section--navy, .on-band) .rail-progress { background: var(--on-band-line); }
:is(.section--navy, .on-band) .rail-progress > span { background: var(--on-band); }

/* ---------- Sticky storytelling ---------- */
.story { display: grid; gap: var(--sp-8); }
.story-media { position: relative; min-width: 0; }
/* Frames are the visual of each step (the step text is always in the list). SSR marks the first
   frame active, so without JavaScript the first visual shows and the others stay out of the way. */
/* Frames share one grid cell (stacked, the tallest sets the height): directly in .story-media or,
   when the media column holds more than the frames, inside a .story-frames wrapper. */
.story-media, .story-frames { display: grid; grid-template-columns: minmax(0, 1fr); }
.story-media > .story-frame, .story-frames > .story-frame { grid-area: 1 / 1; }
.story-frame:not(.is-active) { opacity: 0; visibility: hidden; transform: translate3d(0, 12px, 0); pointer-events: none; }
.story-frame.is-active { opacity: 1; visibility: visible; transform: none; }
.story-frame { transition: opacity 420ms var(--ease-out), transform 520ms var(--ease-out), visibility 0s linear 0s; }
.story-frame:not(.is-active) { transition: opacity 420ms var(--ease-out), transform 520ms var(--ease-out), visibility 0s linear 420ms; }
.story-steps { display: flex; flex-direction: column; min-width: 0; }
.story-step { transition: opacity var(--dur-3) var(--ease); }
@media (min-width: 1024px) {
  .story { grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--grid-gap); align-items: start; }
  .story-media {
    grid-column: 1 / span 5;
    position: sticky;
    top: calc(var(--topbar-h-compact) + var(--header-h-compact) + var(--sp-6));
  }
  .story-steps { grid-column: 7 / span 6; }
  .story--media-right .story-media { grid-column: 8 / span 5; order: 2; }
  .story--media-right .story-steps { grid-column: 1 / span 6; }
  html.motion .story-step:not(.is-active) { opacity: .42; }
}

/* Pinned story (opt-in: [data-story-pin] > .story-pin-frame holding the section head and the story).
   motion.js adds .is-pinned only with motion allowed and when the frame fits the screen. The frame
   sticks under the header at the screen's height; the track adds one scroll distance per step
   (--story-n from motion.js), so the section stays in place until the last step is done. */
@media screen {
  .story-pin {
    --story-pin-top: calc(var(--site-head-h) + var(--sp-4));
    --story-pin-bottom: var(--sp-6);
    --story-pin-h: calc(100svh - var(--story-pin-top) - var(--story-pin-bottom));
    --story-step-d: 40svh;
  }
  .story-pin.is-pinned { height: calc(var(--story-pin-h) + var(--story-n, 4) * var(--story-step-d)); }
  .story-pin.is-pinned > .story-pin-frame {
    position: sticky;
    top: var(--story-pin-top);
    display: flex;
    flex-direction: column;
    height: var(--story-pin-h);
  }
  .story-pin.is-pinned > .story-pin-frame > .sec-head { flex: none; margin-block-end: clamp(var(--sp-4), 3.5svh, var(--section-head-gap)); }
  .story-pin.is-pinned .story { flex: 1 1 auto; min-height: 0; }
  .story-pin.is-pinned .story-media { position: relative; top: auto; }
  /* The active part of the stepped stripe fills with the scrolled share of its step (--sub). */
  .story-pin.is-pinned .stripe-steps > span { position: relative; overflow: hidden; }
  .story-pin.is-pinned .stripe-steps > span.is-active { background: var(--line); }
  :is(.section--navy, .on-band) .story-pin.is-pinned .stripe-steps > span.is-active { background: var(--on-band-line); }
  .story-pin.is-pinned .stripe-steps > span.is-active::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--accent);
    transform-origin: 0 50%;
    transform: scaleX(calc(.08 + .92 * var(--sub, 0)));
  }
}
@media screen and (max-width: 767.98px) {
  /* Phones: the frame stays clear of the fixed quick action bar (site.css .sticky-cta) where there is one. */
  body:has([data-sticky-cta]) .story-pin { --story-pin-bottom: calc(var(--sticky-cta-h) + env(safe-area-inset-bottom, 0px) + var(--sp-4)); }
}
@media screen and (max-width: 1023.98px) {
  /* Narrow screens: the media fills the free height, the active step's text sits under it. The steps
     share one cell and crossfade; all of them stay in the list for screen readers. */
  .story-pin.is-pinned .story { display: flex; flex-direction: column; gap: var(--sp-5); }
  .story-pin.is-pinned .story-media { flex: 1 1 auto; min-height: 0; }
  .story-pin.is-pinned .story-steps { flex: none; display: grid; grid-template-columns: minmax(0, 1fr); }
  .story-pin.is-pinned .story-step { grid-area: 1 / 1; }
  html.motion .story-pin.is-pinned .story-step:not(.is-active) { opacity: 0; }
}
@media screen and (min-width: 1024px) {
  /* Wide screens: media and steps fill the frame's height; every step is in view, the active one lit. */
  .story-pin.is-pinned .story { grid-template-rows: minmax(0, 1fr); align-items: stretch; }
  .story-pin.is-pinned .story-step { flex: 1 1 0; min-height: auto; }
}

/* ---------- Reduced motion and print: static and complete ---------- */
@media (prefers-reduced-motion: reduce) {
  html [data-reveal], html [data-reveal-stagger] > *, html [data-intro], html .meter, html .bars .bar {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    animation: none !important;
  }
}
@media print {
  html [data-reveal], html [data-reveal-stagger] > *, html [data-intro], html .meter, html .bars .bar {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    animation: none !important;
  }
  html .story-frame:not(.is-active) { display: none !important; }
}
