/* Shared abstract effects (see fx.js). */
html, body { overflow-x: clip; }   /* decorative art may bleed past the edge; never a sideways scroll on phones */
.fx-art { width: 100%; height: 100%; display: block; }
.fx-art .fx-art-fg { transform-origin: center; transition: transform .8s cubic-bezier(.2,.8,.2,1); }
.fx-tilt:hover .fx-art .fx-art-fg { transform: scale(1.12) rotate(4deg); }
[data-reveal] { opacity: 0; transform: translateY(34px) scale(.97); filter: blur(6px);
  transition: opacity .8s cubic-bezier(.2,.8,.2,1), transform .8s cubic-bezier(.2,.8,.2,1), filter .8s; }
[data-reveal].fx-in { opacity: 1; transform: none; filter: none; }
.fx-tilt { transition: transform .35s cubic-bezier(.2,.8,.2,1); transform-style: preserve-3d; will-change: transform; }
.fx-tilt::after { content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity .3s;
  background: radial-gradient(360px circle at var(--mx, 50%) var(--my, 50%), rgba(255,255,255,.22), transparent 45%); mix-blend-mode: overlay; }
.fx-tilt:hover::after { opacity: 1; }
.fx-cursor { position: fixed; left: -18px; top: -18px; width: 36px; height: 36px; border-radius: 50%; pointer-events: none; z-index: 100;
  mix-blend-mode: difference; transition: width .25s, height .25s, left .25s, top .25s; }
.fx-cursor.big { width: 76px; height: 76px; left: -38px; top: -38px; }
.fx-marquee { overflow: hidden; white-space: nowrap; }
.fx-mq { display: inline-flex; animation: fx-mq 32s linear infinite; }
.fx-mq span { padding: 0 28px; display: inline-flex; align-items: center; gap: 28px; }
.fx-mq span::after { content: '✺'; opacity: .6; }
@keyframes fx-mq { to { transform: translateX(-50%); } }
.fx-w { display: inline-block; opacity: 0; transform: translateY(.6em) rotate(4deg); animation: fx-w .9s cubic-bezier(.2,.8,.2,1) forwards; }
@keyframes fx-w { to { opacity: 1; transform: none; } }
.fx-grain { position: fixed; inset: -50%; pointer-events: none; z-index: 90; opacity: .07; animation: fx-grain 1.2s steps(6) infinite;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E"); }
@keyframes fx-grain { 0% { transform: translate(0,0) } 20% { transform: translate(-5%,3%) } 40% { transform: translate(4%,-6%) } 60% { transform: translate(-3%,5%) } 80% { transform: translate(6%,2%) } }
.fx-blob { border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%; animation: fx-morph 12s ease-in-out infinite; }
@keyframes fx-morph { 33% { border-radius: 63% 37% 41% 59% / 55% 38% 62% 45%; } 66% { border-radius: 36% 64% 52% 48% / 38% 61% 39% 62%; } }
.fx-spin { animation: fx-spin 24s linear infinite; }
@keyframes fx-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .fx-mq, .fx-grain, .fx-blob, .fx-spin { animation: none; }
  [data-reveal] { opacity: 1; transform: none; filter: none; }
}
