/* Campaign funding bar · SHARED between limited.playtil.es and get.playtil.es.
 *
 * Was limited/css/progress-bars.css. Moved here so the shop hero and the campaign
 * pages render the same bar from one file instead of two copies drifting apart.
 *
 * The CI copies shared/ into BOTH deploys, so each site serves its own /shared/
 * copy from its own origin. Reference it as /shared/campaign-progress.css.
 * Nothing here may use a relative url(): the file sits at a different depth on
 * each site. It currently uses none, and it should stay that way.
 *
 * Needs only tokens that both sites define (colour, spacing, radius, duration).
 * The --flame-* variables are declared inside this file, so it is self-contained.
 * --intensity and --flame-grow are set inline by overfundedEffects() in
 * shared/campaign-format.js.
 */
/* ===== PROGRESS BARS ===== */
.progress-container {
    margin-bottom: var(--spacing-6);
}

.progress-stats {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: var(--spacing-2);
}

.progress-main {
    font-weight: var(--font-weight-bold);
    color: var(--color-dark);
    font-size: var(--font-size-lg);
}

.progress-bar, .sidebar-progress-bar {
    position: relative;
    width: 100%;
    background: rgba(0,0,0,0.15);
    border-radius: var(--radius-full);
    overflow: visible;
    box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
}

.progress-bar {
    height: 12px;
    margin-bottom: var(--spacing-3);
}

.sidebar-progress-bar {
    height: 16px;
    margin-bottom: var(--spacing-6);
    margin-top: var(--spacing-3);
}

.progress-fill, .sidebar-progress-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--color-lagoon), var(--color-sunglow), var(--color-crayola));
    border-radius: var(--radius-full);
    transition: width var(--duration-normal) var(--ease-out);
    position: relative;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2), 0 0 8px rgba(255,107,107,0.3);
}

.progress-cursor {
    position: absolute;
    right: -6px;
    top: 50%;
    transform: translateY(-50%);
    width: 12px;
    height: 12px;
    background: var(--color-dark);
    border: 2px solid white;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

.sidebar-progress-cursor {
    position: absolute;
    right: -8px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    background: var(--color-dark);
    border: 3px solid white;
    border-radius: 50%;
    box-shadow: 0 2px 6px rgba(0,0,0,0.3);
}

.days-remaining, .sidebar-status-text {
    color: var(--color-dark);
    font-weight: var(--font-weight-medium);
    margin-top: var(--spacing-2);
}

.days-remaining {
    font-size: var(--font-size-base);
}

.sidebar-status-text {
    text-align: center;
    font-size: var(--font-size-lg);
    margin-bottom: var(--spacing-1);
}

.campaign-funding {
    margin-bottom: var(--spacing-6);
}

.funding-amount-card {
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    color: var(--color-dark);
    margin-bottom: var(--spacing-1);
}

.funding-goal-card {
    font-size: var(--font-size-sm);
    color: var(--color-dark);
    opacity: 0.8;
    margin-bottom: var(--spacing-4);
}

/* ===== OVERFUNDED EFFECTS ===== */

/* The tiers accumulate: pulse from 100%, shake from 105%, flames from 120%,
   white-hot from 200%. Each adds to the one below rather than replacing it.

   Pulse brightens by fading a warm overlay in and out rather than by animating
   filter: brightness(). Same read, but opacity is a compositor property where
   filter forces a repaint every frame. */

/* Pulse (100%+) */
.progress-overfunded-pulse .progress-fill,
.progress-overfunded-pulse .sidebar-progress-fill {
    position: relative;
    box-shadow:
        0 1px 3px rgba(0,0,0,0.2),
        0 0 8px rgba(255,107,107,0.3),
        0 0 calc(14px * var(--intensity, 0.5)) rgba(255,193,7, calc(0.5 * var(--intensity, 0.5))),
        0 0 calc(24px * var(--intensity, 0.5)) rgba(255,107,107, calc(0.4 * var(--intensity, 0.5)));
}

/* The shimmer lives on ::after, which flames needs for its far tongues. Once
   there is real fire the shimmer has nothing left to say, so it steps aside. */
.progress-overfunded-pulse:not(.progress-overfunded-flames) .progress-fill::after,
.progress-overfunded-pulse:not(.progress-overfunded-flames) .sidebar-progress-fill::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: linear-gradient(90deg, rgba(255,248,220,0), rgba(255,248,220,0.85));
    opacity: 0;
    animation: overfunded-breathe 2.3s ease-in-out infinite;
    pointer-events: none;
}

