/* Afterglow site: the motion layer. Loaded after site.css; nothing here changes layout or colour at rest.
   Transform, opacity and filter only, so it stays smooth on a phone; readers who prefer reduced motion get
   the end states at once. The moves (entrances, the re-pairing, the headline reveal, the strip, route slides) come from
   motion.js and the rules it relies on further down. */

:root {
  --m-quick: 150ms;
  --m-fast: 260ms;
  --m-slow: 420ms;
  --m-stagger: 70ms;
  --m-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* controls answer the finger */
a, .btn, .nav__links a, .pool label, .chipcell, .field input, .field select, .field textarea {
  transition: color var(--m-quick) ease, background-color var(--m-quick) ease, border-color var(--m-quick) ease, text-decoration-color var(--m-quick) ease, transform var(--m-quick) ease;
  -webkit-tap-highlight-color: transparent;
}
.btn:active { transform: translateY(1px); }
.pool label:active { transform: scale(0.99); }
.link-grow::after { transition: transform var(--m-quick) var(--m-ease); }
.table tbody tr td { transition: background-color var(--m-quick) ease; }
.table tbody tr:hover td { background: var(--page); }

/* rows arrive in order after an import */
@keyframes enter-row {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
.table tbody tr { animation: enter-row var(--m-fast) var(--m-ease) both; }
.table tbody tr:nth-child(2) { animation-delay: 25ms; }
.table tbody tr:nth-child(3) { animation-delay: 50ms; }
.table tbody tr:nth-child(4) { animation-delay: 75ms; }
.table tbody tr:nth-child(5) { animation-delay: 100ms; }
.table tbody tr:nth-child(6) { animation-delay: 125ms; }
.table tbody tr:nth-child(7) { animation-delay: 150ms; }
.table tbody tr:nth-child(8) { animation-delay: 175ms; }
.table tbody tr:nth-child(n + 9) { animation-delay: 200ms; }

/* the passport's run comparison: the bars grow from zero in panel order */
@keyframes grow {
  from { transform: scaleX(0); }
  to { transform: none; }
}
.batch__bar { transform-origin: left center; animation: grow var(--m-slow) var(--m-ease) both; animation-delay: calc(var(--m-stagger) * 2); }
.batch__row:nth-child(2) .batch__bar { animation-delay: calc(var(--m-stagger) * 3); }
.batch__row:nth-child(3) .batch__bar { animation-delay: calc(var(--m-stagger) * 4); }
.batch__row:nth-child(n + 4) .batch__bar { animation-delay: calc(var(--m-stagger) * 5); }

/* an import that fails says so with a small shake */
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-5px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(3px); }
}
.status.is-bad { display: inline-block; animation: shake 380ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both; }

@media (prefers-reduced-motion: reduce) {
  .table tbody tr, .batch__bar, .status.is-bad { animation: none; }
  a, .btn, .nav__links a, .pool label, .chipcell, .table tbody tr td, .link-grow::after { transition: none; }
  .btn:active, .pool label:active { transform: none; }
}

/* the nav pills: on hover the pill lifts and a few drawn lines pop out of it, each line drawing itself outward
   (pathLength 1, the dash runs from 1 to 0) on a springy ease; they draw back quickly when the pointer leaves */
