/* ============================================================================
   THE SITE MOTION LAYER — landing page and Academy home.

   One motif, shared with Just Landed: something travels a line. On the landing page the
   Agenterage mark rides a line through "How it works", Join -> Earn, lighting each step
   as it passes. Around it, restraint: cards rise 12px once, a few numbers count up once,
   and on the Academy home the constellation swings into place and then only answers
   the scroll.

   Built from the zysec motion study (E:\automation\misc\zysec-website-motion-study):
   one easing curve, three durations (200 / 320 / 600 ms), nothing idles.

   EVERY rule that hides or moves something sits under html.m — a class only motion.js
   adds, and never with ?nomotion. If the script fails to load, or motion is switched off,
   each page is exactly what it was before this file existed.
   ============================================================================ */

:root {
  --m-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --m-fast: 200ms;
  --m-mid: 320ms;
  --m-slow: 600ms;
}

/* ---------------------------------------------------------------- reveals [5] */
html.m .m-rv {
  opacity: 0; transform: translateY(12px);
  /* The reveal and the hover lift share one transition list. The reveal staggers (its delay
     is --m-d); the hover must answer at once, so translate/shadow/border carry no delay. */
  transition-property: opacity, transform, translate, box-shadow, border-color;
  transition-duration: var(--m-mid), var(--m-mid), var(--m-fast), var(--m-fast), var(--m-fast);
  transition-timing-function: var(--m-ease);
  transition-delay: var(--m-d, 0s), var(--m-d, 0s), 0s, 0s, 0s;
}
html.m .m-rv.m-in { opacity: 1; transform: none; }

/* ---------------------------------------------------------------- hover lift [4]
   Cards answer a pointer: a 4px lift and a shadow. It uses the separate `translate`
   property, never `transform`, so it cannot collide with the reveal. (The site's own
   .card:hover lift used transform, which the reveal's transform:none silently cancelled
   on every card that had faded in — this replaces it.) Real hover devices only. */
@media (hover: hover) and (pointer: fine) {
  html.m .card:not(.m-rv), html.m .acad-card:not(.m-rv) {
    transition: translate var(--m-fast) var(--m-ease), box-shadow var(--m-fast) var(--m-ease),
      border-color var(--m-fast) var(--m-ease);
  }
  html.m [data-motion="reveal"] > .card:hover { transform: none; translate: 0 -4px; box-shadow: var(--shadow-md, 0 12px 28px -14px rgba(15, 15, 40, .3)); }
  html.m .acad-card:hover { translate: 0 -4px; border-color: rgba(255, 255, 255, .3); box-shadow: 0 18px 36px -22px rgba(0, 0, 0, .65); }
  /* a benefit has no card to lift, so its icon tile answers instead */
  html.m .benefit .bic { transition: transform var(--m-fast) var(--m-ease); }
  html.m .benefit:hover .bic { transform: scale(1.1) rotate(-4deg); }
}

/* ---------------------------------------------------------------- "Build. Collaborate. Sell. Earn." [6]
   Scroll picks how many words are lit; CSS does the fade. Dims again on the way back. */
html.m .bce span { opacity: .22; transition: opacity var(--m-slow) var(--m-ease); }
html.m .bce span.m-on { opacity: 1; }

/* ---------------------------------------------------------------- the hero card leans to the mouse
   Driven by the same pointer as the spotlight, through its own slower damper. The card's
   own -2deg tilt is kept as the last term, so at rest it is exactly as it always was. */
html.m .opp-card {
  transform: perspective(900px) rotateX(var(--m-tx, 0deg)) rotateY(var(--m-ty, 0deg)) rotate(-2deg);
}

