/**
 * Text Effects
 *
 * Styles for the [text_effect] shortcode (see inc/text-effects.php for the
 * effect registry). Parameters arrive as CSS custom properties on the span;
 * every var() has a fallback matching the registry default.
 *
 * Modes:
 * - .np-fx--m-loop      Loops continuously.
 * - .np-fx--m-entrance  Hidden until JS adds .is-inview (gated on the
 *                       .np-fx-js root class so text is never lost without JS).
 * - .np-fx--soft        Entrance variant whose text stays visible; only the
 *                       decoration draws in.
 * - .np-fx--m-js        JS-driven (scramble, typewriter, magnetic cursor).
 */

.np-fx {
    display: inline-block;
}

.np-fx .np-fx__ch {
    display: inline-block;
    white-space: pre;
}

/* Entrance effects hide until in view — only when JS is confirmed present. */
.np-fx-js .np-fx--m-entrance:not(.np-fx--soft):not(.is-inview) {
    opacity: 0;
}

/* ---------------------------------------------------------------- Gradient */

.np-fx--gradient-sweep,
.np-fx--gradient-vertical,
.np-fx--rainbow {
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.np-fx--gradient-sweep {
    background-image: linear-gradient(
        100deg,
        var(--fx-c1, #e85d75),
        var(--fx-c2, #7c5cff),
        var(--fx-c1, #e85d75)
    );
    background-size: 200% 100%;
    animation: np-fx-sweep var(--fx-dur, 3s) linear infinite;
}

@keyframes np-fx-sweep {
    to {
        background-position: -200% 0;
    }
}

.np-fx--gradient-vertical {
    background-image: linear-gradient(
        180deg,
        var(--fx-c1, #e85d75),
        var(--fx-c2, #7c5cff)
    );
}

.np-fx--rainbow {
    background-image: linear-gradient(
        90deg,
        #ff5964,
        #ffb54d,
        #ffe066,
        #4ecdc4,
        #5b8cff,
        #a06bff,
        #ff5964
    );
    background-size: 300% 100%;
    animation: np-fx-sweep var(--fx-dur, 6s) linear infinite;
}

/* ---------------------------------------------------------------- Entrance */

.np-fx--fade-up.is-inview {
    animation: np-fx-fade-up var(--fx-dur, 0.7s) cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes np-fx-fade-up {
    from {
        opacity: 0;
        transform: translateY(var(--fx-dist, 0.6em));
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.np-fx--scale-pop.is-inview {
    animation: np-fx-scale-pop var(--fx-dur, 0.6s) cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@keyframes np-fx-scale-pop {
    0% {
        opacity: 0;
        transform: scale(var(--fx-from, 0.5));
    }
    70% {
        opacity: 1;
        transform: scale(1.05);
    }
    100% {
        opacity: 1;
        transform: scale(1);
    }
}

.np-fx--rotate-in.is-inview {
    animation: np-fx-rotate-in var(--fx-dur, 0.7s) cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes np-fx-rotate-in {
    from {
        opacity: 0;
        transform: rotate(var(--fx-ang, -8deg)) translateY(0.35em);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.np-fx--stencil-stamp.is-inview {
    animation: np-fx-stamp var(--fx-dur, 0.45s) cubic-bezier(0.6, 0, 0.4, 1) both;
}

@keyframes np-fx-stamp {
    0% {
        opacity: 0;
        transform: scale(1.7);
    }
    70% {
        opacity: 1;
        transform: scale(0.96);
    }
    100% {
        opacity: 1;
        transform: scale(1);
    }
}

.np-fx--underline-draw {
    background-image: linear-gradient(var(--fx-c1, #e85d75), var(--fx-c1, #e85d75));
    background-repeat: no-repeat;
    background-position: left bottom;
    background-size: 0% var(--fx-thick, 0.09em);
    padding-bottom: 0.08em;
}

.np-fx--underline-draw.is-inview {
    animation: np-fx-underline var(--fx-dur, 0.8s) cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes np-fx-underline {
    to {
        background-size: 100% var(--fx-thick, 0.09em);
    }
}

.np-fx--clip-reveal.is-inview {
    animation: np-fx-clip var(--fx-dur, 0.9s) cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes np-fx-clip {
    from {
        opacity: 1;
        clip-path: inset(0 100% 0 0);
    }
    to {
        opacity: 1;
        clip-path: inset(0 0 0 0);
    }
}

.np-fx--blur-in.is-inview {
    animation: np-fx-blur var(--fx-dur, 0.9s) ease-out both;
}

@keyframes np-fx-blur {
    from {
        opacity: 0;
        filter: blur(var(--fx-blur, 14px));
    }
    to {
        opacity: 1;
        filter: blur(0);
    }
}

.np-fx--flip-in {
    transform-origin: center bottom;
}

.np-fx--flip-in.is-inview {
    animation: np-fx-flip var(--fx-dur, 0.8s) cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes np-fx-flip {
    from {
        opacity: 0;
        transform: perspective(600px) rotateX(70deg);
    }
    to {
        opacity: 1;
        transform: perspective(600px) rotateX(0);
    }
}

/* Elastic drop — per-character stagger via --i set by text-effects.js. */
.np-fx--elastic-drop .np-fx__ch {
    opacity: 0;
}

.np-fx--elastic-drop.is-inview .np-fx__ch {
    animation: np-fx-elastic var(--fx-dur, 0.75s) cubic-bezier(0.2, 0.6, 0.3, 1) both;
    animation-delay: calc(var(--i, 0) * 0.045s);
}

@keyframes np-fx-elastic {
    0% {
        opacity: 0;
        transform: translateY(-1.1em);
    }
    55% {
        opacity: 1;
        transform: translateY(0.14em);
    }
    75% {
        transform: translateY(-0.06em);
    }
    90% {
        transform: translateY(0.03em);
    }
    100% {
        opacity: 1;
        transform: none;
    }
}

/* ----------------------------------------------------------------- Ambient */

.np-fx--wave-float .np-fx__ch {
    animation: np-fx-wave var(--fx-dur, 2.4s) ease-in-out infinite;
    animation-delay: calc(var(--i, 0) * -0.12s);
}

@keyframes np-fx-wave {
    0%,
    100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(calc(var(--fx-amp, 0.12em) * -1));
    }
}

.np-fx--breath {
    animation: np-fx-breath var(--fx-dur, 3.5s) ease-in-out infinite;
}

@keyframes np-fx-breath {
    0%,
    100% {
        transform: scale(1);
    }
    50% {
        transform: scale(var(--fx-amt, 1.05));
    }
}

/* Weight shift — needs a variable font (Google Sans Flex on nicparkes.com). */
.np-fx--weight-shift {
    animation: np-fx-weight var(--fx-dur, 2.5s) ease-in-out infinite;
}

@keyframes np-fx-weight {
    0%,
    100% {
        font-variation-settings: "wght" 300;
    }
    50% {
        font-variation-settings: "wght" 800;
    }
}

.np-fx--thermal-shimmer {
    animation: np-fx-thermal var(--fx-dur, 2s) ease-in-out infinite;
}

@keyframes np-fx-thermal {
    0%,
    100% {
        filter: blur(0);
        transform: skewX(0) translateY(0);
    }
    25% {
        filter: blur(0.6px);
        transform: skewX(0.5deg) translateY(-0.015em);
    }
    50% {
        filter: blur(0.2px);
        transform: skewX(-0.3deg) translateY(0.01em);
    }
    75% {
        filter: blur(0.8px);
        transform: skewX(0.3deg) translateY(-0.01em);
    }
}

.np-fx--neon-pulse {
    color: var(--fx-c1, #4fd8ff);
    animation: np-fx-neon var(--fx-dur, 2s) ease-in-out infinite;
}

@keyframes np-fx-neon {
    0%,
    100% {
        text-shadow:
            0 0 4px var(--fx-c1, #4fd8ff),
            0 0 11px var(--fx-c1, #4fd8ff);
    }
    50% {
        text-shadow:
            0 0 4px var(--fx-c1, #4fd8ff),
            0 0 14px var(--fx-c1, #4fd8ff),
            0 0 30px var(--fx-c1, #4fd8ff);
    }
}

.np-fx--flicker {
    animation: np-fx-flicker var(--fx-dur, 3s) linear infinite;
}

@keyframes np-fx-flicker {
    0%,
    6%,
    8%,
    32%,
    36%,
    77%,
    81%,
    100% {
        opacity: 1;
    }
    7%,
    33%,
    35%,
    78% {
        opacity: 0.25;
    }
    79.5% {
        opacity: 0.6;
    }
}

/* ------------------------------------------------------------- Interactive */

.np-fx--magnetic-cursor .np-fx__ch {
    transition: transform 0.18s ease-out;
    will-change: transform;
}

.np-fx--stretch-morph {
    transform-origin: left center;
    transition: transform var(--fx-dur, 0.35s) cubic-bezier(0.34, 1.56, 0.64, 1);
}

.np-fx--stretch-morph:hover {
    transform: scaleX(var(--fx-amt, 1.25));
}

/* ------------------------------------------------------------------ Decode */

.np-fx--typewriter .np-fx__ch--hidden {
    visibility: hidden;
}

.np-fx__caret {
    display: inline-block;
    width: 2px;
    height: 1em;
    margin-left: 1px;
    vertical-align: -0.1em;
    background: currentColor;
    animation: np-fx-caret 0.7s step-end infinite;
}

@keyframes np-fx-caret {
    50% {
        opacity: 0;
    }
}

/* ------------------------------------------------------------------- Style */

/* Fill is cleared via text-fill-color (not color) so the currentColor
   stroke default still resolves to the inherited text colour. */
.np-fx--outline {
    -webkit-text-stroke: var(--fx-w, 1.5px) var(--fx-c1, currentColor);
    -webkit-text-fill-color: transparent;
}

/* long-shadow and emboss-3d receive their text-shadow stacks inline
   (composed in PHP from the length/depth parameters). */

.np-fx--glitch {
    position: relative;
}

.np-fx--glitch::before,
.np-fx--glitch::after {
    content: attr(data-text);
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    overflow: hidden;
    opacity: 0.85;
}

.np-fx--glitch::before {
    text-shadow: calc(var(--fx-int, 1) * -2px) 0 var(--fx-c1, #00e5ff);
    animation: np-fx-glitch-a var(--fx-dur, 2.5s) infinite linear alternate-reverse;
}

.np-fx--glitch::after {
    text-shadow: calc(var(--fx-int, 1) * 2px) 0 var(--fx-c2, #ff2d95);
    animation: np-fx-glitch-b var(--fx-dur, 2.5s) infinite linear alternate;
}

@keyframes np-fx-glitch-a {
    0% {
        clip-path: inset(12% 0 82% 0);
        transform: translateX(calc(var(--fx-int, 1) * -1px));
    }
    20% {
        clip-path: inset(64% 0 8% 0);
        transform: translateX(calc(var(--fx-int, 1) * 1.5px));
    }
    40% {
        clip-path: inset(30% 0 55% 0);
        transform: translateX(calc(var(--fx-int, 1) * -1.5px));
    }
    60% {
        clip-path: inset(80% 0 5% 0);
        transform: translateX(calc(var(--fx-int, 1) * 1px));
    }
    80% {
        clip-path: inset(45% 0 40% 0);
        transform: translateX(calc(var(--fx-int, 1) * -0.5px));
    }
    100% {
        clip-path: inset(5% 0 90% 0);
        transform: translateX(calc(var(--fx-int, 1) * 0.5px));
    }
}

@keyframes np-fx-glitch-b {
    0% {
        clip-path: inset(78% 0 10% 0);
        transform: translateX(calc(var(--fx-int, 1) * 1px));
    }
    20% {
        clip-path: inset(15% 0 70% 0);
        transform: translateX(calc(var(--fx-int, 1) * -1px));
    }
    40% {
        clip-path: inset(55% 0 30% 0);
        transform: translateX(calc(var(--fx-int, 1) * 1.5px));
    }
    60% {
        clip-path: inset(8% 0 85% 0);
        transform: translateX(calc(var(--fx-int, 1) * -1.5px));
    }
    80% {
        clip-path: inset(38% 0 48% 0);
        transform: translateX(calc(var(--fx-int, 1) * 0.5px));
    }
    100% {
        clip-path: inset(90% 0 2% 0);
        transform: translateX(calc(var(--fx-int, 1) * -0.5px));
    }
}

.np-fx--highlight-marker {
    background-image: linear-gradient(var(--fx-c1, #ffe066), var(--fx-c1, #ffe066));
    background-repeat: no-repeat;
    background-position: 0 62%;
    background-size: 0% 45%;
    padding: 0 0.12em;
    margin: 0 -0.12em;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
}

.np-fx--highlight-marker.is-inview {
    animation: np-fx-highlight var(--fx-dur, 0.8s) cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes np-fx-highlight {
    to {
        background-size: 100% 45%;
    }
}

/* ---------------------------------------------------------- Reduced motion */

@media (prefers-reduced-motion: reduce) {
    .np-fx,
    .np-fx::before,
    .np-fx::after,
    .np-fx .np-fx__ch {
        animation: none !important;
        transition: none !important;
    }

    .np-fx-js .np-fx--m-entrance:not(.np-fx--soft):not(.is-inview),
    .np-fx--elastic-drop .np-fx__ch {
        opacity: 1;
        transform: none;
    }

    .np-fx--glitch::before,
    .np-fx--glitch::after {
        display: none;
    }

    .np-fx--underline-draw {
        background-size: 100% var(--fx-thick, 0.09em);
    }

    .np-fx--highlight-marker {
        background-size: 100% 45%;
    }

    .np-fx--typewriter .np-fx__ch--hidden {
        visibility: visible;
    }

    .np-fx__caret {
        display: none;
    }
}