/* Shake (105-120%): the in-between state, before there is fire. One animation
   does the whole tremble. The old version ran overfunded-pulse and
   overfunded-shake together, both animating transform, so the later one
   silently won and the scale never rendered. Irregular stops rather than a
   ping-pong, so it reads as energy instead of a buzz. */
.progress-overfunded-shake .progress-fill,
.progress-overfunded-shake .sidebar-progress-fill {
    animation: overfunded-shake 0.24s linear infinite;
}

.progress-overfunded-shake .progress-cursor,
.progress-overfunded-shake .sidebar-progress-cursor {
    animation: overfunded-throb 1.15s ease-in-out infinite;
}

@keyframes overfunded-breathe {
    0%, 100% { opacity: 0; }
    50% { opacity: calc(0.6 * var(--intensity, 0.5)); }
}

@keyframes overfunded-throb {
    0%, 100% { transform: translateY(-50%) scale(1); }
    50% { transform: translateY(-50%) scale(calc(1 + 0.22 * var(--intensity, 0.5))); }
}

@keyframes overfunded-shake {
    0%, 100% { transform: translate(0, 0); }
    17% { transform: translate(calc(-1.2px * var(--intensity, 0.5)), calc(0.7px * var(--intensity, 0.5))); }
    33% { transform: translate(calc(0.9px * var(--intensity, 0.5)), calc(-1.1px * var(--intensity, 0.5))); }
    52% { transform: translate(calc(-0.6px * var(--intensity, 0.5)), calc(-0.8px * var(--intensity, 0.5))); }
    71% { transform: translate(calc(1.3px * var(--intensity, 0.5)), calc(0.5px * var(--intensity, 0.5))); }
    88% { transform: translate(calc(-0.9px * var(--intensity, 0.5)), calc(1px * var(--intensity, 0.5))); }
}

/* Flames (120%+): the bar burns at its leading edge, the fire packed into the
   last third and tapering back.

   Three tongue layers at durations chosen to share no common multiple
   (0.53 / 0.79 / 1.13s), so the composite never visibly repeats. None of them use `alternate`: a two-keyframe alternating
   animation is a sine wave, which reads as breathing rather than burning, so
   each runs an irregular multi-stop cycle that closes back on its 0% state.

   The mid layer lives on the bar's own ::after, which paints above the fill
   because it follows the fill in child order.

   Mobile budget: softness comes from wide multi-stop gradient falloff, never
   from filter: blur(). A blurred layer that is also transform-animated has to
   re-rasterise; a soft gradient is one shader pass and free to scale. Nothing
   animates filter or box-shadow either, so all of it is transform and opacity
   only, which the compositor handles without repainting. Same effect on phone
   and desktop, cheap enough not to need a reduced variant. */

/* Colour and scale knobs. The 200%+ tier reuses every layer below this and
   overrides nothing but these knobs. */
.progress-overfunded-flames {
    --flame-core: #fff6d8;
    --flame-hot: #ffc32e;
    --flame-mid: #ff7a33;
    --flame-edge: 224, 27, 61;
    --flame-scale: 1;
    --flame-speed: 1;
    /* --flame-grow runs 0 at 120% to 1 at 200%, set inline by common.js. It
       drives every layer height and this opacity ramp, so the fire opens as a
       flicker at the leading edge and builds from there. */
    --flame-alpha: calc(var(--intensity, 0.5) * (0.45 + 0.55 * var(--flame-grow, 1)));
}

/* White-hot (200%+): the same fire, run hotter, taller and faster. */
.progress-overfunded-whitehot {
    --flame-core: #ffffff;
    --flame-hot: #fff3c4;
    --flame-mid: #ffb02e;
    --flame-edge: 246, 56, 92;
    --flame-scale: 1.45;
    --flame-speed: 0.65;
}

