/* ═══════════ STRIDETOBER — MOTION ═══════════
   "Leaves, not lasers." Spec: PLAN §4. transform/opacity only (stroke draw-ons
   on small SVGs and M34's leaf colour turn are the exceptions). Every loop has a
   reduced-motion exit. */

/* ── keyframes (PLAN §4.3, verbatim) ────────────────────── */
@keyframes leaf-fall   {from{transform:translate3d(0,-12vh,0)}to{transform:translate3d(0,112vh,0)}}
@keyframes leaf-sway   {0%,100%{transform:translateX(-18px) rotate(-8deg)}50%{transform:translateX(18px) rotate(10deg)}}
@keyframes leaf-flutter{0%,100%{transform:rotateX(0) rotateY(0)}50%{transform:rotateX(55deg) rotateY(25deg)}}
@keyframes view-in     {from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes fade-out    {to{opacity:0}}
@keyframes settle      {from{opacity:0;transform:translateY(14px) rotate(-.4deg)}to{opacity:1;transform:none}}
@keyframes digit-out   {to{opacity:0;transform:translateY(60%) rotate(6deg)}}
@keyframes digit-in    {from{opacity:0;transform:translateY(-60%) rotate(-4deg)}to{opacity:1;transform:none}}
@keyframes seal-stamp  {0%{opacity:0;transform:scale(1.8) rotate(-18deg)}60%{opacity:1;transform:scale(.94) rotate(-6deg)}80%{transform:scale(1.03) rotate(-9deg)}100%{transform:scale(1) rotate(-8deg)}}
@keyframes slam        {0%{opacity:0;transform:scale(2.2) rotate(-14deg)}55%{opacity:1;transform:scale(.92) rotate(-5deg)}100%{transform:scale(1) rotate(-6deg)}}
@keyframes thud        {0%,100%{transform:none}30%{transform:translateY(2px)}60%{transform:translateY(-1px)}}
@keyframes gavel       {0%{transform:rotate(0)}40%{transform:rotate(-35deg)}70%{transform:rotate(10deg)}100%{transform:rotate(0)}}
@keyframes draw        {to{stroke-dashoffset:0}}
@keyframes flicker     {0%,100%{opacity:1}42%{opacity:.88}47%{opacity:.62}52%{opacity:.94}70%{opacity:.8}}
@keyframes blink       {50%{opacity:.35}}
@keyframes tally       {0%,12%{stroke-dashoffset:var(--len)}20%,85%{stroke-dashoffset:0}100%{stroke-dashoffset:0;opacity:0}}
@keyframes nope        {0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}
@keyframes pop         {from{opacity:0;transform:scale(.6)}to{opacity:1;transform:scale(1)}}
@keyframes bob         {0%,100%{transform:translateY(-2px)}50%{transform:translateY(2px)}}
@keyframes crown-drop  {0%{opacity:0;transform:translateY(-40px) rotate(-10deg)}70%{opacity:1;transform:translateY(3px) rotate(2deg)}100%{transform:none}}
@keyframes flap        {0%,100%{transform:scaleY(1)}50%{transform:scaleY(.55)}}
@keyframes toast-in    {from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@keyframes tittle-sway {0%,100%{transform:rotate(-12deg)}50%{transform:rotate(12deg)}}
@keyframes pulse       {50%{opacity:.6}}

/* ── M1 leaf layer (PLAN §4.5) ──────────────────────────── */
.leaves { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; contain: strict; }
.leaf {
  position: absolute;
  top: 0;
  left: var(--x);
  width: var(--size);
  height: var(--size);
  color: var(--tint);
  opacity: var(--leaf-opacity);
  animation: leaf-fall var(--dur) linear var(--delay) infinite;
  will-change: transform;
}
.leaf-sway { display: block; width: 100%; height: 100%; animation: leaf-sway var(--sway) var(--ease-swing) infinite; }
.leaf-flip { display: block; width: 100%; height: 100%; fill: currentColor; animation: leaf-flutter var(--flip) ease-in-out infinite; }
.leaf.bat .leaf-flip { animation: flap 180ms ease-in-out infinite; }
.site-head, .site-foot, .tabbar { isolation: isolate; }

/* ── M3 route change ────────────────────────────────────── */
::view-transition-old(root) { animation: 160ms var(--ease-exit) both fade-out; }
::view-transition-new(root) { animation: 320ms var(--ease-settle) both view-in; }
.view-enter { animation: view-in 320ms var(--ease-settle) both; }

/* ── M4 settle-in reveal (hidden only when JS is running) ─ */
html.js [data-reveal]:not(.is-in) { opacity: 0; }
[data-reveal].is-in { animation: settle var(--dur-stamp) var(--ease-settle) both; animation-delay: calc(min(var(--i, 0), 8) * 60ms); }

/* ── M6/M7 countdown ────────────────────────────────────── */
.digit .d-out { animation: digit-out 380ms var(--ease-settle) forwards; }
.digit .d-in { animation: digit-in 380ms var(--ease-settle) both; }
.countdown.urgent .cd-colon { animation: blink 1s steps(1) infinite; }
.countdown-card[data-witching] .candle { animation: flicker 3s infinite; }

/* ── M8/M9 seals, stamps, thud ──────────────────────────── */
.is-in .seal.stamps, .seal.stamps.is-in { animation: seal-stamp var(--dur-stamp) var(--ease-stamp) both; animation-delay: calc(var(--i, 0) * 90ms); }
.is-in .thuds, .thuds.is-in { animation: thud 240ms var(--ease-settle) both; animation-delay: calc(var(--i, 0) * 90ms + 310ms); }
.stamp.slams { animation: slam 480ms var(--ease-stamp) both; }
.seal.stamping { animation: seal-stamp var(--dur-stamp) var(--ease-stamp) both; }
.thud-now { animation: thud 240ms var(--ease-settle) 300ms both; }

/* ── M10 gavel ──────────────────────────────────────────── */
.gavel-strike { animation: gavel 280ms var(--ease-settle); transform-origin: 80% 80%; }

/* ── M11 margin note draw-on ────────────────────────────── */
.note svg path { stroke-dasharray: var(--len, 80); stroke-dashoffset: var(--len, 80); }
.is-in .note svg path, .note.is-in svg path { animation: draw 700ms ease-out 200ms forwards; }
.check-row svg path { stroke-dasharray: 30; stroke-dashoffset: 30; }
.is-in .check-row svg path { animation: draw 500ms ease-out forwards; animation-delay: calc(var(--i, 0) * 180ms + 200ms); }

/* ── M18 counting tally ─────────────────────────────────── */
.tally.counting path { --len: 24; stroke-dasharray: var(--len); animation: tally 2.4s infinite both; }
.tally.counting path:nth-child(2) { animation-delay: 120ms; }
.tally.counting path:nth-child(3) { animation-delay: 240ms; }
.tally.counting path:nth-child(4) { animation-delay: 360ms; }
.tally.counting path:nth-child(5) { animation-delay: 480ms; }

/* ── M17 toast ──────────────────────────────────────────── */
.toast { animation: toast-in 320ms var(--ease-settle) both; }
.toast.is-out { opacity: 0; transform: translateY(8px); transition: opacity 200ms, transform 200ms; animation: none; }

/* ── M13 reading: deltas stay hidden until read, then pop ─ */
.reading .delta { visibility: hidden; }
.delta.pop-in { animation: pop 320ms var(--ease-stamp) both; }

/* ── M19 group-chat decoy ───────────────────────────────── */
.nope { animation: nope 360ms var(--ease-settle); }

/* ── M20 bottle bubble ──────────────────────────────────── */
.bubble { animation: pop 240ms var(--ease-stamp) both; transform-origin: 100% 100%; }

/* ── M22/M25 wordmark tittle, jack, candle ──────────────── */
.wm-tittle { animation: tittle-sway 3s ease-in-out infinite; }
html[data-eve] .wm-jack { animation: flicker 3s infinite; }
.tl-node.today .tl-dot { animation: flicker 3s infinite; }

/* ── M24 coronation ─────────────────────────────────────── */
.crown { animation: bob 3s ease-in-out infinite; }
.crown.dropping { animation: crown-drop 700ms var(--ease-stamp) both, bob 3s ease-in-out 700ms infinite; }

/* ── M2 fallback pulse ──────────────────────────────────── */
.pulse { animation: pulse 400ms ease-in-out; }

/* ── M26 wind gusts: a few leaves blow across every 35–70s ─ */
@keyframes gust-fly {
  0%   { opacity: 0; transform: translate3d(-8vw, 0, 0) rotate(0); }
  8%   { opacity: var(--leaf-opacity); }
  50%  { transform: translate3d(50vw, var(--arc), 0) rotate(calc(var(--turns) * .5)); }
  92%  { opacity: var(--leaf-opacity); }
  100% { opacity: 0; transform: translate3d(108vw, calc(var(--arc) * .4), 0) rotate(var(--turns)); }
}
@keyframes gust-push { 0%, 100% { translate: 0 0; } 45% { translate: 34px 0; } }
.gust-leaf {
  position: absolute;
  left: 0;
  top: var(--y);
  width: var(--size);
  height: var(--size);
  color: var(--tint);
  opacity: 0;
  animation: gust-fly var(--dur) cubic-bezier(.25, .1, .25, 1) var(--delay) both;
  will-change: transform;
}
.gust-leaf svg { width: 100%; height: 100%; }
/* The push moves the leaves, never the fixed layer itself: a fixed box sliding past the edge
   widens the page, and iOS answers by shifting its layout viewport — which knocks the tab bar
   loose. `translate` composes with each leaf's own falling `transform`. */
.leaves.gusting .leaf { animation: leaf-fall var(--dur) linear var(--delay) infinite, gust-push 2.6s ease-in-out; }

/* ── M27 the samara: one ambient "leaf" is a spinning maple seed ─ */
@keyframes samara-spin { to { transform: rotate(360deg); } }
.leaf.samara .leaf-flip { animation: samara-spin var(--flip) linear infinite; }
.leaf.samara .leaf-sway { animation-duration: calc(var(--sway) * 1.6); }

/* ── M30 crest wiggle: hover on a mouse, tap on a phone ─── */
@keyframes wiggle { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-12deg) scale(1.06); } 55% { transform: rotate(9deg); } 80% { transform: rotate(-4deg); } }
.crest.wiggle { animation: wiggle 520ms var(--ease-settle); }
@media (hover: hover) and (pointer: fine) {
  .crest:hover, a:hover > .crest, .roll-card:hover .crest { animation: wiggle 520ms var(--ease-settle); }
}

