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

/* ===== Modern CSS Animations ===== */
/* Bouncing Text - Makes each letter of a short word hop in turn; wrap every letter in a span with --i set to its index. */
.fx-bouncing-text { display: inline-flex; }
.fx-bouncing-text > span {
  display: inline-block;
  animation: fx-bouncing-text-bounce 1.6s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * .09s);
}
@keyframes fx-bouncing-text-bounce {
  0%, 60%, 100% { transform: translateY(0); }
  25% { transform: translateY(-14px); color: var(--wt-primary-ink); }
  40% { transform: translateY(2px); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-bouncing-text, .fx-bouncing-text::before, .fx-bouncing-text::after, .fx-bouncing-text *, .fx-bouncing-text *::before, .fx-bouncing-text *::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; }
}
/* Star Rotate - A five-point star cut-out that turns slowly and speeds up on hover; use it for ratings or promo badges. */
.fx-star-rotate { -webkit-clip-path: polygon(50% 0, 62.3% 33%, 97.6% 34.5%, 70% 56.5%, 79.4% 90.5%, 50% 71%, 20.6% 90.5%, 30% 56.5%, 2.4% 34.5%, 37.7% 33%); clip-path: polygon(50% 0, 62.3% 33%, 97.6% 34.5%, 70% 56.5%, 79.4% 90.5%, 50% 71%, 20.6% 90.5%, 30% 56.5%, 2.4% 34.5%, 37.7% 33%); animation: fx-star-rotate-turn 14s linear infinite; }
.fx-star-rotate:hover { animation-duration: 3s; }
@keyframes fx-star-rotate-turn { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .fx-star-rotate, .fx-star-rotate::before, .fx-star-rotate::after, .fx-star-rotate *, .fx-star-rotate *::before, .fx-star-rotate *::after { animation: none !important; transition: none !important; }
}
/* Complex Animation - Chains four eight-point shapes with rotation for an eye-catching hero ornament. */
.fx-complex-animation {
  -webkit-clip-path: polygon(50% 0, 85% 15%, 100% 50%, 85% 85%, 50% 100%, 15% 85%, 0 50%, 15% 15%); clip-path: polygon(50% 0, 85% 15%, 100% 50%, 85% 85%, 50% 100%, 15% 85%, 0 50%, 15% 15%);
  background: conic-gradient(from 45deg, var(--wt-primary), var(--wt-secondary), var(--wt-accent), var(--wt-primary));
  animation: fx-complex-animation-shift 10s ease-in-out infinite;
}
@keyframes fx-complex-animation-shift {
  0%, 100% { -webkit-clip-path: polygon(50% 0, 85% 15%, 100% 50%, 85% 85%, 50% 100%, 15% 85%, 0 50%, 15% 15%); clip-path: polygon(50% 0, 85% 15%, 100% 50%, 85% 85%, 50% 100%, 15% 85%, 0 50%, 15% 15%); transform: rotate(0deg); }
  25% { -webkit-clip-path: polygon(50% 20%, 100% 0, 80% 50%, 100% 100%, 50% 80%, 0 100%, 20% 50%, 0 0); clip-path: polygon(50% 20%, 100% 0, 80% 50%, 100% 100%, 50% 80%, 0 100%, 20% 50%, 0 0); transform: rotate(45deg); }
  50% { -webkit-clip-path: polygon(50% 0, 100% 0, 100% 50%, 100% 100%, 50% 100%, 0 100%, 0 50%, 0 0); clip-path: polygon(50% 0, 100% 0, 100% 50%, 100% 100%, 50% 100%, 0 100%, 0 50%, 0 0); transform: rotate(90deg) scale(.85); }
  75% { -webkit-clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); transform: rotate(180deg); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-complex-animation, .fx-complex-animation::before, .fx-complex-animation::after, .fx-complex-animation *, .fx-complex-animation *::before, .fx-complex-animation *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Filter Effects ===== */
/* Neon Glow - Wraps icons, logos and transparent images in a flickering neon halo using drop-shadow. */
.fx-filter-neon-glow {
  color: var(--wt-primary-ink);
  filter: drop-shadow(0 0 4px var(--wt-primary)) drop-shadow(0 0 12px var(--wt-primary));
  animation: fx-filter-neon-glow-flicker 3s linear infinite;
}
@keyframes fx-filter-neon-glow-flicker {
  0%, 18%, 22%, 62%, 64%, 100% { filter: drop-shadow(0 0 4px var(--wt-primary)) drop-shadow(0 0 12px var(--wt-primary)); }
  20%, 63% { filter: drop-shadow(0 0 1px var(--wt-primary)); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-filter-neon-glow, .fx-filter-neon-glow::before, .fx-filter-neon-glow::after, .fx-filter-neon-glow *, .fx-filter-neon-glow *::before, .fx-filter-neon-glow *::after { animation: none !important; transition: none !important; }
}
/* Text Filter Effects - Headings come into focus from a blur with a coloured drop shadow - a cinematic title reveal. */
.fx-text-filter-effects { filter: drop-shadow(0 4px 10px rgba(var(--wt-primary-rgb), .45)); animation: fx-text-filter-effects-focus 5s ease-in-out infinite; }
@keyframes fx-text-filter-effects-focus {
  0% { filter: blur(8px) drop-shadow(0 4px 10px rgba(var(--wt-primary-rgb), 0)); opacity: .2; letter-spacing: .25em; }
  30%, 85% { filter: blur(0) drop-shadow(0 4px 10px rgba(var(--wt-primary-rgb), .45)); opacity: 1; letter-spacing: normal; }
  100% { filter: blur(0) drop-shadow(0 4px 10px rgba(var(--wt-primary-rgb), .45)); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .fx-text-filter-effects, .fx-text-filter-effects::before, .fx-text-filter-effects::after, .fx-text-filter-effects *, .fx-text-filter-effects *::before, .fx-text-filter-effects *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Transform Effects ===== */
/* Skew Parallax - On hover the card skews one way and its image drifts the other, creating a quick sense of depth. */
.fx-skew-parallax { overflow: hidden; transition: transform .5s cubic-bezier(.2, .8, .2, 1); }
.fx-skew-parallax img { transform: scale(1.12); transition: transform .6s cubic-bezier(.2, .8, .2, 1); }
.fx-skew-parallax:hover { transform: skewY(-2deg) translateY(-3px); }
.fx-skew-parallax:hover img { transform: scale(1.18) skewY(2deg) translateY(-6px); }
@media (prefers-reduced-motion: reduce) {
  .fx-skew-parallax, .fx-skew-parallax::before, .fx-skew-parallax::after, .fx-skew-parallax *, .fx-skew-parallax *::before, .fx-skew-parallax *::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; }
}
/* Matrix Transform - Uses a single matrix() to scale, skew and lift a tile at once on hover. */
.fx-matrix-transform { transition: transform .5s cubic-bezier(.34, 1.56, .64, 1), box-shadow .5s; }
.fx-matrix-transform:hover, .fx-matrix-transform:focus-visible { transform: matrix(1.05, -.08, .12, 1.05, 0, -8); box-shadow: 0 20px 30px -16px rgba(var(--wt-primary-rgb), .5); }
@media (prefers-reduced-motion: reduce) {
  .fx-matrix-transform, .fx-matrix-transform::before, .fx-matrix-transform::after, .fx-matrix-transform *, .fx-matrix-transform *::before, .fx-matrix-transform *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Transitions ===== */
/* Rainbow Glow - Surrounds a button or card with a glow that cycles through the theme colours while hovered. */
.fx-rainbow-glow { transition: box-shadow .4s ease, transform .4s ease; }
.fx-rainbow-glow:hover, .fx-rainbow-glow:focus-visible { transform: translateY(-2px); animation: fx-rainbow-glow-glow 2.4s linear infinite; }
@keyframes fx-rainbow-glow-glow {
  0%, 100% { box-shadow: 0 0 14px rgba(var(--wt-primary-rgb), .75), 0 0 34px rgba(var(--wt-primary-rgb), .35); }
  33% { box-shadow: 0 0 14px rgba(var(--wt-accent-rgb), .75), 0 0 34px rgba(var(--wt-accent-rgb), .35); }
  66% { box-shadow: 0 0 14px rgba(var(--wt-secondary-rgb), .75), 0 0 34px rgba(var(--wt-secondary-rgb), .35); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-rainbow-glow, .fx-rainbow-glow::before, .fx-rainbow-glow::after, .fx-rainbow-glow *, .fx-rainbow-glow *::before, .fx-rainbow-glow *::after { animation: none !important; transition: none !important; }
}
/* Split Text Fill - Fills a heading or link with the primary colour from both sides at once on hover - top half from the left, bottom half from the right. */
.fx-split-text-fill {
  display: inline-block; text-decoration: none;
  -webkit-text-fill-color: transparent;
  background-image: linear-gradient(var(--wt-primary), var(--wt-primary)), linear-gradient(var(--wt-primary), var(--wt-primary)), linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 0, 100% 100%, 0 0;
  background-size: 0% 50%, 0% 50%, 100% 100%;
  -webkit-background-clip: text; background-clip: text;
  transition: background-size .6s cubic-bezier(.7, 0, .3, 1);
}
.fx-split-text-fill:hover, .fx-split-text-fill:focus-visible { background-size: 100% 50%, 100% 50%, 100% 100%; }
@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .fx-split-text-fill { -webkit-text-fill-color: currentColor; background: none; }
  .fx-split-text-fill:hover { color: var(--wt-primary-ink); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-split-text-fill, .fx-split-text-fill::before, .fx-split-text-fill::after, .fx-split-text-fill *, .fx-split-text-fill *::before, .fx-split-text-fill *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern CSS Gradient Effects ===== */
/* 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; }
}
/* Text Mask - Large text that works as a window onto a moving gradient - or onto an image set with an inline background-image. */
.fx-text-mask {
  color: var(--wt-primary-ink);
  background-image: var(--fx-mask-img, linear-gradient(135deg, var(--wt-primary) 0%, var(--wt-accent) 30%, var(--wt-secondary) 60%, var(--wt-primary) 100%));
  background-size: cover; background-position: 0% 50%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: fx-text-mask-pan 10s ease-in-out infinite alternate;
}
.fx-text-mask:not([style*="--fx-mask-img"]) { background-size: 300% 300%; }
@keyframes fx-text-mask-pan { to { background-position: 100% 50%; } }
@media (prefers-reduced-motion: reduce) {
  .fx-text-mask, .fx-text-mask::before, .fx-text-mask::after, .fx-text-mask *, .fx-text-mask *::before, .fx-text-mask *::after { animation: none !important; transition: none !important; }
}

/* ===== Modern Shadow Effects ===== */
/* Colored Shadows - Tinted shadows in the primary colour (override with --fx-shadow-rgb) that make buttons and images glow softly. */
.fx-colored-shadows {
  box-shadow: 0 14px 28px -12px rgba(var(--fx-shadow-rgb, var(--wt-primary-rgb)), .65);
  transition: box-shadow .35s ease, transform .35s ease;
}
.fx-colored-shadows:hover, .fx-colored-shadows:focus-visible { transform: translateY(-3px); box-shadow: 0 20px 36px -12px rgba(var(--fx-shadow-rgb, var(--wt-primary-rgb)), .8); }
@media (prefers-reduced-motion: reduce) {
  .fx-colored-shadows, .fx-colored-shadows::before, .fx-colored-shadows::after, .fx-colored-shadows *, .fx-colored-shadows *::before, .fx-colored-shadows *::after { animation: none !important; transition: none !important; }
}
/* 3D Text Shadow - Stacks hard shadows under a heading so the letters look extruded, with a soft ambient shadow below. */
.fx-3d-text-shadow {
  color: var(--wt-primary-ink);
  --fx-depth: rgba(0, 0, 0, .35);
  text-shadow: 0 1px 0 var(--fx-depth), 0 2px 0 var(--fx-depth), 0 3px 0 var(--fx-depth), 0 4px 0 var(--fx-depth), 0 5px 0 var(--fx-depth), 0 6px 0 var(--fx-depth),
    0 8px 6px rgba(0, 0, 0, .2), 0 14px 18px rgba(0, 0, 0, .18);
}
@supports (color: color-mix(in srgb, red 50%, blue)) {
  .fx-3d-text-shadow { --fx-depth: color-mix(in srgb, var(--wt-primary) 60%, #000); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-3d-text-shadow, .fx-3d-text-shadow::before, .fx-3d-text-shadow::after, .fx-3d-text-shadow *, .fx-3d-text-shadow *::before, .fx-3d-text-shadow *::after { animation: none !important; transition: none !important; }
}

/* ===== Advanced Animated Backgrounds ===== */
/* Wave/Blob - Soft colour blobs morph in the background while two layers of waves roll along the bottom edge. */
.fx-bg-wave-blob { position: relative; isolation: isolate; overflow: hidden; }
.fx-bg-wave-blob::before, .fx-bg-wave-blob::after { content: ""; position: absolute; pointer-events: none; z-index: -1; }
.fx-bg-wave-blob::before {
  width: 55%; aspect-ratio: 1; top: -25%; left: -12%;
  background: radial-gradient(circle at 50% 50%, rgba(var(--wt-primary-rgb), .32), transparent 68%);
  border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%;
  animation: fx-bg-wave-blob-blob 14s ease-in-out infinite alternate;
}
.fx-bg-wave-blob::after {
  left: 0; right: 0; bottom: 0; height: 60px;
  background:
    radial-gradient(84px 18px at 50% 100%, rgba(var(--wt-primary-rgb), .2) 99%, transparent 101%) 0 100% / 160px 30px repeat-x,
    radial-gradient(118px 24px at 50% 100%, rgba(var(--wt-accent-rgb), .18) 99%, transparent 101%) 0 100% / 220px 40px repeat-x,
    linear-gradient(rgba(var(--wt-primary-rgb), .14), rgba(var(--wt-primary-rgb), .14)) 0 100% / 100% 12px no-repeat;
  animation: fx-bg-wave-blob-wave 9s linear infinite;
}
@keyframes fx-bg-wave-blob-blob {
  0% { transform: translate(0, 0) rotate(0deg); border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%; }
  50% { border-radius: 70% 30% 46% 54% / 30% 39% 61% 70%; }
  100% { transform: translate(110%, 35%) rotate(60deg); border-radius: 30% 70% 70% 30% / 53% 30% 70% 47%; }
}
@keyframes fx-bg-wave-blob-wave { to { background-position: 160px 100%, -220px 100%, 0 100%; } }
@media (prefers-reduced-motion: reduce) {
  .fx-bg-wave-blob, .fx-bg-wave-blob::before, .fx-bg-wave-blob::after, .fx-bg-wave-blob *, .fx-bg-wave-blob *::before, .fx-bg-wave-blob *::after { animation: none !important; transition: none !important; }
}
/* Shapes - Rings, dots, squares and triangles in theme colours float and turn slowly behind the content. */
.fx-bg-shapes { position: relative; isolation: isolate; overflow: hidden; }
.fx-bg-shapes::before, .fx-bg-shapes::after { content: ""; position: absolute; pointer-events: none; z-index: -1; }
.fx-bg-shapes::before, .fx-bg-shapes::after { inset: -10%; background-repeat: no-repeat; }
.fx-bg-shapes::before {
  background-image:
    radial-gradient(circle, transparent 0 38%, rgba(var(--wt-primary-rgb), .35) 40% 50%, transparent 52%),
    radial-gradient(circle, rgba(var(--wt-accent-rgb), .35) 0 48%, transparent 50%),
    conic-gradient(from 150deg at 50% 0, rgba(var(--wt-secondary-rgb), .3) 0 60deg, transparent 0);
  background-size: 90px 90px, 34px 34px, 70px 60px;
  background-position: 12% 22%, 82% 18%, 70% 82%;
  animation: fx-bg-shapes-float 12s ease-in-out infinite alternate;
}
.fx-bg-shapes::after {
  background-image:
    linear-gradient(rgba(var(--wt-secondary-rgb), .22), rgba(var(--wt-secondary-rgb), .22)),
    radial-gradient(circle, transparent 0 40%, rgba(var(--wt-accent-rgb), .3) 42% 52%, transparent 54%),
    radial-gradient(circle, rgba(var(--wt-primary-rgb), .3) 0 48%, transparent 50%);
  background-size: 38px 38px, 60px 60px, 22px 22px;
  background-position: 88% 62%, 22% 80%, 45% 12%;
  animation: fx-bg-shapes-turn 18s ease-in-out infinite alternate;
}
@keyframes fx-bg-shapes-float { to { transform: translate(3%, -5%) rotate(6deg); } }
@keyframes fx-bg-shapes-turn { to { transform: translate(-4%, 4%) rotate(-8deg); } }
@media (prefers-reduced-motion: reduce) {
  .fx-bg-shapes, .fx-bg-shapes::before, .fx-bg-shapes::after, .fx-bg-shapes *, .fx-bg-shapes *::before, .fx-bg-shapes *::after { animation: none !important; transition: none !important; }
}
/* Parallax - Three layers of dots and soft orbs drift at different speeds, giving the section a sense of depth. */
.fx-bg-parallax { position: relative; isolation: isolate; overflow: hidden; }
.fx-bg-parallax::before, .fx-bg-parallax::after { content: ""; position: absolute; pointer-events: none; z-index: -1; }
.fx-bg-parallax::before {
  inset: 0;
  background-image:
    radial-gradient(circle, rgba(var(--wt-primary-rgb), .35) 0 1px, transparent 1.5px),
    radial-gradient(circle, rgba(var(--wt-secondary-rgb), .4) 0 2px, transparent 2.5px);
  background-size: 24px 24px, 70px 70px;
  animation: fx-bg-parallax-layers 20s linear infinite;
}
.fx-bg-parallax::after {
  inset: 0;
  background-image:
    radial-gradient(circle, rgba(var(--wt-accent-rgb), .22) 0 18px, transparent 32px),
    radial-gradient(circle, rgba(var(--wt-primary-rgb), .18) 0 26px, transparent 44px);
  background-size: 220px 220px, 340px 340px;
  background-position: 30px 60px, 180px 10px;
  animation: fx-bg-parallax-near 20s linear infinite;
}
@keyframes fx-bg-parallax-layers { to { background-position: -24px 0, -140px 0; } }
@keyframes fx-bg-parallax-near { to { background-position: -410px 60px, -500px 10px; } }
@media (prefers-reduced-motion: reduce) {
  .fx-bg-parallax, .fx-bg-parallax::before, .fx-bg-parallax::after, .fx-bg-parallax *, .fx-bg-parallax *::before, .fx-bg-parallax *::after { animation: none !important; transition: none !important; }
}
