/* ============================================================================
   hero-voice.css — THE SIGNATURE HERO INTERACTION ("Voice Aura" + soundwave)
   ----------------------------------------------------------------------------
   Self-contained, drop-in layer for the chatlemur.com homepage rebuild.
   Pairs with /static/js/hero-voice.js (window.HeroVoice). Every selector is
   namespaced `hero-voice-` / `hv-` so it can NEVER clash with the existing
   concierge / avatar / homepage styles — this file only ADDS a decorative,
   accessible aura + soundwave AROUND the live demo; it never restyles it.

   Design tokens mirror the flagship spec (Gemini 3.1 Pro, 2026-08-12):
     primary #7C3AED · accent/focus #A78BFA · surface #18181B · bg #09090B.
   Falls back to those literals if the page's :root tokens are absent.

   Motion contract: ALL continuous motion lives under
   `@media (prefers-reduced-motion: no-preference)`. With reduced motion the
   aura holds a single calm frame and the soundwave is static — the state
   still changes colour + the aria-live region still announces, so the
   interaction stays legible and accessible without any animation.

   GPU budget: only `transform` and `opacity` ever animate. No layout, no
   paint-triggering properties, no box-shadow transitions in the rAF path.
   ========================================================================== */

.hero-voice-root,
.hero-voice-stage {
    /* Positioning context for the absolutely-placed aura. Applied by JS to the
       avatar's nearest wrapper so the aura centres on the avatar. */
    position: relative;
}

/* ---------------------------------------------------------------------------
   1. THE VOICE AURA — radial violet gradient that breathes when idle and
      scales to Lenny's live audio amplitude when she speaks.
   --------------------------------------------------------------------------- */
.hero-voice-aura {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 130%;
    /* Square via aspect-ratio so the radial stays circular on any avatar box. */
    aspect-ratio: 1 / 1;
    /* Centre on the avatar, then scale from the middle. JS drives --hv-aura-scale
       (1 → ~1.28) live; the translate keeps it anchored. */
    transform: translate(-50%, -50%) scale(var(--hv-aura-scale, 1));
    transform-origin: center center;
    background: radial-gradient(
        circle,
        rgba(124, 58, 237, 0.20) 0%,
        rgba(124, 58, 237, 0.10) 38%,
        rgba(124, 58, 237, 0.00) 70%
    );
    opacity: var(--hv-aura-opacity, 0.85);
    pointer-events: none;
    z-index: 0;
    will-change: transform, opacity;
    /* When the amplitude value jumps between frames, this short ease keeps the
       aura fluid rather than steppy (the rAF value itself is already smoothed). */
    transition: opacity 0.35s ease;
}

/* Keep the aura strictly BEHIND the avatar/render, never over it. The avatar
   figure and chat widget sit at their natural stacking; the aura is z-index 0
   inside a positioned root, so any real content with position/z-index stacks
   above it. Belt-and-braces: push it back a hair. */
.hero-voice-aura { z-index: 0; }

/* Speaking = the brand violet glows harder + warmer. Listening = a calmer,
   cooler accent so the two states read differently without motion. */
.hero-voice-aura[data-hv-state="speaking"] {
    background: radial-gradient(
        circle,
        rgba(124, 58, 237, 0.32) 0%,
        rgba(124, 58, 237, 0.16) 40%,
        rgba(124, 58, 237, 0.00) 70%
    );
    --hv-aura-opacity: 1;
}
.hero-voice-aura[data-hv-state="listening"] {
    background: radial-gradient(
        circle,
        rgba(167, 139, 250, 0.24) 0%,
        rgba(167, 139, 250, 0.11) 40%,
        rgba(167, 139, 250, 0.00) 70%
    );
    --hv-aura-opacity: 0.92;
}
.hero-voice-aura[data-hv-state="connecting"] {
    --hv-aura-opacity: 0.7;
}

