/* ============================================================================
 * hero_kinetic.css — PREMIUM kinetic-typography & cinematic-motion layer.
 *
 * Loaded AFTER hero_mesh.css. Adds:
 *   1. Per-character H1 kinetic states (drop-in + breathe + magnetic-attract)
 *   2. Multi-layer parallax depth (verdict particles, scroll parallax stage)
 *   3. Corner light-leak ambient pulses
 *   4. Magnetic CTA scan-line + radial ripple + glow follow
 *   5. Phone-frame breath upgrade (rotateY + shadow pulse)
 *   6. URL-input focus glow ring + scan-line + typed-out placeholder cue
 *   7. Recent-checks ticker wobble + saturation pulse + hover pause
 *
 * All effects gated on:
 *   - prefers-reduced-motion: reduce
 *   - body.pb-low-end (skip particles/parallax/heavy effects)
 *   - (hover:hover) and (pointer:fine) for cursor-based behavior
 *
 * Works on all 6 color themes via CSS variables.
 * ========================================================================== */


/* ────────────────────────────────────────────────────────────────────────────
 *  1. Kinetic typography — per-character H1
 *
 *  hero_motion.js SplitText wraps each character in <span class="pb-kc">
 *  with --i (index) custom prop. We drive both entrance and the idle
 *  "breathe" loop with pure CSS keyframes seeded by --i. Magnetic-attract
 *  translation is applied inline by JS via --kx/--ky.
 * ──────────────────────────────────────────────────────────────────────────── */

.hero-copy h1 .pb-kc {
    display: inline-block;
    position: relative;
    /* Inline-block so transforms apply per character without breaking
       wrapping or letter-spacing. */
    transform: translate3d(var(--kx, 0px), var(--ky, 0px), 0);
    will-change: transform, opacity;
    /* Subtle 3D depth - small perspective per letter so breath rotateX
       has volume on hover. */
    transform-style: preserve-3d;
    backface-visibility: hidden;
}

/* Pre-state: characters hidden, dropped 40px down. Entrance animation
   replaces this with the kinetic-drop keyframe sequence. */
.pb-hero-pre .hero-copy h1 .pb-kc {
    opacity: 0;
    transform: translate3d(0, 40px, 0);
}

/* Whitespace span — no animation, just preserves layout. */
.hero-copy h1 .pb-kc.pb-kc-space {
    display: inline;
    transform: none;
    opacity: 1;
    animation: none !important;
}

/* Entrance: characters drop from y:40, opacity:0, stagger 25ms via --i,
   slight overshoot ease. JS adds .pb-kc-in to start. */
.pb-kc-in .hero-copy h1 .pb-kc:not(.pb-kc-space) {
    animation: pb-kc-drop 720ms cubic-bezier(.2, 1.2, .3, 1) both;
    animation-delay: calc(var(--i, 0) * 25ms);
}

@keyframes pb-kc-drop {
    0% {
        opacity: 0;
        transform: translate3d(0, 40px, 0) rotate(-4deg);
        filter: blur(2px);
    }
    65% {
        opacity: 1;
        transform: translate3d(0, -3px, 0) rotate(0.5deg);
        filter: blur(0);
    }
    100% {
        opacity: 1;
        transform: translate3d(var(--kx, 0px), var(--ky, 0px), 0) rotate(0deg);
        filter: blur(0);
    }
}

/* Idle breathe loop — starts AFTER entrance completes. JS adds .pb-kc-live
   to <h1> when timeline finishes (~1.4s). Each character has random-phase
   offset via --i + small modulo to avoid mechanical sync. Scale 1.0 ↔ 1.005,
   6s loop. */
.pb-kc-live .hero-copy h1 .pb-kc:not(.pb-kc-space) {
    animation: pb-kc-breathe 6s ease-in-out infinite;
    animation-delay: calc(var(--i, 0) * -180ms);
}

@keyframes pb-kc-breathe {
    0%, 100% {
        transform: translate3d(var(--kx, 0px), var(--ky, 0px), 0) scale(1);
    }
    50% {
        transform: translate3d(var(--kx, 0px), var(--ky, 0px), 0) scale(1.005);
    }
}

/* Hover magnetic-attract state — set by JS via --kx/--ky inline.
   Smooth transition so motion feels "pulled" not jittery. */
