/* Motion. One authored moment (the cover draws itself), purposeful feedback everywhere else.
   Content is visible by default; every hidden start state is scoped to html.js. Reduced motion is honoured below. */

/* ---------- keyframes ---------- */
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes fade-in { to { opacity: 1; } }
@keyframes bob { from { translate: 0 0; rotate: -1.2deg; } to { translate: 0 -9px; rotate: 1.2deg; } }
@keyframes rise { 0% { opacity: 0; translate: 0 0; scale: 0.8; } 12% { opacity: 0.85; } 100% { opacity: 0; translate: var(--dx) -105vh; scale: 1.15; } }
@keyframes drift { to { translate: -50% 0; } }
@keyframes cta-bob { 0%, 100% { transform: translateY(-2px); } 50% { transform: translateY(3px); } } /* on an <svg> root only `transform` reaches the compositor */
@keyframes cover-in { from { opacity: 0; translate: 0 26px; scale: 0.985; } }
@keyframes letter-in { from { opacity: 0; translate: 0 0.32em; filter: blur(6px); } }
@keyframes write { from { clip-path: inset(-12% 100% -24% -2%); } to { clip-path: inset(-12% -4% -24% -2%); } }
@keyframes fade-up { from { opacity: 0; translate: 0 10px; } }
@keyframes bump { 0% { scale: 1; } 40% { scale: 1.07; } 100% { scale: 1; } }
@keyframes ctl-in { from { opacity: 0; scale: 0.85; } }
@keyframes pop { 0% { scale: 1; } 38% { scale: 1.22; rotate: -6deg; } 100% { scale: 1; rotate: 0deg; } }
@keyframes flash { 0% { background-color: color-mix(in oklab, var(--color-accent) 75%, transparent); } 100% { background-color: transparent; } }
@keyframes halo { from { opacity: 0.85; scale: 0.6; } to { opacity: 0; scale: 2.1; } }
@keyframes tag-in { from { opacity: 0; scale: 0.9; } }
@keyframes pin-drop { from { opacity: 0; translate: 0 -10px; } to { opacity: 1; translate: 0 0; } }
@keyframes fill-on { to { fill-opacity: 1; } }
@keyframes breathe { from { opacity: 0.25; } to { opacity: 1; } }

/* ---------- plates: draw on, then idle ---------- */
.js .plate:not(.is-drawn) .ink { stroke-dasharray: 1; stroke-dashoffset: 1; }
.js .plate:not(.is-drawn) .fine { opacity: 0; }
.plate.is-drawn .ink { stroke-dasharray: 1; stroke-dashoffset: 1; animation: draw 1.35s var(--ease-out) forwards; animation-delay: calc(var(--d, 0s) + var(--i, 0) * 11ms); }
.plate.is-drawn .fine { opacity: 0; animation: fade-in 0.8s ease forwards; animation-delay: calc(var(--d, 0s) + 1s + var(--i, 0) * 7ms); }
.js .plate:not(.is-drawn) .ink.solid { fill-opacity: 0; }
.plate.is-drawn .ink.solid { fill-opacity: 0; animation: draw 1.35s var(--ease-out) forwards, fill-on 0.45s ease forwards; animation-delay: calc(var(--d, 0s) + var(--i, 0) * 11ms), calc(var(--d, 0s) + var(--i, 0) * 11ms + 0.95s); }
.plate.is-static .ink { animation: none; stroke-dasharray: none; stroke-dashoffset: 0; }
.plate.is-static .ink.solid { animation: none; fill-opacity: 1; }
.plate.is-static .fine { animation: none; opacity: 1; }

/* Limbs (legs, claws, tails, fins, feelers) are posed by js/beat.js on one shared 5 fps beat, not by CSS animations: on SVG limbs those
   kept a slow phone's main thread busy on every frame. CSS only fixes the pivots. The plates' float and the bubbles stay CSS (compositor). */
.plate-fish .fin-p { transform-origin: 340px 130px; }
.plate-lobster .feel-l { transform-origin: 216px 166px; }
.plate-lobster .feel-r { transform-origin: 244px 166px; }

/* ---------- cover intro (one authored moment) ---------- */
.js .cover { animation: cover-in 0.9s var(--ease-expo) 0.15s both; }
.js .ch { animation: letter-in 0.85s var(--ease-expo) both; animation-delay: calc(0.5s + var(--i) * 48ms); }
.js .cover-script { animation: write 1.5s var(--ease-in-out) 1.2s both; }
.js .cover-menu { animation: fade-up 0.6s var(--ease-out) 0.35s both; }
.js .cover-tag { animation: fade-up 0.7s var(--ease-out) 2.1s both; }
.js .cta { animation: fade-up 0.7s var(--ease-out) 2.35s both; }
.js .hero-tools { animation: fade-up 0.6s var(--ease-out) 0.6s both; }
.js .hero-spiral { animation: fade-in 0.8s ease 0.2s both; }
html[data-intro="seen"] .cover, html[data-intro="seen"] .ch, html[data-intro="seen"] .cover-script, html[data-intro="seen"] .cover-menu,
html[data-intro="seen"] .cover-tag, html[data-intro="seen"] .cta, html[data-intro="seen"] .hero-tools, html[data-intro="seen"] .hero-spiral { animation: none; }
/* the .cta pill is centred with `translate`, so its entrance must not touch translate */
.js .cta { animation-name: cta-in; }
@keyframes cta-in { from { opacity: 0; } }

