/* Motion layer (2026-10-24) · only under html.fm (full motion).
   Entrances are keyframe animations (fill: backwards) so they never override an element's own transitions. */

/* ---------- entrance: hidden until in view ---------- */
html.fm.m-ready .m-words:not(.m-in) .mw > span,
html.fm.m-ready .m-up:not(.m-in),
html.fm.m-ready .m-st:not(.m-in) { opacity: 0; }
html.fm.m-ready .m-clip:not(.m-in) { clip-path: inset(100% 0 0 0); }

/* words rise from a mask */
.mw { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .1em; margin-bottom: -.1em; }
.mw > span { display: inline-block; }
@keyframes mWord { from { translate: 0 110%; opacity: 0; } to { translate: 0 0; opacity: 1; } }
html.fm .m-words.m-in .mw > span { animation: mWord 1.05s var(--ease) backwards; animation-delay: calc(var(--w, 0) * 38ms); }

/* fade-up blocks and staggered children */
@keyframes mUp { from { translate: 0 28px; opacity: 0; } to { translate: 0 0; opacity: 1; } }
html.fm .m-up.m-in { animation: mUp 1.05s var(--ease) backwards .05s; }
html.fm .m-st.m-in { animation: mUp 1s var(--ease) backwards; animation-delay: calc(var(--i, 0) * 65ms); }

/* media: clip reveal from the bottom, settling scale */
@keyframes mClip { from { clip-path: inset(100% 0 0 0); scale: 1.05; } to { clip-path: inset(0 0 0 0); scale: 1; } }
html.fm .m-clip.m-in { animation: mClip 1.35s var(--ease) backwards; }
html.fm .m-st .m-clip.m-in { animation-delay: calc(var(--i, 0) * 65ms + 90ms); }

/* ---------- section header: rule draws, scroll progress in red, number wipes in, ticks light up ---------- */
.m-sx { position: relative; border-top-color: transparent !important; }
.m-sx::before { content: ""; position: absolute; left: 0; right: 0; top: -2px; height: 2px; background: currentColor; transform-origin: left; }
.m-sx::after { content: ""; position: absolute; left: 0; top: -2px; height: 2px; width: calc(var(--prog, 0) * 100%); background: var(--red); }
.t-ink .m-sx::after, .t-graphite .m-sx::after { background: var(--red-d); }
@keyframes mRule { from { transform: scaleX(0); } }
@keyframes mWipe { from { clip-path: inset(0 100% 0 0); translate: -34px 0; } to { clip-path: inset(0 -10% 0 0); translate: 0 0; } }
@keyframes mTick { from { opacity: 0; scale: 0 1; } }
html.fm.m-ready .m-sx:not(.m-in)::before { transform: scaleX(0); }
html.fm.m-ready .m-sx:not(.m-in) .sx-n, html.fm.m-ready .m-sx:not(.m-in) .sx-ticks i { opacity: 0; }
html.fm .m-sx.m-in::before { animation: mRule 1.4s var(--ease) backwards; }
html.fm .m-sx.m-in .sx-n { animation: mWipe 1.2s var(--ease) backwards .15s; }
html.fm .m-sx.m-in .sx-ticks i { animation: mTick .5s var(--ease) backwards; animation-delay: calc(var(--k, 0) * 45ms + .45s); }

/* ---------- ongoing: pointer tilt with a soft light ---------- */
.m-tilt { transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); will-change: transform; }
.m-tilt.m-tilting { transition: transform .25s ease-out; }
.m-tilt:not(.m-tilting) { transition: transform .7s var(--ease); }
.m-tilt::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity .5s; background: radial-gradient(circle at var(--gx, 50%) var(--gy, 50%), rgba(255, 255, 255, .2), transparent 55%); z-index: 2; }
.m-tilt:hover::after { opacity: 1; }
html.rm .m-tilt { transform: none; }
html.rm .m-tilt::after { display: none; }

/* ---------- ongoing: magnetic buttons (translate is separate from the buttons' own transitions) ---------- */
.m-mag { transition: translate .5s var(--ease), background-color .3s, color .3s, border-color .3s, box-shadow .3s; }

/* ---------- ongoing: slow breathing, glow, shimmer, nudge ---------- */
@keyframes mBreath { 0%, 100% { scale: 1; } 50% { scale: 1.035; } }
html.fm .lens-photo img, html.fm .in-photo { animation: mBreath 14s ease-in-out infinite; }
@keyframes mGlow { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
html.fm .chap.in .chap-num { animation: mGlow 6s ease-in-out infinite; }
.chap-num, .chap-t, .sx-n, .bl-big { will-change: translate; }
.chap-bar { position: relative; overflow: hidden; }
.chap-bar::after { content: ""; position: absolute; top: 0; bottom: 0; width: 30%; left: -30%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .6), transparent); }
html.fm .chap.in .chap-bar::after { animation: mShine 4.5s 1.6s ease-in-out infinite; }
@keyframes mShine { to { left: 110%; } }
@keyframes mNudge { 0%, 82%, 100% { translate: 0 0; } 90% { translate: 5px 0; } }
html.fm .btn .ar { animation: mNudge 3.4s ease-in-out infinite; }
@keyframes mPulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(200, 38, 47, .45); } 60% { box-shadow: 0 0 0 10px rgba(200, 38, 47, 0); } }
html.fm .cta-h { animation: mPulse 3.2s ease-out infinite; }