@media (hover: hover) and (pointer: fine) {
    .hero-copy h1 .pb-kc {
        transition: transform 320ms cubic-bezier(.2, .8, .2, 1);
    }
    /* During breathe, transition kept; transform-origin centered. */
    .pb-kc-live .hero-copy h1 .pb-kc:not(.pb-kc-space) {
        transition: none; /* keyframes own transform during breathe */
    }
    /* When JS adds .pb-kc-attract to <h1>, swap to inline-driven transform
       (no keyframes) so magnetic drag is fluid. */
    .pb-kc-attract .hero-copy h1 .pb-kc:not(.pb-kc-space) {
        animation: none;
        transition: transform 220ms cubic-bezier(.2, .8, .2, 1);
    }
}


/* ────────────────────────────────────────────────────────────────────────────
 *  2. Multi-layer parallax depth — verdict particles
 *
 *  Markup (JS injects on boot, after .hero detection):
 *    <div class="hero-particles" aria-hidden="true">
 *      <span class="hero-particle" data-pk="check"   style="--x:..;--y:..;--d:..;">✓</span>
 *      ...
 *    </div>
 *
 *  z-index plan (relative to hero stacking context):
 *    z:-3 → hero-mesh blobs (existing, far back)
 *    z:-2 → hero-particles (NEW, mid-back, slowest parallax)
 *    z: 0 → phone-frame + sparkles (mid-front)
 *    z: 1 → hero copy + form (front)
 * ──────────────────────────────────────────────────────────────────────────── */

.hero .hero-particles {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 0;
    /* Keep above mesh (z:0) but below content (z:1 in style.css :: .hero > *).
       We sit at the same z as mesh but rendered later so we paint above blob
       blur. Specificity (0,2,0) > .hero > * (0,1,1) — guarantees z:0. */
    overflow: hidden;
    /* JS sets --pkY (parallax-Y) — translates the whole layer with scroll. */
    transform: translate3d(0, var(--pkY, 0px), 0);
    will-change: transform;
}

.hero-particle {
    position: absolute;
    left: calc(var(--x, 50) * 1%);
    top: calc(var(--y, 50) * 1%);
    font-size: 18px;
    line-height: 1;
    font-weight: 900;
    opacity: 0;
    /* Subtle drift on its own + own parallax depth offset via --pd (0..1) */
    transform: translate3d(0, calc(var(--pd, 0) * -8px), 0);
    will-change: transform, opacity;
    /* Compose two animations: fade-in (once) then infinite drift loop.
       Drift delay seeded by --d so particles desync — but fade-in is shared.
       Negative drift delay starts each particle mid-cycle for instant motion. */
    animation:
        pb-particle-fadein 900ms ease-out 1s both,
        pb-particle-drift 18s ease-in-out calc(var(--d, 0) * -1s) infinite;
    user-select: none;
    -webkit-user-select: none;
    /* Soft glow so emoji-glyphs read cinematic, not raw. */
    filter: drop-shadow(0 0 6px currentColor);
}