.nav__links a { transition: color var(--m-quick) ease, background-color var(--m-quick) ease, border-color var(--m-quick) ease, transform 260ms cubic-bezier(0.34, 1.56, 0.64, 1); }
.nav__links a:hover, .nav__links a:focus-visible { transform: translateY(-2px); }
.nav__links a:active { transform: translateY(0) scale(0.97); }
.pop { position: absolute; overflow: visible; pointer-events: none; fill: none; stroke-linecap: round; stroke-width: 2; opacity: 0; transform: scale(0.4); transform-origin: 50% 50%; transition: opacity 120ms ease, transform 200ms ease; }
.pop path { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 160ms ease; }
.pop--cell { stroke: var(--cell); }
.pop--sun { stroke: var(--sun); stroke-width: 2.2; }
@media (hover: hover) {
  .nav__links a:hover .pop, .nav__links a:focus-visible .pop { opacity: 1; transform: none; transition: opacity 80ms ease, transform 420ms cubic-bezier(0.34, 1.56, 0.64, 1) calc(var(--k, 0) * 40ms); }
  .nav__links a:hover .pop path, .nav__links a:focus-visible .pop path { stroke-dashoffset: 0; transition: stroke-dashoffset 360ms cubic-bezier(0.22, 1, 0.36, 1) calc(var(--i, 0) * 45ms); }
}
@media (hover: none) { .pop { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .nav__links a, .nav__links a:hover, .nav__links a:focus-visible, .nav__links a:active { transform: none; }
  .pop, .pop path, .nav__links a:hover .pop, .nav__links a:hover .pop path { transition: none; }
}

/* ---------- the moves: motion.js adds the classes and drives the variables ---------- */

/* entrances: a section's parts rise in, staggered, the first time a fifth of it is on screen */
/* parts fade up out of a slight blur, one after another (after the ui-refresh branch) */
.m-part { transition: opacity 1s cubic-bezier(0.2, 0.8, 0.2, 1), transform 1s cubic-bezier(0.2, 0.8, 0.2, 1), filter 1s cubic-bezier(0.2, 0.8, 0.2, 1); transition-delay: calc(var(--i, 0) * 110ms); }
html.has-motion [data-in]:not(.is-in) .m-part { opacity: 0; transform: translateY(40px); filter: blur(6px); }

/* the re-pairing: --k moves cells 2 and 3 into the other string, --w draws the wires, --g lights the strong pair and the gain */
.rp-cell[data-cell="2"] { transform: translate(calc(var(--k, 0) * -140px), calc(var(--k, 0) * 90px)); }
.rp-cell[data-cell="3"] { transform: translate(calc(var(--k, 0) * 140px), calc(var(--k, 0) * -90px)); }
.rp-wire { stroke-dasharray: 320px; stroke-dashoffset: calc(320px * (1 - var(--w, 1))); }
.rp-num, .rp-label { opacity: calc(0.3 + 0.7 * var(--g, 1)); }
html.reduced [data-hero] { --k: 1; --w: 1; --g: 1; --show: 1; }

/* cards wipe in from the top edge once their section is on screen, one after another */
.wiring, .ppass, .teaser__box { transition: clip-path 760ms var(--m-ease); transition-delay: calc(var(--j, 0) * 90ms); }
.ppass { transition: clip-path 760ms var(--m-ease), filter 520ms var(--m-ease), opacity 520ms var(--m-ease); transition-delay: calc(var(--j, 0) * 90ms), 0ms, 0ms; }
.wiring:nth-child(2), .ppass:nth-child(2) { --j: 1; } .wiring:nth-child(3), .ppass:nth-child(3) { --j: 2; } .ppass:nth-child(4) { --j: 3; }
html.has-motion .strip:not(.is-in) .wiring, html.has-motion .fpass:not(.is-in) .ppass, html.has-motion .teaser:not(.is-in) .teaser__box { clip-path: inset(0 0 100% 0); }
/* how the bench works: the rail draws across as the reader scrolls through the section (motion.js sets the offset), and
   each step lights and settles in turn; without script or under reduced motion all of it is simply there */
.string__wire path { stroke-dasharray: 1; stroke-dashoffset: 0; }
.step__glyph, .step h3 { transition: opacity 460ms var(--m-ease), transform 460ms var(--m-ease); }
html.has-motion .step:not(.is-lit) .step__glyph, html.has-motion .step:not(.is-lit) h3 { opacity: 0.22; transform: translateY(10px); }

/* the strip: the stage zooms in as the section docks (motion.js sets its transform), and a card still off to the right
   sits lower and quieter until it has arrived (--arrive 0..1) */
.strip__stage { will-change: transform, opacity; }
.wiring { transform: translateY(calc((1 - var(--arrive, 1)) * 28px + var(--arc, 0) * 1px)) rotate(calc(var(--rot, 0) * 1deg)); transform-origin: 50% 50%; opacity: calc(0.5 + 0.5 * var(--arrive, 1)); }

/* the hero's headline: a solid amber block sweeps across each line and leaves the words behind (after the Lando Norris
   site's telemetry wipes), setting off slowly, racing through the middle, overshooting and springing back; the lines
   alternate direction (.wipe--rtl). The lede and the buttons rise a beat later. */
.wipe { position: relative; display: inline-block; }
.wipe::after { content: ""; position: absolute; inset: -0.06em -0.12em; background: var(--sun); transform: scaleX(0); transform-origin: left center; pointer-events: none; }
.wipe--rtl::after { transform-origin: right center; }
html.has-motion [data-reveal]:not(.is-revealed) .wipe__in { opacity: 0; }
html.has-motion [data-reveal].is-revealed .wipe::after { animation: wipe-ltr 1050ms linear both; animation-delay: var(--d, 0ms); }
html.has-motion [data-reveal].is-revealed .wipe--rtl::after { animation-name: wipe-rtl; }
html.has-motion [data-reveal].is-revealed .wipe__in { animation: wipe-text 1ms linear both; animation-delay: calc(var(--d, 0ms) + 440ms); }
@keyframes wipe-ltr {
  0% { transform: scaleX(0); transform-origin: left center; animation-timing-function: cubic-bezier(0.85, 0, 0.15, 1); }
  40% { transform: scaleX(1.06); transform-origin: left center; animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  48% { transform: scaleX(1); transform-origin: left center; }
  52% { transform: scaleX(1); transform-origin: right center; animation-timing-function: cubic-bezier(0.85, 0, 0.15, 1); }
  100% { transform: scaleX(0); transform-origin: right center; }
}
@keyframes wipe-rtl {
  0% { transform: scaleX(0); transform-origin: right center; animation-timing-function: cubic-bezier(0.85, 0, 0.15, 1); }
  40% { transform: scaleX(1.06); transform-origin: right center; animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  48% { transform: scaleX(1); transform-origin: right center; }
  52% { transform: scaleX(1); transform-origin: left center; animation-timing-function: cubic-bezier(0.85, 0, 0.15, 1); }
  100% { transform: scaleX(0); transform-origin: left center; }
}
@keyframes wipe-text { from { opacity: 0; } to { opacity: 1; } }
/* the intro's first screen: the sun's outline draws slowly, its fill comes up, the rays draw one after another; then it
   comes alive (breathing, turning) and the beams grow down toward the cell */
html.is-intro .sun__disc { fill-opacity: 0; stroke-dasharray: 1; stroke-dashoffset: 1; animation: draw-disc 1300ms ease-in-out both, fill-in 500ms ease 1150ms both, sun-breathe 5s ease-in-out 2400ms infinite alternate; }
html.is-intro .sun__rays { animation: sun-turn 80s linear 2400ms infinite; }
html.is-intro .sun__rays path { stroke-dasharray: 1; stroke-dashoffset: 1; animation: ray-out 340ms ease-out both; animation-delay: calc(var(--i, 0) * 90ms + 1400ms); }
html.is-intro .sun__beams { transform-box: fill-box; transform-origin: 0 0; animation: beams-out 800ms cubic-bezier(0.3, 0.7, 0.2, 1) 2500ms both; }
@keyframes draw-disc { to { stroke-dashoffset: 0; } }
@keyframes fill-in { to { fill-opacity: 1; } }
@keyframes ray-out { to { stroke-dashoffset: 0; } }
@keyframes beams-out { from { transform: scale(0.02); } to { transform: scale(1); } }
.rise { transition: opacity 600ms var(--m-ease), transform 600ms var(--m-ease); transition-delay: var(--d, 0ms); }
html.has-motion [data-reveal].rise:not(.is-revealed) { opacity: 0; transform: translateY(14px); }
.grow { transition: opacity 900ms var(--m-ease), transform 900ms var(--m-ease); }
html.has-motion [data-reveal].grow:not(.is-revealed) { opacity: 0; transform: scale(0.97); }
.fade { transition: opacity 900ms var(--m-ease); }   /* the hero's slot: its transform belongs to the pointer, so it only fades in */
html.has-motion [data-reveal].fade:not(.is-revealed) { opacity: 0; }

/* route changes: the view slides along the nav axis, with the View Transitions API or with classes */
#view { view-transition-name: view; }
@keyframes vt-out { to { opacity: 0; transform: translateX(-24px); } }
@keyframes vt-in { from { opacity: 0; transform: translateX(24px); } }
@keyframes vt-out-back { to { opacity: 0; transform: translateX(24px); } }
@keyframes vt-in-back { from { opacity: 0; transform: translateX(-24px); } }
::view-transition-old(view) { animation: vt-out var(--m-quick) ease both; }
::view-transition-new(view) { animation: vt-in var(--m-fast) var(--m-ease) both; }
html[data-dir="back"]::view-transition-old(view) { animation-name: vt-out-back; }
html[data-dir="back"]::view-transition-new(view) { animation-name: vt-in-back; }
.view.is-leaving { animation: vt-out var(--m-quick) ease both; }
.view.is-entering { animation: vt-in var(--m-fast) var(--m-ease) both; }
html[data-dir="back"] .view.is-leaving { animation-name: vt-out-back; }
html[data-dir="back"] .view.is-entering { animation-name: vt-in-back; }

@media (prefers-reduced-motion: reduce) {
  .m-part, .rise, .grow, .fade, .step__glyph, .step h3, .wiring, .ppass, .teaser__box { transition: none; }
  .wipe::after, .wipe__in, .sun__rays path, .sun__beams { animation: none; }
  html.is-intro .hero__panel { translate: 0 0; opacity: 1; transition: none; }
  .ticker__track, .sun__disc, .sun__rays, .sun__beam { animation: none; }
  .recycle path { animation: none; stroke-dashoffset: 0; }
  .hero__panel { --tx: 12; --ty: -3; }
  [data-hero] { --k: 1; --w: 1; --g: 1; --show: 1; }
  ::view-transition-old(view), ::view-transition-new(view), .view.is-leaving, .view.is-entering { animation: none; }
}
html.reduced .m-part, html.reduced .rise, html.reduced .grow, html.reduced .fade { transition: none; }

/* sunlight: the disc breathes, the rays turn slowly, and the dashes of each beam travel down toward the panel */
.sun__disc, .sun__rays { transform-box: fill-box; transform-origin: center; }
.sun__disc { animation: sun-breathe 5s ease-in-out infinite alternate; }
.sun__rays { animation: sun-turn 80s linear infinite; }
.sun__beam { animation: sun-beam 1.4s linear infinite; animation-delay: calc(var(--b, 0) * -0.45s); }
@keyframes sun-breathe { from { transform: scale(0.95); } to { transform: scale(1.05); } }
@keyframes sun-turn { to { transform: rotate(360deg); } }
@keyframes sun-beam { to { stroke-dashoffset: -16; } }
