/* ===== "Behind the scenes" explainer — builds on styles.css tokens ===== */

/* Scroll position, published per stop by the script and read all over this file.
   The initial values are the finished state, so the page still reads correctly
   if the script never runs. --i and --col stagger elements within one stop. */
@property --reveal { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --depart { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --p { syntax: "<number>"; inherits: true; initial-value: 0.5; }
@property --i { syntax: "<number>"; inherits: false; initial-value: 0; }
@property --col { syntax: "<number>"; inherits: false; initial-value: 0; }

.explainer { width: min(1080px, 100%); margin: 0 auto; padding: 0 clamp(16px, 5vw, 40px) 60px; }

/* ---------- hero ---------- */
.hero { text-align: center; padding: clamp(40px, 8vh, 90px) 0 30px; }
.hero-eyebrow {
  display: inline-block; font-size: 0.78rem; letter-spacing: 2px; text-transform: uppercase;
  color: var(--mint); background: var(--mint-soft); border: 1px solid var(--border-strong);
  padding: 6px 14px; border-radius: 999px; margin-bottom: 22px;
  opacity: 0; animation: reveal .7s var(--ease) .05s forwards;
}
.hero h1 {
  font-size: clamp(1.8rem, 4.4vw, 3.1rem); line-height: 1.1; margin: 0 auto; max-width: 15ch;
  background: linear-gradient(120deg, #fff 30%, var(--mint) 100%);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  opacity: 0; animation: reveal .8s var(--ease) .12s forwards;
}
.hero p { color: var(--muted); font-size: 1.02rem; max-width: 56ch; margin: 18px auto 0; line-height: 1.6;
  opacity: 0; animation: reveal .8s var(--ease) .2s forwards; }
.hero-strip { width: 100%; max-width: 760px; margin: 34px auto 0; height: 120px;
  opacity: 0; animation: reveal 1s var(--ease) .3s forwards; }
.scrollcue { margin-top: 30px; color: var(--muted); font-size: 0.8rem; display: flex; flex-direction: column;
  align-items: center; gap: 6px; opacity: 0; animation: reveal 1s var(--ease) .5s forwards; }
.scrollcue span { display: inline-block; animation: bob 1.8s ease-in-out infinite; font-size: 1.3rem; color: var(--mint); }
@keyframes bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(6px); } }

/* ---------- journey / spine ---------- */
.journey { position: relative; margin-top: 20px; }
.spine { position: absolute; left: 50%; top: 0; bottom: 0; width: 3px; transform: translateX(-50%);
  background: rgba(71,215,172,0.12); border-radius: 3px; overflow: hidden; }
.spine-fill { position: absolute; left: 0; top: 0; width: 100%; height: 0;
  background: linear-gradient(180deg, var(--mint), var(--mint-2)); box-shadow: 0 0 12px var(--mint);
  transition: height .15s linear; }
@media (max-width: 820px) { .spine { left: 22px; } }

/* ---------- stops ---------- */
.stop {
  position: relative; display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 5vw, 60px);
  align-items: center; padding: clamp(40px, 9vh, 90px) 0; min-height: 40vh;
}
.stop-copy { max-width: 42ch; }
.stop:nth-child(even) { direction: rtl; }
.stop:nth-child(even) > * { direction: ltr; }
.stop-node {
  position: absolute; left: 50%; top: 50%; z-index: 3;
  transform: translate(-50%, -50%) scale(calc(0.55 + var(--reveal) * 0.45));
  width: 16px; height: 16px; border-radius: 50%; background: var(--petrol);
  border: 3px solid rgba(71,215,172,0.3); transition: border-color .5s, box-shadow .5s;
}
.stop.in-view .stop-node { border-color: var(--mint); box-shadow: 0 0 16px var(--mint); }
.stop-num { font-size: 0.9rem; font-weight: 800; color: var(--mint); letter-spacing: 2px; font-variant-numeric: tabular-nums; }
.stop-title { font-size: clamp(1.3rem, 3vw, 1.9rem); margin: 8px 0 12px; display: flex; align-items: center; gap: 12px; }
.stop-ico { font-size: 1.6rem; filter: drop-shadow(0 0 8px rgba(71,215,172,0.4)); }
.stop-text { color: var(--muted); font-size: 1.02rem; line-height: 1.65; }