@keyframes pb-particle-fadein {
    0%   { opacity: 0; transform: translate3d(0, calc(var(--pd, 0) * -8px + 14px), 0); }
    100% { opacity: 0.55; transform: translate3d(0, calc(var(--pd, 0) * -8px), 0); }
}
.hero-particle.is-good { color: var(--good, #38e0a8); }
.hero-particle.is-warn { color: var(--warn, #ffc94a); }
.hero-particle.is-bad  { color: var(--bad,  #ff5d8f); }

@keyframes pb-particle-drift {
    0%, 100% {
        transform: translate3d(0, calc(var(--pd, 0) * -8px), 0) rotate(0deg);
        opacity: 0.55;
    }
    25% {
        transform: translate3d(12px, calc(var(--pd, 0) * -8px - 14px), 0) rotate(8deg);
        opacity: 0.7;
    }
    50% {
        transform: translate3d(-8px, calc(var(--pd, 0) * -8px + 10px), 0) rotate(-4deg);
        opacity: 0.45;
    }
    75% {
        transform: translate3d(-14px, calc(var(--pd, 0) * -8px - 6px), 0) rotate(6deg);
        opacity: 0.65;
    }
}

/* On result page (.has-result) — hide all decoration. */
body.has-result .hero-particles,
body.has-result .hero-light-leak {
    display: none;
}


/* ────────────────────────────────────────────────────────────────────────────
 *  3. Corner light-leak — cinematic ambient
 *
 *  Two radial-gradient overlays anchored to top-right and bottom-left
 *  corners. Slow opposing-phase pulse (6s & 7.5s for non-syncing organic feel).
 * ──────────────────────────────────────────────────────────────────────────── */

.hero .hero-light-leak {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 0;
    overflow: hidden;
    mix-blend-mode: screen;
    /* Specificity (0,2,0) > .hero > * (0,1,1). */
}

.hero-light-leak-tr {
    position: absolute;
    top: -60px;
    right: -60px;
    width: 360px;
    height: 360px;
    background: radial-gradient(
        circle at 30% 30%,
        rgba(var(--accent-3-rgb), 0.32) 0%,
        rgba(var(--accent-3-rgb), 0.12) 24%,
        rgba(var(--accent-3-rgb), 0.0) 60%
    );
    filter: blur(8px);
    animation: pb-leak-pulse 6s ease-in-out infinite;
    border-radius: 50%;
}

.hero-light-leak-bl {
    position: absolute;
    bottom: -80px;
    left: -80px;
    width: 320px;
    height: 320px;
    background: radial-gradient(
        circle at 70% 70%,
        rgba(var(--accent-rgb), 0.26) 0%,
        rgba(var(--accent-rgb), 0.08) 26%,
        rgba(var(--accent-rgb), 0.0) 62%
    );
    filter: blur(10px);
    animation: pb-leak-pulse 7.5s ease-in-out infinite 1.6s reverse;
    border-radius: 50%;
}

@keyframes pb-leak-pulse {
    0%, 100% { opacity: 0.45; transform: scale(1) translate3d(0, 0, 0); }
    50%      { opacity: 0.85; transform: scale(1.08) translate3d(8px, -6px, 0); }
}

@media (min-width: 1440px) {
    .hero-light-leak-tr { width: 480px; height: 480px; }
    .hero-light-leak-bl { width: 420px; height: 420px; }
}


/* ────────────────────────────────────────────────────────────────────────────
 *  4. Magnetic CTA enhancement — scan-line + radial ripple
 *
 *  Builds on existing hero_mesh.css magnetic CTA. We add:
 *    - Inner running scan-line on hover (1.6s loop, 0.15 opacity)
 *    - Radial ripple on click (JS injects .pb-cta-ripple span)
 *    - Subtle inner glow (--pb-mx/--pb-my from JS now also drives a
 *      sharper "spot" via separate ::before pseudo)
 * ──────────────────────────────────────────────────────────────────────────── */

.check-form.check-form-hero button#submit-btn {
    /* Keep visible scan-line/ripple inside button. */
    isolation: isolate;
}

/* Scan-line: thin diagonal sheen on hover. */
.check-form.check-form-hero button#submit-btn::before {
    content: "";
    position: absolute;
    top: 0;
    left: -120%;
    width: 60%;
    height: 100%;
    background: linear-gradient(
        100deg,
        transparent 0%,
        rgba(255, 255, 255, 0.18) 45%,
        rgba(255, 255, 255, 0.45) 50%,
        rgba(255, 255, 255, 0.18) 55%,
        transparent 100%
    );
    transform: skewX(-18deg);
    pointer-events: none;
    opacity: 0;
    transition: opacity 200ms ease;
    border-radius: inherit;
    mix-blend-mode: overlay;
    z-index: 1;
}

.check-form.check-form-hero button#submit-btn:hover::before,
.check-form.check-form-hero button#submit-btn:focus-visible::before {
    opacity: 1;
    animation: pb-cta-scanline 1.6s ease-in-out infinite;
}

@keyframes pb-cta-scanline {
    0%   { left: -120%; }
    100% { left:  220%; }
}

/* Click ripple — JS appends <span class="pb-cta-ripple"> with --rx/--ry. */
.check-form.check-form-hero button#submit-btn .pb-cta-ripple {
    position: absolute;
    left: var(--rx, 50%);
    top: var(--ry, 50%);
    width: 12px;
    height: 12px;
    margin: -6px 0 0 -6px;
    border-radius: 50%;
    background: radial-gradient(
        circle,
        rgba(255, 255, 255, 0.55) 0%,
        rgba(255, 255, 255, 0.15) 40%,
        rgba(255, 255, 255, 0) 70%
    );
    pointer-events: none;
    transform: scale(0);
    opacity: 0.85;
    animation: pb-cta-ripple 700ms ease-out forwards;
    mix-blend-mode: overlay;
    z-index: 2;
}

@keyframes pb-cta-ripple {
    0%   { transform: scale(0);  opacity: 0.85; }
    100% { transform: scale(48); opacity: 0;    }
}

/* data-magnetic="1" set by JS — currently unused beyond being a marker
   for the inspector that JS magnetic system is live. Keep existing
   transition from hero_mesh.css. */


/* ────────────────────────────────────────────────────────────────────────────
 *  5. Phone-frame breath upgrade — rotateY + shadow pulse
 *
 *  Existing phone_frame_motion.js does GSAP y-bob (4px). We add a CSS layer:
 *    - rotateY 0 ↔ 0.4deg (8s loop, paper-thin perspective)
 *    - Drop-shadow alpha 0.4 ↔ 0.5 (synced with rotateY)
 *  Existing GSAP y-bob continues underneath via wrapper, not conflicting.
 * ──────────────────────────────────────────────────────────────────────────── */

.hero-phone-wrap {
    perspective: 1400px;
    transform-style: preserve-3d;
}

.hero-phone-wrap .pb-inv-phone-frame {
    /* Apply the cinematic micro-rotate on the inner frame, not the wrap
       (which is already getting GSAP y-bob). This composes cleanly. */
    animation: pb-phone-tilt 8s ease-in-out infinite;
    transform-style: preserve-3d;
    will-change: transform, filter;
}

@keyframes pb-phone-tilt {
    0%, 100% {
        transform: rotateY(0deg) rotateX(0deg);
        filter: drop-shadow(0 18px 38px rgba(0, 0, 0, 0.4));
    }
    50% {
        transform: rotateY(0.4deg) rotateX(-0.2deg);
        filter: drop-shadow(0 22px 44px rgba(0, 0, 0, 0.5));
    }
}


/* ────────────────────────────────────────────────────────────────────────────
 *  6. URL-input polish — focus glow ring + scan-line
 *
 *  Existing #url-input is flat. We add:
 *    - Outer glow ring on focus (mint, 200ms fade in)
 *    - Inner mint scan-dot running left → right (2s loop, focus only)
 *    - Existing placeholder text — preserved exactly (kinetic typing is
 *      driven by JS swapping placeholder over time on initial visit)
 * ──────────────────────────────────────────────────────────────────────────── */

.check-form.check-form-hero {
    position: relative;
    transition:
        box-shadow 240ms ease,
        border-color 240ms ease;
}

/* Focus glow ring — applied to the FORM (not the input) so it visually
   surrounds the whole input+button group. .is-input-focus is added by
   hero_motion.js initInputPolish() on input focus. */
.check-form.check-form-hero.is-input-focus {
    box-shadow:
        0 0 0 3px rgba(var(--accent-3-rgb), 0.15),
        0 0 22px 4px rgba(var(--accent-3-rgb), 0.18),
        0 24px 60px -24px rgba(var(--accent-2-rgb), 0.45),
        0 0 0 1px rgba(var(--accent-3-rgb), 0.35) inset;
    border-color: rgba(var(--accent-3-rgb), 0.5) !important;
}

.check-form.check-form-hero #url-input:focus,
.check-form.check-form-hero #url-input:focus-visible {
    outline: none;
}

/* Scan-dot overlay — visible only when input has focus.
   We anchor it inside .check-form via an absolutely positioned span
   that JS injects (.pb-input-scan). It runs along the bottom edge. */
.check-form.check-form-hero .pb-input-scan {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 2px;
    width: 100%;
    pointer-events: none;
    overflow: hidden;
    border-radius: 0 0 14px 14px;
    opacity: 0;
    transition: opacity 240ms ease;
    z-index: 2;
}

.check-form.check-form-hero.is-input-focus .pb-input-scan {
    opacity: 1;
}

.check-form.check-form-hero .pb-input-scan::after {
    content: "";
    position: absolute;
    left: -28%;
    top: 0;
    width: 28%;
    height: 100%;
    background: linear-gradient(
        90deg,
        transparent 0%,
        rgba(var(--accent-3-rgb), 0.0) 5%,
        rgba(var(--accent-3-rgb), 0.55) 50%,
        rgba(var(--accent-3-rgb), 0.0) 95%,
        transparent 100%
    );
    filter: blur(0.5px);
    animation: pb-input-scan 2s ease-in-out infinite;
}

@keyframes pb-input-scan {
    0%   { left: -28%; }
    100% { left: 100%; }
}


/* ────────────────────────────────────────────────────────────────────────────
 *  7. Recent-checks ticker upgrade — wobble + saturation pulse + hover scale
 *
 *  Existing .hero-ticker uses CSS marquee. We add per-item subtle vertical
 *  wobble (±1px) with staggered phases. On hover the whole track pauses
 *  (already implemented in hero_mesh.css). New: item under cursor gets
 *  scale 1.08 + glow. JS attaches mouseenter listeners.
 * ──────────────────────────────────────────────────────────────────────────── */

.hero-ticker-item {
    /* Each item gets --w (random 0..9) — JS sets via inline style on build.
       Wobble period 4.5s, phase shifted by --w. */
    animation: pb-ticker-wobble 4.5s ease-in-out infinite;
    animation-delay: calc(var(--w, 0) * -0.45s);
    transition: transform 280ms cubic-bezier(.2, .8, .2, 1),
                filter 280ms ease;
}

@keyframes pb-ticker-wobble {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-1px); }
}