/* ---------------------------------------------------------------- the rail [15] */
html.m [data-motion="rail"] { position: relative; }
html.m [data-motion="rail"] > li { position: relative; z-index: 1; }
.m-rail { display: none; }
html.m .m-rail {
  display: block; position: absolute; inset: 0; width: 100%; height: 100%;
  overflow: visible; pointer-events: none; z-index: 0;
}
html.m .m-rail .m-track { fill: none; stroke: var(--hairline-strong, #c8c4be); stroke-width: 2; stroke-dasharray: 2 6; stroke-linecap: round; }
html.m .m-rail .m-line {
  fill: none; stroke: var(--primary, #5645d4); stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: var(--m-len, 1) var(--m-len, 1); stroke-dashoffset: var(--m-off, 1);
}
/* the traveller: the Agenterage mark itself, a navy tile with the orange chevron */
html.m .m-mark {
  position: absolute; left: 0; top: 0; width: 26px; height: 26px; margin: -13px 0 0 -13px; z-index: 2;
  pointer-events: none; border-radius: 8px; background: #0a1530;
  box-shadow: 0 8px 18px -8px rgba(10, 21, 48, .7), 0 0 0 2px #fff;
  transform: translate(var(--m-x, 0px), var(--m-y, 0px));
}
html.m .m-mark svg { width: 100%; height: 100%; display: block; transform: rotate(var(--m-a, 90deg)); }

/* steps light as the mark passes them; dim again on the way back [6] */
html.m [data-motion="rail"] > li > span {
  background: #fff; color: var(--slate, #615d59); box-shadow: inset 0 0 0 1.5px var(--hairline-strong, #c8c4be);
  transition: background var(--m-mid) var(--m-ease), color var(--m-mid) var(--m-ease),
    box-shadow var(--m-mid) var(--m-ease), transform var(--m-mid) var(--m-ease);
}
html.m [data-motion="rail"] > li.m-lit > span {
  background: var(--primary, #5645d4); color: #fff; box-shadow: 0 0 0 5px rgba(86, 69, 212, .14);
}
html.m [data-motion="rail"] > li > div { transition: opacity var(--m-mid) var(--m-ease); opacity: .55; }
html.m [data-motion="rail"] > li.m-lit > div { opacity: 1; }

/* ---------------------------------------------------------------- hero spotlight [14]
   A torch that follows the (damped) mouse across the landing hero. It does two things at
   once: a soft warm glow, and it REVEALS a dot-grid "network" that is otherwise invisible —
   the grid exists only inside the light. --m-sr (0..1) opens it on enter and closes it on
   leave. Fine pointers only; never on touch, never with reduced motion. Behind the copy. */
.m-spot { display: none; }
html.m .m-spot {
  display: block; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  --m-rad: calc(var(--m-sr, 0) * 340px);
}
html.m .m-spot::before,
html.m .m-spot::after { content: ""; position: absolute; inset: 0; }
html.m .m-spot::before {
  background: radial-gradient(var(--m-rad) circle at var(--m-mx, 50%) var(--m-my, 50%),
    rgba(255, 90, 43, .17), rgba(123, 63, 242, .10) 45%, transparent 72%);
}
html.m .m-spot::after {
  background-image: radial-gradient(rgba(255, 255, 255, .55) 1px, transparent 1.7px);
  background-size: 22px 22px;
  -webkit-mask-image: radial-gradient(var(--m-rad) circle at var(--m-mx, 50%) var(--m-my, 50%), #000 0%, rgba(0, 0, 0, .5) 45%, transparent 75%);
          mask-image: radial-gradient(var(--m-rad) circle at var(--m-mx, 50%) var(--m-my, 50%), #000 0%, rgba(0, 0, 0, .5) 45%, transparent 75%);
}

/* ---------------------------------------------------------------- Academy home */
/* the per-module bars fill once when the cards are drawn */
html.m .mini > i { transform-origin: left center; animation: mFill var(--m-slow) var(--m-ease) both; }
@keyframes mFill { from { transform: scaleX(0); } }
/* MODULES UNFOLD. The page shows and hides a module's lessons with display:none, so the
   page below jumped by the full height. Here the list is a one-row grid whose row animates
   from 0fr to 1fr, so it unfolds and the page below follows. While closed the rows are
   visibility:hidden (after the fold finishes), so the keyboard cannot tab into them. */
html.m .mod .eps {
  display: grid; grid-template-rows: 0fr; border-top-color: transparent;
  transition: grid-template-rows var(--m-mid) var(--m-ease), border-top-color var(--m-mid) var(--m-ease);
}
html.m .mod.open .eps { grid-template-rows: 1fr; border-top-color: var(--hair); }
html.m .mod .eps-in { min-height: 0; overflow: hidden; visibility: hidden; transition: visibility 0s linear var(--m-mid); }
html.m .mod.open .eps-in { visibility: visible; transition: visibility 0s; }
/* rows slide in a few at a time — only when the member opened it, never on page load */
html.m .mod.m-opening .ep { animation: mEpIn var(--m-mid) var(--m-ease) both; }
html.m .mod.m-opening .ep:nth-child(2) { animation-delay: 30ms; }
html.m .mod.m-opening .ep:nth-child(3) { animation-delay: 60ms; }
html.m .mod.m-opening .ep:nth-child(4) { animation-delay: 90ms; }
html.m .mod.m-opening .ep:nth-child(5) { animation-delay: 120ms; }
html.m .mod.m-opening .ep:nth-child(6) { animation-delay: 150ms; }
html.m .mod.m-opening .ep:nth-child(n+7) { animation-delay: 180ms; }
@keyframes mEpIn { from { opacity: 0; transform: translateY(-6px); } }

/* TRACK SWITCH. The highlight glides from the old track card to the new one (a ghost drawn
   by motion.js, since the picker is rebuilt on every switch), and the hero copy and module
   list arrive fresh. */
html.m #trackPicker { position: relative; }
html.m .m-trk-ghost {
  position: absolute; z-index: 0; pointer-events: none; border-radius: 16px;
  border: 1.5px solid transparent;
  background: linear-gradient(120deg, rgba(26, 33, 66, .96), rgba(20, 26, 54, .96)) padding-box,
              linear-gradient(110deg, #ff5a2b, #ff64c8 55%, #7b3ff2) border-box;
  transition: left var(--m-mid) var(--m-ease), top var(--m-mid) var(--m-ease),
    width var(--m-mid) var(--m-ease), height var(--m-mid) var(--m-ease);
}
html.m #trackPicker .trk { position: relative; z-index: 1; }
html.m #trackPicker .trk.on.m-wait { background: transparent; box-shadow: none; border-color: transparent; }
html.m .m-fresh { animation: mFresh var(--m-mid) var(--m-ease) both; }
@keyframes mFresh { from { opacity: 0; transform: translateY(8px); } }

/* the constellation: orbits are turned by motion.js; halo and core arrive once */
html.m .art .halo { animation: mBloom var(--m-slow) var(--m-ease) both; }
html.m .art .core { animation: mCore var(--m-slow) var(--m-ease) 120ms both; }
@keyframes mBloom { from { opacity: 0; transform: scale(.88); } }
@keyframes mCore { from { transform: scale(.9); } }
html.m .art .orbit { transform: rotate(var(--m-r, 0deg)); }

/* ---------------------------------------------------------------- reduced motion [10]
   motion.js takes a separate static branch; these are the belt to its braces. */
@media (prefers-reduced-motion: reduce) {
  html.m .m-rv { opacity: 1; transform: none; transition: none; }
  html.m .bce span { opacity: 1; transition: none; }
  html.m [data-motion="rail"] > li > span, html.m [data-motion="rail"] > li > div { transition: none; }
  html.m .mini > i, html.m .art .halo, html.m .art .core { animation: none; }
  html.m .mod .eps, html.m .mod .eps-in { transition: none; }
  html.m .mod.m-opening .ep, html.m .m-fresh { animation: none; }
}