/* Copy and stage are scrubbed by scroll: they rise and fade in as the stop arrives,
   then drift up and dim again as it leaves, so the journey reads as one continuous move. */
.stop-copy {
  opacity: calc(var(--reveal) - var(--depart) * 0.75);
  transform: translateY(calc((1 - var(--reveal)) * 34px - var(--depart) * 22px));
}
.stop-stage {
  opacity: calc(var(--reveal) - var(--depart) * 0.7);
  transform: translateY(calc((1 - var(--reveal)) * 26px - var(--depart) * 14px))
             scale(calc(0.965 + var(--reveal) * 0.035));
}
/* The stage pins while its copy scrolls past, giving each step a moment to play out.
   Both columns start at the top of the stop so the tall rows read as one column of
   copy moving past a held graphic, rather than as content marooned in empty space. */
@media (min-width: 821px) {
  /* the extra height is what the pin travels through — mobile has no pin, so it stays compact */
  .stop { align-items: start; min-height: 96vh; }
  .stop-copy { padding-top: clamp(10px, 4vh, 40px); }
  .stop-stage { position: sticky; top: clamp(80px, 13vh, 130px); }
  .stop-node { top: clamp(96px, 15vh, 150px); }
}

/* ---------- stage shell ---------- */
.stage-card {
  position: relative; background: var(--panel); border: 1px solid var(--border); border-radius: 20px;
  padding: 22px; box-shadow: var(--shadow); overflow: hidden; min-height: 240px;
  display: flex; align-items: center; justify-content: center;
}
.stage-card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--mint), transparent); opacity: 0.35; }
/* A card with a legend becomes two rows: the artwork takes the free space and the
   legend takes exactly the height it needs, so text that wraps on narrow screens
   pushes the artwork up instead of covering it. */
.stage-card:has(.stage-legend) {
  display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: 1fr auto;
  align-items: center; justify-items: center; row-gap: 14px; padding-bottom: 0;
}
.stage-legend {
  justify-self: stretch; width: calc(100% + 44px); margin: 0 -22px;
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 16px;
  padding: 11px 18px; border-top: 1px solid var(--border); background: rgba(6, 4, 31, 0.55);
  font-size: 0.74rem; color: var(--muted);
  opacity: calc(var(--reveal) * var(--reveal));
}
.stage-legend-key { display: inline-flex; align-items: center; gap: 7px; }
.stage-legend-key i { width: 11px; height: 11px; border-radius: 3px; flex: none; }

/* ---------- city (steps 1 & 2) ---------- */
.city { width: 100%; height: auto; transform-origin: center bottom;
  transform: scale(calc(0.93 + var(--reveal) * 0.07)); }
