/* Solao Base - modern CSS effects used by this template. Each effect is one class: fx-NAME. */

/* ===== Modern CSS Animations ===== */
/* Orbital Motion - Two small planets circle around an avatar, logo or icon on separate orbits. */
.fx-orbital-motion {
  position: relative; display: inline-grid; place-items: center; width: 9rem; height: 9rem;
  border-radius: 50%; border: 1px dashed rgba(var(--wt-primary-rgb), .45);
}
.fx-orbital-motion::before, .fx-orbital-motion::after {
  content: ""; position: absolute; top: 50%; left: 50%; border-radius: 50%; pointer-events: none;
}
.fx-orbital-motion::before {
  width: 14px; height: 14px; margin: -7px; background: var(--wt-primary);
  box-shadow: 0 0 10px rgba(var(--wt-primary-rgb), .7);
  animation: fx-orbital-motion-outer 5s linear infinite;
}
.fx-orbital-motion::after {
  width: 10px; height: 10px; margin: -5px; background: var(--wt-accent);
  animation: fx-orbital-motion-inner 3.2s linear infinite reverse;
}
@keyframes fx-orbital-motion-outer { from { transform: rotate(0deg) translateX(4.5rem) rotate(0deg); } to { transform: rotate(360deg) translateX(4.5rem) rotate(-360deg); } }
@keyframes fx-orbital-motion-inner { from { transform: rotate(0deg) translateX(3.1rem); } to { transform: rotate(360deg) translateX(3.1rem); } }
@media (prefers-reduced-motion: reduce) {
  .fx-orbital-motion, .fx-orbital-motion::before, .fx-orbital-motion::after, .fx-orbital-motion *, .fx-orbital-motion *::before, .fx-orbital-motion *::after { animation: none !important; transition: none !important; }
}
/* Heartbeat - A double-beat pulse for like buttons, favourite icons and notification badges. */
.fx-heartbeat { display: inline-block; animation: fx-heartbeat-beat 1.5s ease-in-out infinite; transform-origin: center; }
@keyframes fx-heartbeat-beat {
  0%, 40%, 100% { transform: scale(1); }
  12% { transform: scale(1.2); }
  24% { transform: scale(.96); }
  32% { transform: scale(1.14); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-heartbeat, .fx-heartbeat::before, .fx-heartbeat::after, .fx-heartbeat *, .fx-heartbeat *::before, .fx-heartbeat *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Clip-path Effects ===== */
/* Wave Animation - Gives the bottom edge of a hero image or header a gently rolling wave. */
.fx-wave-animation { -webkit-clip-path: polygon(0 0, 100% 0, 100% 86%, 93.8% 80.3%, 87.5% 78%, 81.3% 80.3%, 75% 86%, 68.8% 91.7%, 62.5% 94%, 56.3% 91.7%, 50% 86%, 43.8% 80.3%, 37.5% 78%, 31.3% 80.3%, 25% 86%, 18.8% 91.7%, 12.5% 94%, 6.3% 91.7%, 0 86%); clip-path: polygon(0 0, 100% 0, 100% 86%, 93.8% 80.3%, 87.5% 78%, 81.3% 80.3%, 75% 86%, 68.8% 91.7%, 62.5% 94%, 56.3% 91.7%, 50% 86%, 43.8% 80.3%, 37.5% 78%, 31.3% 80.3%, 25% 86%, 18.8% 91.7%, 12.5% 94%, 6.3% 91.7%, 0 86%); animation: fx-wave-animation-wave 4s ease-in-out infinite alternate; }
@keyframes fx-wave-animation-wave { from { -webkit-clip-path: polygon(0 0, 100% 0, 100% 86%, 93.8% 80.3%, 87.5% 78%, 81.3% 80.3%, 75% 86%, 68.8% 91.7%, 62.5% 94%, 56.3% 91.7%, 50% 86%, 43.8% 80.3%, 37.5% 78%, 31.3% 80.3%, 25% 86%, 18.8% 91.7%, 12.5% 94%, 6.3% 91.7%, 0 86%); clip-path: polygon(0 0, 100% 0, 100% 86%, 93.8% 80.3%, 87.5% 78%, 81.3% 80.3%, 75% 86%, 68.8% 91.7%, 62.5% 94%, 56.3% 91.7%, 50% 86%, 43.8% 80.3%, 37.5% 78%, 31.3% 80.3%, 25% 86%, 18.8% 91.7%, 12.5% 94%, 6.3% 91.7%, 0 86%); } to { -webkit-clip-path: polygon(0 0, 100% 0, 100% 86%, 93.8% 91.7%, 87.5% 94%, 81.3% 91.7%, 75% 86%, 68.8% 80.3%, 62.5% 78%, 56.3% 80.3%, 50% 86%, 43.8% 91.7%, 37.5% 94%, 31.3% 91.7%, 25% 86%, 18.8% 80.3%, 12.5% 78%, 6.3% 80.3%, 0 86%); clip-path: polygon(0 0, 100% 0, 100% 86%, 93.8% 91.7%, 87.5% 94%, 81.3% 91.7%, 75% 86%, 68.8% 80.3%, 62.5% 78%, 56.3% 80.3%, 50% 86%, 43.8% 91.7%, 37.5% 94%, 31.3% 91.7%, 25% 86%, 18.8% 80.3%, 12.5% 78%, 6.3% 80.3%, 0 86%); } }
@media (prefers-reduced-motion: reduce) {
  .fx-wave-animation, .fx-wave-animation::before, .fx-wave-animation::after, .fx-wave-animation *, .fx-wave-animation *::before, .fx-wave-animation *::after { animation: none !important; transition: none !important; }
}
/* SVG Path (Heart) - A heart-shaped cut-out traced from the classic heart curve, scaling to any size, with a soft beat. */
.fx-svg-path-heart { -webkit-clip-path: polygon(50% 24.9%, 50.3% 22.9%, 52% 17.6%, 56.1% 10.8%, 63% 4.9%, 72% 2%, 81.8% 3.3%, 90.7% 8.8%, 96.8% 17.6%, 99% 28.2%, 96.8% 39.3%, 90.7% 49.9%, 81.8% 59.8%, 72% 69%, 63% 77.7%, 56.1% 85.6%, 52% 92.1%, 50.3% 96.5%, 50% 98%, 49.7% 96.5%, 48% 92.1%, 43.9% 85.6%, 37% 77.7%, 28% 69%, 18.2% 59.8%, 9.3% 49.9%, 3.2% 39.3%, 1% 28.2%, 3.2% 17.6%, 9.3% 8.8%, 18.2% 3.3%, 28% 2%, 37% 4.9%, 43.9% 10.8%, 48% 17.6%, 49.7% 22.9%); clip-path: polygon(50% 24.9%, 50.3% 22.9%, 52% 17.6%, 56.1% 10.8%, 63% 4.9%, 72% 2%, 81.8% 3.3%, 90.7% 8.8%, 96.8% 17.6%, 99% 28.2%, 96.8% 39.3%, 90.7% 49.9%, 81.8% 59.8%, 72% 69%, 63% 77.7%, 56.1% 85.6%, 52% 92.1%, 50.3% 96.5%, 50% 98%, 49.7% 96.5%, 48% 92.1%, 43.9% 85.6%, 37% 77.7%, 28% 69%, 18.2% 59.8%, 9.3% 49.9%, 3.2% 39.3%, 1% 28.2%, 3.2% 17.6%, 9.3% 8.8%, 18.2% 3.3%, 28% 2%, 37% 4.9%, 43.9% 10.8%, 48% 17.6%, 49.7% 22.9%); animation: fx-svg-path-heart-beat 1.8s ease-in-out infinite; }
@keyframes fx-svg-path-heart-beat { 0%, 45%, 100% { transform: scale(1); } 15% { transform: scale(1.08); } 30% { transform: scale(1.03); } }
@media (prefers-reduced-motion: reduce) {
  .fx-svg-path-heart, .fx-svg-path-heart::before, .fx-svg-path-heart::after, .fx-svg-path-heart *, .fx-svg-path-heart *::before, .fx-svg-path-heart *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Filter Effects ===== */
/* Invert Colors - Flips an image or card to its negative on hover while hue-rotate keeps the colours recognisable. */
.fx-invert-colors { transition: filter .4s ease; }
.fx-invert-colors:hover, .fx-invert-colors:focus-visible { filter: invert(1) hue-rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .fx-invert-colors, .fx-invert-colors::before, .fx-invert-colors::after, .fx-invert-colors *, .fx-invert-colors *::before, .fx-invert-colors *::after { animation: none !important; transition: none !important; }
}
/* Glitch Filter - Short bursts of hue, contrast and position jumps make an image look like a corrupted signal. */
.fx-glitch-filter { animation: fx-glitch-filter-glitch 3.5s steps(1) infinite; }
@keyframes fx-glitch-filter-glitch {
  0%, 86%, 100% { filter: none; transform: none; }
  88% { filter: hue-rotate(90deg) saturate(3) contrast(1.6); transform: translate(-4px, 1px); }
  90% { filter: invert(.15) contrast(2); transform: translate(4px, -2px) skewX(6deg); }
  92% { filter: hue-rotate(-70deg) saturate(2); transform: translate(-2px, 0); }
  94% { filter: brightness(1.6); transform: translate(2px, 1px); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-glitch-filter, .fx-glitch-filter::before, .fx-glitch-filter::after, .fx-glitch-filter *, .fx-glitch-filter *::before, .fx-glitch-filter *::after { animation: none !important; transition: none !important; }
}
/* Advanced Combo - A figure whose blurred, muted image sharpens and zooms on hover while a frosted caption slides up. */
.fx-advanced-combo { position: relative; overflow: hidden; display: inline-block; margin: 0; }
.fx-advanced-combo img { display: block; filter: grayscale(.5) blur(1px) brightness(.85); transform: scale(1.05); transition: filter .5s, transform .6s; }
.fx-advanced-combo figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; padding: .6rem .8rem; color: #fff;
  background: rgba(0, 0, 0, .35); -webkit-backdrop-filter: blur(8px) saturate(1.4); backdrop-filter: blur(8px) saturate(1.4);
  transform: translateY(100%); transition: transform .45s cubic-bezier(.2, .8, .2, 1);
}
.fx-advanced-combo:hover img, .fx-advanced-combo:focus-within img { filter: none; transform: scale(1.12); }
.fx-advanced-combo:hover figcaption, .fx-advanced-combo:focus-within figcaption { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .fx-advanced-combo, .fx-advanced-combo::before, .fx-advanced-combo::after, .fx-advanced-combo *, .fx-advanced-combo *::before, .fx-advanced-combo *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Transform Effects ===== */
/* 3D Card Tilt - Tilts a card in 3D with a moving glare on hover - a pure CSS take on the mouse-follow tilt. */
.fx-3d-card-tilt {
  position: relative; overflow: hidden; transform-style: preserve-3d;
  transform: perspective(900px) rotateX(0deg) rotateY(0deg);
  transition: transform .55s cubic-bezier(.2, .8, .2, 1), box-shadow .55s;
}
.fx-3d-card-tilt::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, .45) 48%, transparent 62%);
  transform: translateX(-60%); transition: transform .7s ease, opacity .4s;
}
.fx-3d-card-tilt:hover, .fx-3d-card-tilt:focus-within {
  transform: perspective(900px) rotateX(8deg) rotateY(-12deg) translateY(-4px);
  box-shadow: 18px 22px 40px -18px rgba(var(--wt-primary-rgb), .55);
}
.fx-3d-card-tilt:hover::after, .fx-3d-card-tilt:focus-within::after { opacity: 1; transform: translateX(60%); }
@media (prefers-reduced-motion: reduce) {
  .fx-3d-card-tilt, .fx-3d-card-tilt::before, .fx-3d-card-tilt::after, .fx-3d-card-tilt *, .fx-3d-card-tilt *::before, .fx-3d-card-tilt *::after { animation: none !important; transition: none !important; }
}
/* 3D Rotating Cube - A spinning six-sided cube; give the element six children for the faces and set --fx-size if needed. */
.fx-3d-rotating-cube {
  --fx-half: calc(var(--fx-size, 6rem) / 2);
  position: relative; width: var(--fx-size, 6rem); height: var(--fx-size, 6rem);
  transform-style: preserve-3d;
  animation: fx-3d-rotating-cube-spin 12s linear infinite;
}
.fx-3d-rotating-cube:hover { animation-play-state: paused; }
.fx-3d-rotating-cube > * {
  position: absolute; inset: 0; display: grid; place-items: center; font-size: 1.6rem;
  color: var(--wt-on-primary, #fff); border: 1px solid rgba(255, 255, 255, .35);
  background: rgba(var(--wt-primary-rgb), .88);
}
.fx-3d-rotating-cube > :nth-child(1) { transform: translateZ(var(--fx-half)); }
.fx-3d-rotating-cube > :nth-child(2) { transform: rotateY(180deg) translateZ(var(--fx-half)); background: rgba(var(--wt-secondary-rgb), .88); }
.fx-3d-rotating-cube > :nth-child(3) { transform: rotateY(90deg) translateZ(var(--fx-half)); background: rgba(var(--wt-accent-rgb), .88); }
.fx-3d-rotating-cube > :nth-child(4) { transform: rotateY(-90deg) translateZ(var(--fx-half)); background: rgba(var(--wt-secondary-rgb), .88); }
.fx-3d-rotating-cube > :nth-child(5) { transform: rotateX(90deg) translateZ(var(--fx-half)); background: rgba(var(--wt-accent-rgb), .88); }
.fx-3d-rotating-cube > :nth-child(6) { transform: rotateX(-90deg) translateZ(var(--fx-half)); }
@keyframes fx-3d-rotating-cube-spin {
  from { transform: perspective(700px) rotateX(-22deg) rotateY(0deg); }
  to { transform: perspective(700px) rotateX(-22deg) rotateY(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-3d-rotating-cube, .fx-3d-rotating-cube::before, .fx-3d-rotating-cube::after, .fx-3d-rotating-cube *, .fx-3d-rotating-cube *::before, .fx-3d-rotating-cube *::after { animation: none !important; transition: none !important; }
}
/* Translate 3D - Stacked layers separate along the Z axis on hover, like an exploded view of your interface. */
.fx-translate-3d { position: relative; transform-style: preserve-3d; transform: perspective(800px); transition: transform .6s cubic-bezier(.2, .8, .2, 1); }
.fx-translate-3d > * { transition: transform .6s cubic-bezier(.2, .8, .2, 1); }
.fx-translate-3d:hover { transform: perspective(800px) rotateX(48deg) rotateZ(-28deg); }
.fx-translate-3d:hover > :nth-child(1) { transform: translate3d(0, 0, 0); }
.fx-translate-3d:hover > :nth-child(2) { transform: translate3d(0, 0, 30px); }
.fx-translate-3d:hover > :nth-child(3) { transform: translate3d(0, 0, 60px); }
.fx-translate-3d:hover > :nth-child(4) { transform: translate3d(0, 0, 90px); }
@media (prefers-reduced-motion: reduce) {
  .fx-translate-3d, .fx-translate-3d::before, .fx-translate-3d::after, .fx-translate-3d *, .fx-translate-3d *::before, .fx-translate-3d *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Transitions ===== */
/* Neon Fill Button - An outline button that fills with colour from the left and glows; works on any .btn or link. */
.fx-neon-fill-button, .btn.fx-neon-fill-button {
  position: relative; isolation: isolate; overflow: hidden; z-index: 0;
  color: var(--wt-primary-ink); background: transparent; border: 2px solid var(--wt-primary);
  transition: color .35s ease, box-shadow .35s ease;
}
.fx-neon-fill-button::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--wt-primary);
  transform: scaleX(0); transform-origin: left center; transition: transform .4s cubic-bezier(.7, 0, .3, 1);
}
.fx-neon-fill-button:hover, .fx-neon-fill-button:focus-visible, .btn.fx-neon-fill-button:hover, .btn.fx-neon-fill-button:focus-visible {
  color: var(--wt-on-primary, #fff); border-color: var(--wt-primary);
  box-shadow: 0 0 12px rgba(var(--wt-primary-rgb), .6), 0 0 32px rgba(var(--wt-primary-rgb), .35);
}
.fx-neon-fill-button:hover::before, .fx-neon-fill-button:focus-visible::before { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .fx-neon-fill-button, .fx-neon-fill-button::before, .fx-neon-fill-button::after, .fx-neon-fill-button *, .fx-neon-fill-button *::before, .fx-neon-fill-button *::after { animation: none !important; transition: none !important; }
}
/* Liquid Ripple - A button that fills with a swirling liquid from the bottom on hover. */
.fx-liquid-ripple, .btn.fx-liquid-ripple {
  position: relative; isolation: isolate; overflow: hidden; z-index: 0;
  color: var(--wt-primary-ink); background: var(--wt-surface, #fff); border: 2px solid var(--wt-primary);
  transition: color .5s ease;
}
.fx-liquid-ripple::before {
  content: ""; position: absolute; z-index: -1; left: 50%; top: 100%; width: 240%; aspect-ratio: 1;
  margin-left: -120%; margin-top: 12%; border-radius: 42%;
  background: var(--wt-primary);
  transition: top .8s ease, margin-top .8s ease;
  animation: fx-liquid-ripple-swirl 5s linear infinite;
}
.fx-liquid-ripple:hover, .fx-liquid-ripple:focus-visible, .btn.fx-liquid-ripple:hover, .btn.fx-liquid-ripple:focus-visible { color: var(--wt-on-primary, #fff); border-color: var(--wt-primary); }
.fx-liquid-ripple:hover::before, .fx-liquid-ripple:focus-visible::before { top: 50%; margin-top: -120%; }
.fx-liquid-ripple:active { transform: scale(.97); }
@keyframes fx-liquid-ripple-swirl { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .fx-liquid-ripple, .fx-liquid-ripple::before, .fx-liquid-ripple::after, .fx-liquid-ripple *, .fx-liquid-ripple *::before, .fx-liquid-ripple *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Gradient Effects ===== */
/* Animated Rainbow - A full-spectrum gradient that flows endlessly across banners, buttons and progress bars. */
.fx-animated-rainbow {
  color: #fff;
  background: linear-gradient(90deg, #ff3d7f, #ff9f1c, #ffd23f, #3bce73, #2ec4ff, #7b5cff, #ff3d7f);
  background-size: 300% 100%;
  animation: fx-animated-rainbow-flow 8s linear infinite;
}
@keyframes fx-animated-rainbow-flow { to { background-position: -150% 0; } }
@media (prefers-reduced-motion: reduce) {
  .fx-animated-rainbow, .fx-animated-rainbow::before, .fx-animated-rainbow::after, .fx-animated-rainbow *, .fx-animated-rainbow *::before, .fx-animated-rainbow *::after { animation: none !important; transition: none !important; }
}
/* Animated Border - A gradient border that rotates around a card or button; browsers without @property show it still. */
@property --fx-animated-border-angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.fx-animated-border {
  border: 3px solid transparent;
  background:
    linear-gradient(var(--wt-surface, #fff), var(--wt-surface, #fff)) padding-box,
    conic-gradient(from var(--fx-animated-border-angle), var(--wt-primary), var(--wt-accent), var(--wt-secondary), var(--wt-primary)) border-box;
  animation: fx-animated-border-turn 4s linear infinite;
}
@keyframes fx-animated-border-turn { to { --fx-animated-border-angle: 360deg; } }
@media (prefers-reduced-motion: reduce) {
  .fx-animated-border, .fx-animated-border::before, .fx-animated-border::after, .fx-animated-border *, .fx-animated-border *::before, .fx-animated-border *::after { animation: none !important; transition: none !important; }
}
/* Iridescent - A holographic, pearly sheen that shifts its colours as the card is hovered. */
.fx-iridescent {
  position: relative; overflow: hidden; color: #1d1d2b;
  background: linear-gradient(120deg, #f6d5f7, #fbe9d7, #d5f2ef, #d7e2fb, #e9d5fb, #f6d5f7);
  background-size: 300% 300%; background-position: 0% 50%;
  transition: background-position 1.2s ease;
}
.fx-iridescent::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; mix-blend-mode: overlay;
  background: linear-gradient(105deg, transparent 35%, rgba(255, 255, 255, .7) 50%, transparent 65%);
  background-size: 250% 100%; background-position: 100% 0; transition: background-position 1.2s ease;
}
.fx-iridescent:hover, .fx-iridescent:focus-within { background-position: 100% 50%; }
.fx-iridescent:hover::after, .fx-iridescent:focus-within::after { background-position: 0 0; }
@media (prefers-reduced-motion: reduce) {
  .fx-iridescent, .fx-iridescent::before, .fx-iridescent::after, .fx-iridescent *, .fx-iridescent *::before, .fx-iridescent *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern Shadow Effects ===== */
/* Neumorphism - Soft extruded surfaces that match the page background; they press in on hover and adapt to dark mode. */
.fx-neumorphism {
  --fx-neu-bg: var(--wt-bg, #e9edf2);
  background: var(--fx-neu-bg); border: 0;
  --fx-neu-dark: rgba(0, 0, 0, .14); --fx-neu-light: rgba(255, 255, 255, .75);
  box-shadow: 8px 8px 18px var(--fx-neu-dark), -8px -8px 18px var(--fx-neu-light);
  transition: box-shadow .35s ease;
}
@supports (color: color-mix(in srgb, red 50%, blue)) {
  .fx-neumorphism {
    --fx-neu-dark: color-mix(in srgb, var(--fx-neu-bg) 78%, #000);
    --fx-neu-light: color-mix(in srgb, var(--fx-neu-bg) 70%, #fff);
  }
}
.fx-neumorphism:hover, .fx-neumorphism:focus-visible, .fx-neumorphism:active { box-shadow: inset 6px 6px 12px var(--fx-neu-dark), inset -6px -6px 12px var(--fx-neu-light); }
@media (prefers-reduced-motion: reduce) {
  .fx-neumorphism, .fx-neumorphism::before, .fx-neumorphism::after, .fx-neumorphism *, .fx-neumorphism *::before, .fx-neumorphism *::after { animation: none !important; transition: none !important; }
}
/* Outline Glow - A glowing focus ring for inputs, buttons and cards that appears on hover and keyboard focus. */
.fx-outline-glow { outline: 2px solid transparent; outline-offset: 2px; transition: box-shadow .3s ease, border-color .3s ease; }
.fx-outline-glow:hover, .fx-outline-glow:focus, .fx-outline-glow:focus-visible, .fx-outline-glow:focus-within {
  border-color: var(--wt-primary);
  box-shadow: 0 0 0 3px rgba(var(--wt-primary-rgb), .3), 0 0 18px rgba(var(--wt-primary-rgb), .45);
}
@media (prefers-reduced-motion: reduce) {
  .fx-outline-glow, .fx-outline-glow::before, .fx-outline-glow::after, .fx-outline-glow *, .fx-outline-glow *::before, .fx-outline-glow *::after { animation: none !important; transition: none !important; }
}

/* ===== Advanced Animated Backgrounds ===== */
/* Gradient - A slow, breathing wash of the primary, secondary and accent colours flowing behind the section. */
.fx-bg-gradient-flow { position: relative; isolation: isolate; overflow: hidden; }
.fx-bg-gradient-flow::before, .fx-bg-gradient-flow::after { content: ""; position: absolute; pointer-events: none; z-index: -1; }
.fx-bg-gradient-flow::before {
  inset: 0;
  background: linear-gradient(120deg, rgba(var(--wt-primary-rgb), .30), rgba(var(--wt-secondary-rgb), .22), rgba(var(--wt-accent-rgb), .28), rgba(var(--wt-primary-rgb), .30));
  background-size: 300% 300%;
  animation: fx-bg-gradient-flow-flow 16s ease infinite;
}
@keyframes fx-bg-gradient-flow-flow { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
@media (prefers-reduced-motion: reduce) {
  .fx-bg-gradient-flow, .fx-bg-gradient-flow::before, .fx-bg-gradient-flow::after, .fx-bg-gradient-flow *, .fx-bg-gradient-flow *::before, .fx-bg-gradient-flow *::after { animation: none !important; transition: none !important; }
}
/* Particles - Two layers of tiny glowing dots drifting upward at different speeds, like dust in light. */
.fx-bg-particles { position: relative; isolation: isolate; overflow: hidden; }
.fx-bg-particles::before, .fx-bg-particles::after { content: ""; position: absolute; pointer-events: none; z-index: -1; }
.fx-bg-particles::before, .fx-bg-particles::after { inset: 0; }
.fx-bg-particles::before {
  background-image:
    radial-gradient(circle at 10% 20%, rgba(var(--wt-primary-rgb), .65) 0 2px, transparent 3px),
    radial-gradient(circle at 35% 70%, rgba(var(--wt-accent-rgb), .6) 0 1.5px, transparent 2.5px),
    radial-gradient(circle at 60% 35%, rgba(var(--wt-secondary-rgb), .55) 0 2px, transparent 3px),
    radial-gradient(circle at 85% 80%, rgba(var(--wt-primary-rgb), .5) 0 1.5px, transparent 2.5px);
  background-size: 180px 180px;
  animation: fx-bg-particles-near 14s linear infinite;
}
.fx-bg-particles::after {
  opacity: .7;
  background-image:
    radial-gradient(circle at 20% 55%, rgba(var(--wt-accent-rgb), .55) 0 3px, transparent 4px),
    radial-gradient(circle at 70% 15%, rgba(var(--wt-primary-rgb), .45) 0 3.5px, transparent 4.5px),
    radial-gradient(circle at 50% 90%, rgba(var(--wt-secondary-rgb), .4) 0 2.5px, transparent 3.5px);
  background-size: 300px 300px;
  animation: fx-bg-particles-far 30s linear infinite;
}
@keyframes fx-bg-particles-near { to { background-position: 0 -180px; } }
@keyframes fx-bg-particles-far { to { background-position: 0 -300px; } }
@media (prefers-reduced-motion: reduce) {
  .fx-bg-particles, .fx-bg-particles::before, .fx-bg-particles::after, .fx-bg-particles *, .fx-bg-particles *::before, .fx-bg-particles *::after { animation: none !important; transition: none !important; }
}
/* Glitch - Faint scanlines with short bursts of shifted colour bands - a cyber look that keeps the text calm. */
.fx-bg-glitch { position: relative; isolation: isolate; overflow: hidden; }
.fx-bg-glitch::before, .fx-bg-glitch::after { content: ""; position: absolute; pointer-events: none; z-index: -1; }
.fx-bg-glitch::before {
  inset: 0;
  background: repeating-linear-gradient(0deg, rgba(var(--wt-primary-rgb), .07) 0 2px, transparent 2px 5px);
}
.fx-bg-glitch::after {
  inset: 0;
  background: linear-gradient(90deg, rgba(var(--wt-accent-rgb), .22), rgba(var(--wt-primary-rgb), .22) 50%, rgba(var(--wt-secondary-rgb), .22));
  -webkit-clip-path: inset(50% 0 50% 0); clip-path: inset(50% 0 50% 0);
  animation: fx-bg-glitch-bands 4s steps(1) infinite;
}
@keyframes fx-bg-glitch-bands {
  0%, 70%, 100% { -webkit-clip-path: inset(50% 0 50% 0); clip-path: inset(50% 0 50% 0); transform: none; }
  72% { -webkit-clip-path: inset(12% 0 78% 0); clip-path: inset(12% 0 78% 0); transform: translateX(-3%); }
  75% { -webkit-clip-path: inset(58% 0 30% 0); clip-path: inset(58% 0 30% 0); transform: translateX(4%); }
  78% { -webkit-clip-path: inset(30% 0 62% 0); clip-path: inset(30% 0 62% 0); transform: translateX(-2%); }
  81% { -webkit-clip-path: inset(80% 0 6% 0); clip-path: inset(80% 0 6% 0); transform: translateX(3%); }
  84% { -webkit-clip-path: inset(50% 0 50% 0); clip-path: inset(50% 0 50% 0); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-bg-glitch, .fx-bg-glitch::before, .fx-bg-glitch::after, .fx-bg-glitch *, .fx-bg-glitch *::before, .fx-bg-glitch *::after { animation: none !important; transition: none !important; }
}