/* ---------------------------------------------------------------------------
   2. THE SOUNDWAVE VISUALIZER — a row of bars under the avatar/mic. Reacts to
      the user's mic while they speak, then turns #7C3AED and reacts to Lenny's
      reply audio. Bar heights are driven by JS via per-bar --hv-level (0..1).
   --------------------------------------------------------------------------- */
.hero-voice-wave {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    height: 40px;
    margin: 14px auto 0;
    max-width: 240px;
    pointer-events: none;
    /* Fades in only once the demo is live/active; calm and low when idle. */
    opacity: var(--hv-wave-opacity, 0.55);
    transition: opacity 0.4s ease;
    /* currentColor drives the bars; state sets the colour. */
    color: #A78BFA;
}
.hero-voice-wave[data-hv-state="speaking"] {
    color: #7C3AED;
    --hv-wave-opacity: 1;
}
.hero-voice-wave[data-hv-state="listening"] {
    color: #A78BFA;
    --hv-wave-opacity: 1;
}

.hero-voice-bar {
    flex: 0 0 4px;
    width: 4px;
    height: 100%;
    border-radius: 999px;
    background: currentColor;
    /* scaleY from the centre; JS sets --hv-level per bar (0..1). */
    transform: scaleY(var(--hv-level, 0.12));
    transform-origin: center center;
    will-change: transform;
    /* Micro-smoothing between frames — cheap, transform-only. */
    transition: transform 0.06s linear;
    opacity: 0.9;
}

/* ---------------------------------------------------------------------------
   3. SCREEN-READER STATE REGION — accessibility as a first-class feature.
      Visually hidden, announced politely. JS writes "Lenny is listening…",
      "Lenny is speaking…", etc. (Suppressed automatically when the page's own
      live-status element is already announcing, to avoid double VoiceOver.)
   --------------------------------------------------------------------------- */
.hero-voice-live {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   4. MOTION — everything continuous is gated behind prefers-reduced-motion.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
    /* Idle breathing: a slow 4s scale 1 → 1.05. Only runs while JS has NOT
       taken over the scale (i.e. the .hv-breathing class is present in idle).
       During speaking/listening JS removes .hv-breathing and drives
       --hv-aura-scale directly from the live amplitude. */
    .hero-voice-aura.hv-breathing {
        animation: hv-breathe 4s ease-in-out infinite;
    }

    @keyframes hv-breathe {
        0%,
        100% {
            transform: translate(-50%, -50%) scale(1);
        }
        50% {
            transform: translate(-50%, -50%) scale(1.05);
        }
    }

    /* Idle soundwave: a gentle, low, staggered shimmer so the demo feels alive
       and "listening" before any audio. JS overrides per-bar --hv-level the
       moment real audio arrives. */
    .hero-voice-wave.hv-idle .hero-voice-bar {
        animation: hv-idle-bar 2.4s ease-in-out infinite;
    }
    .hero-voice-wave.hv-idle .hero-voice-bar:nth-child(2n) { animation-delay: -0.4s; }
    .hero-voice-wave.hv-idle .hero-voice-bar:nth-child(3n) { animation-delay: -0.9s; }
    .hero-voice-wave.hv-idle .hero-voice-bar:nth-child(4n) { animation-delay: -1.3s; }
    .hero-voice-wave.hv-idle .hero-voice-bar:nth-child(5n) { animation-delay: -1.8s; }

    @keyframes hv-idle-bar {
        0%,
        100% { transform: scaleY(0.14); }
        50%  { transform: scaleY(0.4); }
    }
}

/* Reduced motion (default when the user asks for less): a single calm frame.
   No animation, no rAF-driven scale — the state still changes colour and the
   aria-live region still announces, so nothing is lost but the movement. */
@media (prefers-reduced-motion: reduce) {
    .hero-voice-aura {
        transform: translate(-50%, -50%) scale(1.02);
        animation: none !important;
    }
    .hero-voice-bar {
        transform: scaleY(0.28);
        transition: none;
        animation: none !important;
    }
}