/* Hover: item scales up with glow. Only on fine-pointer hover-capable
   devices, otherwise touch users get pointless tap-state. */
@media (hover: hover) and (pointer: fine) {
    .hero-ticker:hover .hero-ticker-item:hover {
        transform: translateY(0) scale(1.08);
        filter: drop-shadow(0 6px 14px rgba(var(--accent-3-rgb), 0.25))
                drop-shadow(0 0 6px rgba(var(--accent-3-rgb), 0.18));
        animation-play-state: paused;
    }
    .hero-ticker:hover .hero-ticker-item:hover .tk-pct,
    .hero-ticker:hover .hero-ticker-item:hover .tk-name,
    .hero-ticker:hover .hero-ticker-item:hover .tk-verdict {
        text-shadow: 0 0 8px currentColor;
    }
}


/* ────────────────────────────────────────────────────────────────────────────
 *  Responsive — narrow viewports keep effects sane
 * ──────────────────────────────────────────────────────────────────────────── */

@media (max-width: 900px) {
    /* Particles drop to 4 (instead of 8) on small viewports — CSS hides
       odd-numbered ones. Real count enforced by JS too. */
    .hero-particle:nth-child(2n+1) {
        display: none;
    }
    .hero-light-leak-tr { width: 220px; height: 220px; top: -40px; right: -40px; }
    .hero-light-leak-bl { width: 200px; height: 200px; bottom: -50px; left: -50px; }
}

