@keyframes flash {
    0% {
        opacity: 100%;
    }
    50% {
        opacity: 25%;
    }
    100% {
        opacity: 100%;
    }
}
/* The board arrows (threats, hints) breathe so they read as live signals, not
   board furniture. Only opacity moves, so it composites — the arrow geometry
   never re-rasters. The peak stays below 1: a fully solid arrow blots out the
   wood grain and turns back into the flat sticker this animation is meant to
   avoid. */
@keyframes arrowPulse {
    0% {
        opacity: 0.5;
    }
    50% {
        opacity: 0.65;
    }
    100% {
        opacity: 0.5;
    }
}
@keyframes plaqueSwing {
    0% {
        transform: translateY(-3vh) rotate(4deg);
        opacity: 0;
    }
    45% {
        transform: translateY(0) rotate(-2deg);
        opacity: 1;
    }
    75% {
        transform: rotate(1deg);
    }
    100% {
        transform: rotate(0deg);
    }
}

/* A king into the last third of its lives flashes; the health frame is a
   steady reading, so this is the only urgency the indicator shouts. */
.square.check-critical .piece {
    animation: flash 1s ease-in-out 0s infinite;
}
/* A fuse on its last two moves flashes faster — it is about to go off. */
.square.fuse-critical .piece {
    animation: flash 0.6s ease-in-out 0s infinite;
}
.plaque.open {
    animation: plaqueSwing 0.6s ease-out;
}