/* ── M31 the harvest sky: sun rises by day, moon and stars by night ─ */
@keyframes rise { from { transform: translateY(46px); } to { transform: none; } }
@keyframes breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }
@keyframes twinkle { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }
.sky-orb { animation: rise 1.8s var(--ease-settle) both; }
html[data-daypart="afternoon"] .sky-orb { animation: rise 1.8s var(--ease-settle) both, breathe 7s ease-in-out 1.8s infinite; }
.sky-star { animation: twinkle 2.8s ease-in-out infinite; }
.sky-star:nth-of-type(2) { animation-delay: .9s; }
.sky-star:nth-of-type(3) { animation-delay: 1.7s; }

/* ── M33 the squirrel: crosses once a session, pauses to judge you ─ */
@keyframes scurry {
  0%   { transform: translateX(0); }
  40%  { transform: translateX(calc(-50vw - 40px)); }
  52%  { transform: translateX(calc(-50vw - 40px)); }
  100% { transform: translateX(calc(-100vw - 140px)); }
}
@keyframes hop { from { transform: translateY(0) rotate(-3deg); } to { transform: translateY(-8px) rotate(4deg); } }
.squirrel { animation: scurry 5.4s linear forwards; }
.sq-body { animation: hop 240ms ease-in-out infinite alternate; }
.squirrel.fled { opacity: 0; transition: opacity 300ms; }