.progress-overfunded-flames .progress-fill,
.progress-overfunded-flames .sidebar-progress-fill {
    position: relative;
    /* The warm half expands as the fire grows, eating into the lagoon rather
       than the other way round: lagoon 40% -> 8% of the bar as grow goes 0 -> 1. */
    background: linear-gradient(90deg,
        var(--color-lagoon) calc(40% - 32% * var(--flame-grow, 1)),
        var(--flame-mid) calc(65% - 25% * var(--flame-grow, 1)),
        var(--flame-hot) calc(85% - 8% * var(--flame-grow, 1)),
        var(--flame-core));
    box-shadow:
        0 1px 3px rgba(0,0,0,0.2),
        0 0 calc(10px * var(--intensity, 0.5)) rgba(255,140,66, calc(0.85 * var(--intensity, 0.5))),
        0 0 calc(28px * var(--intensity, 0.5)) rgba(var(--flame-edge), calc(0.55 * var(--intensity, 0.5)));
}

/* Near tongues: dense, white-hot at the base where they meet the bar. Packed
   into the last third and tapering hard backwards, so the leading edge is
   unmistakably the source.

   Tongues are anchored in px from the box's right edge, not in percentages.
   background-clip is border-box, so a gradient whose falloff runs past the
   layer's own edge is chopped by a hard straight line: the box needs at least
   the widest tongue's x-radius of headroom past the bar. Anchoring in px also
   keeps the fire the same size cluster at the tip whatever the bar's width. */
