/* The effects layer, and the surfaces built on top of it.
 *
 * Loaded after games.css and before access.css — so a game's own styling is
 * the base for these, and the accessibility overrides still win over both.
 */

/* ============ Particle canvas ============
   Fixed to the viewport and outside .app, for the reasons set out at the top
   of js/core/fx.js. z-index 50 clears the game (5), the hub rail (40) and the
   access bar (45), but stays under the dwell ring (60) and the settings sheet
   (100): sparks never cover the feedback an eye-gaze player is aiming with. */
#fx-layer {
    position: fixed;
    inset: 0;
    z-index: 50;
    pointer-events: none;
    display: block;
}

/* ============ Pig ============
   Decoration throughout — aria-hidden, never a scan stop. The number at risk,
   the Hold button's label and the spoken announcements remain the only things
   that actually carry the state. */
.pig {
    position: relative;
    display: block;
    flex-shrink: 0;
    /* `hidden` is only display:none from the UA sheet, so the `display: block`
       above would quietly beat it and leave the pig laid out after the setting
       turned it off. */

    width: clamp(84px, min(19vw, calc(26 * var(--vh))), 190px);
    aspect-ratio: 6 / 5;
    /* Reset per turn by JS. Named here so the pig has a sane resting pose even
       if it is painted before the first roll. */
    --pig-scale: 1;
    --pig-fill: #F3A8BC;
    --pig-deep: #DE7E98;
}
.pig[hidden] { display: none; }
.pig-svg { width: 100%; height: 100%; display: block; }

/* The pig sits beside the die, never instead of it: the pips are the result,
   and counting them is real practice for the players this is built for. */
.pig-tray { gap: clamp(6px, 2vw, 28px); }
/* The density steps shrink the pig rather than dropping it. It is the one
   channel in this game that does not require reading a two-digit number, so a
   player on a short screen at large zoom — very much the target device — is
   the last person who should lose it. The die still wins ties on size, because
   the die is the one carrying the result. */
body.is-tight .pig { width: clamp(72px, min(16vw, calc(20 * var(--vh))), 150px); }
body.is-tighter .pig { width: clamp(56px, min(12vw, calc(15 * var(--vh))), 104px); }

.pig-grow {
    transform: scale(var(--pig-scale));
    transform-origin: 60px 50px;
    /* Overshoot on the way up: the pig should look pumped, not resized. */
    transition: transform .42s cubic-bezier(.34, 1.7, .5, 1);
}
.pig-figure { transition: opacity .12s linear; }
.pig-body { fill: var(--pig-fill); transition: fill .4s ease; }
.pig-ear { fill: var(--pig-deep); transition: fill .4s ease; }
.pig-leg { fill: var(--pig-deep); transition: fill .4s ease; }
.pig-snout { fill: var(--pig-deep); transition: fill .4s ease; }
.pig-nostril { fill: rgba(60, 20, 34, .62); }
.pig-eye { fill: #2E1420; }
.pig-tail { stroke: var(--pig-deep); transition: stroke .4s ease; }
.pig-shine { fill: rgba(255, 255, 255, .38); }
.pig-blush { fill: rgba(226, 92, 122, .32); opacity: 0; transition: opacity .4s ease; }
.pig-pop { fill: var(--sun); opacity: 0; }

/* Mood. Colour warms toward coral as the stake grows, so the pig reads at a
   glance from across a room — the same information as the "N at risk" pill,
   in the channel a player who cannot yet read the pill still has. */
.pig.is-plump { --pig-fill: #F6A08C; --pig-deep: #E07E68; }
.pig.is-tense { --pig-fill: #F58B60; --pig-deep: #D96F4A; }
.pig.is-critical { --pig-fill: var(--coral); --pig-deep: #C9503A; }
.pig.is-tense .pig-blush, .pig.is-critical .pig-blush { opacity: 1; }

/* Breathing. Only from 'tense' — an animation that runs from the first roll
   stops meaning anything by the third. */
.pig.is-tense .pig-wobble {
    animation: pigBreathe 1.5s ease-in-out infinite;
    transform-origin: 60px 50px;
}
.pig.is-critical .pig-wobble {
    animation: pigStrain .42s ease-in-out infinite;
    transform-origin: 60px 50px;
}
@keyframes pigBreathe {
    0%, 100% { transform: scale(1) rotate(0deg); }
    50% { transform: scale(1.035) rotate(-1.2deg); }
}
@keyframes pigStrain {
    0%, 100% { transform: scale(1.02) rotate(1.6deg); }
    25% { transform: scale(1.06) rotate(-1.8deg); }
    50% { transform: scale(1.02) rotate(1.4deg); }
    75% { transform: scale(1.07) rotate(-1.5deg); }
}

/* Burst. The figure snaps outward and vanishes; fx.js throws the fragments.
   The star is what remains, and on its own it is the entire burst when
   effects are off — see the reduced-motion block below. */
.pig.is-burst .pig-grow { transition: none; animation: pigBurst .34s cubic-bezier(.3, 1.5, .6, 1) forwards; }
.pig.is-burst .pig-pop { animation: pigPopFlash .5s ease-out forwards; }
@keyframes pigBurst {
    0% { transform: scale(var(--pig-scale)); }
    35% { transform: scale(calc(var(--pig-scale) * 1.22)); opacity: 1; }
    36% { opacity: 0; }
    100% { transform: scale(calc(var(--pig-scale) * 1.22)); opacity: 0; }
}
@keyframes pigPopFlash {
    0% { opacity: 0; transform: scale(.4); }
    22% { opacity: 1; transform: scale(1.1); }
    100% { opacity: 0; transform: scale(1.3); }
}
.pig-pop { transform-origin: 60px 50px; }

/* Hold: the pig lets its air out and settles back to nothing. */
.pig.is-deflating .pig-grow { transition: transform .55s cubic-bezier(.4, 0, .5, 1); }

/* Reduced motion (and effects off) must still tell the player what happened.
   The pig keeps its size steps and keeps a burst state — what goes is the
   travel, the breathing and the overshoot, not the information. */
body.reduced-motion .pig-grow { transition: none; }
body.reduced-motion .pig.is-burst .pig-figure { opacity: 0; }
body.reduced-motion .pig.is-burst .pig-pop { opacity: 1; }
.pig.is-burst.is-still .pig-figure { opacity: 0; }
.pig.is-burst.is-still .pig-pop { opacity: 1; }