.building { transition: fill .6s; }
.building rect { fill: rgba(71,215,172,0.10); stroke: rgba(71,215,172,0.35); stroke-width: 1; }
.building .win { fill: var(--mint); opacity: 0.5; animation: twinkle 3s ease-in-out infinite; }
@keyframes twinkle { 0%,100% { opacity: 0.3; } 50% { opacity: 0.85; } }
/* change step: the city dims away as you scroll, leaving the changed function lit */
.city.dimmed .building { opacity: calc(1 - var(--reveal) * 0.78); }
.city.dimmed .building.lit { opacity: 1; }
.building.lit rect { fill: rgba(71,215,172,0.85); stroke: var(--mint-2); filter: drop-shadow(0 0 10px var(--mint)); }
.building.lit .win { fill: #04231a; opacity: 0.9; animation: none; }
.glow-ring { fill: none; stroke: var(--mint); stroke-width: 2; opacity: 0; }
.stop.in-view .glow-ring { animation: ring 2.2s ease-out infinite; }
@keyframes ring { 0% { r: 6px; opacity: 0.8; } 100% { r: 46px; opacity: 0; } }
.cursor-tap { opacity: 0; }
.stop.in-view .cursor-tap { animation: tap 2.2s var(--ease) .3s; }
@keyframes tap { 0% { opacity: 0; transform: translate(6px,-6px) scale(1.3); } 20% { opacity: 1; } 40% { transform: translate(0,0) scale(0.8); } 60%,100% { opacity: 0; } }

/* ---------- wires (steps 3 & 4) ---------- */
.map { width: 100%; height: auto; }
/* each wire draws itself as you scroll, one after the next */
.wire { fill: none; stroke-width: 2.5; stroke-linecap: round;
  --drawn: clamp(0, calc((var(--reveal) - var(--i) * 0.16) * 2.4), 1);
  stroke-dasharray: var(--len); stroke-dashoffset: calc(var(--len) * (1 - var(--drawn))); }
.wire.coral { stroke: var(--code); }
.wire.indigo { stroke: var(--req); }
.node-box { fill: var(--panel-2); stroke: var(--border); stroke-width: 1; }
.node-box.src { fill: rgba(71,215,172,0.85); stroke: var(--mint-2); }
.node-label { fill: var(--muted); font-size: 11px; font-family: inherit; }
.test-pill-svg { opacity: calc(0.34 + var(--reveal) * 0.66); }
.test-pill-svg rect { fill: var(--panel-2); stroke: var(--border); stroke-width: 1; }
.test-pill-svg.hit rect { fill: var(--mint-soft); stroke: var(--border-strong); }
.test-pill-svg text { fill: var(--muted); font-size: 11px; }
.test-pill-svg.hit text { fill: var(--mint); }
/* the sparks only start travelling once their wire has been drawn */
.spark { fill: var(--code); opacity: calc(var(--reveal) * var(--reveal)); filter: drop-shadow(0 0 4px var(--code)); }

/* ---------- rulebook (step 4) ---------- */
.rulebook { display: flex; flex-direction: column; gap: 9px; width: 100%; }
/* rules slide in one by one, then the touched ones tick */
.rule-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
  --q: clamp(0, calc((var(--reveal) - var(--i) * 0.11) * 3.2), 1);
  opacity: calc(0.25 + var(--q) * 0.75); transform: translateX(calc((1 - var(--q)) * -18px));
  transition: border-color .5s var(--ease), box-shadow .5s var(--ease); }
.rule-check { width: 20px; height: 20px; border-radius: 6px; border: 2px solid var(--muted); flex: none;
  display: grid; place-items: center; color: transparent; font-size: 12px; font-weight: 900; transition: all .4s; }
/* The alpha lives in the gradient rather than on opacity, so the label stays legible. */
.rule-line { flex: 1; height: 24px; border-radius: 7px; display: flex; align-items: center; padding: 0 10px;
  background: linear-gradient(90deg, rgba(144,152,184,0.4), transparent);
  font-size: 0.74rem; font-weight: 600; color: var(--muted); }
