/* PPFX — dependency-free port of Magic UI effects (blur-fade, text-reveal, number-ticker,
   magic-card, border-beam, marquee, meteors, light-rays, retro-grid, hyper-text, shimmer-button,
   scroll-progress, aurora/gradient text, dot/grid patterns, noise).
   Theme with --fx-accent, --fx-accent-2, --fx-line, --fx-bg (zero-specificity defaults below). */

:where(:root) {
  --fx-accent: #3ddc97;
  --fx-accent-2: #38bdf8;
  --fx-line: rgba(255, 255, 255, 0.12);
  --fx-bg: #07100e;
  --fx-fg: #eef6f3;
}

.fx-sr {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- blur-fade (motion: 0.4s easeOut, delay 0.04s + delay, blur 6px, offset 6px) ---------- */
.fx-blur-fade {
  --_o: var(--fx-bf-offset, 6px);
  --_x: 0px;
  --_y: calc(var(--_o) * -1);
  opacity: 0;
  filter: blur(var(--fx-bf-blur, 6px));
  transform: translate3d(var(--_x), var(--_y), 0);
  transition:
    opacity var(--fx-bf-dur, 0.4s) ease-out calc(0.04s + var(--fx-delay, 0s)),
    filter var(--fx-bf-dur, 0.4s) ease-out calc(0.04s + var(--fx-delay, 0s)),
    transform var(--fx-bf-dur, 0.4s) ease-out calc(0.04s + var(--fx-delay, 0s));
}
.fx-blur-fade[data-dir="up"] { --_y: var(--_o); }
.fx-blur-fade[data-dir="left"] { --_x: var(--_o); --_y: 0px; }
.fx-blur-fade[data-dir="right"] { --_x: calc(var(--_o) * -1); --_y: 0px; }
.fx-blur-fade.fx-in { opacity: 1; filter: none; transform: none; }

/* ---------- text-reveal ---------- */
.fx-text-reveal { position: relative; z-index: 0; height: var(--fx-tr-height, 200vh); }
.fx-tr-stick {
  position: sticky; top: 0; display: flex; align-items: center;
  height: 50%; max-width: 56rem; margin: 0 auto; padding: 5rem 1rem;
}
.fx-tr-words {
  display: flex; flex-wrap: wrap; padding: 1.25rem; font-weight: 700; line-height: 1.2;
  font-size: clamp(1.5rem, 1rem + 2.2vw, 3rem);
  color: color-mix(in srgb, var(--fx-fg) 20%, transparent);
}
.fx-tr-word { position: relative; margin: 0 0.25rem; }
.fx-tr-ghost { position: absolute; left: 0; top: 0; opacity: 0.3; white-space: nowrap; }
.fx-tr-fg { color: var(--fx-fg); opacity: 0; }
.fx-text-reveal.fx-static { height: auto; }
.fx-text-reveal.fx-static .fx-tr-stick { position: static; height: auto; padding: 1rem; }
.fx-text-reveal.fx-static .fx-tr-fg { opacity: 1; }

/* ---------- number-ticker ---------- */
.fx-number-ticker { display: inline-block; letter-spacing: 0.05em; font-variant-numeric: tabular-nums; }

/* ---------- hyper-text (mono letters, uppercase) ---------- */
.fx-hyper { white-space: normal; }
.fx-hyper-word { display: inline-block; white-space: nowrap; }
.fx-hyper-word span { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.fx-hyper-sp { display: inline-block; width: 0.75rem; }

/* ---------- magic-card (cursor spotlight on border + background; --mx/--my set by JS) ---------- */
.fx-magic-card {
  --_size: var(--fx-mc-size, 200px);
  position: relative; isolation: isolate; overflow: hidden;
  border: 1px solid transparent; border-radius: var(--fx-mc-radius, 0.75rem);
  background:
    linear-gradient(var(--fx-bg) 0 0) padding-box,
    radial-gradient(var(--_size) circle at var(--mx, -200px) var(--my, -200px),
      var(--fx-accent), var(--fx-accent-2), var(--fx-line) 100%) border-box;
}
.fx-magic-card::before {
  content: ""; position: absolute; inset: 1px; z-index: -1; border-radius: inherit;
  pointer-events: none; opacity: 0; transition: opacity 0.3s;
  background: radial-gradient(var(--_size) circle at var(--mx, -200px) var(--my, -200px),
    var(--fx-mc-spot, #1c2a26), transparent 100%);
}
@media (hover: hover) { .fx-magic-card:hover::before { opacity: 0.8; } }

/* ---------- border-beam (offset-path rect; host needs border-radius) ---------- */
:where(.fx-beam-host) { position: relative; }
.fx-border-beam {
  position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  border: var(--fx-bb-width, 1px) solid transparent;
  -webkit-mask: linear-gradient(transparent, transparent) padding-box, linear-gradient(#000, #000) border-box;
  -webkit-mask-composite: source-in;
  mask: linear-gradient(transparent, transparent) padding-box, linear-gradient(#000, #000) border-box;
  mask-composite: intersect;
}
.fx-border-beam > i {
  position: absolute; aspect-ratio: 1; width: var(--fx-bb-size, 50px);
  offset-path: rect(0 auto auto 0 round var(--fx-bb-size, 50px));
  background: linear-gradient(to left, var(--fx-bb-from, var(--fx-accent)), var(--fx-bb-to, var(--fx-accent-2)), transparent);
  animation: fx-beam var(--fx-bb-dur, 6s) linear infinite;
  animation-delay: calc(var(--fx-bb-delay, 0s) * -1);
}
.fx-border-beam.fx-reverse > i { animation-direction: reverse; }
@keyframes fx-beam { from { offset-distance: 0%; } to { offset-distance: 100%; } }
@supports not (offset-path: rect(0 auto auto 0 round 50px)) { .fx-border-beam { display: none; } }

/* ---------- marquee (JS wraps children into a track and clones it) ---------- */
.fx-marquee {
  --fx-gap: 1rem; --fx-duration: 40s;
  display: flex; gap: var(--fx-gap); overflow: hidden; padding: 0.5rem;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
.fx-marquee-vertical {
  flex-direction: column;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
}
.fx-marquee__track {
  display: flex; flex-shrink: 0; justify-content: space-around; gap: var(--fx-gap); min-width: 100%;
  animation: fx-marquee var(--fx-duration) linear infinite;
}
.fx-marquee-vertical .fx-marquee__track { flex-direction: column; min-width: 0; animation-name: fx-marquee-v; }
.fx-marquee-reverse .fx-marquee__track { animation-direction: reverse; }
.fx-marquee:focus-within .fx-marquee__track { animation-play-state: paused; }
@media (hover: hover) { .fx-marquee:not(.fx-marquee-nopause):hover .fx-marquee__track { animation-play-state: paused; } }
@keyframes fx-marquee { from { transform: translateX(0); } to { transform: translateX(calc(-100% - var(--fx-gap))); } }
@keyframes fx-marquee-v { from { transform: translateY(0); } to { transform: translateY(calc(-100% - var(--fx-gap))); } }

/* ---------- meteors (JS injects spans; keyframes from Magic UI tailwind config) ---------- */
:where(.fx-meteors) { position: relative; }
.fx-meteors { overflow: hidden; isolation: isolate; }
.fx-meteor {
  --angle: -35deg;
  position: absolute; z-index: -1; width: 2px; height: 2px; border-radius: 9999px; pointer-events: none;
  background: var(--fx-meteor, var(--fx-accent)); box-shadow: 0 0 0 1px #ffffff10;
  transform: rotate(var(--angle));
  animation: fx-meteor 5s linear infinite;
}
.fx-meteor::after {
  content: ""; position: absolute; top: 50%; z-index: -1; width: 50px; height: 1px; transform: translateY(-50%);
  background: linear-gradient(to right, var(--fx-meteor, var(--fx-accent)), transparent);
}
@keyframes fx-meteor {
  0% { transform: rotate(var(--angle)) translateX(0); opacity: 1; }
  70% { opacity: 1; }
  100% { transform: rotate(var(--angle)) translateX(-500px); opacity: 0; }
}

/* ---------- light-rays (JS injects .fx-ray with --l --w --r --s --i --d --dl) ---------- */
:where(.fx-light-rays) { position: absolute; inset: 0; }
.fx-light-rays {
  --_c: var(--fx-rays-color, color-mix(in srgb, var(--fx-accent-2) 28%, transparent));
  isolation: isolate; overflow: hidden; border-radius: inherit; pointer-events: none;
}
.fx-light-rays::before, .fx-light-rays::after { content: ""; position: absolute; inset: 0; opacity: 0.6; }
.fx-light-rays::before { background: radial-gradient(circle at 20% 15%, color-mix(in srgb, var(--_c) 45%, transparent), transparent 70%); }
.fx-light-rays::after { background: radial-gradient(circle at 80% 10%, color-mix(in srgb, var(--_c) 35%, transparent), transparent 75%); }
.fx-ray {
  position: absolute; top: -12%; left: var(--l); width: var(--w); height: var(--fx-rays-length, 70vh);
  transform-origin: top; transform: translateX(-50%); rotate: var(--r); opacity: 0;
  border-radius: 9999px; mix-blend-mode: screen; pointer-events: none;
  background: linear-gradient(to bottom, color-mix(in srgb, var(--_c) 70%, transparent), transparent);
  filter: blur(var(--fx-rays-blur, 36px));
  animation: fx-ray var(--d) ease-in-out var(--dl) infinite;
}
/* 10% repeat pause (motion repeatDelay) baked in as a trailing hold */
@keyframes fx-ray {
  0% { opacity: 0; rotate: calc(var(--r) - var(--s)); }
  45.45% { opacity: var(--i); rotate: calc(var(--r) + var(--s)); }
  90.91%, 100% { opacity: 0; rotate: calc(var(--r) - var(--s)); }
}

/* ---------- retro-grid (perspective 200px, rotateX 65deg, 60px cells, 15s linear) ---------- */
:where(.fx-retro-grid) { position: absolute; inset: 0; }
.fx-retro-grid { --_cell: var(--fx-rg-cell, 60px); overflow: hidden; pointer-events: none; opacity: 0.5; perspective: 200px; }
.fx-rg-plane { position: absolute; inset: 0; transform: rotateX(var(--fx-rg-angle, 65deg)); }
.fx-rg-lines {
  position: absolute; top: 0; left: 0; width: 600%; margin-left: -200%;
  height: calc(var(--_cell) * 60); /* even cell count so -50% → 0 loops seamlessly */
  transform-origin: 100% 0;
  background-repeat: repeat; background-size: var(--_cell) var(--_cell);
  background-image:
    linear-gradient(to right, var(--fx-rg-line, var(--fx-accent)) 1px, transparent 0),
    linear-gradient(to bottom, var(--fx-rg-line, var(--fx-accent)) 1px, transparent 0);
  animation: fx-grid 15s linear infinite;
}
.fx-retro-grid::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to top, var(--fx-bg), transparent 90%); }
@keyframes fx-grid { from { transform: translateY(-50%); } to { transform: translateY(0); } }

/* ---------- shimmer-button (single element; ::before = spark, ::after = backdrop) ---------- */
.fx-shimmer-btn {
  --spread: 90deg;
  --_color: var(--fx-sb-color, var(--fx-accent));
  --_speed: var(--fx-sb-speed, 3s);
  --_cut: var(--fx-sb-cut, 0.05em);
  --_radius: var(--fx-sb-radius, 100px);
  --_bg: var(--fx-sb-bg, #000);
  position: relative; z-index: 0; display: inline-flex; align-items: center; justify-content: center;
  overflow: hidden; padding: 0.75rem 1.5rem; border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--_radius); background: var(--_bg); color: #fff; font: inherit;
  white-space: nowrap; text-decoration: none; cursor: pointer;
  transform: translateZ(0); transition: transform 0.3s ease-in-out;
}
.fx-shimmer-btn:active { transform: translateY(1px); }
.fx-shimmer-btn:focus-visible { outline: 2px solid var(--fx-accent-2); outline-offset: 3px; }
.fx-shimmer-btn::before {
  content: ""; position: absolute; z-index: -2; top: -100%; left: 0; height: 300%; aspect-ratio: 1;
  translate: -33.333% 0; filter: blur(2px);
  background: conic-gradient(from calc(270deg - (var(--spread) * 0.5)), transparent 0, var(--_color) var(--spread), transparent var(--spread));
  animation: fx-shimmer-slide var(--_speed) ease-in-out infinite alternate, fx-spin-around calc(var(--_speed) * 2) linear infinite;
}
.fx-shimmer-btn::after {
  content: ""; position: absolute; z-index: -1; inset: var(--_cut); border-radius: var(--_radius);
  background: var(--_bg); box-shadow: inset 0 -8px 10px #ffffff1f; transition: box-shadow 0.3s ease-in-out;
}
.fx-shimmer-btn:hover::after { box-shadow: inset 0 -6px 10px #ffffff3f; }
.fx-shimmer-btn:active::after { box-shadow: inset 0 -10px 10px #ffffff3f; }
/* slide the (3x) spark square across the full width; left+translate % reproduce translate(100cqw - 100%) */
@keyframes fx-shimmer-slide { to { left: 100%; translate: -66.667% 0; } }
@keyframes fx-spin-around {
  0% { rotate: 0deg; }
  15%, 35% { rotate: 90deg; }
  65%, 85% { rotate: 270deg; }
  100% { rotate: 360deg; }
}

/* ---------- scroll-progress ---------- */
.fx-scroll-progress {
  position: fixed; inset: 0 0 auto 0; z-index: 50; height: var(--fx-sp-h, 2px); pointer-events: none;
  transform-origin: 0 50%; transform: scaleX(var(--fx-progress, 0));
  background: linear-gradient(to right, var(--fx-accent), var(--fx-accent-2));
}

/* ---------- aurora-text / animated gradient text ---------- */
.fx-aurora-text {
  --_speed: var(--fx-aurora-speed, 1);
  display: inline-block;
  background-image: linear-gradient(135deg,
    var(--fx-aurora-1, var(--fx-accent)), var(--fx-aurora-2, var(--fx-accent-2)),
    var(--fx-aurora-3, #a78bfa), var(--fx-aurora-4, #f0abfc), var(--fx-aurora-1, var(--fx-accent)));
  background-size: 200% auto; -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: fx-aurora calc(10s / var(--_speed)) ease-in-out infinite alternate;
}
@keyframes fx-aurora {
  0% { background-position: 0% 50%; transform: rotate(-5deg) scale(0.9); }
  25% { background-position: 50% 100%; transform: rotate(5deg) scale(1.1); }
  50% { background-position: 100% 50%; transform: rotate(-3deg) scale(0.95); }
  75% { background-position: 50% 0%; transform: rotate(3deg) scale(1.05); }
  100% { background-position: 0% 50%; transform: rotate(-5deg) scale(0.9); }
}
.fx-gradient-text {
  --_size: var(--fx-gt-size, 300%);
  display: inline;
  background-image: linear-gradient(to right, var(--fx-accent), var(--fx-accent-2), var(--fx-accent));
  background-size: var(--_size) 100%; -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: fx-gradient 8s linear infinite;
}
@keyframes fx-gradient { to { background-position: var(--_size) 0; } }

/* ---------- dot / grid patterns (decorative layers; place inside a positioned parent) ---------- */
:where(.fx-dots, .fx-grid, .fx-noise) { position: absolute; inset: 0; }
.fx-dots, .fx-grid, .fx-noise { pointer-events: none; }
.fx-dots {
  --_dot: var(--fx-dot, color-mix(in srgb, var(--fx-accent) 45%, transparent));
  background-image: radial-gradient(circle at center, var(--_dot) 1px, transparent 1.5px);
  background-size: var(--fx-dot-gap, 16px) var(--fx-dot-gap, 16px);
}
/* glow: two interleaved dot groups pulse out of phase (per-dot random timing needs SVG; this approximates it) */
.fx-dots-glow { background: none; }
.fx-dots-glow::before, .fx-dots-glow::after {
  content: ""; position: absolute; inset: 0; background-size: 32px 32px;
  animation: fx-dot-glow 3s ease-in-out infinite alternate;
}
.fx-dots-glow::before {
  background-image:
    radial-gradient(circle at 8px 8px, var(--_dot) 1px, transparent 1.5px),
    radial-gradient(circle at 24px 24px, var(--_dot) 1px, transparent 1.5px);
}
.fx-dots-glow::after {
  background-image:
    radial-gradient(circle at 24px 8px, var(--_dot) 1px, transparent 1.5px),
    radial-gradient(circle at 8px 24px, var(--_dot) 1px, transparent 1.5px);
  animation-duration: 4.7s; animation-delay: -1.8s;
}
@keyframes fx-dot-glow { from { opacity: 0.4; } to { opacity: 1; } }
.fx-grid {
  background-image:
    linear-gradient(to right, var(--fx-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--fx-line) 1px, transparent 1px);
  background-size: var(--fx-grid-size, 40px) var(--fx-grid-size, 40px);
}
.fx-mask-fade {
  -webkit-mask-image: radial-gradient(ellipse at center, #000 30%, transparent 75%);
  mask-image: radial-gradient(ellipse at center, #000 30%, transparent 75%);
}

/* ---------- noise-texture (feTurbulence fractalNoise .4 × 6 octaves, desaturated, slope .15) ---------- */
.fx-noise {
  z-index: 0; opacity: 0.5; user-select: none; background-size: 256px 256px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.4' numOctaves='6' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='.15'/%3E%3CfeFuncG type='linear' slope='.15'/%3E%3CfeFuncB type='linear' slope='.15'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.6'/%3E%3C/svg%3E");
}
/* same filter with slope 1: light grain for dark backgrounds */
.fx-noise-light {
  opacity: 0.35; mix-blend-mode: screen;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.4' numOctaves='6' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='1'/%3E%3CfeFuncG type='linear' slope='1'/%3E%3CfeFuncB type='linear' slope='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.6'/%3E%3C/svg%3E");
}

/* ---------- reduced motion: final state, no animation ---------- */
@media (prefers-reduced-motion: reduce) {
  .fx-blur-fade { opacity: 1; filter: none; transform: none; transition: none; }
  .fx-marquee__track, .fx-border-beam > i, .fx-shimmer-btn::before, .fx-aurora-text, .fx-gradient-text,
  .fx-dots-glow::before, .fx-dots-glow::after { animation: none; }
  .fx-marquee { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .fx-aurora-text { transform: none; }
  .fx-border-beam { display: none; }
  .fx-meteor { display: none; }
  .fx-rg-lines { animation: none; transform: translateY(-50%); }
  .fx-ray { animation: none; opacity: calc(var(--i) * 0.5); }
  .fx-shimmer-btn, .fx-shimmer-btn::after, .fx-magic-card::before { transition: none; }
}