/* ---------- reveals ---------- */
.mask-in { transition: translate 0.85s var(--ease-expo); }
.js .rv-title:not(.in) .mask-in { translate: 0 112%; }
.rv { transition: opacity 0.6s var(--ease-out) var(--rd, 0ms), translate 0.6s var(--ease-out) var(--rd, 0ms); }
.js .rv:not(.in) { opacity: 0; translate: 0 14px; }

/* ---------- chart ---------- */
.chart:not(.is-drawn) .pin { opacity: 0; }
.chart.is-drawn .pin { animation: pin-drop 0.55s var(--ease-out) both; animation-delay: calc(1.1s + var(--i, 0) * 80ms); }
.chart.is-static .pin { animation: none; opacity: 1; }
.chart .ripple.r2 { animation: breathe 5.5s ease-in-out infinite alternate; }
.chart .ripple.r2:nth-of-type(odd) { animation-duration: 7s; animation-delay: -2s; }
.chart-wrap:not(.in-view) .ripple { animation-play-state: paused; }

/* ---------- language switch: a soft crossfade with a touch of blur hides the swap ---------- */
main, .foot, .dock-nav { transition: opacity 0.22s ease, filter 0.22s ease; }
.is-switching main, .is-switching .foot, .is-switching .dock-nav { opacity: 0; filter: blur(4px); transition-duration: 0.15s; }

/* ---------- pause everything decorative when the tab is hidden, or the user pauses ---------- */
html[data-hidden] .pl *, html[data-hidden] .bubbles i, html[data-hidden] .waves-row, html[data-hidden] .ripple, html[data-hidden] .cta-ico .ico { animation-play-state: paused !important; }

html[data-motion="off"] .pl-in, html[data-motion="off"] .plate *, html[data-motion="off"] .bubbles i, html[data-motion="off"] .waves-row,
html[data-motion="off"] .cta-ico .ico, html[data-motion="off"] .chart .ripple, html[data-motion="off"] .pin-halo { animation: none !important; }
html[data-motion="off"].js .plate .ink { stroke-dasharray: none; stroke-dashoffset: 0; fill-opacity: 1; }
html[data-motion="off"].js .plate:not(.is-drawn) .ink { stroke-dasharray: none; stroke-dashoffset: 0; }
html[data-motion="off"].js .plate .fine, html[data-motion="off"].js .plate:not(.is-drawn) .fine { opacity: 1; }
html[data-motion="off"] .bubbles { display: none; }
html[data-motion="off"] .cover, html[data-motion="off"] .ch, html[data-motion="off"] .cover-script, html[data-motion="off"] .cover-menu,
html[data-motion="off"] .cover-tag, html[data-motion="off"] .cta, html[data-motion="off"] .hero-tools, html[data-motion="off"] .hero-spiral { animation: none; }
html[data-motion="off"] .rv, html[data-motion="off"] .mask-in { transition: none; }
html[data-motion="off"].js .rv:not(.in) { opacity: 1; translate: 0 0; }
html[data-motion="off"].js .rv-title:not(.in) .mask-in { translate: 0 0; }
html[data-motion="off"] .chart .pin { opacity: 1; }
html[data-motion="off"] .pills--ghost, html[data-motion="off"] .sheet, html[data-motion="off"] .scrim, html[data-motion="off"] .peek { transition-duration: 0.01ms; }

/* ---------- calm version for weak phones (set by the head script or app.js) ----------
   The plates are drawn at once and stand still, the bubbles go; the cover entrance, reveals, sheet and every tap feedback stay. */
html[data-perf="lite"] .pl-in, html[data-perf="lite"] .plate *, html[data-perf="lite"] .bubbles i, html[data-perf="lite"] .waves-row,
html[data-perf="lite"] .cta-ico .ico, html[data-perf="lite"] .chart .ripple { animation: none !important; }
html[data-perf="lite"].js .plate .ink, html[data-perf="lite"].js .plate:not(.is-drawn) .ink { stroke-dasharray: none; stroke-dashoffset: 0; fill-opacity: 1; }
html[data-perf="lite"].js .plate .fine, html[data-perf="lite"].js .plate:not(.is-drawn) .fine { opacity: 1; }
html[data-perf="lite"] .bubbles { display: none; }
