/* motion.css: the motion system for Eidolon.
 * Tokens (durations, easings, spring-like curves), keyframes, and the reduced-motion fallbacks.
 * Rules: transform and opacity only for anything that loops; fill/stroke transitions only on the
 * creature's small SVG; everything pauses when the tab is hidden (html.is-hidden) and under
 * prefers-reduced-motion loops stop while crossfades stay (opacity only). */

:root {
  /* durations */
  --d-tap: 110ms;        /* press down */
  --d-fast: 180ms;       /* hover, focus, small state */
  --d-mid: 320ms;        /* crossfades, chips, readouts */
  --d-slow: 560ms;       /* body colour crossfade, mood word */
  --d-reveal: 720ms;     /* section reveal */
  --d-atmo: 1100ms;      /* atmosphere wash crossfade */
  --d-breath: 4600ms;    /* one breath */
  --d-breath-sleep: 6800ms;
  /* easings */
  --ease-out: cubic-bezier(.2, .7, .2, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --ease-in: cubic-bezier(.5, 0, .9, .4);
  /* spring-like curves (overshoot) */
  --spring: cubic-bezier(.34, 1.56, .64, 1);
  --spring-soft: cubic-bezier(.3, 1.25, .5, 1);
  --spring-hard: cubic-bezier(.2, 1.9, .5, 1);
  /* distances */
  --lift: -2px;
  --reveal-y: 18px;
}

/* ---- the creature rig (groups wrapped around the contract's own elements) ---- */
.art svg .rig { transform-box: fill-box; transform-origin: 50% 100%; animation: breath var(--d-breath) var(--ease-in-out) infinite; }
.art.m-sleeping svg .rig { animation-duration: var(--d-breath-sleep); animation-name: breath-sleep; }
.art.m-nervous svg .shiver { animation: shiver .28s steps(2, jump-none) infinite; }
.art svg .tilt { transform-box: fill-box; transform-origin: 50% 92%; transition: transform var(--d-slow) var(--ease-out); will-change: transform; }
.art svg .face { transform-box: fill-box; transform-origin: center; transition: transform 240ms var(--ease-out); }
.art svg .pupils { transform-box: fill-box; transition: transform 240ms var(--ease-out); }
.art svg .eyes { transform-box: fill-box; transform-origin: center; }
.art svg .brows { transform-box: fill-box; transform-origin: center; }
.art svg .face.is-in, .art svg .extras.is-in { animation: face-in var(--d-mid) var(--spring-soft) both; }
.art svg .face.is-out, .art svg .extras.is-out { animation: face-out 220ms var(--ease-in) both; pointer-events: none; }
.art svg .rig .ink-fade, .art svg rect.bg { transition: fill var(--d-slow) var(--ease-out), stroke var(--d-slow) var(--ease-out); }
.art svg .puff { animation: puff 1.9s var(--ease-in-out) infinite; transform-box: fill-box; transform-origin: center; }
.art svg .puff:nth-child(2), .art svg .puff:nth-child(4) { animation-delay: -.9s; }
.art svg .zz { animation: zz-bob 3.2s var(--ease-in-out) infinite; transform-box: fill-box; transform-origin: center; }
.art svg .star { animation: twinkle 2.6s var(--ease-in-out) infinite; }
.art svg .star:nth-child(3) { animation-delay: -1.1s; } .art svg .star:nth-child(4) { animation-delay: -2s; }
.art svg .sweat { animation: sweat-wobble 1.4s var(--ease-in-out) infinite; transform-box: fill-box; transform-origin: 50% 0%; }
.art svg .shadow { transition: stroke var(--d-slow) var(--ease-out); }

@keyframes breath { 0%, 100% { transform: scale(1, 1); } 50% { transform: scale(.991, 1.017); } }
@keyframes breath-sleep { 0%, 100% { transform: scale(1, 1); } 50% { transform: scale(.986, 1.026); } }
@keyframes shiver { 0% { transform: translate(-.6px, 0); } 100% { transform: translate(.6px, 0); } }
@keyframes face-in { 0% { opacity: 0; transform: scale(.86); } 100% { opacity: 1; transform: scale(1); } }
@keyframes face-out { 0% { opacity: 1; } 100% { opacity: 0; } }
@keyframes puff { 0%, 100% { opacity: .55; transform: translateY(0) scale(1); } 50% { opacity: .95; transform: translateY(-3px) scale(1.12); } }
@keyframes zz-bob { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(2px, -4px); } }
@keyframes twinkle { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@keyframes sweat-wobble { 0%, 100% { transform: scaleY(1); } 50% { transform: scaleY(1.12); } }

/* ---- the fx overlay (site particles layered above the contract SVG, never inside it) ---- */
.fx { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.fx .sparkle { transform-box: fill-box; transform-origin: center; animation: sparkle 2.2s var(--ease-in-out) infinite; opacity: 0; }
.fx .drop { transform-box: fill-box; transform-origin: center; animation: drop 1.7s var(--ease-in) infinite; opacity: 0; }
.fx .steam { transform-box: fill-box; transform-origin: 50% 100%; animation: steam 2.1s var(--ease-out) infinite; opacity: 0; }
.fx .zee { transform-box: fill-box; transform-origin: center; animation: zee 3.4s var(--ease-in-out) infinite; opacity: 0; }
.fx .mote { transform-box: fill-box; transform-origin: center; animation: mote 7s var(--ease-in-out) infinite; opacity: 0; }
.fx .burst { transform-box: fill-box; transform-origin: center; animation: burst 900ms var(--ease-out) both; }
.fx .shell { transform-box: fill-box; transform-origin: 50% 100%; }
.fx .crack { stroke-dasharray: 200; stroke-dashoffset: 200; }
.fx.is-hatching .crack { animation: crack 520ms var(--ease-out) 220ms both; }
.fx.is-hatching .shell-l { animation: shell-l 620ms var(--ease-in) 760ms both; }
.fx.is-hatching .shell-r { animation: shell-r 620ms var(--ease-in) 760ms both; }
.art.is-egg svg:not(.fx) { opacity: 0; transform: scale(.6); }
.art.is-hatched svg:not(.fx) { animation: hatch 820ms var(--spring) 760ms both; }

@keyframes sparkle { 0%, 100% { opacity: 0; transform: scale(.2) rotate(0deg); } 40% { opacity: 1; transform: scale(1) rotate(25deg); } 70% { opacity: .7; transform: scale(.7) rotate(45deg); } }
@keyframes drop { 0% { opacity: 0; transform: translateY(-6px) scale(.8); } 20% { opacity: .95; transform: translateY(0) scale(1); } 100% { opacity: 0; transform: translateY(44px) scale(.9); } }
@keyframes steam { 0% { opacity: 0; transform: translateY(6px) scale(.7); } 25% { opacity: .8; } 100% { opacity: 0; transform: translateY(-34px) scale(1.25); } }
@keyframes zee { 0% { opacity: 0; transform: translate(0, 8px) scale(.6); } 25% { opacity: .95; } 100% { opacity: 0; transform: translate(14px, -40px) scale(1.15); } }
@keyframes mote { 0%, 100% { opacity: 0; transform: translate(0, 0); } 30%, 70% { opacity: .5; } 50% { transform: translate(6px, -12px); } }
@keyframes burst { 0% { opacity: 1; transform: translate(0, 0) scale(.3); } 100% { opacity: 0; transform: translate(var(--bx), var(--by)) scale(1); } }
@keyframes crack { to { stroke-dashoffset: 0; } }
@keyframes shell-l { to { opacity: 0; transform: translate(-28px, 18px) rotate(-28deg); } }
@keyframes shell-r { to { opacity: 0; transform: translate(28px, 18px) rotate(28deg); } }
@keyframes hatch { 0% { opacity: 0; transform: scale(.6); } 60% { opacity: 1; } 100% { opacity: 1; transform: scale(1); } }

/* ---- plates and ui ---- */
.plate { transition: transform var(--d-mid) var(--spring-soft), box-shadow var(--d-slow) var(--ease-out), border-color var(--d-slow) var(--ease-out); }
.plate.is-dipping .art { animation: dip 360ms var(--spring-soft); }
.plate .art { transition: box-shadow var(--d-slow) var(--ease-out); }
.plate .art .layer { position: absolute; inset: 0; transition: opacity var(--d-mid) var(--ease-out), transform var(--d-mid) var(--ease-out); }
.plate .art .layer.out { opacity: 0; transform: scale(.98); }
.plate .art .layer.in { animation: layer-in var(--d-mid) var(--ease-out) both; }
@keyframes layer-in { from { opacity: 0; transform: scale(1.02); } to { opacity: 1; transform: scale(1); } }
@keyframes dip { 0% { transform: scale(1); } 35% { transform: scale(.975); } 100% { transform: scale(1); } }

.btn, .chip, .theme-toggle, .sound-toggle, .nav a {
  transition: transform var(--d-mid) var(--spring), background var(--d-fast) var(--ease-out), color var(--d-fast) var(--ease-out),
    border-color var(--d-fast) var(--ease-out), box-shadow var(--d-fast) var(--ease-out), opacity var(--d-fast) var(--ease-out);
}
.btn:active, .chip:active, .theme-toggle:active, .sound-toggle:active { transition-duration: var(--d-tap); transform: scale(.96); }
.btn.is-magnet { transition: transform var(--d-fast) var(--ease-out); }
.btn.is-magnet.is-leaving { transition: transform var(--d-slow) var(--spring); }

.reveal { opacity: 0; transform: translateY(var(--reveal-y)); transition: opacity var(--d-reveal) var(--ease-out), transform var(--d-reveal) var(--ease-out); transition-delay: calc(var(--i, 0) * 70ms); }
.reveal.in { opacity: 1; transform: none; }

.mood-word .w { display: inline-block; animation: word-in var(--d-slow) var(--spring-soft) both; }
.mood-word .w.out { position: absolute; left: 0; animation: word-out 260ms var(--ease-in) both; }
@keyframes word-in { from { opacity: 0; transform: translateY(10px) rotate(-1.5deg); } to { opacity: 1; transform: none; } }
@keyframes word-out { to { opacity: 0; transform: translateY(-8px); } }

.sim .line { transition: d 0s; }
.sim .dot { transform-box: fill-box; transform-origin: center; transition: transform var(--d-mid) var(--spring), fill var(--d-fast) var(--ease-out); }
.sim .dot.is-active { transform: scale(1.7); }
.sim .ring { transform-box: fill-box; transform-origin: center; animation: ring 700ms var(--ease-out) both; }
.sim .pulse { transform-box: fill-box; transform-origin: center; animation: pulse 2.4s var(--ease-out) infinite; }
.sim.is-drawing .line { animation: draw 1300ms var(--ease-out) both; }
.sim.is-drawing .dot { animation: dot-in var(--d-mid) var(--spring) both; animation-delay: calc(var(--i, 0) * 60ms + 200ms); }
@keyframes draw { from { stroke-dashoffset: var(--len, 1200); } to { stroke-dashoffset: 0; } }
@keyframes dot-in { from { opacity: 0; transform: scale(0); } to { opacity: 1; transform: scale(1); } }
@keyframes ring { 0% { opacity: .6; transform: scale(.4); } 100% { opacity: 0; transform: scale(2.4); } }
@keyframes pulse { 0% { opacity: .5; transform: scale(.6); } 100% { opacity: 0; transform: scale(2.6); } }

.atmo i { transition: opacity var(--d-atmo) var(--ease-in-out), transform 900ms var(--ease-out); will-change: opacity, transform; }
.light { transition: opacity var(--d-slow) var(--ease-out); will-change: transform; }
.depth i { will-change: transform; }
.companion { transition: opacity var(--d-mid) var(--ease-out), transform var(--d-slow) var(--spring-soft); }
.companion:not(.on) { opacity: 0; transform: translateY(16px) scale(.9); pointer-events: none; }

.skeleton { position: relative; overflow: hidden; }
.skeleton::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,.35), transparent); transform: translateX(-100%); animation: shimmer 1.6s var(--ease-in-out) infinite; }
@keyframes shimmer { to { transform: translateX(100%); } }
.art.is-loading::before { content: ''; position: absolute; inset: 0; margin: auto; width: 46%; height: 46%; border-radius: 50%; background: var(--rule); opacity: .6; animation: egg-pulse 1.8s var(--ease-in-out) infinite; }
@keyframes egg-pulse { 0%, 100% { transform: scale(1); opacity: .5; } 50% { transform: scale(1.06); opacity: .75; } }