@media (max-width: 720px) {
    /* Magnetic CTA scan-line still works, but ripple radius limited. */
    .check-form.check-form-hero button#submit-btn .pb-cta-ripple {
        animation-duration: 600ms;
    }
    /* Phone-frame tilt off on mobile (smaller frame, doesn't read). */
    .hero-phone-wrap .pb-inv-phone-frame {
        animation: none;
    }
    /* Light-leak shrinks more. */
    .hero-light-leak-tr,
    .hero-light-leak-bl {
        display: none;
    }
    /* Per-character entrance still works, but breathe loop turned off
       (saves CPU on mobile). */
    .pb-kc-live .hero-copy h1 .pb-kc:not(.pb-kc-space) {
        animation: none;
    }
}


/* ────────────────────────────────────────────────────────────────────────────
 *  prefers-reduced-motion: hard kill-switch
 * ──────────────────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .hero-copy h1 .pb-kc {
        animation: none !important;
        transition: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
    .hero-particle {
        animation: none !important;
    }
    .hero-light-leak-tr,
    .hero-light-leak-bl {
        animation: none !important;
    }
    .check-form.check-form-hero button#submit-btn::before,
    .check-form.check-form-hero button#submit-btn .pb-cta-ripple,
    .check-form.check-form-hero .pb-input-scan::after,
    .hero-ticker-item,
    .hero-phone-wrap .pb-inv-phone-frame {
        animation: none !important;
    }
}


/* ────────────────────────────────────────────────────────────────────────────
 *  Low-end devices — body.pb-low-end
 *  Skip particles, light-leaks, kinetic breathe loop. Keep entrance + magnetic.
 * ──────────────────────────────────────────────────────────────────────────── */

.pb-low-end .hero-particles,
.pb-low-end .hero-light-leak {
    display: none !important;
}

.pb-low-end .pb-kc-live .hero-copy h1 .pb-kc {
    animation: none !important;
}

.pb-low-end .hero-phone-wrap .pb-inv-phone-frame {
    animation: none !important;
}

.pb-low-end .check-form.check-form-hero button#submit-btn::before {
    /* Scan-line disabled on low-end — keep only glow halo. */
    display: none !important;
}

.pb-low-end .hero-ticker-item {
    animation: none !important;
}