/* ── M34 the tree: every leaf turns once, then some let go ─ */
@keyframes turn   { 0% { color: var(--from); } 45% { color: var(--tree-gold); } 100% { color: var(--to); } }
@keyframes shiver { 0%, 100% { transform: none; } 30% { transform: rotate(1.4deg); } 65% { transform: rotate(-.8deg); } }
/* steps(), not a smooth fade: four repaints per leaf instead of sixty a second. */
.tl { color: var(--from); animation: turn var(--t) steps(4, jump-none) var(--d) both; }
.tl.holdout { animation: none; }
/* Before kickoff: green, and the crown sways a little, like it's holding its breath (M38). */
@keyframes sway { 0%, 100% { transform: rotate(-.5deg); } 50% { transform: rotate(.6deg); } }
.tree.waiting .tl { animation: none; color: var(--from); }
.tree.waiting .tree-crown { animation: sway 5.5s ease-in-out infinite; }
.tree-crown.shiver { animation: shiver 1.6s var(--ease-swing); }
.tree-drop.is-landed .leaf-sway, .tree-drop.is-landed .leaf-flip { animation: none; }
.tree-drop.is-landed { opacity: 0; transition: opacity 1.2s ease 12s; }

/* ── M35 residents: flap in flight, hop on foot, the owl sleeps by day ─ */
@keyframes doze { 0% { opacity: 0; transform: translate(0, 0) scale(.6); } 30% { opacity: 1; } 100% { opacity: 0; transform: translate(-10px, -18px) scale(1); } }
@keyframes dig  { 0%, 100% { transform: none; } 50% { transform: translateY(3px) rotate(-8deg); } }
.critter.is-flying .critter-body { animation: flap 220ms ease-in-out infinite; }
.critter.is-walking .critter-body { animation: hop 240ms ease-in-out infinite alternate; }
.critter.is-digging .critter-body { animation: dig 260ms ease-in-out infinite; }
html:is([data-daypart="morning"], [data-daypart="afternoon"]):not([data-eve]) .critter-owl::after {
  content: "💤";
  position: absolute;
  left: -48%;
  top: -46%;
  font-size: 55%;
  animation: doze 3s ease-out infinite;
}