.progress-overfunded-flames .progress-fill::before,
.progress-overfunded-flames .sidebar-progress-fill::before {
    content: '';
    position: absolute;
    left: 0;
    right: -30px;
    bottom: 4px;
    height: calc((10px + 50px * var(--flame-grow, 1)) * var(--flame-scale));
    background:
        radial-gradient(ellipse 17px 100% at right 30px bottom 0, var(--flame-core), var(--flame-hot) 20%, var(--flame-mid) 42%, rgba(var(--flame-edge),.50) 62%, rgba(var(--flame-edge),.16) 81%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse 13px  74% at right 42px bottom 0, var(--flame-core), var(--flame-hot) 22%, var(--flame-mid) 44%, rgba(var(--flame-edge),.45) 64%, rgba(var(--flame-edge),.14) 82%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse  9px  50% at right 56px bottom 0, var(--flame-hot), var(--flame-mid) 34%, rgba(var(--flame-edge),.42) 58%, rgba(var(--flame-edge),.13) 80%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse  7px  31% at right 72px bottom 0, var(--flame-hot), var(--flame-mid) 36%, rgba(var(--flame-edge),.38) 60%, rgba(var(--flame-edge),.12) 82%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse  5px  18% at right 88px bottom 0, var(--flame-hot), var(--flame-mid) 38%, rgba(var(--flame-edge),.32) 62%, rgba(var(--flame-edge),0) 100%);
    /* Every tongue core sits on this box's bottom edge, so an unfaded boundary
       merges them into a bright slab ending in a hard line across the bar. Fade
       the last few px so the fire meets the bar instead of being cut by it. */
    -webkit-mask-image: linear-gradient(to top, transparent 0, #000 6px);
    mask-image: linear-gradient(to top, transparent 0, #000 6px);
    transform-origin: bottom right;
    animation: flame-lick-near calc(0.53s * var(--flame-speed)) linear infinite;
    pointer-events: none;
}

/* Mid tongues: on the bar itself, painting above the fill. */
.progress-bar.progress-overfunded-flames::after,
.sidebar-progress-bar.progress-overfunded-flames::after {
    content: '';
    position: absolute;
    left: 0;
    right: -32px;
    bottom: 5px;
    height: calc((12px + 64px * var(--flame-grow, 1)) * var(--flame-scale));
    background:
        radial-gradient(ellipse 16px 100% at right 32px bottom 0, var(--flame-core), var(--flame-hot) 24%, var(--flame-mid) 46%, rgba(var(--flame-edge),.42) 66%, rgba(var(--flame-edge),.13) 84%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse 11px  70% at right 46px bottom 0, var(--flame-hot), var(--flame-mid) 32%, rgba(var(--flame-edge),.38) 58%, rgba(var(--flame-edge),.12) 80%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse  8px  44% at right 62px bottom 0, var(--flame-hot), var(--flame-mid) 36%, rgba(var(--flame-edge),.32) 60%, rgba(var(--flame-edge),.10) 82%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse  6px  25% at right 80px bottom 0, var(--flame-hot), var(--flame-mid) 40%, rgba(var(--flame-edge),.26) 64%, rgba(var(--flame-edge),0) 100%);
    /* Every tongue core sits on this box's bottom edge, so an unfaded boundary
       merges them into a bright slab ending in a hard line across the bar. Fade
       the last few px so the fire meets the bar instead of being cut by it. */
    -webkit-mask-image: linear-gradient(to top, transparent 0, #000 6px);
    mask-image: linear-gradient(to top, transparent 0, #000 6px);
    transform-origin: bottom right;
    animation: flame-lick-mid calc(0.79s * var(--flame-speed)) linear infinite;
    pointer-events: none;
}

/* Far tongues: much taller, sparser, softer. Reads as the top of the flame. */
.progress-overfunded-flames .progress-fill::after,
.progress-overfunded-flames .sidebar-progress-fill::after {
    content: '';
    position: absolute;
    left: 0;
    right: -34px;
    bottom: 6px;
    height: calc((14px + 78px * var(--flame-grow, 1)) * var(--flame-scale));
    background:
        radial-gradient(ellipse 15px 100% at right 34px bottom 0, var(--flame-hot), var(--flame-mid) 26%, rgba(var(--flame-edge),.34) 52%, rgba(var(--flame-edge),.11) 76%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse 10px  66% at right 50px bottom 0, var(--flame-hot), var(--flame-mid) 30%, rgba(var(--flame-edge),.28) 54%, rgba(var(--flame-edge),.09) 78%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse  7px  38% at right 68px bottom 0, var(--flame-hot), var(--flame-mid) 34%, rgba(var(--flame-edge),.24) 56%, rgba(var(--flame-edge),.08) 80%, rgba(var(--flame-edge),0) 100%),
        radial-gradient(ellipse  5px  20% at right 88px bottom 0, var(--flame-hot), var(--flame-mid) 38%, rgba(var(--flame-edge),.20) 60%, rgba(var(--flame-edge),0) 100%);
    /* Every tongue core sits on this box's bottom edge, so an unfaded boundary
       merges them into a bright slab ending in a hard line across the bar. Fade
       the last few px so the fire meets the bar instead of being cut by it. */
    -webkit-mask-image: linear-gradient(to top, transparent 0, #000 6px);
    mask-image: linear-gradient(to top, transparent 0, #000 6px);
    transform-origin: bottom right;
    animation: flame-lick-far calc(1.13s * var(--flame-speed)) ease-in-out infinite;
    pointer-events: none;
}

/* The leading-edge dot becomes the white-hot core of the fire. */
.progress-overfunded-flames .progress-cursor,
.progress-overfunded-flames .sidebar-progress-cursor {
    background: var(--flame-core);
    border-color: var(--flame-hot);
    box-shadow:
        0 0 5px var(--flame-hot),
        0 0 calc(14px * var(--intensity, 0.5)) var(--flame-mid),
        0 0 calc(28px * var(--intensity, 0.5)) rgba(var(--flame-edge), 0.65);
    animation: flame-ember calc(0.29s * var(--flame-speed)) linear infinite;
}

@keyframes flame-lick-near {
    0% { transform: scaleY(0.70) scaleX(1) skewX(0deg); opacity: calc(0.72 * var(--flame-alpha, 0.6)); }
    13% { transform: scaleY(1.08) scaleX(0.97) skewX(-4deg); opacity: calc(0.96 * var(--flame-alpha, 0.6)); }
    26% { transform: scaleY(0.84) scaleX(1.02) skewX(3deg); opacity: calc(0.78 * var(--flame-alpha, 0.6)); }
    39% { transform: scaleY(1.26) scaleX(0.94) skewX(-6deg); opacity: var(--flame-alpha, 0.6); }
    52% { transform: scaleY(0.76) scaleX(1.01) skewX(2deg); opacity: calc(0.70 * var(--flame-alpha, 0.6)); }
    64% { transform: scaleY(1.14) scaleX(0.96) skewX(-3deg); opacity: calc(0.92 * var(--flame-alpha, 0.6)); }
    78% { transform: scaleY(0.88) scaleX(1.03) skewX(5deg); opacity: calc(0.80 * var(--flame-alpha, 0.6)); }
    91% { transform: scaleY(1.02) scaleX(0.98) skewX(-1deg); opacity: calc(0.86 * var(--flame-alpha, 0.6)); }
    100% { transform: scaleY(0.70) scaleX(1) skewX(0deg); opacity: calc(0.72 * var(--flame-alpha, 0.6)); }
}

@keyframes flame-lick-mid {
    0% { transform: scaleY(0.92) translateX(0) skewX(2deg); opacity: calc(0.50 * var(--flame-alpha, 0.6)); }
    17% { transform: scaleY(1.24) translateX(-2px) skewX(-5deg); opacity: calc(0.75 * var(--flame-alpha, 0.6)); }
    31% { transform: scaleY(0.80) translateX(1.5px) skewX(4deg); opacity: calc(0.44 * var(--flame-alpha, 0.6)); }
    48% { transform: scaleY(1.34) translateX(-1px) skewX(-7deg); opacity: calc(0.82 * var(--flame-alpha, 0.6)); }
    63% { transform: scaleY(0.86) translateX(2px) skewX(3deg); opacity: calc(0.50 * var(--flame-alpha, 0.6)); }
    81% { transform: scaleY(1.16) translateX(-1.5px) skewX(-4deg); opacity: calc(0.68 * var(--flame-alpha, 0.6)); }
    100% { transform: scaleY(0.92) translateX(0) skewX(2deg); opacity: calc(0.50 * var(--flame-alpha, 0.6)); }
}

@keyframes flame-lick-far {
    0% { transform: scaleY(0.78) translateX(1px) skewX(-3deg); opacity: calc(0.30 * var(--flame-alpha, 0.6)); }
    21% { transform: scaleY(1.18) translateX(-2px) skewX(6deg); opacity: calc(0.56 * var(--flame-alpha, 0.6)); }
    37% { transform: scaleY(0.68) translateX(2.5px) skewX(-2deg); opacity: calc(0.26 * var(--flame-alpha, 0.6)); }
    55% { transform: scaleY(1.32) translateX(-3px) skewX(8deg); opacity: calc(0.62 * var(--flame-alpha, 0.6)); }
    72% { transform: scaleY(0.74) translateX(1.5px) skewX(-4deg); opacity: calc(0.32 * var(--flame-alpha, 0.6)); }
    88% { transform: scaleY(1.10) translateX(-1px) skewX(5deg); opacity: calc(0.50 * var(--flame-alpha, 0.6)); }
    100% { transform: scaleY(0.78) translateX(1px) skewX(-3deg); opacity: calc(0.30 * var(--flame-alpha, 0.6)); }
}

@keyframes flame-ember {
    0% { transform: translateY(-50%) scale(1); }
    27% { transform: translateY(-50%) scale(calc(1 + 0.30 * var(--intensity, 0.5))); }
    48% { transform: translateY(-50%) scale(calc(1 + 0.08 * var(--intensity, 0.5))); }
    71% { transform: translateY(-50%) scale(calc(1 + 0.36 * var(--intensity, 0.5))); }
    100% { transform: translateY(-50%) scale(1); }
}

/* Keep the colour and glow of every tier, drop the motion. Catch-all rather than
   a list, so any layer added later is covered without touching this block. */
@media (prefers-reduced-motion: reduce) {
    [class*="progress-overfunded"],
    [class*="progress-overfunded"]::before,
    [class*="progress-overfunded"]::after,
    [class*="progress-overfunded"] *,
    [class*="progress-overfunded"] *::before,
    [class*="progress-overfunded"] *::after {
        animation: none !important;
    }

    /* Tongues get their opacity from the animation, so pin them mid-cycle. */
    .progress-overfunded-flames .progress-fill::before,
    .progress-overfunded-flames .sidebar-progress-fill::before {
        opacity: calc(0.85 * var(--intensity, 0.5));
    }

    .progress-bar.progress-overfunded-flames::after,
    .sidebar-progress-bar.progress-overfunded-flames::after {
        opacity: calc(0.6 * var(--intensity, 0.5));
    }

    .progress-overfunded-flames .progress-fill::after,
    .progress-overfunded-flames .sidebar-progress-fill::after {
        opacity: calc(0.45 * var(--intensity, 0.5));
    }

}