.rule-row.on { border-color: var(--req); box-shadow: 0 0 16px -6px var(--req); }
.rule-row.on .rule-check { border-color: var(--req); background: var(--req); color: #06041F; }
.rule-row.on .rule-line { background: linear-gradient(90deg, rgba(124,131,255,0.8), transparent); color: var(--text); }
.stop.in-view .rule-row.on { animation: rulepulse 2.4s ease-in-out infinite; }
@keyframes rulepulse { 0%,100% { box-shadow: 0 0 16px -8px var(--req); } 50% { box-shadow: 0 0 20px -2px var(--req); } }

/* ---------- memory cards (step 5) ---------- */
.mem-stack { display: flex; flex-direction: column; gap: 10px; width: 100%; }
/* the history is recalled card by card as the step scrolls in */
.mem-card { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 12px;
  padding: 12px 14px; border-radius: 12px; background: var(--panel-2); border: 1px solid var(--border);
  --q: clamp(0, calc((var(--reveal) - var(--i) * 0.1) * 3.4), 1);
  opacity: var(--q); transform: translateX(calc((1 - var(--q)) * -22px)); }
.mem-name { font-weight: 600; font-size: 0.86rem; color: var(--text); font-variant-numeric: tabular-nums; }
.mem-clock { display: flex; align-items: center; gap: 6px; color: var(--code); font-size: 0.8rem; font-weight: 700; }
.mem-hist { display: flex; gap: 4px; }
.mem-dot { width: 12px; height: 12px; border-radius: 4px; }
.mem-dot.pass { background: var(--mint); }
.mem-dot.fail { background: var(--code); }
.mem-shimmer { position: absolute; inset: 0; background: linear-gradient(105deg, transparent 40%, rgba(71,215,172,0.16) 50%, transparent 60%);
  transform: translateX(-100%); pointer-events: none; }
.stop.in-view .mem-shimmer { animation: shimmer 4.5s ease-in-out .3s infinite; }
@keyframes shimmer { to { transform: translateX(100%); } }

/* ---------- scoreboard (step 6) ---------- */
.scoreboard { display: flex; flex-direction: column; gap: 11px; width: 100%; }
/* every bar grows under the scroll, the leader first */
.score-row { display: grid; grid-template-columns: 74px 1fr 34px; align-items: center; gap: 10px;
  --q: clamp(0, calc((var(--reveal) - var(--i) * 0.08) * 3), 1);
  opacity: calc(0.3 + var(--q) * 0.7); }
.score-name { font-size: 0.8rem; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.score-track { height: 15px; border-radius: 8px; background: #08061c; border: 1px solid var(--border); overflow: hidden; }
.score-fill { height: 100%; border-radius: 8px; box-shadow: 0 0 10px -2px currentColor;
  width: calc(var(--w) * var(--q)); }
.score-fill.mint { background: var(--mint); color: var(--mint); }
.score-fill.coral { background: var(--code); color: var(--code); }
.score-fill.indigo { background: var(--req); color: var(--req); }
.score-val { font-size: 0.76rem; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
.score-star { color: var(--mint); opacity: 0; }
.stop.in-view .score-star { opacity: 1; animation: twinkle 2.6s ease-in-out 1.4s infinite; }

/* ---------- time jar (step 7) ---------- */
.jar-wrap { display: flex; align-items: center; gap: 22px; }
.jar { width: 130px; height: 200px; }
.jar-body { fill: rgba(255,255,255,0.02); stroke: var(--border-strong); stroke-width: 2; }
/* height and y are scrubbed from script, so the jar fills exactly as far as you have scrolled */
.jar-liquid { fill: url(#jargrad); }
.budget-line { stroke: var(--code); stroke-width: 2; stroke-dasharray: 5 4; }
.budget-tag { fill: var(--code); font-size: 11px; font-weight: 700; }
.jar-note { color: var(--muted); font-size: 0.9rem; line-height: 1.6; max-width: 24ch; }
.jar-note b { color: var(--mint); }
.drop { fill: var(--mint); opacity: 0; }
.stop.in-view .drop { animation: dropIn 1.6s var(--ease) infinite; }
@keyframes dropIn { 0% { opacity: 0; transform: translateY(-60px); } 30% { opacity: 1; } 100% { opacity: 0; transform: translateY(0); } }
.drop.reject { fill: var(--muted); }
.stop.in-view .drop.reject { animation: dropReject 2.2s var(--ease) 1.2s infinite; }
@keyframes dropReject { 0% { opacity: 0; transform: translateY(-50px); } 30% { opacity: 0.9; transform: translateY(-6px); } 55% { transform: translateY(-26px) translateX(16px); } 100% { opacity: 0; transform: translateY(-60px) translateX(30px); } }

/* ---------- finale (step 8) ---------- */
.finale { display: flex; flex-direction: column; align-items: center; gap: 16px; width: 100%; }
.timeshift { display: flex; align-items: center; justify-content: center; gap: clamp(12px, 3vw, 26px); padding: 22px 0 8px; }
/* hours lands first, the arrow reaches across, then minutes arrives — all on scroll */
.timeshift-from, .timeshift-to {
  font-size: clamp(1.7rem, 5vw, 2.7rem); font-weight: 800; text-transform: uppercase; letter-spacing: 1px;
}
.timeshift-from { color: var(--muted);
  --q: clamp(0, calc(var(--reveal) * 2.4), 1);
  opacity: var(--q); transform: translateY(calc((1 - var(--q)) * 14px)); }
.timeshift-to { color: var(--mint);
  --q: clamp(0, calc((var(--reveal) - 0.42) * 2.4), 1);
  opacity: var(--q); transform: translateY(calc((1 - var(--q)) * 14px)); }
.timeshift-arrow {
  font-size: clamp(1.3rem, 3vw, 2rem); color: var(--mint);
  --q: clamp(0, calc((var(--reveal) - 0.24) * 3), 1);
  opacity: var(--q); transform: translateX(calc((1 - var(--q)) * -14px)); }
.finale-line { font-size: 1.05rem; color: var(--text); text-align: center; }
/* The whole suite as tiles: a mint sweep crosses the field and the selected few
   light up as it reaches their column, so most of the suite stays dark. */
.suite-grid-wrap { position: relative; width: 100%; margin-top: 4px; overflow: hidden; }
.suite-grid { display: grid; grid-template-columns: repeat(10, 1fr); gap: 6px; }
.suite-tile { aspect-ratio: 1; border-radius: 4px; background: var(--panel-2); border: 1px solid var(--border); }
/* --q ramps exactly as the sweep's bright band reaches this tile's column */
.suite-tile.run {
  --q: clamp(0, calc((var(--reveal) - 0.26 - var(--col) * 0.05) * 8), 1);
  background: color-mix(in srgb, var(--mint) calc(var(--q) * 100%), var(--panel-2));
  border-color: color-mix(in srgb, var(--mint-2) calc(var(--q) * 100%), var(--border));
  box-shadow: 0 0 calc(var(--q) * 12px) -2px var(--mint);
}
.stop.in-view .suite-tile.run { animation: twinkle 3s ease-in-out infinite; }
/* the band is dragged across the field by the scroll itself */
.suite-sweep { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 40%, rgba(71,215,172,0.16) 50%, transparent 60%);
  transform: translateX(calc(-100% + var(--reveal) * 200%)); }

/* ---------- closing CTA ---------- */
.cta { text-align: center; padding: 40px 0 10px; }
.cta a { display: inline-flex; align-items: center; gap: 10px; padding: 14px 26px; border-radius: 14px;
  background: linear-gradient(120deg, var(--mint), var(--mint-2)); color: #04231a; font-weight: 800;
  text-decoration: none; box-shadow: 0 12px 34px -14px var(--mint); transition: transform .2s var(--ease); }
.cta a:hover { transform: translateY(-3px); }

/* ---------- responsive ---------- */
@media (max-width: 820px) {
  .stop { grid-template-columns: 1fr; gap: 22px; padding-left: 46px; }
  .stop:nth-child(even) { direction: ltr; }
  .stop-node { left: 22px; }
  .jar-wrap { flex-direction: column; }
}
@media (prefers-reduced-motion: reduce) {
  /* Shortening the duration would leave looping animations strobing, so stop them outright.
     Pinning the scroll progress at "finished" also freezes every scrubbed reveal, which is
     the only way to stop scroll-driven motion — !important beats the script's inline values. */
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .stop { --reveal: 1 !important; --depart: 0 !important; --p: 0.5 !important; }
  .stop-copy, .stop-stage { opacity: 1 !important; transform: none !important; }
  .stop-stage { position: relative !important; }
}