.msg.ok { animation: msg-in var(--d-mid) var(--ease-out) both; }
@keyframes msg-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ---- pause everything when the tab is hidden ---- */
html.is-hidden *, html.is-hidden *::before, html.is-hidden *::after { animation-play-state: paused !important; }

/* ---- reduced motion: loops stop, crossfades stay (opacity only), nothing slides ---- */
@media (prefers-reduced-motion: reduce) {
  .art svg .rig, .art.m-sleeping svg .rig, .art.m-nervous svg .shiver, .art svg .puff, .art svg .zz, .art svg .star, .art svg .sweat,
  .fx .sparkle, .fx .drop, .fx .steam, .fx .zee, .fx .mote, .sim .pulse, .art.is-loading::before, .skeleton::after { animation: none !important; }
  .fx .sparkle, .fx .drop, .fx .steam, .fx .zee, .fx .mote { opacity: .6; }
  .art svg .face.is-in, .art svg .extras.is-in { animation: face-out 300ms linear reverse both; }
  .plate.is-dipping .art { animation: none; }
  .plate .art .layer.in { animation: none; }
  .reveal { transform: none; transition: opacity var(--d-mid) var(--ease-out); }
  .btn, .chip, .theme-toggle, .sound-toggle { transition-property: background, color, border-color, box-shadow, opacity; }
  .btn:active, .chip:active { transform: none; }
  .sim.is-drawing .line, .sim.is-drawing .dot, .sim .ring, .art.is-hatched svg, .fx .burst, .fx.is-hatching .crack, .fx.is-hatching .shell-l, .fx.is-hatching .shell-r { animation: none !important; }
  .art.is-egg svg:not(.fx) { opacity: 1; transform: none; }
  .fx .shell, .fx .crack { display: none; }
  .mood-word .w { animation: none; }
  .mood-word .w.out { display: none; }
  .companion:not(.on) { transform: none; }
  .atmo i { transition: opacity var(--d-atmo) var(--ease-in-out); transform: none !important; }
  .depth i { transform: none !important; }
}