/* ── M36 the wildlife: creatures cross the page on their own schedule ──
   .roamer carries the one-shot crossing (linear, so the held keyframes read as
   real stops); .roamer-gait carries the loop — a weight-shift, a dart, a hop or
   a wingbeat. .rev plays the crossing backward and turns the animal around. */
@keyframes roam-amble {
  0%   { transform: translate3d(-16vw, 0, 0); }
  26%  { transform: translate3d(18vw, 0, 0); }
  34%  { transform: translate3d(18vw, 0, 0); }   /* stops to graze */
  68%  { transform: translate3d(62vw, 0, 0); }
  74%  { transform: translate3d(62vw, 0, 0); }   /* looks around */
  100% { transform: translate3d(116vw, 0, 0); }
}
@keyframes roam-scurry {
  0%   { transform: translate3d(-10vw, 0, 0); }
  9%   { transform: translate3d(9vw, 0, 0); }  15% { transform: translate3d(9vw, 0, 0); }
  27%  { transform: translate3d(28vw, 0, 0); } 32% { transform: translate3d(28vw, 0, 0); }
  48%  { transform: translate3d(51vw, 0, 0); } 54% { transform: translate3d(51vw, 0, 0); }
  70%  { transform: translate3d(74vw, 0, 0); } 75% { transform: translate3d(74vw, 0, 0); }
  100% { transform: translate3d(112vw, 0, 0); }
}
@keyframes roam-soar {
  0%   { transform: translate3d(-14vw, 0, 0); }
  35%  { transform: translate3d(34vw, -3vh, 0); }
  70%  { transform: translate3d(72vw, 2vh, 0); }
  100% { transform: translate3d(114vw, -1vh, 0); }
}
@keyframes gait-shift { 0%, 100% { transform: none; } 50% { transform: translateY(-5%) rotate(-1.5deg); } }
@keyframes gait-trot  { from { transform: translateY(0) rotate(-2deg); } to { transform: translateY(-9%) rotate(2deg); } }
@keyframes gait-bound { from { transform: translateY(0) rotate(-5deg); } to { transform: translateY(-24%) rotate(6deg); } }
@keyframes gait-dart  { from { transform: translateY(0) rotate(-3deg); } to { transform: translateY(-13%) rotate(4deg); } }
/* Touched: a startle, then a look the other way. Shared by M35 and M36. */
@keyframes startle { 0% { transform: none; } 25% { transform: translateY(-34%) scale(1.14) rotate(-7deg); }
                     60% { transform: translateY(0) scale(.96); } 100% { transform: none; } }
@keyframes peek    { 0%, 100% { transform: scaleX(1); } 18%, 78% { transform: scaleX(-1); } }

.gait-amble { animation: roam-amble var(--dur) linear both; }
.gait-trot, .gait-hop { animation: roam-amble var(--dur) linear both; }
.gait-dart { animation: roam-scurry var(--dur) linear both; }
.gait-soar { animation: roam-soar var(--dur) linear both; }
.roamer.rev { animation-direction: reverse; }
.gait-amble .roamer-gait { animation: gait-shift 1.5s ease-in-out infinite; }
.gait-trot .roamer-gait { animation: gait-trot 420ms ease-in-out infinite alternate; }
.gait-hop .roamer-gait { animation: gait-bound 440ms cubic-bezier(.3, 0, .5, 1) infinite alternate; }
.gait-dart .roamer-gait { animation: gait-dart 240ms ease-in-out infinite alternate; }
.gait-soar .roamer-gait { animation: flap 950ms ease-in-out infinite; transform-origin: 50% 40%; }
.roamer.spooked .roamer-gait { animation: startle 420ms var(--ease-stamp); }
.roamer.bolting .roamer-gait { animation-duration: 160ms; }

/* ── M35 residents: breathing at home, a look around, a startle when touched ─ */
.critter-body { animation: breathe var(--breath, 4s) ease-in-out infinite; }
.critter.peeking .critter-body { animation: peek 1.4s ease-in-out; }
.critter.spooked .critter-body { animation: startle 420ms var(--ease-stamp); }

/* ── reduced motion (PLAN §4.2): near-zero, never animation:none ── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: .01ms !important;
  }
  .leaves, .wild { display: none; }
  .tally.counting path { animation-name: none !important; stroke-dasharray: none; }
}
html[data-motion="reduce"] *, html[data-motion="reduce"] *::before, html[data-motion="reduce"] *::after {
  animation-duration: .01ms !important;
  animation-iteration-count: 1 !important;
  animation-delay: 0ms !important;
  transition-duration: .01ms !important;
}
html[data-motion="reduce"] .leaves, html[data-motion="reduce"] .wild { display: none; }
html[data-motion="reduce"] .tally.counting path { animation-name: none !important; stroke-dasharray: none; }
