/* ==========================================================================
   Hero characters - live SVG
   The pupils follow the cursor and the mouth opens into a grin when the
   cursor comes close. Built by scripts/build_hero_characters.py.

   Note on layout: main.css sizes .hero-character by height with width:auto,
   which works for an <img> because it has an intrinsic ratio. Once the <img>
   is swapped for a <span> wrapper we have to restate the ratio ourselves -
   it comes from the artwork's viewBox, 595.28 x 841.89.

   Note on motion: the inline script in home.html already floats these
   characters, so there is deliberately no float animation here. Two would
   fight over the same transform.
   ========================================================================== */

.hero-character-slot {
    aspect-ratio: 595.28 / 841.89;
    width: auto;
    /* Intro is opacity only. The float script owns `transform` on this
       element, so animating transform here would be overwritten. */
    opacity: 0;
    transition: opacity 0.7s ease;
}

.hero-character-slot.is-ready {
    opacity: 1;
}

.hero-character-slot--boy {
    transition-delay: 0.12s;
}

.hero-character-inner,
.hero-character-svg {
    display: block;
    width: 100%;
    height: 100%;
}

.hero-character-svg {
    overflow: visible;
}

/* Pupils are positioned by JS; this transition is what makes them glide
   instead of snapping. */
.zw-pupil {
    transition: transform 0.35s cubic-bezier(0.23, 1, 0.32, 1);
}

/* Mouth cross-fade. Both mouths occupy the same spot in the artwork, so
   swapping opacity reads as the character breaking into a grin. */
.zw-mouth-closed,
.zw-mouth-open {
    transition: opacity 0.22s ease;
}

.zw-mouth-open {
    opacity: 0;
}

.hero-character-slot.is-grinning .zw-mouth-closed {
    opacity: 0;
}

.hero-character-slot.is-grinning .zw-mouth-open {
    opacity: 1;
}

/* ---- The girl's wave ----------------------------------------------------
   Her raised hand is ten separate shapes that are not adjacent in document
   order, so each is rotated individually rather than wrapped in a group -
   same result, without disturbing what paints over what.

   transform-box: view-box makes transform-origin resolve against the
   artwork's own coordinates, so 426 464 is the wrist. */
.zw-wave {
    transform-box: view-box;
    transform-origin: 426px 464px;
}

.hero-character-slot.is-waving .zw-wave {
    animation: zw-wave 0.75s ease-in-out 3;
}

@keyframes zw-wave {
    0%, 100% { transform: rotate(0deg); }
    25%      { transform: rotate(-12deg); }
    75%      { transform: rotate(12deg); }
}

/* ---- Reduced motion ---------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .hero-character-slot {
        opacity: 1;
        transition: none;
    }

    .zw-pupil {
        transition: none;
    }

    .hero-character-slot.is-waving .zw-wave {
        animation: none;
    }
}
